diff --git a/audio_format.h b/audio_format.h index 985d135..84f80d8 100644 --- a/audio_format.h +++ b/audio_format.h @@ -8,6 +8,7 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. diff --git a/error_reporter.cpp b/error_reporter.cpp index 2a73984..5fc40e4 100644 --- a/error_reporter.cpp +++ b/error_reporter.cpp @@ -8,6 +8,7 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. diff --git a/error_reporter.h b/error_reporter.h index 5e8c168..ab5b958 100644 --- a/error_reporter.h +++ b/error_reporter.h @@ -8,6 +8,7 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. diff --git a/fm_transmitter.cbp b/fm_transmitter.cbp index f6cd1b1..b302fbd 100644 --- a/fm_transmitter.cbp +++ b/fm_transmitter.cbp @@ -43,6 +43,8 @@ + + diff --git a/fm_transmitter.depend b/fm_transmitter.depend index 7db4c44..207e4af 100644 --- a/fm_transmitter.depend +++ b/fm_transmitter.depend @@ -52,31 +52,33 @@ 1437597555 /home/pi/Projects/fm_transmitter/error_reporter.h -1435357888 source:/home/marcin/Repozytoria/fm_transmitter/error_reporter.cpp +1438083081 source:/home/marcin/Repozytoria/fm_transmitter/error_reporter.cpp "error_reporter.h" -1435358040 /home/marcin/Repozytoria/fm_transmitter/error_reporter.h +1438083081 /home/marcin/Repozytoria/fm_transmitter/error_reporter.h -1436380561 source:/home/marcin/Repozytoria/fm_transmitter/main.cpp +1438083081 source:/home/marcin/Repozytoria/fm_transmitter/main.cpp "transmitter.h" -1436384608 /home/marcin/Repozytoria/fm_transmitter/transmitter.h +1438084671 /home/marcin/Repozytoria/fm_transmitter/transmitter.h "wave_reader.h" - "audio_format.h" + "stdin_reader.h" + "error_reporter.h" -1436380561 /home/marcin/Repozytoria/fm_transmitter/wave_reader.h +1438090504 /home/marcin/Repozytoria/fm_transmitter/wave_reader.h - "error_reporter.h" + "audio_format.h" "pcm_wave_header.h" + "error_reporter.h" -1435355417 /home/marcin/Repozytoria/fm_transmitter/pcm_wave_header.h +1438083081 /home/marcin/Repozytoria/fm_transmitter/pcm_wave_header.h -1436384617 source:/home/marcin/Repozytoria/fm_transmitter/transmitter.cpp +1438084940 source:/home/marcin/Repozytoria/fm_transmitter/transmitter.cpp "transmitter.h" @@ -85,11 +87,10 @@ - -1435675612 /home/marcin/Repozytoria/fm_transmitter/audio_format.h +1438083081 /home/marcin/Repozytoria/fm_transmitter/audio_format.h -1436380561 source:/home/marcin/Repozytoria/fm_transmitter/wave_reader.cpp +1438090504 source:/home/marcin/Repozytoria/fm_transmitter/wave_reader.cpp "wave_reader.h" @@ -236,3 +237,15 @@ 1437741006 source:/home/pi/new_transmitter/stdin_reader.cpp "stdin_reader.h" +1438091088 /home/marcin/Repozytoria/fm_transmitter/stdin_reader.h + + + "audio_format.h" + "error_reporter.h" + +1438085397 source:/home/marcin/Repozytoria/fm_transmitter/stdin_reader.cpp + "stdin_reader.h" + + + + diff --git a/main.cpp b/main.cpp index 9635632..e8f76dc 100644 --- a/main.cpp +++ b/main.cpp @@ -8,6 +8,7 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -51,11 +52,11 @@ int main(int argc, char **argv) try { transmitter = new Transmitter(filename, frequency); - AudioFormat *format = transmitter->getFormat(); + AudioFormat format = transmitter->getFormat(); cout << "Playing: " << filename << ", " - << format->sampleRate << " Hz, " - << format->bitsPerSample << " bits, " - << ((format->channels > 0x01) ? "stereo" : "mono") << endl; + << format.sampleRate << " Hz, " + << format.bitsPerSample << " bits, " + << ((format.channels > 0x01) ? "stereo" : "mono") << endl; transmitter->play(); } catch (exception &e) { diff --git a/pcm_wave_header.h b/pcm_wave_header.h index 152cd31..fd74de2 100644 --- a/pcm_wave_header.h +++ b/pcm_wave_header.h @@ -8,6 +8,7 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. diff --git a/stdin_reader.cpp b/stdin_reader.cpp index 570b75f..0dfcf43 100644 --- a/stdin_reader.cpp +++ b/stdin_reader.cpp @@ -1,22 +1,124 @@ +/* + fm_transmitter - use Raspberry Pi as FM transmitter + + Copyright (c) 2015, Marcin Kondej + All rights reserved. + + See https://github.com/markondej/fm_transmitter + + Redistribution and use in source and binary forms, with or without modification, are + permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be + used to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + #include "stdin_reader.h" - +#include +#include +#include + +using std::exception; +using std::ostringstream; + StdinReader::StdinReader() -{ - //ctor -} - -StdinReader::~StdinReader() -{ - //dtor +{ + ostringstream oss; + + doStop = false; + + int returnCode = pthread_create(&thread, NULL, (volatile void*)(&this->readStdin), NULL); + if (returnCode) { + oss << "Cannot create new thread (code: " << returnCode << ")"; + errorMessage = oss.str(); + throw exception(); + } } -vector *StdinReader::getFrames(unsigned int count) +StdinReader::~StdinReader() { - return new vector(); + doStop = true; + pthread_join(thread, NULL); +} + +StdinReader *StdinReader::getInstance() +{ + static StdinReader instance; + return &instance; +} + +void StdinReader::readStdin() +{ + char *readBuffer = new char[BUFFER_SIZE]; + while(!doStop) { + int bytes = read(STDIN_FILENO, readBuffer, BUFFER_SIZE); + buffer.insert(buffer.end(), readBuffer, readBuffer + bytes); + usleep(1); + } +} + +vector *StdinReader::getFrames(unsigned int frameCount) +{ + unsigned int bytesToRead, bufferSize, bytesPerFrame, offset, zeroOffset, restBytes; + vector *frames = new vector(); + + bufferSize = buffer.size(); + bytesPerFrame = (BITS_PER_SAMPLE >> 3) * CHANNELS; + bytesToRead = frameCount * bytesPerFrame; + restBytes = bufferSize % bytesPerFrame; + + if (bytesToRead > bufferSize) { + bytesToRead = bufferSize - restBytes; + frameCount = bytesToRead / bytesPerFrame; + } + + zeroOffset = bufferSize - bytesToRead - restBytes; + + for (unsigned int i = 0; i < frameCount; i++) { + offset = zeroOffset + bytesPerFrame * i; + if (CHANNELS != 1) { + if (BITS_PER_SAMPLE != 8) { + frames->push_back(((int)(signed char)buffer[offset + 1] + (int)(signed char)buffer[offset + 3]) / (float)0x100); + } else { + frames->push_back(((int)buffer[offset] + (int)buffer[offset + 1]) / (float)0x100 - 1.0f); + } + } else { + if (BITS_PER_SAMPLE != 8) { + frames->push_back((signed char)buffer[offset + 1] / (float)0x80); + } else { + frames->push_back(buffer[offset] / (float)0x80 - 1.0f); + } + } + } + + buffer.clear(); + + return frames; } AudioFormat *StdinReader::getFormat() { AudioFormat *format = new AudioFormat; + format->sampleRate = SAMPLE_RATE; + format->bitsPerSample = BITS_PER_SAMPLE; + format->channels = CHANNELS; return format; } diff --git a/stdin_reader.h b/stdin_reader.h index d9e1d4f..a281836 100644 --- a/stdin_reader.h +++ b/stdin_reader.h @@ -1,19 +1,66 @@ +/* + fm_transmitter - use Raspberry Pi as FM transmitter + + Copyright (c) 2015, Marcin Kondej + All rights reserved. + + See https://github.com/markondej/fm_transmitter + + Redistribution and use in source and binary forms, with or without modification, are + permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or other + materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its contributors may be + used to endorse or promote products derived from this software without specific + prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + #ifndef STDIN_READER_H #define STDIN_READER_H #include +#include #include "audio_format.h" +#include "error_reporter.h" + +#define BUFFER_SIZE 128 +#define SAMPLE_RATE 22500 +#define BITS_PER_SAMPLE 1 +#define CHANNELS 1 using std::vector; -class StdinReader +class StdinReader : public ErrorReporter { public: - StdinReader(); virtual ~StdinReader(); - vector *getFrames(unsigned int count); + pthread_t thread; + static StdinReader *getInstance(); + vector *getFrames(unsigned int frameCount); AudioFormat *getFormat(); + private: + StdinReader(); + + bool doStop; + void readStdin(); + vector buffer; }; #endif // STDIN_READER_H diff --git a/transmitter.cpp b/transmitter.cpp index 343e6bc..7c46e47 100644 --- a/transmitter.cpp +++ b/transmitter.cpp @@ -8,6 +8,7 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -46,8 +47,6 @@ using std::ostringstream; #define ACCESS64(base, offset) *(volatile unsigned long long*)((int)base + offset) bool Transmitter::isTransmitting = false; -vector *Transmitter::buffer = NULL; -unsigned int Transmitter::frameOffset = 0; Transmitter::Transmitter(string filename, double frequency) : readStdin(filename == "-") @@ -88,16 +87,15 @@ Transmitter::Transmitter(string filename, double frequency) : peripherals = (volatile unsigned*)peripheralsMap; + AudioFormat *audioFormat; if (!readStdin) { waveReader = new WaveReader(filename); - format = waveReader->getFormat(); + audioFormat = waveReader->getFormat(); } else { - stdinReader = new StdinReader(); - format = stdinReader->getFormat(); + stdinReader = StdinReader::getInstance(); + audioFormat = stdinReader->getFormat(); } - - ACCESS(peripherals, 0x00200000) = (ACCESS(peripherals, 0x00200000) & 0xFFFF8FFF) | (0x01 << 14); - ACCESS(peripherals, 0x00101070) = (0x5A << 24) | (0x01 << 9) | (0x01 << 4) | 0x06; + format = *audioFormat; clockDivisor = (unsigned int)((500 << 12) / frequency + 0.5); } @@ -112,22 +110,15 @@ void Transmitter::play() throw exception(); } + frameOffset = 0; isTransmitting = true; pthread_t thread; - int returnCode; - frameOffset = 0; - - unsigned int bufferFrames = (unsigned int)((unsigned long long)format->sampleRate * BUFFER_TIME / 1000000); + unsigned int bufferFrames = (unsigned int)((unsigned long long)format.sampleRate * BUFFER_TIME / 1000000); buffer = (!readStdin) ? waveReader->getFrames(bufferFrames, frameOffset) : stdinReader->getFrames(bufferFrames); - void *params[3]; - params[0] = &format->sampleRate; - params[1] = &clockDivisor; - params[2] = peripherals; - - returnCode = pthread_create(&thread, NULL, &Transmitter::transmit, (void*)params); + int returnCode = pthread_create(&thread, NULL, (volatile void*)(&this->transmit), NULL); if (returnCode) { oss << "Cannot create new thread (code: " << returnCode << ")"; errorMessage = oss.str(); @@ -147,16 +138,15 @@ void Transmitter::play() pthread_join(thread, NULL); } -void Transmitter::transmit(void *params) +void Transmitter::transmit(void*) { unsigned long long current, start, playbackStart; unsigned int offset = 0, length, temp; vector *frames; float *data; - unsigned int sampleRate = *((unsigned int**)params)[0]; - unsigned int clockDivisor = *((unsigned int**)params)[1]; - volatile unsigned *peripherals = ((unsigned int**)params)[2]; + ACCESS(peripherals, 0x00200000) = (ACCESS(peripherals, 0x00200000) & 0xFFFF8FFF) | (0x01 << 14); + ACCESS(peripherals, 0x00101070) = (0x5A << 24) | (0x01 << 9) | (0x01 << 4) | 0x06; playbackStart = ACCESS64(peripherals, 0x00003004); current = playbackStart; @@ -168,7 +158,7 @@ void Transmitter::transmit(void *params) current = ACCESS64(peripherals, 0x00003004); } frames = buffer; - frameOffset = (current - playbackStart) * sampleRate / 1000000; + frameOffset = (current - playbackStart) * format.sampleRate / 1000000; buffer = NULL; length = frames->size(); @@ -189,7 +179,7 @@ void Transmitter::transmit(void *params) usleep(1); current = ACCESS64(peripherals, 0x00003004); - offset = (current - start) * sampleRate / 1000000; + offset = (current - start) * format.sampleRate / 1000000; } } @@ -197,21 +187,21 @@ void Transmitter::transmit(void *params) delete frames; } + + ACCESS(peripherals, 0x00101070) = (0x5A << 24); } Transmitter::~Transmitter() { - ACCESS(peripherals, 0x00101070) = (0x5A << 24); munmap(peripherals, 0x002FFFFF); if (!readStdin) { delete waveReader; } else { delete stdinReader; } - delete format; } -AudioFormat *Transmitter::getFormat() +AudioFormat& Transmitter::getFormat() { return format; } diff --git a/transmitter.h b/transmitter.h index 2bc3bda..af04c51 100644 --- a/transmitter.h +++ b/transmitter.h @@ -8,6 +8,7 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -35,6 +36,7 @@ #include "wave_reader.h" #include "stdin_reader.h" +#include "error_reporter.h" #define BUFFER_TIME 1000000 @@ -46,21 +48,21 @@ class Transmitter : public ErrorReporter Transmitter(string filename, double frequency); virtual ~Transmitter(); - AudioFormat *getFormat(); + AudioFormat &getFormat(); void play(); private: bool readStdin; - AudioFormat *format; + AudioFormat format; WaveReader *waveReader; StdinReader *stdinReader; unsigned int clockDivisor; volatile unsigned *peripherals; - static vector *buffer; + vector *buffer; + unsigned int frameOffset; static bool isTransmitting; - static unsigned int frameOffset; - static void transmit(void *params); + void transmit(void*); }; #endif // TRANSMITTER_H diff --git a/wave_reader.cpp b/wave_reader.cpp index 7a14e1b..ee9c446 100644 --- a/wave_reader.cpp +++ b/wave_reader.cpp @@ -8,6 +8,7 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -35,8 +36,6 @@ #include #include -#include - using std::exception; using std::ostringstream; @@ -142,12 +141,11 @@ vector *WaveReader::readData(unsigned int bytesToRead, bool closeFileOnExc return data; } -vector *WaveReader::getFrames(unsigned int count, unsigned int frameOffset) { - unsigned int bytesToRead, bytesLeft, bytesPerFrame, frameCount, offset; +vector *WaveReader::getFrames(unsigned int frameCount, unsigned int frameOffset) { + unsigned int bytesToRead, bytesLeft, bytesPerFrame, offset; vector *frames = new vector(); vector *data; - frameCount = count; bytesPerFrame = (header.bitsPerSample >> 3) * header.channels; bytesToRead = frameCount * bytesPerFrame; bytesLeft = header.subchunk2Size - frameOffset * bytesPerFrame; diff --git a/wave_reader.h b/wave_reader.h index e411ee3..40fd245 100644 --- a/wave_reader.h +++ b/wave_reader.h @@ -8,6 +8,7 @@ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. @@ -36,9 +37,9 @@ #include #include #include -#include "error_reporter.h" -#include "pcm_wave_header.h" #include "audio_format.h" +#include "pcm_wave_header.h" +#include "error_reporter.h" using std::vector; using std::string; @@ -51,7 +52,7 @@ class WaveReader : public ErrorReporter virtual ~WaveReader(); AudioFormat *getFormat(); - vector *getFrames(unsigned int count, unsigned int offset); + vector *getFrames(unsigned int frameCount, unsigned int frameOffset); bool isEnd(); private: string filename;