kopia lustrzana https://github.com/markondej/fm_transmitter
New implementation based on threads
rodzic
66316f0011
commit
117812c382
29
README.md
29
README.md
|
@ -1,2 +1,29 @@
|
|||
# fm_transmitter
|
||||
Raspberry Pi as FM transmitter, custom source
|
||||
|
||||
Use Raspberry Pi as FM transmitter. Now supports both RPi 1 and RPi 2 boards.
|
||||
|
||||
This project uses the general clock output to produce frequency modulated radio communication. It is based on idea originaly posted here: [http://icrobotics.co.uk/wiki/index.php/Turning_the_Raspberry_Pi_Into_an_FM_Transmitter](http://icrobotics.co.uk/wiki/index.php/Turning_the_Raspberry_Pi_Into_an_FM_Transmitter), but does not use DMA controller in order to distribute samples to output (clock generator),so sound quality is worse as in PiFm project and only mono transmition is available but this makes possible to run it on all kind boards.
|
||||
|
||||
## How to use it
|
||||
|
||||
To compile this project you can use Code::Blocks IDE [(http://codeblocks.org/)](http://codeblocks.org/) or alternatively convert CBP file into makefile.
|
||||
|
||||
Then you can use it by typing:
|
||||
```
|
||||
sudo ./fm_transmitter [filename] [frequency]
|
||||
```
|
||||
|
||||
Like:
|
||||
```
|
||||
sudp ./fm_transmitter star_wars.wav 100.0
|
||||
```
|
||||
|
||||
You can open WAVE files.
|
||||
|
||||
Please keep in mind that transmitting on certain frequencies without special permissions may be illegal in your country.
|
||||
|
||||
## New features
|
||||
|
||||
* works both on RPi 1 and RPi 2
|
||||
* reads mono and stereo files
|
||||
* based on threads
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
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 AUDIO_FORMAT_H
|
||||
#define AUDIO_FORMAT_H
|
||||
|
||||
struct AudioFormat
|
||||
{
|
||||
unsigned short channels;
|
||||
unsigned short bitsPerSample;
|
||||
unsigned int sampleRate;
|
||||
};
|
||||
|
||||
#endif // AUDIO_FORMAT_H
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
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 "error_reporter.h"
|
||||
|
||||
string ErrorReporter::errorMessage = string();
|
||||
|
||||
string ErrorReporter::getLastError()
|
||||
{
|
||||
return errorMessage;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
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 ERROR_REPORTER_H
|
||||
#define ERROR_REPORTER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
using std::string;
|
||||
|
||||
class ErrorReporter
|
||||
{
|
||||
public:
|
||||
static string getLastError();
|
||||
protected:
|
||||
static string errorMessage;
|
||||
};
|
||||
|
||||
#endif // ERROR_REPORTER_H
|
|
@ -31,11 +31,16 @@
|
|||
<Compiler>
|
||||
<Add option="-Wall" />
|
||||
<Add option="-fexceptions" />
|
||||
<Add option="-fpermissive" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add library="pthread" />
|
||||
<Add library="m" />
|
||||
</Linker>
|
||||
<Unit filename="README.md" />
|
||||
<Unit filename="audio_format.h" />
|
||||
<Unit filename="error_reporter.cpp" />
|
||||
<Unit filename="error_reporter.h" />
|
||||
<Unit filename="main.cpp" />
|
||||
<Unit filename="pcm_wave_header.h" />
|
||||
<Unit filename="transmitter.cpp" />
|
||||
|
|
|
@ -1,27 +1,29 @@
|
|||
# depslib dependency file v1.0
|
||||
1428106519 source:/home/pi/Projects/fm_transmitter/main.cpp
|
||||
<stdlib.h>
|
||||
1436392352 source:/home/pi/Projects/fm_transmitter/main.cpp
|
||||
<iostream>
|
||||
"transmitter.h"
|
||||
<cstdlib>
|
||||
|
||||
1436392352 /home/pi/Projects/fm_transmitter/transmitter.h
|
||||
"wave_reader.h"
|
||||
"transmitter.h"
|
||||
"audio_format.h"
|
||||
|
||||
1428103370 /home/pi/Projects/fm_transmitter/transmitter.h
|
||||
<vector>
|
||||
|
||||
1435350499 source:/home/pi/Projects/fm_transmitter/transmitter.cpp
|
||||
1436393762 source:/home/pi/Projects/fm_transmitter/transmitter.cpp
|
||||
"transmitter.h"
|
||||
<exception>
|
||||
<sstream>
|
||||
<cmath>
|
||||
<string.h>
|
||||
<unistd.h>
|
||||
<sys/mman.h>
|
||||
<fcntl.h>
|
||||
<math.h>
|
||||
<exception>
|
||||
<iostream>
|
||||
|
||||
1427846902 /home/pi/Projects/fm_transmitter/pcm_wave_reader.h
|
||||
<string>
|
||||
<vector>
|
||||
"pcm_wave_header.h"
|
||||
|
||||
1427920302 /home/pi/Projects/fm_transmitter/pcm_wave_header.h
|
||||
1436392352 /home/pi/Projects/fm_transmitter/pcm_wave_header.h
|
||||
|
||||
1427847773 source:/home/pi/Projects/fm_transmitter/pcm_wave_reader.cpp
|
||||
"pcm_wave_reader.h"
|
||||
|
@ -30,16 +32,152 @@
|
|||
<iostream>
|
||||
<fstream>
|
||||
|
||||
1428103341 /home/pi/Projects/fm_transmitter/wave_reader.h
|
||||
1436391132 /home/pi/Projects/fm_transmitter/wave_reader.h
|
||||
<string>
|
||||
<vector>
|
||||
<fstream>
|
||||
"error_reporter.h"
|
||||
"pcm_wave_header.h"
|
||||
|
||||
1435350606 source:/home/pi/Projects/fm_transmitter/wave_reader.cpp
|
||||
1436392352 source:/home/pi/Projects/fm_transmitter/wave_reader.cpp
|
||||
"wave_reader.h"
|
||||
<string.h>
|
||||
<exception>
|
||||
<iostream>
|
||||
<fstream>
|
||||
<math.h>
|
||||
<sstream>
|
||||
<string.h>
|
||||
|
||||
1436392352 source:/home/pi/Projects/fm_transmitter/error_reporter.cpp
|
||||
"error_reporter.h"
|
||||
|
||||
1436392352 /home/pi/Projects/fm_transmitter/error_reporter.h
|
||||
<string>
|
||||
|
||||
1435357888 source:/home/marcin/Repozytoria/fm_transmitter/error_reporter.cpp
|
||||
"error_reporter.h"
|
||||
|
||||
1435358040 /home/marcin/Repozytoria/fm_transmitter/error_reporter.h
|
||||
<string>
|
||||
|
||||
1436380561 source:/home/marcin/Repozytoria/fm_transmitter/main.cpp
|
||||
<iostream>
|
||||
"transmitter.h"
|
||||
<cstdlib>
|
||||
|
||||
1436384608 /home/marcin/Repozytoria/fm_transmitter/transmitter.h
|
||||
"wave_reader.h"
|
||||
"audio_format.h"
|
||||
|
||||
1436380561 /home/marcin/Repozytoria/fm_transmitter/wave_reader.h
|
||||
<string>
|
||||
<vector>
|
||||
<fstream>
|
||||
"error_reporter.h"
|
||||
"pcm_wave_header.h"
|
||||
|
||||
1435355417 /home/marcin/Repozytoria/fm_transmitter/pcm_wave_header.h
|
||||
|
||||
1436384617 source:/home/marcin/Repozytoria/fm_transmitter/transmitter.cpp
|
||||
"transmitter.h"
|
||||
<exception>
|
||||
<sstream>
|
||||
<cmath>
|
||||
<string.h>
|
||||
<unistd.h>
|
||||
<sys/mman.h>
|
||||
<fcntl.h>
|
||||
<pthread.h>
|
||||
|
||||
1435675612 /home/marcin/Repozytoria/fm_transmitter/audio_format.h
|
||||
|
||||
1436380561 source:/home/marcin/Repozytoria/fm_transmitter/wave_reader.cpp
|
||||
"wave_reader.h"
|
||||
<exception>
|
||||
<sstream>
|
||||
<string.h>
|
||||
|
||||
1435357888 source:/media/D6A2F3CBA2F3ADDD/C++/fm_transmitter/error_reporter.cpp
|
||||
"error_reporter.h"
|
||||
|
||||
1435358040 /media/D6A2F3CBA2F3ADDD/C++/fm_transmitter/error_reporter.h
|
||||
<string>
|
||||
|
||||
1436384675 source:/media/D6A2F3CBA2F3ADDD/C++/fm_transmitter/main.cpp
|
||||
<iostream>
|
||||
"transmitter.h"
|
||||
<cstdlib>
|
||||
|
||||
1436384608 /media/D6A2F3CBA2F3ADDD/C++/fm_transmitter/transmitter.h
|
||||
"wave_reader.h"
|
||||
"audio_format.h"
|
||||
|
||||
1436380561 /media/D6A2F3CBA2F3ADDD/C++/fm_transmitter/wave_reader.h
|
||||
<string>
|
||||
<vector>
|
||||
<fstream>
|
||||
"error_reporter.h"
|
||||
"pcm_wave_header.h"
|
||||
|
||||
1435355417 /media/D6A2F3CBA2F3ADDD/C++/fm_transmitter/pcm_wave_header.h
|
||||
|
||||
1435675612 /media/D6A2F3CBA2F3ADDD/C++/fm_transmitter/audio_format.h
|
||||
|
||||
1436384617 source:/media/D6A2F3CBA2F3ADDD/C++/fm_transmitter/transmitter.cpp
|
||||
"transmitter.h"
|
||||
<exception>
|
||||
<sstream>
|
||||
<cmath>
|
||||
<string.h>
|
||||
<unistd.h>
|
||||
<sys/mman.h>
|
||||
<fcntl.h>
|
||||
<pthread.h>
|
||||
|
||||
1436380561 source:/media/D6A2F3CBA2F3ADDD/C++/fm_transmitter/wave_reader.cpp
|
||||
"wave_reader.h"
|
||||
<exception>
|
||||
<sstream>
|
||||
<string.h>
|
||||
|
||||
1436392352 /home/pi/Projects/fm_transmitter/audio_format.h
|
||||
|
||||
1436392352 source:/home/pi/fm_transmitter/error_reporter.cpp
|
||||
"error_reporter.h"
|
||||
|
||||
1436392352 /home/pi/fm_transmitter/error_reporter.h
|
||||
<string>
|
||||
|
||||
1436392352 source:/home/pi/fm_transmitter/main.cpp
|
||||
<iostream>
|
||||
"transmitter.h"
|
||||
<cstdlib>
|
||||
|
||||
1437397513 /home/pi/fm_transmitter/transmitter.h
|
||||
"wave_reader.h"
|
||||
"audio_format.h"
|
||||
|
||||
1437397514 /home/pi/fm_transmitter/wave_reader.h
|
||||
<string>
|
||||
<vector>
|
||||
<fstream>
|
||||
"error_reporter.h"
|
||||
"pcm_wave_header.h"
|
||||
|
||||
1436392352 /home/pi/fm_transmitter/pcm_wave_header.h
|
||||
|
||||
1436392352 /home/pi/fm_transmitter/audio_format.h
|
||||
|
||||
1437577878 source:/home/pi/fm_transmitter/transmitter.cpp
|
||||
"transmitter.h"
|
||||
<exception>
|
||||
<sstream>
|
||||
<cmath>
|
||||
<string.h>
|
||||
<unistd.h>
|
||||
<sys/mman.h>
|
||||
<fcntl.h>
|
||||
|
||||
1437577736 source:/home/pi/fm_transmitter/wave_reader.cpp
|
||||
"wave_reader.h"
|
||||
<exception>
|
||||
<sstream>
|
||||
<string.h>
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<CodeBlocks_layout_file>
|
||||
<ActiveTarget name="Debug" />
|
||||
<File name="README.md" open="1" top="0" tabpos="6">
|
||||
<Cursor position="750" topLine="0" />
|
||||
</File>
|
||||
<File name="main.cpp" open="1" top="0" tabpos="4">
|
||||
<Cursor position="151" topLine="0" />
|
||||
</File>
|
||||
<File name="transmitter.cpp" open="1" top="1" tabpos="2">
|
||||
<Cursor position="2667" topLine="143" />
|
||||
</File>
|
||||
<File name="transmitter.h" open="1" top="0" tabpos="3">
|
||||
<Cursor position="209" topLine="0" />
|
||||
</File>
|
||||
<File name="wave_reader.cpp" open="1" top="0" tabpos="1">
|
||||
<Cursor position="1768" topLine="9" />
|
||||
</File>
|
||||
<File name="wave_reader.h" open="1" top="0" tabpos="5">
|
||||
<Cursor position="294" topLine="0" />
|
||||
</File>
|
||||
</CodeBlocks_layout_file>
|
69
main.cpp
69
main.cpp
|
@ -1,7 +1,38 @@
|
|||
#include <stdlib.h>
|
||||
/*
|
||||
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 <iostream>
|
||||
#include "wave_reader.h"
|
||||
#include "transmitter.h"
|
||||
#include "transmitter.h"
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -12,19 +43,29 @@ int main(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int code = 0;
|
||||
string filename = argv[1];
|
||||
double frequency = (argc < 3) ? 100.0 : (::atof(argv[2]));
|
||||
Transmitter *transmitter = NULL;
|
||||
|
||||
try {
|
||||
WaveReader *reader = new WaveReader(filename);
|
||||
Transmitter *transmitter = new Transmitter(frequency);
|
||||
PCMWaveHeader *header = reader->getHeader();
|
||||
std::vector<float> *samples = reader->getSamples();
|
||||
transmitter->transmit(samples, header->sampleRate);
|
||||
delete transmitter;
|
||||
delete samples;
|
||||
delete reader;
|
||||
transmitter = new Transmitter(filename, frequency);
|
||||
|
||||
AudioFormat *format = transmitter->getFormat();
|
||||
cout << "Playing: " << filename << ", "
|
||||
<< format->sampleRate << " Hz, "
|
||||
<< format->bitsPerSample << " bits, "
|
||||
<< ((format->channels > 0x01) ? "stereo" : "mono") << endl;
|
||||
|
||||
transmitter->play();
|
||||
} catch (exception &e) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
cout << "Error: " << ErrorReporter::getLastError() << endl;
|
||||
code = 1;
|
||||
}
|
||||
|
||||
if (transmitter != NULL) {
|
||||
delete transmitter;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,35 @@
|
|||
/*
|
||||
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 PCM_WAVE_HEADER_H
|
||||
#define PCM_WAVE_HEADER_H
|
||||
|
||||
|
|
199
transmitter.cpp
199
transmitter.cpp
|
@ -1,29 +1,97 @@
|
|||
/*
|
||||
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 "transmitter.h"
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
|
||||
using std::exception;
|
||||
using std::ostringstream;
|
||||
|
||||
#define ACCESS(base, offset) *(volatile unsigned int*)((int)base + offset)
|
||||
#define ACCESS64(base, offset) *(volatile unsigned long long*)((int)base + offset)
|
||||
|
||||
Transmitter::Transmitter(double frequency)
|
||||
{
|
||||
|
||||
bool Transmitter::isTransmitting = false;
|
||||
vector<float> *Transmitter::buffer = NULL;
|
||||
unsigned int Transmitter::frameOffset = 0;
|
||||
|
||||
Transmitter::Transmitter(string filename, double frequency)
|
||||
{
|
||||
ostringstream oss;
|
||||
bool isBcm2835 = true;
|
||||
|
||||
FILE *pipe = popen("uname -m", "r");
|
||||
if (pipe) {
|
||||
char buffer[64];
|
||||
string machine = "";
|
||||
while (!feof(pipe)) {
|
||||
if (fgets(buffer, 64, pipe)) {
|
||||
machine += buffer;
|
||||
}
|
||||
}
|
||||
pclose(pipe);
|
||||
|
||||
if (machine != "armv6l\n") {
|
||||
isBcm2835 = false;
|
||||
}
|
||||
}
|
||||
|
||||
int memFd;
|
||||
if ((memFd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
|
||||
std::cout << "Error: sudo privileges are required" << std::endl;
|
||||
throw std::exception();
|
||||
oss << "Cannot open /dev/mem (permission denied)";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
void *peripheralsMap = mmap(NULL, 0x002FFFFF, PROT_READ | PROT_WRITE, MAP_SHARED, memFd, 0x3F000000);
|
||||
void *peripheralsMap = mmap(NULL, 0x002FFFFF, PROT_READ | PROT_WRITE, MAP_SHARED, memFd, isBcm2835 ? 0x20000000 : 0x3F000000);
|
||||
close(memFd);
|
||||
if (peripheralsMap == MAP_FAILED) {
|
||||
std::cout << "Error: cannot obtain access to peripherals (mmap error)" << std::endl;
|
||||
throw std::exception();
|
||||
oss << "Cannot obtain access to peripherals (mmap error)";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
peripherals = (volatile unsigned*)peripheralsMap;
|
||||
peripherals = (volatile unsigned*)peripheralsMap;
|
||||
|
||||
waveReader = new WaveReader(filename);
|
||||
|
||||
format.sampleRate = waveReader->getHeader()->sampleRate;
|
||||
format.channels = waveReader->getHeader()->channels;
|
||||
format.bitsPerSample = waveReader->getHeader()->bitsPerSample;
|
||||
|
||||
ACCESS(peripherals, 0x00200000) = (ACCESS(peripherals, 0x00200000) & 0xFFFF8FFF) | (0x01 << 14);
|
||||
ACCESS(peripherals, 0x00101070) = (0x5A << 24) | (0x01 << 9) | (0x01 << 4) | 0x06;
|
||||
|
@ -31,29 +99,110 @@ Transmitter::Transmitter(double frequency)
|
|||
clockDivisor = (unsigned int)((500 << 12) / frequency + 0.5);
|
||||
}
|
||||
|
||||
void Transmitter::transmit(std::vector<float> *samples, unsigned int sampleRate) {
|
||||
unsigned int offset = 0, length = samples->size(), temp;
|
||||
float *data = &(*samples)[0];
|
||||
void Transmitter::play()
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
unsigned long long current = 0;
|
||||
unsigned long long start = ACCESS64(peripherals, 0x00003004);
|
||||
if (isTransmitting) {
|
||||
oss << "Cannot play, transmitter already in use";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
temp = offset;
|
||||
if (offset >= length) break;
|
||||
isTransmitting = true;
|
||||
pthread_t thread;
|
||||
int returnCode;
|
||||
|
||||
ACCESS(peripherals, 0x00101074) = (0x5A << 24) | clockDivisor - (int)(round(data[offset] * 16.0));
|
||||
frameOffset = 0;
|
||||
|
||||
while (temp >= offset) {
|
||||
usleep(1);
|
||||
unsigned int bufferFrames = format.sampleRate * BUFFER_TIME / 100000;
|
||||
|
||||
current = ACCESS64(peripherals, 0x00003004);
|
||||
offset = (unsigned int)((current - start) * sampleRate / 1000000);
|
||||
buffer = waveReader->getFrames(bufferFrames, frameOffset);
|
||||
|
||||
void *params[3];
|
||||
params[0] = &format.sampleRate;
|
||||
params[1] = &clockDivisor;
|
||||
params[2] = peripherals;
|
||||
|
||||
returnCode = pthread_create(&thread, NULL, &Transmitter::transmit, (void*)params);
|
||||
if (returnCode) {
|
||||
oss << "Cannot create new thread (code: " << returnCode << ")";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
while(!waveReader->isEnd()) {
|
||||
if (buffer == NULL) {
|
||||
buffer = waveReader->getFrames(bufferFrames, frameOffset + bufferFrames);
|
||||
}
|
||||
usleep(BUFFER_TIME / 2);
|
||||
}
|
||||
|
||||
isTransmitting = false;
|
||||
pthread_join(thread, NULL);
|
||||
}
|
||||
|
||||
void Transmitter::transmit(void *params)
|
||||
{
|
||||
unsigned long long current, start, playbackStart;
|
||||
unsigned int offset = 0, length, temp;
|
||||
vector<float> *frames;
|
||||
float *data;
|
||||
|
||||
unsigned int sampleRate = *((unsigned int**)params)[0];
|
||||
unsigned int clockDivisor = *((unsigned int**)params)[1];
|
||||
volatile unsigned *peripherals = ((unsigned int**)params)[2];
|
||||
|
||||
playbackStart = ACCESS64(peripherals, 0x00003004);
|
||||
current = playbackStart;
|
||||
start = playbackStart;
|
||||
|
||||
while (isTransmitting) {
|
||||
while (buffer == NULL) {
|
||||
usleep(1);
|
||||
current = ACCESS64(peripherals, 0x00003004);
|
||||
}
|
||||
frames = buffer;
|
||||
frameOffset = (current - playbackStart) * sampleRate / 1000000;
|
||||
buffer = NULL;
|
||||
|
||||
length = frames->size();
|
||||
data = &(*frames)[0];
|
||||
|
||||
offset = 0;
|
||||
|
||||
while (true) {
|
||||
temp = offset;
|
||||
if (offset >= length) {
|
||||
offset -= length;
|
||||
break;
|
||||
}
|
||||
|
||||
ACCESS(peripherals, 0x00101074) = (0x5A << 24) | clockDivisor - (int)(round(data[offset] * 16.0));
|
||||
|
||||
while (temp >= offset) {
|
||||
usleep(1);
|
||||
|
||||
current = ACCESS64(peripherals, 0x00003004);
|
||||
offset = (current - start) * sampleRate / 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
start = ACCESS64(peripherals, 0x00003004);
|
||||
|
||||
delete frames;
|
||||
}
|
||||
}
|
||||
|
||||
Transmitter::~Transmitter()
|
||||
{
|
||||
ACCESS(peripherals, 0x00101070) = (0x5A << 24);
|
||||
munmap(peripherals, 0x002FFFFF);
|
||||
peripherals = NULL;
|
||||
delete waveReader;
|
||||
}
|
||||
|
||||
AudioFormat *Transmitter::getFormat()
|
||||
{
|
||||
return &format;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,64 @@
|
|||
/*
|
||||
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 TRANSMITTER_H
|
||||
#define TRANSMITTER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
class Transmitter
|
||||
#include "wave_reader.h"
|
||||
#include "audio_format.h"
|
||||
|
||||
#define BUFFER_TIME 100000
|
||||
|
||||
using std::string;
|
||||
|
||||
class Transmitter : public ErrorReporter
|
||||
{
|
||||
public:
|
||||
Transmitter(double frequency);
|
||||
Transmitter(string filename, double frequency);
|
||||
virtual ~Transmitter();
|
||||
void transmit(std::vector<float> *samples, unsigned int sampleRate);
|
||||
|
||||
AudioFormat *getFormat();
|
||||
void play();
|
||||
private:
|
||||
AudioFormat format;
|
||||
WaveReader *waveReader;
|
||||
unsigned int clockDivisor;
|
||||
volatile unsigned *peripherals;
|
||||
volatile unsigned *peripherals;
|
||||
|
||||
static vector<float> *buffer;
|
||||
static bool isTransmitting;
|
||||
static unsigned int frameOffset;
|
||||
|
||||
static void transmit(void *params);
|
||||
};
|
||||
|
||||
#endif // TRANSMITTER_H
|
||||
|
|
226
wave_reader.cpp
226
wave_reader.cpp
|
@ -1,117 +1,191 @@
|
|||
/*
|
||||
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 "wave_reader.h"
|
||||
#include <string.h>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <math.h>
|
||||
|
||||
WaveReader::WaveReader(std::string filename)
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
|
||||
using std::exception;
|
||||
using std::ostringstream;
|
||||
|
||||
WaveReader::WaveReader(std::string filename) :
|
||||
filename(filename)
|
||||
{
|
||||
std::vector<char> buffer;
|
||||
unsigned int length;
|
||||
int error;
|
||||
char *headerData;
|
||||
vector<char> *data;
|
||||
unsigned int bytesToRead, headerOffset;
|
||||
ostringstream oss;
|
||||
|
||||
std::ifstream is(filename.c_str(), std::ifstream::binary);
|
||||
ifs.open(filename.c_str(), ifstream::binary);
|
||||
headerData = (char*)((void*)&header);
|
||||
|
||||
if (!is) {
|
||||
std::cout << "Error: cannot open '" << filename << "', file does not exist" << std::endl;
|
||||
throw std::exception();
|
||||
if (!ifs.is_open()) {
|
||||
oss << "Cannot open " << filename << ", file does not exist";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
is.seekg(0, is.end);
|
||||
length = is.tellg();
|
||||
is.seekg(0, is.beg);
|
||||
ifs.seekg(0, ifs.end);
|
||||
fileSize = ifs.tellg();
|
||||
ifs.seekg(0, ifs.beg);
|
||||
|
||||
if (length < sizeof(PCMWaveHeader)) {
|
||||
std::cout << "Error: data corrupted" << std::endl;
|
||||
throw std::exception();
|
||||
bytesToRead = sizeof(PCMWaveHeader::chunkID) + sizeof(PCMWaveHeader::chunkSize) + sizeof(PCMWaveHeader::format);
|
||||
data = readData(bytesToRead, true);
|
||||
memcpy(headerData, &(*data)[0], bytesToRead);
|
||||
headerOffset = bytesToRead;
|
||||
delete data;
|
||||
|
||||
if ((string(header.chunkID, 4) != string("RIFF")) || (string(header.format, 4) != string("WAVE"))) {
|
||||
oss << "Error while opening " << filename << ", WAVE file expected";
|
||||
errorMessage = oss.str();
|
||||
ifs.close();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
buffer.resize(length);
|
||||
is.read(&buffer[0], length);
|
||||
is.close();
|
||||
bytesToRead = sizeof(PCMWaveHeader::subchunk1ID) + sizeof(PCMWaveHeader::subchunk1Size);
|
||||
data = readData(bytesToRead, true);
|
||||
memcpy(&headerData[headerOffset], &(*data)[0], bytesToRead);
|
||||
headerOffset += bytesToRead;
|
||||
delete data;
|
||||
|
||||
memcpy(&header, &buffer[0], sizeof(PCMWaveHeader));
|
||||
|
||||
if ((error = checkDataFormat(&header)) > 0) {
|
||||
std::cout << "Error: unsupported data format (" << error << ")" << std::endl;
|
||||
throw std::exception();
|
||||
unsigned int subchunk1MinSize = sizeof(PCMWaveHeader) - headerOffset - sizeof(PCMWaveHeader::subchunk2ID) - sizeof(PCMWaveHeader::subchunk2Size);
|
||||
if ((string(header.subchunk1ID, 4) != string("fmt ")) || (header.subchunk1Size < subchunk1MinSize)) {
|
||||
oss << "Error while opening " << filename << ", data corrupted";
|
||||
errorMessage = oss.str();
|
||||
ifs.close();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
if (length < sizeof(PCMWaveHeader) + header.subchunk2Size) {
|
||||
std::cout << "Error: data corrupted" << std::endl;
|
||||
throw std::exception();
|
||||
data = readData(header.subchunk1Size, true);
|
||||
memcpy(&headerData[headerOffset], &(*data)[0], subchunk1MinSize);
|
||||
headerOffset += subchunk1MinSize;
|
||||
delete data;
|
||||
|
||||
if ((header.audioFormat != WAVE_FORMAT_PCM) ||
|
||||
(header.byteRate != (header.bitsPerSample >> 3) * header.channels * header.sampleRate) ||
|
||||
(header.blockAlign != (header.bitsPerSample >> 3) * header.channels) ||
|
||||
(((header.bitsPerSample >> 3) != 1) && ((header.bitsPerSample >> 3) != 2))) {
|
||||
oss << "Error while opening " << filename << ", unsupported WAVE format";
|
||||
errorMessage = oss.str();
|
||||
ifs.close();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
data.resize(header.subchunk2Size);
|
||||
memcpy(&data[0], &buffer[sizeof(PCMWaveHeader)], header.subchunk2Size);
|
||||
bytesToRead = sizeof(PCMWaveHeader::subchunk2ID) + sizeof(PCMWaveHeader::subchunk2Size);
|
||||
data = readData(bytesToRead, true);
|
||||
memcpy(&headerData[headerOffset], &(*data)[0], bytesToRead);
|
||||
headerOffset += bytesToRead;
|
||||
delete data;
|
||||
|
||||
if ((string(header.subchunk2ID, 4) != string("data")) || (header.subchunk2Size + ifs.tellg() < fileSize)) {
|
||||
oss << "Error while opening " << filename << ", data corrupted";
|
||||
errorMessage = oss.str();
|
||||
ifs.close();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
dataOffset = ifs.tellg();
|
||||
}
|
||||
|
||||
WaveReader::~WaveReader()
|
||||
{
|
||||
|
||||
ifs.close();
|
||||
}
|
||||
|
||||
int WaveReader::checkDataFormat(PCMWaveHeader *header)
|
||||
vector<char> *WaveReader::readData(unsigned int bytesToRead, bool closeFileOnException)
|
||||
{
|
||||
int error = 0;
|
||||
vector<char> *data = new vector<char>();
|
||||
ostringstream oss;
|
||||
|
||||
if (std::string(header->chunkID, 4) != std::string("RIFF")) {
|
||||
error |= 0x01;
|
||||
}
|
||||
if (std::string(header->format, 4) != std::string("WAVE")) {
|
||||
error |= (0x01 << 1);
|
||||
}
|
||||
if (std::string(header->subchunk1ID, 4) != std::string("fmt ")) {
|
||||
error |= (0x01 << 2);
|
||||
}
|
||||
if (header->subchunk1Size != 16) {
|
||||
error |= (0x01 << 3);
|
||||
}
|
||||
if (header->audioFormat != WAVE_FORMAT_PCM) {
|
||||
error |= (0x01 << 4);
|
||||
}
|
||||
if (header->byteRate != (header->bitsPerSample >> 3) * header->channels * header->sampleRate) {
|
||||
error |= (0x01 << 5);
|
||||
}
|
||||
if (header->blockAlign != (header->bitsPerSample >> 3) * header->channels) {
|
||||
error |= (0x01 << 6);
|
||||
}
|
||||
if (((header->bitsPerSample >> 3) != 1) && ((header->bitsPerSample >> 3) != 2)) {
|
||||
error |= (0x01 << 7);
|
||||
}
|
||||
if (std::string(header->subchunk2ID, 4) != std::string("data")) {
|
||||
error |= (0x01 << 8);
|
||||
if (fileSize < (unsigned int)ifs.tellg() + bytesToRead) {
|
||||
oss << "Error while reading " << filename << ", data corrupted";
|
||||
if (closeFileOnException) ifs.close();
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
return error;
|
||||
data->resize(bytesToRead);
|
||||
ifs.read(&(*data)[0], bytesToRead);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
std::vector<float> *WaveReader::getSamples()
|
||||
{
|
||||
std::vector<float> *samples = new std::vector<float>();
|
||||
unsigned char frameSize = header.channels * (header.bitsPerSample >> 3);
|
||||
unsigned int framesCount = header.subchunk2Size / frameSize;
|
||||
unsigned int frameOffset = 0, dataOffset;
|
||||
vector<float> *WaveReader::getFrames(unsigned int count, unsigned int frameOffset) {
|
||||
unsigned int bytesToRead, bytesLeft, bytesPerFrame, frameCount, offset;
|
||||
vector<float> *frames = new vector<float>();
|
||||
vector<char> *data;
|
||||
|
||||
while (frameOffset < framesCount) {
|
||||
dataOffset = frameOffset * frameSize;
|
||||
frameCount = count;
|
||||
bytesPerFrame = (header.bitsPerSample >> 3) * header.channels;
|
||||
bytesToRead = frameCount * bytesPerFrame;
|
||||
bytesLeft = header.subchunk2Size - frameOffset * bytesPerFrame;
|
||||
|
||||
if (bytesToRead > bytesLeft) {
|
||||
bytesToRead = bytesLeft - bytesLeft % bytesPerFrame;
|
||||
frameCount = bytesToRead / bytesPerFrame;
|
||||
}
|
||||
|
||||
ifs.seekg(dataOffset + frameOffset * bytesPerFrame);
|
||||
|
||||
data = readData(bytesToRead, false);
|
||||
for (unsigned int i = 0; i < frameCount; i++) {
|
||||
offset = bytesPerFrame * i;
|
||||
if (header.channels != 1) {
|
||||
// TODO: Stereo to mono conversion
|
||||
if (header.bitsPerSample != 8) {
|
||||
frames->push_back(((int)(signed char)(*data)[offset + 1] + (int)(signed char)(*data)[offset + 3]) / (float)0x100);
|
||||
} else {
|
||||
frames->push_back(((int)(*data)[offset] + (int)(*data)[offset + 1]) / (float)0x100 - 1.0f);
|
||||
}
|
||||
} else {
|
||||
if (header.bitsPerSample != 8) {
|
||||
samples->push_back((signed char)data[dataOffset + 1] / (float)0x80);
|
||||
frames->push_back((signed char)(*data)[offset + 1] / (float)0x80);
|
||||
} else {
|
||||
samples->push_back(data[dataOffset] / (float)0x80 - 1.0f);
|
||||
frames->push_back((*data)[offset] / (float)0x80 - 1.0f);
|
||||
}
|
||||
}
|
||||
frameOffset++;
|
||||
}
|
||||
return samples;
|
||||
|
||||
delete data;
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
bool WaveReader::isEnd()
|
||||
{
|
||||
return header.subchunk2Size + dataOffset - ifs.tellg() == 0;
|
||||
}
|
||||
|
||||
PCMWaveHeader *WaveReader::getHeader()
|
||||
{
|
||||
return &header;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,21 +1,64 @@
|
|||
/*
|
||||
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 WAVE_READER_H
|
||||
#define WAVE_READER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include "error_reporter.h"
|
||||
#include "pcm_wave_header.h"
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::ifstream;
|
||||
|
||||
class WaveReader
|
||||
class WaveReader : public ErrorReporter
|
||||
{
|
||||
public:
|
||||
WaveReader(std::string filename);
|
||||
WaveReader(string filename);
|
||||
virtual ~WaveReader();
|
||||
int checkDataFormat(PCMWaveHeader *header);
|
||||
std::vector<float> *getSamples();
|
||||
PCMWaveHeader *getHeader();
|
||||
|
||||
PCMWaveHeader *getHeader();
|
||||
vector<float> *getFrames(unsigned int count, unsigned int offset);
|
||||
bool isEnd();
|
||||
private:
|
||||
string filename;
|
||||
PCMWaveHeader header;
|
||||
std::vector<char> data;
|
||||
unsigned int fileSize, dataOffset;
|
||||
ifstream ifs;
|
||||
|
||||
vector<char> *readData(unsigned int bytesToRead, bool closeFileOnException);
|
||||
};
|
||||
|
||||
#endif // WAVE_READER_H
|
||||
|
|
Ładowanie…
Reference in New Issue