kopia lustrzana https://github.com/markondej/fm_transmitter
Memory leak fixes
rodzic
5be5c731c5
commit
f84525adfa
|
@ -1,44 +1,44 @@
|
|||
/*
|
||||
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 sampleRate;
|
||||
};
|
||||
|
||||
#endif // AUDIO_FORMAT_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.
|
||||
*/
|
||||
|
||||
#ifndef AUDIO_FORMAT_H
|
||||
#define AUDIO_FORMAT_H
|
||||
|
||||
struct AudioFormat
|
||||
{
|
||||
unsigned short channels;
|
||||
unsigned short bitsPerSample;
|
||||
unsigned sampleRate;
|
||||
};
|
||||
|
||||
#endif // AUDIO_FORMAT_H
|
||||
|
|
|
@ -1,41 +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.
|
||||
*/
|
||||
|
||||
#include "error_reporter.h"
|
||||
|
||||
string ErrorReporter::errorMessage = string();
|
||||
|
||||
string ErrorReporter::getLastError()
|
||||
{
|
||||
return errorMessage;
|
||||
}
|
||||
/*
|
||||
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"
|
||||
|
||||
ErrorReporter::ErrorReporter(string message) :
|
||||
errorMessage(message)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorReporter::~ErrorReporter() throw()
|
||||
{
|
||||
}
|
||||
|
||||
const char* ErrorReporter::what() const throw()
|
||||
{
|
||||
return errorMessage.c_str();
|
||||
}
|
||||
|
|
|
@ -31,19 +31,24 @@
|
|||
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
|
||||
#ifndef ERROR_REPORTER_H
|
||||
#define ERROR_REPORTER_H
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
using std::exception;
|
||||
using std::string;
|
||||
|
||||
class ErrorReporter
|
||||
{
|
||||
|
||||
class ErrorReporter : public exception
|
||||
{
|
||||
public:
|
||||
static string getLastError();
|
||||
explicit ErrorReporter(string message);
|
||||
virtual ~ErrorReporter() throw();
|
||||
|
||||
virtual const char* what() const throw();
|
||||
protected:
|
||||
static string errorMessage;
|
||||
};
|
||||
|
||||
#endif // ERROR_REPORTER_H
|
||||
string errorMessage;
|
||||
};
|
||||
|
||||
#endif // ERROR_REPORTER_H
|
||||
|
|
193
main.cpp
193
main.cpp
|
@ -1,96 +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 <iostream>
|
||||
#include "transmitter.h"
|
||||
#include <cstdlib>
|
||||
#include <csignal>
|
||||
|
||||
using namespace std;
|
||||
|
||||
Transmitter* transmitter = NULL;
|
||||
|
||||
void sigIntHandler(int sigNum)
|
||||
{
|
||||
if (transmitter != NULL) {
|
||||
cout << "Stopping..." << endl;
|
||||
transmitter->stop();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
double frequency = 100.0;
|
||||
bool loop = false;
|
||||
string filename;
|
||||
|
||||
bool showUsage = true;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (string("-f") == argv[i]) {
|
||||
if (i < argc - 1) {
|
||||
frequency = ::atof(argv[i + 1]);
|
||||
i++;
|
||||
}
|
||||
} else if (string("-r") == argv[i]) {
|
||||
loop = true;
|
||||
} else {
|
||||
if (i == argc - 1) {
|
||||
showUsage = false;
|
||||
filename = argv[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (showUsage) {
|
||||
cout << "Usage: " << argv[0] << " [-f frequency] [-r] FILE" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
signal(SIGINT, sigIntHandler);
|
||||
|
||||
try {
|
||||
transmitter = Transmitter::getInstance();
|
||||
|
||||
AudioFormat format = Transmitter::getFormat(filename);
|
||||
cout << "Playing: " << ((filename != "-") ? filename : "stdin") << ", "
|
||||
<< format.sampleRate << " Hz, "
|
||||
<< format.bitsPerSample << " bits, "
|
||||
<< ((format.channels > 0x01) ? "stereo" : "mono") << endl;
|
||||
|
||||
transmitter->play(filename, frequency, loop);
|
||||
} catch (exception &e) {
|
||||
cout << "Error: " << ErrorReporter::getLastError() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
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 "transmitter.h"
|
||||
#include <cstdlib>
|
||||
#include <csignal>
|
||||
|
||||
using namespace std;
|
||||
|
||||
Transmitter* transmitter = NULL;
|
||||
|
||||
void sigIntHandler(int sigNum)
|
||||
{
|
||||
if (transmitter != NULL) {
|
||||
cout << "Stopping..." << endl;
|
||||
transmitter->stop();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
double frequency = 100.0;
|
||||
bool loop = false;
|
||||
string filename;
|
||||
|
||||
bool showUsage = true;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (string("-f") == argv[i]) {
|
||||
if (i < argc - 1) {
|
||||
frequency = ::atof(argv[i + 1]);
|
||||
i++;
|
||||
}
|
||||
} else if (string("-r") == argv[i]) {
|
||||
loop = true;
|
||||
} else {
|
||||
if (i == argc - 1) {
|
||||
showUsage = false;
|
||||
filename = argv[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (showUsage) {
|
||||
cout << "Usage: " << argv[0] << " [-f frequency] [-r] FILE" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
signal(SIGINT, sigIntHandler);
|
||||
|
||||
try {
|
||||
transmitter = Transmitter::getInstance();
|
||||
|
||||
AudioFormat* format = Transmitter::getFormat(filename);
|
||||
cout << "Playing: " << ((filename != "-") ? filename : "stdin") << ", "
|
||||
<< format->sampleRate << " Hz, "
|
||||
<< format->bitsPerSample << " bits, "
|
||||
<< ((format->channels > 0x01) ? "stereo" : "mono") << endl;
|
||||
delete format;
|
||||
|
||||
transmitter->play(filename, frequency, loop);
|
||||
} catch (exception &error) {
|
||||
cout << "Error: " << error.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
2
makefile
2
makefile
|
@ -1,7 +1,7 @@
|
|||
CFLAGS = -Wall -fexceptions -lpthread -lm -O3 -fpermissive -fno-strict-aliasing
|
||||
TARGET = fm_transmitter
|
||||
|
||||
OBJS = main.o wave_reader.o stdin_reader.o error_reporter.o transmitter.o
|
||||
OBJS = main.o error_reporter.o wave_reader.o stdin_reader.o transmitter.o
|
||||
|
||||
all: $(OBJS)
|
||||
g++ $(CFLAGS) -o $(TARGET) $(OBJS)
|
||||
|
|
|
@ -1,56 +1,56 @@
|
|||
/*
|
||||
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
|
||||
|
||||
#define WAVE_FORMAT_PCM 0x0001
|
||||
|
||||
struct PCMWaveHeader
|
||||
{
|
||||
char chunkID[4];
|
||||
unsigned chunkSize;
|
||||
char format[4];
|
||||
char subchunk1ID[4];
|
||||
unsigned subchunk1Size;
|
||||
unsigned short audioFormat;
|
||||
unsigned short channels;
|
||||
unsigned sampleRate;
|
||||
unsigned byteRate;
|
||||
unsigned short blockAlign;
|
||||
unsigned short bitsPerSample;
|
||||
char subchunk2ID[4];
|
||||
unsigned subchunk2Size;
|
||||
};
|
||||
|
||||
#endif // PCM_WAVE_HEADER
|
||||
/*
|
||||
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
|
||||
|
||||
#define WAVE_FORMAT_PCM 0x0001
|
||||
|
||||
struct PCMWaveHeader
|
||||
{
|
||||
char chunkID[4];
|
||||
unsigned chunkSize;
|
||||
char format[4];
|
||||
char subchunk1ID[4];
|
||||
unsigned subchunk1Size;
|
||||
unsigned short audioFormat;
|
||||
unsigned short channels;
|
||||
unsigned sampleRate;
|
||||
unsigned byteRate;
|
||||
unsigned short blockAlign;
|
||||
unsigned short bitsPerSample;
|
||||
char subchunk2ID[4];
|
||||
unsigned subchunk2Size;
|
||||
};
|
||||
|
||||
#endif // PCM_WAVE_HEADER
|
||||
|
|
335
stdin_reader.cpp
335
stdin_reader.cpp
|
@ -1,169 +1,166 @@
|
|||
/*
|
||||
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 <exception>
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
using std::exception;
|
||||
using std::ostringstream;
|
||||
|
||||
bool StdinReader::doStop = false;
|
||||
bool StdinReader::isReading = false;
|
||||
bool StdinReader::isDataAccess = false;
|
||||
vector<char> StdinReader::stream;
|
||||
|
||||
StdinReader::StdinReader()
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
int returnCode = pthread_create(&thread, NULL, &StdinReader::readStdin, NULL);
|
||||
if (returnCode) {
|
||||
oss << "Cannot create new thread (code: " << returnCode << ")";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
while (!isReading) {
|
||||
usleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
StdinReader::~StdinReader()
|
||||
{
|
||||
doStop = true;
|
||||
pthread_join(thread, NULL);
|
||||
}
|
||||
|
||||
StdinReader *StdinReader::getInstance()
|
||||
{
|
||||
static StdinReader instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void *StdinReader::readStdin(void *params)
|
||||
{
|
||||
long flag = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
fcntl(STDIN_FILENO, F_SETFL, flag | O_NONBLOCK);
|
||||
|
||||
char *readBuffer = new char[1024];
|
||||
while (!doStop) {
|
||||
isReading = true;
|
||||
|
||||
while (isDataAccess && !doStop) {
|
||||
usleep(1);
|
||||
}
|
||||
if (doStop) {
|
||||
break;
|
||||
}
|
||||
unsigned streamSize = stream.size();
|
||||
if (streamSize < MAX_STREAM_SIZE) {
|
||||
int bytes = read(STDIN_FILENO, readBuffer, (streamSize + 1024 > MAX_STREAM_SIZE) ? MAX_STREAM_SIZE - streamSize : 1024);
|
||||
if (bytes > 0) {
|
||||
stream.insert(stream.end(), readBuffer, readBuffer + bytes);
|
||||
}
|
||||
}
|
||||
|
||||
isReading = false;
|
||||
usleep(1);
|
||||
}
|
||||
delete readBuffer;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vector<float> *StdinReader::getFrames(unsigned frameCount, bool &forceStop)
|
||||
{
|
||||
while (isReading && !forceStop) {
|
||||
usleep(1);
|
||||
}
|
||||
if (forceStop) {
|
||||
doStop = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
isDataAccess = true;
|
||||
|
||||
unsigned offset, bytesToRead, bytesPerFrame;
|
||||
unsigned streamSize = stream.size();
|
||||
if (!streamSize) {
|
||||
isDataAccess = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vector<float> *frames = new vector<float>();
|
||||
bytesPerFrame = (STREAM_BITS_PER_SAMPLE >> 3) * STREAM_CHANNELS;
|
||||
bytesToRead = frameCount * bytesPerFrame;
|
||||
|
||||
if (bytesToRead > streamSize) {
|
||||
bytesToRead = streamSize - streamSize % bytesPerFrame;
|
||||
frameCount = bytesToRead / bytesPerFrame;
|
||||
}
|
||||
|
||||
vector<char> data;
|
||||
data.resize(bytesToRead);
|
||||
memcpy(&(data[0]), &(stream[0]), bytesToRead);
|
||||
stream.erase(stream.begin(), stream.begin() + bytesToRead);
|
||||
isDataAccess = false;
|
||||
|
||||
for (unsigned i = 0; i < frameCount; i++) {
|
||||
offset = bytesPerFrame * i;
|
||||
if (STREAM_CHANNELS != 1) {
|
||||
if (STREAM_BITS_PER_SAMPLE != 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 (STREAM_BITS_PER_SAMPLE != 8) {
|
||||
frames->push_back((signed char)data[offset + 1] / (float)0x80);
|
||||
} else {
|
||||
frames->push_back(data[offset] / (float)0x80 - 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
AudioFormat *StdinReader::getFormat()
|
||||
{
|
||||
AudioFormat *format = new AudioFormat;
|
||||
format->sampleRate = STREAM_SAMPLE_RATE;
|
||||
format->bitsPerSample = STREAM_BITS_PER_SAMPLE;
|
||||
format->channels = STREAM_CHANNELS;
|
||||
return format;
|
||||
}
|
||||
/*
|
||||
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 "error_reporter.h"
|
||||
#include <sstream>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
using std::ostringstream;
|
||||
|
||||
bool StdinReader::doStop = false;
|
||||
bool StdinReader::isReading = false;
|
||||
bool StdinReader::isDataAccess = false;
|
||||
vector<char> StdinReader::stream;
|
||||
|
||||
StdinReader::StdinReader()
|
||||
{
|
||||
int returnCode = pthread_create(&thread, NULL, &StdinReader::readStdin, NULL);
|
||||
if (returnCode) {
|
||||
ostringstream oss;
|
||||
oss << "Cannot create new thread (code: " << returnCode << ")";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
|
||||
while (!isReading) {
|
||||
usleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
StdinReader::~StdinReader()
|
||||
{
|
||||
doStop = true;
|
||||
pthread_join(thread, NULL);
|
||||
}
|
||||
|
||||
StdinReader* StdinReader::getInstance()
|
||||
{
|
||||
static StdinReader instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void *StdinReader::readStdin(void *params)
|
||||
{
|
||||
long flag = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||
fcntl(STDIN_FILENO, F_SETFL, flag | O_NONBLOCK);
|
||||
|
||||
char *readBuffer = new char[1024];
|
||||
while (!doStop) {
|
||||
isReading = true;
|
||||
|
||||
while (isDataAccess && !doStop) {
|
||||
usleep(1);
|
||||
}
|
||||
if (doStop) {
|
||||
break;
|
||||
}
|
||||
unsigned streamSize = stream.size();
|
||||
if (streamSize < MAX_STREAM_SIZE) {
|
||||
int bytes = read(STDIN_FILENO, readBuffer, (streamSize + 1024 > MAX_STREAM_SIZE) ? MAX_STREAM_SIZE - streamSize : 1024);
|
||||
if (bytes > 0) {
|
||||
stream.insert(stream.end(), readBuffer, readBuffer + bytes);
|
||||
}
|
||||
}
|
||||
|
||||
isReading = false;
|
||||
usleep(1);
|
||||
}
|
||||
delete readBuffer;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vector<float>* StdinReader::getFrames(unsigned frameCount, bool &forceStop)
|
||||
{
|
||||
while (isReading && !forceStop) {
|
||||
usleep(1);
|
||||
}
|
||||
if (forceStop) {
|
||||
doStop = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
isDataAccess = true;
|
||||
|
||||
unsigned offset, bytesToRead, bytesPerFrame;
|
||||
unsigned streamSize = stream.size();
|
||||
if (!streamSize) {
|
||||
isDataAccess = false;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vector<float> *frames = new vector<float>();
|
||||
bytesPerFrame = (STREAM_BITS_PER_SAMPLE >> 3) * STREAM_CHANNELS;
|
||||
bytesToRead = frameCount * bytesPerFrame;
|
||||
|
||||
if (bytesToRead > streamSize) {
|
||||
bytesToRead = streamSize - streamSize % bytesPerFrame;
|
||||
frameCount = bytesToRead / bytesPerFrame;
|
||||
}
|
||||
|
||||
vector<char> data;
|
||||
data.resize(bytesToRead);
|
||||
memcpy(&(data[0]), &(stream[0]), bytesToRead);
|
||||
stream.erase(stream.begin(), stream.begin() + bytesToRead);
|
||||
isDataAccess = false;
|
||||
|
||||
for (unsigned i = 0; i < frameCount; i++) {
|
||||
offset = bytesPerFrame * i;
|
||||
if (STREAM_CHANNELS != 1) {
|
||||
if (STREAM_BITS_PER_SAMPLE != 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 (STREAM_BITS_PER_SAMPLE != 8) {
|
||||
frames->push_back((signed char)data[offset + 1] / (float)0x80);
|
||||
} else {
|
||||
frames->push_back(data[offset] / (float)0x80 - 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
AudioFormat* StdinReader::getFormat()
|
||||
{
|
||||
AudioFormat* format = new AudioFormat;
|
||||
format->sampleRate = STREAM_SAMPLE_RATE;
|
||||
format->bitsPerSample = STREAM_BITS_PER_SAMPLE;
|
||||
format->channels = STREAM_CHANNELS;
|
||||
return format;
|
||||
}
|
||||
|
|
134
stdin_reader.h
134
stdin_reader.h
|
@ -1,67 +1,67 @@
|
|||
/*
|
||||
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 <vector>
|
||||
#include <fcntl.h>
|
||||
#include "audio_format.h"
|
||||
#include "error_reporter.h"
|
||||
|
||||
#define MAX_STREAM_SIZE 2097152
|
||||
#define STREAM_SAMPLE_RATE 22050
|
||||
#define STREAM_BITS_PER_SAMPLE 16
|
||||
#define STREAM_CHANNELS 1
|
||||
|
||||
using std::vector;
|
||||
|
||||
class StdinReader : public ErrorReporter
|
||||
{
|
||||
public:
|
||||
virtual ~StdinReader();
|
||||
|
||||
pthread_t thread;
|
||||
vector<float>* getFrames(unsigned frameCount, bool &forceStop);
|
||||
AudioFormat* getFormat();
|
||||
|
||||
static StdinReader* getInstance();
|
||||
private:
|
||||
StdinReader();
|
||||
|
||||
static vector<char> stream;
|
||||
static void* readStdin(void* params);
|
||||
static bool doStop, isDataAccess, isReading;
|
||||
};
|
||||
|
||||
#endif // STDIN_READER_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.
|
||||
*/
|
||||
|
||||
#ifndef STDIN_READER_H
|
||||
#define STDIN_READER_H
|
||||
|
||||
#include <vector>
|
||||
#include <fcntl.h>
|
||||
#include "audio_format.h"
|
||||
#include "error_reporter.h"
|
||||
|
||||
#define MAX_STREAM_SIZE 2097152
|
||||
#define STREAM_SAMPLE_RATE 22050
|
||||
#define STREAM_BITS_PER_SAMPLE 16
|
||||
#define STREAM_CHANNELS 1
|
||||
|
||||
using std::vector;
|
||||
|
||||
class StdinReader
|
||||
{
|
||||
public:
|
||||
virtual ~StdinReader();
|
||||
|
||||
pthread_t thread;
|
||||
vector<float>* getFrames(unsigned frameCount, bool &forceStop);
|
||||
AudioFormat* getFormat();
|
||||
|
||||
static StdinReader* getInstance();
|
||||
private:
|
||||
StdinReader();
|
||||
|
||||
static vector<char> stream;
|
||||
static void* readStdin(void* params);
|
||||
static bool doStop, isDataAccess, isReading;
|
||||
};
|
||||
|
||||
#endif // STDIN_READER_H
|
||||
|
|
579
transmitter.cpp
579
transmitter.cpp
|
@ -1,290 +1,289 @@
|
|||
/*
|
||||
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 "wave_reader.h"
|
||||
#include "stdin_reader.h"
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
using std::exception;
|
||||
using std::ostringstream;
|
||||
|
||||
#define GPIO_BASE 0x00200000
|
||||
#define CLK0_BASE 0x00101070
|
||||
#define CLK0DIV_BASE 0x00101074
|
||||
#define TCNT_BASE 0x00003004
|
||||
|
||||
#define STDIN_READ_DELAY 700000
|
||||
|
||||
#define ACCESS(base, offset) *(volatile unsigned*)((int)base + offset)
|
||||
#define ACCESS64(base, offset) *(volatile unsigned long long*)((int)base + offset)
|
||||
|
||||
bool Transmitter::isTransmitting = false;
|
||||
unsigned Transmitter::clockDivisor = 0;
|
||||
unsigned Transmitter::frameOffset = 0;
|
||||
vector<float>* Transmitter::buffer = NULL;
|
||||
void* Transmitter::peripherals = NULL;
|
||||
|
||||
Transmitter::Transmitter()
|
||||
{
|
||||
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);
|
||||
|
||||
machine = machine.substr(0, machine.length() - 1);
|
||||
if (machine != "armv6l") {
|
||||
isBcm2835 = false;
|
||||
}
|
||||
}
|
||||
|
||||
int memFd;
|
||||
if ((memFd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
|
||||
oss << "Cannot open /dev/mem (permission denied)";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
peripherals = mmap(NULL, 0x002FFFFF, PROT_READ | PROT_WRITE, MAP_SHARED, memFd, isBcm2835 ? 0x20000000 : 0x3F000000);
|
||||
close(memFd);
|
||||
if (peripherals == MAP_FAILED) {
|
||||
oss << "Cannot obtain access to peripherals (mmap error)";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
}
|
||||
|
||||
Transmitter::~Transmitter()
|
||||
{
|
||||
munmap(peripherals, 0x002FFFFF);
|
||||
}
|
||||
|
||||
Transmitter* Transmitter::getInstance()
|
||||
{
|
||||
static Transmitter instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void Transmitter::play(string filename, double frequency, bool loop)
|
||||
{
|
||||
ostringstream oss;
|
||||
|
||||
if (isTransmitting) {
|
||||
oss << "Cannot play, transmitter already in use";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
WaveReader* file = NULL;
|
||||
StdinReader* stdin = NULL;
|
||||
AudioFormat* format;
|
||||
|
||||
bool readStdin = filename == "-";
|
||||
|
||||
if (!readStdin) {
|
||||
file = new WaveReader(filename);
|
||||
format = file->getFormat();
|
||||
} else {
|
||||
stdin = StdinReader::getInstance();
|
||||
format = stdin->getFormat();
|
||||
usleep(STDIN_READ_DELAY);
|
||||
}
|
||||
|
||||
clockDivisor = (unsigned)((500 << 12) / frequency + 0.5);
|
||||
|
||||
isTransmitting = true;
|
||||
doStop = false;
|
||||
|
||||
unsigned bufferFrames = (unsigned)((unsigned long long)format->sampleRate * BUFFER_TIME / 1000000);
|
||||
|
||||
buffer = (!readStdin) ? file->getFrames(bufferFrames, 0) : stdin->getFrames(bufferFrames, doStop);
|
||||
|
||||
pthread_t thread;
|
||||
void* params = (void*)&format->sampleRate;
|
||||
|
||||
int returnCode = pthread_create(&thread, NULL, &Transmitter::transmit, params);
|
||||
if (returnCode) {
|
||||
oss << "Cannot create new thread (code: " << returnCode << ")";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
usleep(BUFFER_TIME / 2);
|
||||
|
||||
bool doPlay = true;
|
||||
while (doPlay && !doStop) {
|
||||
while ((readStdin || !file->isEnd(frameOffset + bufferFrames)) && !doStop) {
|
||||
if (buffer == NULL) {
|
||||
buffer = (!readStdin) ? file->getFrames(bufferFrames, frameOffset + bufferFrames) : stdin->getFrames(bufferFrames, doStop);
|
||||
}
|
||||
usleep(BUFFER_TIME / 2);
|
||||
}
|
||||
if (loop && !readStdin && !doStop) {
|
||||
isTransmitting = false;
|
||||
|
||||
buffer = file->getFrames(bufferFrames, 0);
|
||||
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
isTransmitting = true;
|
||||
|
||||
returnCode = pthread_create(&thread, NULL, &Transmitter::transmit, params);
|
||||
if (returnCode) {
|
||||
oss << "Cannot create new thread (code: " << returnCode << ")";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
} else {
|
||||
doPlay = false;
|
||||
}
|
||||
}
|
||||
isTransmitting = false;
|
||||
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
if (!readStdin) {
|
||||
delete file;
|
||||
}
|
||||
}
|
||||
|
||||
void* Transmitter::transmit(void* params)
|
||||
{
|
||||
unsigned long long current, start, playbackStart;
|
||||
unsigned offset, length, temp;
|
||||
vector<float>* frames = NULL;
|
||||
float value = 0.0;
|
||||
float* data;
|
||||
#ifndef NO_PREEMP
|
||||
float prevValue = 0.0;
|
||||
#endif
|
||||
|
||||
unsigned sampleRate = *(unsigned*)(params);
|
||||
|
||||
#ifndef NO_PREEMP
|
||||
float preemp = 0.75 - 250000.0 / (float)(sampleRate * 75);
|
||||
#endif
|
||||
|
||||
ACCESS(peripherals, GPIO_BASE) = (ACCESS(peripherals, GPIO_BASE) & 0xFFFF8FFF) | (0x01 << 14);
|
||||
ACCESS(peripherals, CLK0_BASE) = (0x5A << 24) | (0x01 << 9) | (0x01 << 4) | 0x06;
|
||||
|
||||
frameOffset = 0;
|
||||
playbackStart = ACCESS64(peripherals, TCNT_BASE);
|
||||
current = playbackStart;
|
||||
start = playbackStart;
|
||||
|
||||
while (isTransmitting) {
|
||||
while ((buffer == NULL) && !isTransmitting) {
|
||||
usleep(1);
|
||||
current = ACCESS64(peripherals, TCNT_BASE);
|
||||
}
|
||||
if (!isTransmitting) {
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
value = data[offset];
|
||||
|
||||
#ifndef NO_PREEMP
|
||||
value = value + (value - prevValue) * preemp;
|
||||
value = (value < -1.0) ? -1.0 : ((value > 1.0) ? 1.0 : value);
|
||||
#endif
|
||||
|
||||
ACCESS(peripherals, CLK0DIV_BASE) = (0x5A << 24) | ((clockDivisor) - (int)(round(value * 16.0)));
|
||||
while (temp >= offset) {
|
||||
usleep(1);
|
||||
current = ACCESS64(peripherals, TCNT_BASE);
|
||||
offset = (current - start) * (sampleRate) / 1000000;
|
||||
}
|
||||
#ifndef NO_PREEMP
|
||||
prevValue = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
start = ACCESS64(peripherals, TCNT_BASE);
|
||||
delete frames;
|
||||
}
|
||||
|
||||
ACCESS(peripherals, CLK0_BASE) = (0x5A << 24);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AudioFormat& Transmitter::getFormat(string filename)
|
||||
{
|
||||
WaveReader* file;
|
||||
StdinReader* stdin;
|
||||
AudioFormat* format;
|
||||
|
||||
if (filename != "-") {
|
||||
file = new WaveReader(filename);
|
||||
format = file->getFormat();
|
||||
delete file;
|
||||
} else {
|
||||
stdin = StdinReader::getInstance();
|
||||
format = stdin->getFormat();
|
||||
}
|
||||
return *format;
|
||||
}
|
||||
|
||||
void Transmitter::stop()
|
||||
{
|
||||
doStop = true;
|
||||
}
|
||||
/*
|
||||
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 "wave_reader.h"
|
||||
#include "stdin_reader.h"
|
||||
#include <sstream>
|
||||
#include <cmath>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
using std::ostringstream;
|
||||
|
||||
#define GPIO_BASE 0x00200000
|
||||
#define CLK0_BASE 0x00101070
|
||||
#define CLK0DIV_BASE 0x00101074
|
||||
#define TCNT_BASE 0x00003004
|
||||
|
||||
#define STDIN_READ_DELAY 700000
|
||||
|
||||
#define ACCESS(base, offset) *(volatile unsigned*)((int)base + offset)
|
||||
#define ACCESS64(base, offset) *(volatile unsigned long long*)((int)base + offset)
|
||||
|
||||
bool Transmitter::isTransmitting = false;
|
||||
unsigned Transmitter::clockDivisor = 0;
|
||||
unsigned Transmitter::frameOffset = 0;
|
||||
vector<float>* Transmitter::buffer = NULL;
|
||||
void* Transmitter::peripherals = NULL;
|
||||
|
||||
Transmitter::Transmitter()
|
||||
{
|
||||
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);
|
||||
|
||||
machine = machine.substr(0, machine.length() - 1);
|
||||
if (machine != "armv6l") {
|
||||
isBcm2835 = false;
|
||||
}
|
||||
}
|
||||
|
||||
int memFd;
|
||||
if ((memFd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
|
||||
throw ErrorReporter("Cannot open /dev/mem (permission denied)");
|
||||
}
|
||||
|
||||
peripherals = mmap(NULL, 0x002FFFFF, PROT_READ | PROT_WRITE, MAP_SHARED, memFd, isBcm2835 ? 0x20000000 : 0x3F000000);
|
||||
close(memFd);
|
||||
if (peripherals == MAP_FAILED) {
|
||||
throw ErrorReporter("Cannot obtain access to peripherals (mmap error)");
|
||||
}
|
||||
}
|
||||
|
||||
Transmitter::~Transmitter()
|
||||
{
|
||||
munmap(peripherals, 0x002FFFFF);
|
||||
}
|
||||
|
||||
Transmitter* Transmitter::getInstance()
|
||||
{
|
||||
static Transmitter instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
void Transmitter::play(string filename, double frequency, bool loop)
|
||||
{
|
||||
if (isTransmitting) {
|
||||
throw ErrorReporter("Cannot play, transmitter already in use");
|
||||
}
|
||||
|
||||
WaveReader* file = NULL;
|
||||
StdinReader* stdin = NULL;
|
||||
AudioFormat* format;
|
||||
|
||||
bool readStdin = filename == "-";
|
||||
|
||||
if (!readStdin) {
|
||||
file = new WaveReader(filename);
|
||||
format = file->getFormat();
|
||||
} else {
|
||||
stdin = StdinReader::getInstance();
|
||||
format = stdin->getFormat();
|
||||
usleep(STDIN_READ_DELAY);
|
||||
}
|
||||
|
||||
clockDivisor = (unsigned)((500 << 12) / frequency + 0.5);
|
||||
|
||||
isTransmitting = true;
|
||||
doStop = false;
|
||||
|
||||
unsigned bufferFrames = (unsigned)((unsigned long long)format->sampleRate * BUFFER_TIME / 1000000);
|
||||
|
||||
buffer = (!readStdin) ? file->getFrames(bufferFrames, 0) : stdin->getFrames(bufferFrames, doStop);
|
||||
|
||||
pthread_t thread;
|
||||
void* params = (void*)&format->sampleRate;
|
||||
|
||||
int returnCode = pthread_create(&thread, NULL, &Transmitter::transmit, params);
|
||||
if (returnCode) {
|
||||
if (!readStdin) {
|
||||
delete file;
|
||||
}
|
||||
delete format;
|
||||
ostringstream oss;
|
||||
oss << "Cannot create new thread (code: " << returnCode << ")";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
|
||||
usleep(BUFFER_TIME / 2);
|
||||
|
||||
bool doPlay = true;
|
||||
while (doPlay && !doStop) {
|
||||
while ((readStdin || !file->isEnd(frameOffset + bufferFrames)) && !doStop) {
|
||||
if (buffer == NULL) {
|
||||
buffer = (!readStdin) ? file->getFrames(bufferFrames, frameOffset + bufferFrames) : stdin->getFrames(bufferFrames, doStop);
|
||||
}
|
||||
usleep(BUFFER_TIME / 2);
|
||||
}
|
||||
if (loop && !readStdin && !doStop) {
|
||||
isTransmitting = false;
|
||||
|
||||
buffer = file->getFrames(bufferFrames, 0);
|
||||
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
isTransmitting = true;
|
||||
|
||||
returnCode = pthread_create(&thread, NULL, &Transmitter::transmit, params);
|
||||
if (returnCode) {
|
||||
if (!readStdin) {
|
||||
delete file;
|
||||
}
|
||||
delete format;
|
||||
ostringstream oss;
|
||||
oss << "Cannot create new thread (code: " << returnCode << ")";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
} else {
|
||||
doPlay = false;
|
||||
}
|
||||
}
|
||||
isTransmitting = false;
|
||||
|
||||
pthread_join(thread, NULL);
|
||||
|
||||
if (!readStdin) {
|
||||
delete file;
|
||||
}
|
||||
delete format;
|
||||
}
|
||||
|
||||
void* Transmitter::transmit(void* params)
|
||||
{
|
||||
unsigned long long current, start, playbackStart;
|
||||
unsigned offset, length, temp;
|
||||
vector<float>* frames = NULL;
|
||||
float value = 0.0;
|
||||
float* data;
|
||||
#ifndef NO_PREEMP
|
||||
float prevValue = 0.0;
|
||||
#endif
|
||||
|
||||
unsigned sampleRate = *(unsigned*)(params);
|
||||
|
||||
#ifndef NO_PREEMP
|
||||
float preemp = 0.75 - 250000.0 / (float)(sampleRate * 75);
|
||||
#endif
|
||||
|
||||
ACCESS(peripherals, GPIO_BASE) = (ACCESS(peripherals, GPIO_BASE) & 0xFFFF8FFF) | (0x01 << 14);
|
||||
ACCESS(peripherals, CLK0_BASE) = (0x5A << 24) | (0x01 << 9) | (0x01 << 4) | 0x06;
|
||||
|
||||
frameOffset = 0;
|
||||
playbackStart = ACCESS64(peripherals, TCNT_BASE);
|
||||
current = playbackStart;
|
||||
start = playbackStart;
|
||||
|
||||
while (isTransmitting) {
|
||||
while ((buffer == NULL) && !isTransmitting) {
|
||||
usleep(1);
|
||||
current = ACCESS64(peripherals, TCNT_BASE);
|
||||
}
|
||||
if (!isTransmitting) {
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
value = data[offset];
|
||||
|
||||
#ifndef NO_PREEMP
|
||||
value = value + (value - prevValue) * preemp;
|
||||
value = (value < -1.0) ? -1.0 : ((value > 1.0) ? 1.0 : value);
|
||||
#endif
|
||||
|
||||
ACCESS(peripherals, CLK0DIV_BASE) = (0x5A << 24) | ((clockDivisor) - (int)(round(value * 16.0)));
|
||||
while (temp >= offset) {
|
||||
usleep(1);
|
||||
current = ACCESS64(peripherals, TCNT_BASE);
|
||||
offset = (current - start) * (sampleRate) / 1000000;
|
||||
}
|
||||
#ifndef NO_PREEMP
|
||||
prevValue = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
start = ACCESS64(peripherals, TCNT_BASE);
|
||||
delete frames;
|
||||
}
|
||||
|
||||
ACCESS(peripherals, CLK0_BASE) = (0x5A << 24);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AudioFormat* Transmitter::getFormat(string filename)
|
||||
{
|
||||
WaveReader* file;
|
||||
StdinReader* stdin;
|
||||
AudioFormat* format;
|
||||
|
||||
if (filename != "-") {
|
||||
file = new WaveReader(filename);
|
||||
format = file->getFormat();
|
||||
delete file;
|
||||
} else {
|
||||
stdin = StdinReader::getInstance();
|
||||
format = stdin->getFormat();
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
void Transmitter::stop()
|
||||
{
|
||||
doStop = true;
|
||||
}
|
||||
|
|
138
transmitter.h
138
transmitter.h
|
@ -1,69 +1,69 @@
|
|||
/*
|
||||
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 "error_reporter.h"
|
||||
#include "audio_format.h"
|
||||
#include <vector>
|
||||
|
||||
using std::vector;
|
||||
|
||||
#define BUFFER_TIME 1000000
|
||||
|
||||
using std::string;
|
||||
|
||||
class Transmitter : public ErrorReporter
|
||||
{
|
||||
public:
|
||||
virtual ~Transmitter();
|
||||
|
||||
void play(string filename, double frequency, bool loop);
|
||||
void stop();
|
||||
|
||||
static Transmitter* getInstance();
|
||||
static AudioFormat& getFormat(string filename);
|
||||
private:
|
||||
Transmitter();
|
||||
|
||||
bool doStop;
|
||||
|
||||
static void* peripherals;
|
||||
static vector<float>* buffer;
|
||||
static unsigned frameOffset, clockDivisor;
|
||||
static bool isTransmitting;
|
||||
static void* transmit(void* params);
|
||||
};
|
||||
|
||||
#endif // TRANSMITTER_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.
|
||||
*/
|
||||
|
||||
#ifndef TRANSMITTER_H
|
||||
#define TRANSMITTER_H
|
||||
|
||||
#include "error_reporter.h"
|
||||
#include "audio_format.h"
|
||||
#include <vector>
|
||||
|
||||
using std::vector;
|
||||
|
||||
#define BUFFER_TIME 1000000
|
||||
|
||||
using std::string;
|
||||
|
||||
class Transmitter
|
||||
{
|
||||
public:
|
||||
virtual ~Transmitter();
|
||||
|
||||
void play(string filename, double frequency, bool loop);
|
||||
void stop();
|
||||
|
||||
static Transmitter* getInstance();
|
||||
static AudioFormat* getFormat(string filename);
|
||||
private:
|
||||
Transmitter();
|
||||
|
||||
bool doStop;
|
||||
|
||||
static void* peripherals;
|
||||
static vector<float>* buffer;
|
||||
static unsigned frameOffset, clockDivisor;
|
||||
static bool isTransmitting;
|
||||
static void* transmit(void* params);
|
||||
};
|
||||
|
||||
#endif // TRANSMITTER_H
|
||||
|
|
386
wave_reader.cpp
386
wave_reader.cpp
|
@ -1,193 +1,193 @@
|
|||
/*
|
||||
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 <exception>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
|
||||
using std::exception;
|
||||
using std::ostringstream;
|
||||
|
||||
WaveReader::WaveReader(string filename) :
|
||||
filename(filename)
|
||||
{
|
||||
char* headerData;
|
||||
vector<char>* data;
|
||||
unsigned bytesToRead, headerOffset;
|
||||
ostringstream oss;
|
||||
|
||||
ifs.open(filename.c_str(), ifstream::binary);
|
||||
headerData = (char*)((void*)&header);
|
||||
|
||||
if (!ifs.is_open()) {
|
||||
oss << "Cannot open " << filename << ", file does not exist";
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
ifs.seekg(0, ifs.end);
|
||||
fileSize = ifs.tellg();
|
||||
ifs.seekg(0, ifs.beg);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
bytesToRead = sizeof(PCMWaveHeader::subchunk1ID) + sizeof(PCMWaveHeader::subchunk1Size);
|
||||
data = readData(bytesToRead, true);
|
||||
memcpy(&headerData[headerOffset], &(*data)[0], bytesToRead);
|
||||
headerOffset += bytesToRead;
|
||||
delete data;
|
||||
|
||||
unsigned 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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
vector<char>* WaveReader::readData(unsigned bytesToRead, bool closeFileOnException)
|
||||
{
|
||||
ostringstream oss;
|
||||
if (fileSize < (unsigned)ifs.tellg() + bytesToRead) {
|
||||
oss << "Error while reading " << filename << ", data corrupted";
|
||||
if (closeFileOnException) ifs.close();
|
||||
errorMessage = oss.str();
|
||||
throw exception();
|
||||
}
|
||||
|
||||
vector<char>* data = new vector<char>();
|
||||
data->resize(bytesToRead);
|
||||
ifs.read(&(*data)[0], bytesToRead);
|
||||
return data;
|
||||
}
|
||||
|
||||
vector<float>* WaveReader::getFrames(unsigned frameCount, unsigned frameOffset) {
|
||||
unsigned bytesToRead, bytesLeft, bytesPerFrame, offset;
|
||||
vector<float>* frames = new vector<float>();
|
||||
vector<char>* data;
|
||||
|
||||
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 i = 0; i < frameCount; i++) {
|
||||
offset = bytesPerFrame * i;
|
||||
if (header.channels != 1) {
|
||||
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) {
|
||||
frames->push_back((signed char)(*data)[offset + 1] / (float)0x80);
|
||||
} else {
|
||||
frames->push_back((*data)[offset] / (float)0x80 - 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete data;
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
bool WaveReader::isEnd(unsigned frameOffset)
|
||||
{
|
||||
return header.subchunk2Size <= frameOffset * (header.bitsPerSample >> 3) * header.channels;
|
||||
}
|
||||
|
||||
AudioFormat* WaveReader::getFormat()
|
||||
{
|
||||
AudioFormat* format = new AudioFormat;
|
||||
format->channels = header.channels;
|
||||
format->sampleRate = header.sampleRate;
|
||||
format->bitsPerSample = header.bitsPerSample;
|
||||
return format;
|
||||
}
|
||||
/*
|
||||
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 "error_reporter.h"
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
|
||||
using std::ostringstream;
|
||||
using std::exception;
|
||||
|
||||
WaveReader::WaveReader(string filename) :
|
||||
filename(filename)
|
||||
{
|
||||
char* headerData;
|
||||
vector<char>* data;
|
||||
unsigned bytesToRead, headerOffset;
|
||||
ostringstream oss;
|
||||
|
||||
ifs.open(filename.c_str(), ifstream::binary);
|
||||
headerData = (char*)((void*)&header);
|
||||
|
||||
if (!ifs.is_open()) {
|
||||
oss << "Cannot open " << filename << ", file does not exist";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
|
||||
ifs.seekg(0, ifs.end);
|
||||
fileSize = ifs.tellg();
|
||||
ifs.seekg(0, ifs.beg);
|
||||
|
||||
try {
|
||||
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";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
|
||||
bytesToRead = sizeof(PCMWaveHeader::subchunk1ID) + sizeof(PCMWaveHeader::subchunk1Size);
|
||||
data = readData(bytesToRead, true);
|
||||
memcpy(&headerData[headerOffset], &(*data)[0], bytesToRead);
|
||||
headerOffset += bytesToRead;
|
||||
delete data;
|
||||
|
||||
unsigned 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";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
|
||||
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";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
|
||||
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";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
} catch (ErrorReporter &error) {
|
||||
ifs.close();
|
||||
throw error;
|
||||
}
|
||||
|
||||
dataOffset = ifs.tellg();
|
||||
}
|
||||
|
||||
WaveReader::~WaveReader()
|
||||
{
|
||||
ifs.close();
|
||||
}
|
||||
|
||||
vector<char>* WaveReader::readData(unsigned bytesToRead, bool closeFileOnException)
|
||||
{
|
||||
if (fileSize < (unsigned)ifs.tellg() + bytesToRead) {
|
||||
ostringstream oss;
|
||||
oss << "Error while reading " << filename << ", data corrupted";
|
||||
if (closeFileOnException) ifs.close();
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
|
||||
vector<char>* data = new vector<char>();
|
||||
data->resize(bytesToRead);
|
||||
ifs.read(&(*data)[0], bytesToRead);
|
||||
return data;
|
||||
}
|
||||
|
||||
vector<float>* WaveReader::getFrames(unsigned frameCount, unsigned frameOffset) {
|
||||
unsigned bytesToRead, bytesLeft, bytesPerFrame, offset;
|
||||
vector<float>* frames = new vector<float>();
|
||||
vector<char>* data;
|
||||
|
||||
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);
|
||||
|
||||
try {
|
||||
data = readData(bytesToRead, false);
|
||||
} catch (ErrorReporter &error) {
|
||||
delete frames;
|
||||
throw error;
|
||||
}
|
||||
for (unsigned i = 0; i < frameCount; i++) {
|
||||
offset = bytesPerFrame * i;
|
||||
if (header.channels != 1) {
|
||||
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) {
|
||||
frames->push_back((signed char)(*data)[offset + 1] / (float)0x80);
|
||||
} else {
|
||||
frames->push_back((*data)[offset] / (float)0x80 - 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete data;
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
bool WaveReader::isEnd(unsigned frameOffset)
|
||||
{
|
||||
return header.subchunk2Size <= frameOffset * (header.bitsPerSample >> 3) * header.channels;
|
||||
}
|
||||
|
||||
AudioFormat* WaveReader::getFormat()
|
||||
{
|
||||
AudioFormat* format = new AudioFormat;
|
||||
format->channels = header.channels;
|
||||
format->sampleRate = header.sampleRate;
|
||||
format->bitsPerSample = header.bitsPerSample;
|
||||
return format;
|
||||
}
|
||||
|
|
131
wave_reader.h
131
wave_reader.h
|
@ -1,66 +1,65 @@
|
|||
/*
|
||||
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 "audio_format.h"
|
||||
#include "pcm_wave_header.h"
|
||||
#include "error_reporter.h"
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::ifstream;
|
||||
|
||||
class WaveReader : public ErrorReporter
|
||||
{
|
||||
public:
|
||||
WaveReader(string filename);
|
||||
virtual ~WaveReader();
|
||||
|
||||
AudioFormat* getFormat();
|
||||
vector<float>* getFrames(unsigned frameCount, unsigned frameOffset);
|
||||
bool isEnd(unsigned frameOffset);
|
||||
private:
|
||||
string filename;
|
||||
PCMWaveHeader header;
|
||||
unsigned fileSize, dataOffset;
|
||||
ifstream ifs;
|
||||
|
||||
vector<char>* readData(unsigned bytesToRead, bool closeFileOnException);
|
||||
};
|
||||
|
||||
#endif // WAVE_READER_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.
|
||||
*/
|
||||
|
||||
#ifndef WAVE_READER_H
|
||||
#define WAVE_READER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include "audio_format.h"
|
||||
#include "pcm_wave_header.h"
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::ifstream;
|
||||
|
||||
class WaveReader
|
||||
{
|
||||
public:
|
||||
WaveReader(string filename);
|
||||
virtual ~WaveReader();
|
||||
|
||||
AudioFormat* getFormat();
|
||||
vector<float>* getFrames(unsigned frameCount, unsigned frameOffset);
|
||||
bool isEnd(unsigned frameOffset);
|
||||
private:
|
||||
string filename;
|
||||
PCMWaveHeader header;
|
||||
unsigned fileSize, dataOffset;
|
||||
ifstream ifs;
|
||||
|
||||
vector<char>* readData(unsigned bytesToRead, bool closeFileOnException);
|
||||
};
|
||||
|
||||
#endif // WAVE_READER_H
|
||||
|
|
Ładowanie…
Reference in New Issue