/****************************************************************************
* Copyright (C) 2015 Dimok
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
****************************************************************************/
#ifndef _AXSOUND_H_
#define _AXSOUND_H_
#include
#include
class Voice {
public:
enum VoicePriorities {
PRIO_MIN = 1,
PRIO_MAX = 31
};
enum VoiceStates {
STATE_STOPPED,
STATE_START,
STATE_PLAYING,
STATE_STOP,
};
Voice(int32_t prio)
: state(STATE_STOPPED) {
lastLoopCounter = 0;
nextBufferSize = 0;
voice = AXAcquireVoice(prio, 0, 0);
if (voice) {
AXVoiceBegin(voice);
AXSetVoiceType(voice, 0);
setVolume(0x80000000);
AXVoiceDeviceMixData mix[6];
memset(mix, 0, sizeof(mix));
mix[0].bus[0].volume = 0x8000;
mix[0].bus[0].delta = 0;
mix[1].bus[0].volume = 0x8000;
mix[1].bus[0].delta = 0;
AXSetVoiceDeviceMix(voice, 0, 0, mix);
AXSetVoiceDeviceMix(voice, 1, 0, mix);
AXVoiceEnd(voice);
}
}
~Voice() {
if (voice) {
AXFreeVoice(voice);
}
}
void play(const uint8_t *buffer, uint32_t bufferSize, const uint8_t *nextBuffer, uint32_t nextBufSize, uint16_t format, uint32_t sampleRate) {
if (!voice)
return;
memset(&voiceBuffer, 0, sizeof(voiceBuffer));
voiceBuffer.data = buffer;
voiceBuffer.dataType = format;
voiceBuffer.loopingEnabled = (nextBuffer == NULL) ? 0 : 1;
voiceBuffer.currentOffset = 0;
voiceBuffer.endOffset = (bufferSize >> 1) - 1;
voiceBuffer.loopOffset = ((nextBuffer - buffer) >> 1);
nextBufferSize = nextBufSize;
// TODO: handle support for 3.1.0 with dynamic libs instead of static linking it
//uint32_t samplesPerSec = (AXGetInputSamplesPerSec != 0) ? AXGetInputSamplesPerSec() : 32000;
uint32_t samplesPerSec = AXGetInputSamplesPerSec();
memset(&ratioBits, 0, sizeof(ratioBits));
ratioBits.ratio = (uint32_t) (0x00010000 * ((float) sampleRate / (float) samplesPerSec));
AXSetVoiceOffsets(voice, &voiceBuffer);
AXSetVoiceSrc(voice, &ratioBits);
AXSetVoiceSrcType(voice, 1);
AXSetVoiceState(voice, 1);
}
void stop() {
if (voice)
AXSetVoiceState(voice, 0);
}
void setVolume(uint32_t vol) {
if (voice) {
AXVoiceVeData data;
data.volume = vol >> 16;
data.delta = vol & 0xFFFF;
AXSetVoiceVe(voice, &data);
}
}
void setNextBuffer(const uint8_t *buffer, uint32_t bufferSize) {
voiceBuffer.loopOffset = ((buffer - (const uint8_t *) voiceBuffer.data) >> 1);
nextBufferSize = bufferSize;
AXSetVoiceLoopOffset(voice, voiceBuffer.loopOffset);
}
bool isBufferSwitched() {
uint32_t loopCounter = AXGetVoiceLoopCount(voice);
if (lastLoopCounter != loopCounter) {
lastLoopCounter = loopCounter;
AXSetVoiceEndOffset(voice, voiceBuffer.loopOffset + (nextBufferSize >> 1) - 1);
return true;
}
return false;
}
uint32_t getInternState() const {
if (voice)
return ((uint32_t *) voice)[1];
return 0;
}
uint32_t getState() const {
return state;
}
void setState(uint32_t s) {
state = s;
}
void *getVoice() const {
return voice;
}
private:
AXVoice *voice;
AXVoiceSrc ratioBits;
AXVoiceOffsets voiceBuffer;
uint32_t state;
uint32_t nextBufferSize;
uint32_t lastLoopCounter;
};
#endif // _AXSOUND_H_