Вам было когда нибудь интересно, как «звучит» электрический сигнал, проходящий по дорожкам печатных плат между микросхем, транзисторов, диодов, резисторов и конденсаторов? Один из вариантов такого сигнала в современной электронике — цифровая шина, а один из популярных интерфейсов для обмена данных по шине — UART. Он часто используется в микроконтроллерах для связи с компьютером или какой либо переферией. Чтобы получить звук на шине, вовсе не обязательно подключать динамик с усилителем к реальной шине с UARTом, ведь ее можно симулировать в программе. Вам интересно, какие звуки в итоге получились, или нужна программа, чтобы самому поэкспериментировать? Тогда прошу под кат.
Слушаем файлы на шине с UART
Какой звук получится, если передавать файлы через UART? Вот некоторые примеры, полученные при следующих параметрах UART:
- Скорость 115200 бод
- Разрядность 8 бит
- Бит проверки на четность: отсутствует
- Длина стоп бита: 1
Звук игры Сталкер Тень Чернобыля (файл XR_3DA.exe, в самом конце трека, начиная с 2:36, есть мелодия).
Звук текста и кода статьи про синтезатор речи (сама статья тут).
Как звучит фотография «Лены»?
Получился просто шум.
Звук книги «Энтропия и прогноз времянных рядов в теории динамических систем» в pdf формате.
Звук прошивки микроконтроллера серии Atmega для wav плеера.
Для чего это можно использовать?
Теоретически, может быть такая информация в виде текста, или картинки, или видео, или в виде программы, которая будет иметь не только функциональный смысл или эстетическую значимость, но также и «красивый» звук цифровой шины, тогда это получается некая «цифровая» поэзия. Также можно разнообразить сэмплы для дабстепа Вообще, на мой взгляд, слушать звуки цифровой шины примерно так же интересно, как слушать шум радиоволн на коротких волнах, в общем на любителя.
Как это работает или немного про UART
Что такое UART можно почитать на википедии. UART очень легко симулировать в программе. По сути необходимо лишь уметь создавать перепад сигнала от 0 до 1 и обратно (в случае WAV файла с разрядностью 16 бит, это значения от -A до +A, где A это ампилутда сигнала) и записывать его в звуковой файл. Интерфейс UART функционирует примерно так: после стартового бита, который равен логическому «нулю», нужно выставлять уровень в зависимости от предоставленных данных, от младшего бита к старшему. Далее идет бит четности, который можно не использовать. Под конец сообщения ставится стоп бит (логическая «единица»), длина которого может быть разной. Пример кода можно посмотреть в исходниках, которые есть в конце статьи. Подробнее про UART можно посмотреть в сети, материала очень много. UART можно использовать не по назначению, например как ШИМ, а в нашем случае это означает, что теоретически можно даже передать полноценный звуковой сигнал сразу на динамик, как это делается в wav плеерах на микроконтроллере. Однако, я скорее предлагаю использовать его как генератор меандра. Частоту тона и фазу сигнала при этом можно предоставлять в виде бит данных, например 00001111 создаст меандр, период которого будет равен 10-ти периодам времени передачи одного бита (так как в данном случае есть еще стартовый бит, равный 0, и стоповый бит, равный 1). Из-за стартового и стопового бита не все периоды меандров получится передать, например в таком случае 01100110, так как по сути мы будем слушать такую последовательность на шине 0011001101. Если использовать высокую скорость передачи данных, например 115200 бод, то имеет смысл создавать слышимые звуковые частоты, растянув периоды меадров на несколько байт.
...
По данной ссылке можно скачать программу для преобразования файла в звук шины UART. Также есть версия с использованием OpenAL, чтобы воспроизводить звук в процессе работы программы, вот ссылка.
Исходный код программы предоставлен ниже:
#ifndef SOUNDS_DIGITAL_BUS_H_INCLUDED
#define SOUNDS_DIGITAL_BUS_H_INCLUDED
#define SDB_WAV_FILE_NAME "sdb_output.wav"
#define SDB_UART_BIT 8
#define SDB_UART_PARITY 0
#define SDB_UART_STOP_BIT 1
#define SDB_UART_BAUDRATE 9600
#define SDB_UART_BAUDRATE_MAX 921600
/// максимальное значение (амплитуда) сэмпла аудио
#define SDB_MAX_DATA 30000
/// каналов в аудио
#define SDB_CANNEL 1
/// кол-во бит (разрешение) аудио
#define SDB_BIT 16
/// частота дискретизации аудио
#define SDB_FREQUENCY 96000
/// Количество буферов в очереди OpenAL
#define OPENAL_NUM_OF_DYNBUF 32
/// Настройки OpenAL
#define SDB_OPENAL_BIT SDB_BIT
#define SDB_OPENAL_CANNEL SDB_CANNEL
#define SDB_OPENAL_FREQUENCY SDB_FREQUENCY
#define SDB_OPENAL_FORMAT AL_FORMAT_MONO16
/// Количество байт в буфере
#define SDB_BUFFER_MAX 4800
/// использовать OpenAL для вывода аудио (если Да, то выставить 1)
#define SDB_WITH_OPENAL 1
/// режим отладки (если Да, то выставить 1)
#define SDB_WITH_DEBUG_MODE 0
#if SDB_WITH_OPENAL == 1
// Подключение библиотеки OpenAL Для вывода звука
#include <openal/al.h>
#include <openal/alc.h>
#endif
#if SDB_WITH_DEBUG_MODE == 1
// Для режима отладки
#include <stdio.h>
#include <locale.h>
#endif
//для работы с файлами
#include <stdio.h>
//для работы со строками
#include <string.h>
class sdb {
private:
#if SDB_WITH_OPENAL == 1
// работа с openAl взята из библиотеки
// синтезатора речи speesy
ALCdevice* openAlDevice;
ALCcontext* openAlContext;
ALuint openAlSource;
signed char openAlnBuf; //количество буферов
#endif
// ----------------------------------------
// для записи в WAV файл
FILE *fpSave;
unsigned short wavBlockAlign;
unsigned long wavSubchunk2Size;
unsigned long wavChunkSize;
unsigned char wavLenDataType;
// ----------------------------------------
// для генерирования звуков шин данных
double dTime; // длина времени одного сэмпла, в с.
double allTime; // общее время трека
short busState; // состояние шины (уровень сигнала)
short busDataOne[SDB_BUFFER_MAX]; // буферы, куда пишем wav
short busDataTwo[SDB_BUFFER_MAX];
unsigned char switchBuffer; // переключатель между буферами
unsigned int posBufferOne, posBufferTwo; // позиция в буферах
unsigned int posAllBuffer; // общая позиция
char wavFileName[512]; // имя wav файла
char isCreateWavFileFlag; // флаг, что wav файл был создан
char isBufferOneFlag; // флаг, что готов первый буфер
char isBufferTwoFlag;
unsigned int uartBaudrate; // скорость UART в бод
unsigned int uartT;
unsigned char uartBit; // количество бит
unsigned char uartStopBit; // количество стоп бит
unsigned char uartParityBit;
unsigned char isAudioOutput;
unsigned char isWavFileOutput;
#if SDB_WITH_OPENAL == 1
ALboolean CheckALCError(void);
ALboolean CheckALError(void);
char initOpenAL(void);
void destroyOpenAL(void);
void playOpenAlSound(void);
void stopOpenAlSound(void);
void closeOpenAlSound(void);
int getBufferStatusOpenAl(void);
void setBufferOpenAl(signed short *buf,unsigned long siz);
char updateOpenAl(void);
#endif
char createWavFile(char * filename,unsigned long sampleRate,unsigned short bitsPerSample, unsigned short numChannels);
void writeSampleWavFile(void *data);
void writeDataBlockWavFile(void *data,unsigned long len);
void closeWavFile(void);
void busDelay(unsigned short us);
public:
sdb(void);
~sdb(void);
/** @brief функция генерирует звук одного байта шины 1-wire
@param[in] data байт для отправки по 1-wire
*/
void oneWireSendByte(unsigned char data);
/** @brief генерирует звук сброса шины 1-wire
*/
void oneWireReset(void);
/** @brief останаливает работу шины 1- wire
*/
void oneWireStop(void);
/** @brief передает один байт по шине UART
@param[in] data один символ шины UART
*/
void uartSendByte(unsigned char data);
/** @brief передает данные по шине UART
@param[in] data один символ шины UART
*/
void uartSend(unsigned long data);
/** @brief устанавливает скорость UART
@param[in] baudrate скорость шины UART
*/
void uartSetBaudrate(unsigned long baudrate);
/** @brief устанавливает количество отправляемых бит
@param[in] bit количество бит, отправляемых шиной UART за один раз
*/
void uartSetBit(unsigned char bit);
/** @brief устанавливает количество стоп битов
Данная функция устаналивает количество стоп битов.
Минимальное значение стоп бита 1.
@param[in] bit количество стоп битов
*/
void uartSetStopBit(unsigned char bit);
/** @brief устанавливает бит четности
Данная функция устанавливает флаг использования в UART бита четности.
Если передать 1, то бит четности будет задействован, если передать 0, то
передача данных по UART будет идти без бита четности.
@param[in] state флаг, включающий бит четности.
*/
void uartSetParityBit(unsigned char state);
/** @brief функция останавливает передачу UART
Данная функция завершает работу UART, сохраняет или воспроизводит оставшиеся байты.
Функцию вызывать обязательно в конце передачи данных по шине.
*/
void uartStop(void);
/** @brief функция устанавливает имя wav файла
@param[in] filename имя wav файла
*/
void setWavFileName(char* filename);
/** @brief включить вывод аудио через OpenAL
*/
void playAudioOn(void);
/** @brief выключить вывод аудио через OpenAL
*/
void playAudioOff(void);
/** @brief включить запись аудио в wav файл
*/
void recordOn(void);
/** @brief выключить запись аудио в wav файл
*/
void recordOff(void);
};
#endif // MUSICDIGITALBUS_H_INCLUDED
#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("alcOpenDevicen");
#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("alcMakeContextCurrentn");
#endif
alcMakeContextCurrent(openAlContext); // set active context
} else {
#if SDB_WITH_DEBUG_MODE == 1
printf("Error contextn");
#endif
return 0;
}
} else {
#if SDB_WITH_DEBUG_MODE == 1
printf("Error Open Devicen");
#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: %dn",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: %dn",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: %dn",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: %dn",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<<i)) == 1<<i) {
busState = -SDB_MAX_DATA;
busDelay(uartT);
busState = -SDB_MAX_DATA;
pBit++;
} else {
busState = SDB_MAX_DATA;
busDelay(uartT);
busState = -SDB_MAX_DATA;
}
}
// бит честности
if (uartParityBit != 0) {
if ((pBit & 0x0001) == 0) {
busState = -SDB_MAX_DATA;
busDelay(uartT);
busState = -SDB_MAX_DATA;
} else {
busState = SDB_MAX_DATA;
busDelay(uartT);
busState = -SDB_MAX_DATA;
}
}
// стоп бит
busState = -SDB_MAX_DATA;
for (register unsigned char i = 0; i < uartStopBit; i++)
busDelay(uartT);
busState = -SDB_MAX_DATA;
}
// функция передает данные по шине uart
void sdb::uartSend(unsigned long data) {
unsigned short pBit = 0; // переменная для бита четности
// старт бит
busState = SDB_MAX_DATA;
busDelay(uartT);
busState = -SDB_MAX_DATA;
// данные
for (register unsigned char i = 0; i < uartBit; i++) {
if((data & (1<<i)) == 1<<i) {
busState = -SDB_MAX_DATA;
busDelay(uartT);
busState = -SDB_MAX_DATA;
} else {
busState = SDB_MAX_DATA;
busDelay(uartT);
busState = -SDB_MAX_DATA;
}
}
// бит честности
if (uartParityBit != 0) {
if ((pBit & 0x0001) == 0) {
busState = -SDB_MAX_DATA;
busDelay(uartT);
busState = -SDB_MAX_DATA;
} else {
busState = SDB_MAX_DATA;
busDelay(uartT);
busState = -SDB_MAX_DATA;
}
}
// стоп бит
busState = -SDB_MAX_DATA;
for (register unsigned char i = 0; i < uartStopBit; i++)
busDelay(uartT);
busState = -SDB_MAX_DATA;
}
// функция устанавливает скорость UART
void sdb::uartSetBaudrate(unsigned long baudrate) {
if (baudrate > 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;
}
}
#ifndef MAIN_H_INCLUDED
#define MAIN_H_INCLUDED
#define LINUX 0x00
#define WINDOWS 0x01
#define RU 0x00
#define EN 0x01
/// Тип операционой системы
#define TYPE_OS WINDOWS
/// Язык программы
#define LANGUAGE_PROGRAM RU
#define UART_BUS 0x01
#define ONE_WIRE_BUS 0x02
#include <iostream>
#include "SoundsDigitalBus.h"
#include "stdlib.h"
#include <stdio.h>
#endif // MAIN_H_INCLUDED
#include "main.h"
sdb soundsDigitalBus;
int main() {
static FILE *fp = NULL; // файл с данными
char strData[512]; // буфер для строк
char strChar = 0; // символ
unsigned char busType; // тип цифровой шины
int strPos = 0; // позиция в строке
int uartBaudrate = 0; // скорость UART
int uartBit = 8;
int uartStopBit = 0;
//int uartParityBit = 0;
#if TYPE_OS==WINDOWS and LANGUAGE_PROGRAM==RU
setlocale(LC_ALL, "Russian");
printf("Введите скорость UART в бод, или укажите 0, если хотите 1-wire.n");
#else
printf("Enter the UART baud rate, or specify 0 if you want 1-wire.n");
#endif
printf("UART Baudrate: ");
memset(strData,0,512);
while(1) {
strChar = getchar();
if ((strChar >= '0') && (strChar <= '9')) {
strData[strPos++] = strChar;
} else
break;
}
uartBaudrate = atoi(strData);
if (uartBaudrate == 0) {
busType = ONE_WIRE_BUS;
} else {
busType = UART_BUS;
soundsDigitalBus.uartSetBaudrate(uartBaudrate);
}
printf("n");
if (busType == UART_BUS) {
#if TYPE_OS==WINDOWS and LANGUAGE_PROGRAM==RU
printf("Введите количество бит UARTn");
#else
printf("Enter the number of bits UART.n");
#endif
printf("UART bit: ");
memset(strData,0,512);
while(1) {
strChar = getchar();
if ((strChar >= '0') && (strChar <= '9')) {
strData[strPos++] = strChar;
} else
break;
}
uartBit = atoi(strData);
soundsDigitalBus.uartSetBit(uartBit);
printf("n");
#if TYPE_OS==WINDOWS and LANGUAGE_PROGRAM==RU
printf("Введите количество стоп бит UARTn");
#else
printf("Enter the number of stop bits UART.n");
#endif
printf("UART stop bit: ");
memset(strData,0,512);
while(1) {
strChar = getchar();
if ((strChar >= '0') && (strChar <= '9')) {
strData[strPos++] = strChar;
} else
break;
}
uartStopBit = atoi(strData);
soundsDigitalBus.uartSetStopBit(uartStopBit);
printf("n");
#if TYPE_OS==WINDOWS and LANGUAGE_PROGRAM==RU
printf("Использовать бит четности в UART? (Y/n)n");
#else
printf("Use the parity bit in the UART? (Y/n)n");
#endif
strChar = getchar();
if ((strChar == 'n')
|| (strChar == 'N')
|| (strChar == 'т')
|| (strChar == 'Т')) {
soundsDigitalBus.uartSetParityBit(0);
printf("not usedn");
} else {
soundsDigitalBus.uartSetParityBit(1);
printf("Yes, usen");
}
getchar();
printf("n");
}
FILE_M:
printf("n");
#if TYPE_OS==WINDOWS
printf("Укажите файл для преобразования его в запись цифровой шины.n");
printf("Например: D: \ Games \ SR2 \ Rangers.txtn");
printf("Файл: ");
#else
printf("Specify the file to convert it to record digital bus.n");
printf("For example: D: \ Games \ SR2 \ Rangers.txtn");
printf("File: ");
#endif
memset(strData,0,512);
strPos = 0;
while(1) {
strChar = getchar();
if (strChar != 'n') {
strData[strPos++] = strChar;
} else
break;
}
fp = fopen(strData,"rb");
if (fp == NULL) {
printf("n");
#if TYPE_OS==WINDOWS
printf("Ошибка! Файл %s не найден!n",strData);
printf("Поробуйте правильно указать путь до файла.n");
printf("...n");
#else
printf("Error! File %s not found!n",strData);
printf("Try to correctly specify the path to the file.n");
printf("...n");
#endif
getchar();
goto FILE_M;
}
//soundsDigitalBus.setWavFileName(strData);
printf("n");
#if SDB_WITH_OPENAL == 1
#if TYPE_OS==WINDOWS
printf("Воспроизводить аудио во время работы цифровой шины? (Y/n)n");
#else
printf("Play audio while working digital bus? (Y/n)n");
#endif
strChar = getchar();
if ((strChar == 'n')
|| (strChar == 'N')
|| (strChar == 'т')
|| (strChar == 'Т')) {
soundsDigitalBus.playAudioOff();
printf("not usedn");
} else {
soundsDigitalBus.playAudioOn();
printf("Yes, usen");
}
getchar();
printf("n");
#if TYPE_OS==WINDOWS
printf("Записывать аудио во время работы цифровой шины? (Y/n)n");
#else
printf("Record audio while working digital bus? (Y/n)n");
#endif
strChar = getchar();
if ((strChar == 'n')
|| (strChar == 'N')
|| (strChar == 'т')
|| (strChar == 'Т')) {
soundsDigitalBus.recordOff();
printf("not usedn");
} else {
soundsDigitalBus.recordOn();
printf("Yes, usen");
}
getchar();
#else
soundsDigitalBus.recordOn();
#endif
printf("n");
#if TYPE_OS==WINDOWS
printf("Преобразование начато.n");
#else
printf("The transformation started.n");
#endif
unsigned char uartData[8];
if (busType == ONE_WIRE_BUS) {
soundsDigitalBus.oneWireReset();
}
while(1) {
if (fread(uartData,sizeof(unsigned char),1,fp) > 0) {
if (busType == UART_BUS) {
if (uartBit == 8) {
soundsDigitalBus.uartSendByte(uartData[0]);
} else {
soundsDigitalBus.uartSend(uartData[0]);
}
} else
if (busType == ONE_WIRE_BUS) {
soundsDigitalBus.oneWireSendByte(uartData[0]);
}
} else
break;
}
fclose(fp);
if (busType == ONE_WIRE_BUS) {
soundsDigitalBus.oneWireStop();
} else
if (busType == UART_BUS) {
soundsDigitalBus.uartStop();
}
#if TYPE_OS==WINDOWS
printf("Преобразование завершено.n");
#else
printf("Conversion completed.n");
#endif
return 0;
//soundsDigitalBus.oneWireReset();
soundsDigitalBus.uartSetBaudrate(1200);
for (int i = 0; i < 256; i ++) {
for (int len = 0; len < 8; len++) {
soundsDigitalBus.uartSendByte(i);
}
printf("%dn",i);
}
soundsDigitalBus.oneWireStop();
return 0;
}
P.S. Заметил ошибку, что в исходном коде стартовый бит равен логической 1, а не 0, а стоповый равен 0, а не 1. Кому необходимо принципиальное соотвествение звукового сигнала реальности, может исправить ошибку сам.
Автор: ELEKTRO_YAR