«Музыка» цифровой шины с интерфейсом UART
#include "SoundsDigitalBus.h"
#if SDB_WITH_OPENAL == 1
// обработчики ошибок
ALboolean sdb::CheckALCError(void) {
ALenum ErrCode;
ErrCode = alcGetError(openAlDevice);
if (ErrCode != ALC_NO_ERROR) {
return AL_FALSE;
}
return AL_TRUE;
}
ALboolean sdb::CheckALError(void) {
ALenum ErrCode;
if ((ErrCode = alGetError()) != AL_NO_ERROR) {
return AL_FALSE;
}
return AL_TRUE;
}
// инициализация OpenAL
char sdb::initOpenAL(void) {
ALfloat SourcePos[] = {0.0, 0.0, 0.0};
ALfloat SourceVel[] = {0.0, 0.0, 0.0};
// Позиция слушателя.
ALfloat ListenerPos[] = { 0.0, 0.0, 0.0 };
// Скорость слушателя.
ALfloat ListenerVel[] = { 0.0, 0.0, 0.0 };
// Ориентация слушателя. (Первые 3 элемента – направление «на», последние 3 – «вверх»)
ALfloat ListenerOri[] = { 0.0, 0.0, -1.0, 0.0, 1.0, 0.0 };
#if SDB_WITH_DEBUG_MODE == 1
printf("alcOpenDevice\n");
#endif
openAlDevice = alcOpenDevice(0); // open default device
if (openAlDevice != 0) {
openAlContext = alcCreateContext(openAlDevice,0); // create context
if (openAlContext != 0) {
#if SDB_WITH_DEBUG_MODE == 1
printf("alcMakeContextCurrent\n");
#endif
alcMakeContextCurrent(openAlContext); // set active context
} else {
#if SDB_WITH_DEBUG_MODE == 1
printf("Error context\n");
#endif
return 0;
}
} else {
#if SDB_WITH_DEBUG_MODE == 1
printf("Error Open Device\n");
#endif
return 0;
}
// Позиция
alListenerfv(AL_POSITION, ListenerPos);
// Скорость
alListenerfv(AL_VELOCITY, ListenerVel);
// Ориентация
alListenerfv(AL_ORIENTATION, ListenerOri);
alGenSources(1, &openAlSource);
if (!CheckALError())
return false;
alSourcef (openAlSource, AL_PITCH, 1.0f);
alSourcef (openAlSource, AL_GAIN, 1.0f);
alSourcefv(openAlSource, AL_POSITION, SourcePos);
alSourcefv(openAlSource, AL_VELOCITY, SourceVel);
alSourcei (openAlSource, AL_LOOPING, AL_FALSE);
alSourcei(openAlSource, AL_LOOPING, AL_FALSE);
openAlnBuf = 0;
return 1;
}
void sdb::destroyOpenAL(void) {
alSourceStop(openAlSource);
// Выключаем текущий контекст
alcMakeContextCurrent(0);
// Уничтожаем контекст
alcDestroyContext(openAlContext);
// Закрываем звуковое устройство
alcCloseDevice(openAlDevice);
}
void sdb::playOpenAlSound(void) {
alSourcePlay(openAlSource);
}
void sdb::stopOpenAlSound(void) {
alSourceStop(openAlSource);
}
void sdb::closeOpenAlSound(void) {
alSourceStop(openAlSource);
if (alIsSource(openAlSource))
alDeleteSources(1, &openAlSource);
}
int sdb::getBufferStatusOpenAl(void) {
int processed = 0;
if (openAlnBuf == 0)
return 1;
alGetSourcei(openAlSource, AL_BUFFERS_PROCESSED, &processed);
CheckALError();
#if SDB_WITH_DEBUG_MODE == 1
printf("getBufferStatus: %d\n",processed);
#endif
if (processed != 0) {
return processed;
}
return 0;
}
void sdb::setBufferOpenAl(signed short* buf, unsigned long siz) {
int processed = 0;
ALuint BufID = 0;
#if _OPENAL_FORMAT == AL_FORMAT_MONO16
siz = siz*2;
#endif // _OPENAL_FORMAT
#if _OPENAL_FORMAT == AL_FORMAT_STEREO16
siz = siz*4;
#endif // _OPENAL_FORMAT
#if _OPENAL_FORMAT == AL_FORMAT_STEREO8
siz = siz*2;
#endif // _OPENAL_FORMAT
// Получаем количество отработанных буферов
alGetSourcei(openAlSource, AL_BUFFERS_PROCESSED, &processed);
CheckALError();
//если отработанных буферов нет, есть новые данные и число буферов не превысило максимума
if ((processed == 0) && (openAlnBuf < OPENAL_NUM_OF_DYNBUF)) {
openAlnBuf++; //увеличиваем число буферов
alGenBuffers(1, &BufID); //создаем новый буфер
alBufferData(BufID,SDB_OPENAL_FORMAT,buf,siz,SDB_OPENAL_FREQUENCY); //загружаем данные в новый буфер
alSourceQueueBuffers(openAlSource, 1, &BufID); //добавляем буфер в очередь
if (openAlnBuf == 1)
alSourcePlay(openAlSource);
} else {
#if SDB_WITH_DEBUG_MODE == 1
printf("processed: %d openAlnBuf: %d\n",processed,openAlnBuf);
#endif
// ждем, когда будет обработан хотя бы один буфер
while (getBufferStatusOpenAl() == 0);
// убираем из очереди буфер
alSourceUnqueueBuffers(openAlSource, 1, &BufID);
CheckALError();
// загружаем новый буфер
alBufferData(BufID,SDB_OPENAL_FORMAT,buf,siz,SDB_OPENAL_FREQUENCY);
CheckALError();
alSourceQueueBuffers(openAlSource, 1, &BufID);
CheckALError();
}
}
// функция очищяет все буферы по мере их опустошения, и останавливает проигрывание
// возвращает 1 если еще есть не пустые буферы
char sdb::updateOpenAl(void) {
int processed = 0;
ALuint BufID;
// Получаем количество отработанных буферов
alGetSourcei(openAlSource, AL_BUFFERS_PROCESSED, &processed);
#if SDB_WITH_DEBUG_MODE == 1
printf("updateOpenAl: %d\n",processed);
#endif
// если обработаны все буферы
if (openAlnBuf == processed) {
// Если таковые существуют то
while (processed--) {
// Исключаем их из очереди
alSourceUnqueueBuffers(openAlSource, 1, &BufID);
if (!CheckALError())
return 0;
alDeleteBuffers(1, &BufID);
openAlnBuf--;
}
alSourceStop(openAlSource);
#if SDB_WITH_DEBUG_MODE == 1
printf("alSourceStop: %d\n",openAlnBuf);
#endif
return 0;
}
return 1;
}
#endif
// задержка для шин данных. тут генерируется звук
void sdb::busDelay(unsigned short us) {
double Time = (double)us/1000000.0;
double locTime = allTime;
char isFlag = 0;
// создаем wav файл, если он не был создан ранее
if (isCreateWavFileFlag == 0) {
if (isWavFileOutput == 1) {
isFlag = createWavFile(wavFileName,SDB_FREQUENCY,SDB_BIT,SDB_CANNEL);
// если файл был успешно открыт, то ставим флаг
if (isFlag == 1)
isCreateWavFileFlag = 1;
}
if (isAudioOutput == 1) {
initOpenAL();
if (isWavFileOutput == 0)
isCreateWavFileFlag = 1;
}
}
allTime = allTime + Time;
// если файл был открыт
if (isCreateWavFileFlag == 1)
// начинаем делать сэмплы аудиоданных
while(locTime < allTime) {
if (switchBuffer == 0) {
if (posBufferOne >= SDB_BUFFER_MAX) {
posBufferOne = 0;
posBufferTwo = 0;
busDataTwo[posBufferTwo++] = busState;
isBufferOneFlag = 1;
switchBuffer = 1;
if (isWavFileOutput == 1)
writeDataBlockWavFile(busDataOne,SDB_BUFFER_MAX);
#if SDB_WITH_OPENAL == 1
if (isAudioOutput == 1)
setBufferOpenAl(busDataOne,SDB_BUFFER_MAX);
#endif
} else {
busDataOne[posBufferOne++] = busState;
}
} else
if (switchBuffer == 1) {
if (posBufferTwo >= SDB_BUFFER_MAX) {
posBufferOne = 0;
posBufferTwo = 0;
busDataOne[posBufferOne++] = busState;
isBufferTwoFlag = 1;
switchBuffer = 0;
if (isWavFileOutput == 1)
writeDataBlockWavFile(busDataTwo,SDB_BUFFER_MAX);
#if SDB_WITH_OPENAL == 1
if (isAudioOutput == 1)
setBufferOpenAl(busDataTwo,SDB_BUFFER_MAX);
#endif
} else {
busDataTwo[posBufferTwo++] = busState;
}
}
posAllBuffer++;
locTime = locTime + dTime;
}
}
char sdb::createWavFile(char * filename,unsigned long sampleRate,unsigned short bitsPerSample, unsigned short numChannels) {
char type[4];
const unsigned long subchunk1Size = 16;
unsigned long byteRate;
const unsigned short audioFormat = 1;
unsigned short len_str = 0;
char str_filename[512] = {0};
unsigned short i;
// количество байт в одном сэмле одного канала
wavLenDataType = bitsPerSample/8;
wavSubchunk2Size = 0;
wavChunkSize = wavSubchunk2Size + 44 - 8;
// Количество байт на одну выборку
wavBlockAlign = bitsPerSample / (8 * numChannels);
//Количество байт, переданных за секунду воспроизведения.
byteRate = sampleRate * wavBlockAlign;
strcpy(str_filename,filename);
len_str = strlen(str_filename);
if (len_str < 4)
return 0;
// проверка имени файла на наличие расширения .wav
i = 0;
while(i < len_str) {
if (filename[i] == '.' && (i + 3) < len_str) {
if (((filename[i + 1] == 'w')
&& (filename[i + 2] == 'a')
&& (filename[i + 3] == 'v'))
||
((filename[i + 1] == 'W')
&& (filename[i + 2] == 'A')
&& (filename[i + 3] == 'V'))) {
// если имя имеет расширение wav
break;
} else {
if ((i + 3) >= 512)
return 0;
filename[i + 1] = 'w';
filename[i + 2] = 'a';
filename[i + 3] = 'v';
len_str = i + 4;
break;
}
} else
if ((i + 1) == len_str) {
if ((i + 3) >= 512)
return 0;
filename[i + 1] = '.';
filename[i + 2] = 'w';
filename[i + 3] = 'a';
filename[i + 4] = 'v';
len_str = i + 5;
break;
}
i++;
}
type[0] = filename[len_str - 4];
type[1] = filename[len_str - 3];
type[2] = filename[len_str - 2];
type[3] = filename[len_str - 1];
if (type[0]!='.'||type[1]!='w'||type[2]!='a'||type[3]!='v') {
if (type[0]!='.'||type[1]!='W'||type[2]!='A'||type[3]!='V') {
return 0;
}
}
fpSave=fopen(str_filename,"wb");
type[0]='R';
type[1]='I';
type[2]='F';
type[3]='F';
fwrite(&type,sizeof(char),4,fpSave);
fwrite(&wavChunkSize,sizeof(unsigned long),1,fpSave);
type[0]='W';
type[1]='A';
type[2]='V';
type[3]='E';
fwrite(&type,sizeof(char),4,fpSave);
type[0]='f';
type[1]='m';
type[2]='t';
type[3]=' ';
fwrite(&type,sizeof(char),4,fpSave);
fwrite(&subchunk1Size,sizeof(unsigned long),1,fpSave);
fwrite(&audioFormat,sizeof(unsigned short),1,fpSave);
fwrite(&numChannels,sizeof(unsigned short),1,fpSave);
fwrite(&sampleRate,sizeof(unsigned long),1,fpSave);
fwrite(&byteRate,sizeof(unsigned long),1,fpSave);
fwrite(&wavBlockAlign,sizeof(unsigned short),1,fpSave);
// Количество бит в сэмпле. Так называемая "глубина” или точность звучания. 8 бит, 16 бит и т.д.
fwrite(&bitsPerSample,sizeof(unsigned short),1,fpSave);
type[0]='d';
type[1]='a';
type[2]='t';
type[3]='a';
// subchunk2Id
// Содержит символы "data” (0x64617461 в big-endian представлении)
fwrite(&type, sizeof(char), 4,fpSave);
wavSubchunk2Size = 0;
//Количество байт в области данных.
fwrite(&wavSubchunk2Size, sizeof(unsigned long), 1,fpSave);
return 1;
}
void sdb::writeSampleWavFile(void* data) {
fwrite(data, wavLenDataType, wavBlockAlign, fpSave);
wavSubchunk2Size = wavSubchunk2Size + wavLenDataType*wavBlockAlign;
}
void sdb::writeDataBlockWavFile(void* data, unsigned long len) {
fwrite(data, wavLenDataType, len, fpSave);
wavSubchunk2Size = wavSubchunk2Size + len*wavLenDataType;
}
// данная функция закрывает аудиофайл и записывает количесвто байт данных.
void sdb::closeWavFile(void) {
wavChunkSize = wavSubchunk2Size + 44 - 8;
fseek(fpSave,4,SEEK_SET);
fwrite(&wavChunkSize,4,1,fpSave);
fseek(fpSave,40,SEEK_SET);
fwrite(&wavSubchunk2Size,4,1,fpSave);
fclose(fpSave);
}
// конструктор
sdb::sdb(void) {
openAlnBuf = 0;
wavBlockAlign = 0;
wavSubchunk2Size = 0;
wavChunkSize = 0;
wavLenDataType = 0;
fpSave = NULL;
strcat(wavFileName,SDB_WAV_FILE_NAME);
dTime = 1.0/(double)SDB_OPENAL_FREQUENCY;
allTime = 0.0;
// переключатель буферов на первом буфере
switchBuffer = 0;
// позиция в буферах (сумма)
posAllBuffer = 0;
// позиции в буфере обнуляем
posBufferOne = 0;
posBufferTwo = 0;
isBufferOneFlag = 0;
isBufferTwoFlag = 0;
isCreateWavFileFlag = 0;
busState = SDB_MAX_DATA;
uartSetBaudrate(SDB_UART_BAUDRATE);
uartSetBit(SDB_UART_BIT);
uartSetStopBit(SDB_UART_STOP_BIT);
uartSetParityBit(SDB_UART_PARITY);
recordOn();
playAudioOn();
}
// деструктор
sdb::~sdb() {
if (isCreateWavFileFlag == 1) {
if (posBufferOne > 0) {
if (isWavFileOutput == 1)
writeDataBlockWavFile(busDataOne,posBufferOne);
#if SDB_WITH_OPENAL == 1
if (isAudioOutput == 1)
setBufferOpenAl(busDataOne,posBufferTwo);
#endif
} else
if (posBufferTwo > 0) {
if (isWavFileOutput == 1)
writeDataBlockWavFile(busDataTwo,posBufferTwo);
#if SDB_WITH_OPENAL == 1
if (isAudioOutput == 1)
setBufferOpenAl(busDataTwo,posBufferTwo);
#endif
}
if (isWavFileOutput == 1)
closeWavFile();
isCreateWavFileFlag = 0;
#if SDB_WITH_OPENAL == 1
if (isAudioOutput == 1) {
while (1) {
// Ждем, когда звук проиграет до конца
if (updateOpenAl() == 0)
break;
}
closeOpenAlSound();
destroyOpenAL();
}
#endif
}
}
// функция передает данные по шине one wire
void sdb::oneWireSendByte(unsigned char data) {
for (register unsigned char i = 0; i < 8; i++) {
if((data & (1 << i)) == 1 << i) {
busState = 0;
busDelay(12);
busState = SDB_MAX_DATA;
busDelay(65);
} else {
busState = 0;
busDelay(65);
busState = SDB_MAX_DATA;
busDelay(12);
}
}
busState = SDB_MAX_DATA;
}
// функция передает один байт по шине uart
void sdb::uartSendByte(unsigned char data) {
unsigned short pBit = 0; // переменная для бита четности
// старт бит
busState = SDB_MAX_DATA;
busDelay(uartT);
busState = -SDB_MAX_DATA;
// данные
for (register unsigned char i = 0; i < 8; i++) {
if((data & (1< SDB_UART_BAUDRATE_MAX)
baudrate = SDB_UART_BAUDRATE_MAX;
uartBaudrate = baudrate;
uartT = 1000000 / baudrate;
}
void sdb::uartSetBit(unsigned char bit) {
if (bit > 32)
bit = 32;
if (bit == 0)
bit = 1;
if (bit < 8)
bit = 8;
uartBit = bit;
}
void sdb::uartSetStopBit(unsigned char bit) {
if (bit == 0)
bit = 1;
uartStopBit = bit;
}
void sdb::uartSetParityBit(unsigned char state) {
if (state > 1)
state = 1;
uartParityBit = state;
}
//функция определяет есть ли устройство на шине
void sdb::oneWireReset(void) {
busState = SDB_MAX_DATA;
busDelay(100);
busState = 0;//логический "0"
busDelay(485);//ждем минимум 480мкс
busState = SDB_MAX_DATA;
busDelay(65);//ждем минимум 60мкс и смотрим что на шине
busState = 0;//логический "0"
busDelay(400);
busState = SDB_MAX_DATA;
busDelay(100);
}
// функция останавливает шину 1-wire
void sdb::oneWireStop(void) {
if (isCreateWavFileFlag == 1) {
if (posBufferOne > 0) {
if (isWavFileOutput == 1)
writeDataBlockWavFile(busDataOne,posBufferOne);
#if SDB_WITH_OPENAL == 1
if (isAudioOutput == 1)
setBufferOpenAl(busDataOne,posBufferOne);
#endif
} else
if (posBufferTwo > 0) {
if (isWavFileOutput == 1)
writeDataBlockWavFile(busDataTwo,posBufferTwo);
#if SDB_WITH_OPENAL == 1
if (isAudioOutput == 1)
setBufferOpenAl(busDataTwo,posBufferTwo);
#endif
}
#if SDB_WITH_OPENAL == 1
while (1) {
// Ждем, когда звук проиграет до конца
if (updateOpenAl() == 0)
break;
}
closeOpenAlSound();
destroyOpenAL();
#endif
if (isWavFileOutput == 1)
closeWavFile();
isCreateWavFileFlag = 0;
}
}
void sdb::uartStop(void) {
if (isCreateWavFileFlag == 1) {
if (posBufferOne > 0) {
if (isWavFileOutput == 1)
writeDataBlockWavFile(busDataOne,posBufferOne);
#if SDB_WITH_OPENAL == 1
if (isAudioOutput == 1)
setBufferOpenAl(busDataOne,posBufferOne);
#endif
} else
if (posBufferTwo > 0) {
if (isWavFileOutput == 1)
writeDataBlockWavFile(busDataTwo,posBufferTwo);
#if SDB_WITH_OPENAL == 1
if (isAudioOutput == 1)
setBufferOpenAl(busDataTwo,posBufferTwo);
#endif
}
#if SDB_WITH_OPENAL == 1
if (isAudioOutput == 1) {
while (1) {
// Ждем, когда звук проиграет до конца
if (updateOpenAl() == 0)
break;
}
closeOpenAlSound();
destroyOpenAL();
}
#endif
if (isWavFileOutput == 1)
closeWavFile();
isCreateWavFileFlag = 0;
}
}
void sdb::setWavFileName(char* filename) {
strcat(wavFileName,filename);
}
void sdb::playAudioOn(void) {
if (isCreateWavFileFlag == 0)
isAudioOutput = 1;
}
void sdb::playAudioOff(void) {
if (isCreateWavFileFlag == 0)
isAudioOutput = 0;
}
void sdb::recordOn(void) {
if (isCreateWavFileFlag == 0)
isWavFileOutput = 1;
}
void sdb::recordOff(void) {
if (isCreateWavFileFlag == 0) {
if (isAudioOutput == 1)
isWavFileOutput = 0;
else
isWavFileOutput = 1;
}
}