«Музыка» цифровой шины с интерфейсом UART

hwtjx4znykkrp5_poz3bx1xfpae.jpeg
#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;
        }
    }


© Geektimes