kopia lustrzana https://github.com/markondej/fm_transmitter
New universal reader
rodzic
c9ccbd584d
commit
7c5bc916bb
7
makefile
7
makefile
|
@ -3,15 +3,12 @@ TARGET = fm_transmitter
|
|||
|
||||
CPP=$(CCPREFIX)g++
|
||||
|
||||
all: main.o error_reporter.o wave_reader.o stdin_reader.o transmitter.o
|
||||
$(CPP) $(CFLAGS) -o $(TARGET) main.o error_reporter.o wave_reader.o stdin_reader.o transmitter.o
|
||||
all: main.o error_reporter.o wave_reader.o transmitter.o
|
||||
$(CPP) $(CFLAGS) -o $(TARGET) main.o error_reporter.o wave_reader.o transmitter.o
|
||||
|
||||
wave_reader.o: wave_reader.cpp wave_reader.h
|
||||
$(CPP) $(CFLAGS) -c wave_reader.cpp
|
||||
|
||||
stdin_reader.o: stdin_reader.cpp stdin_reader.h
|
||||
$(CPP) $(CFLAGS) -c stdin_reader.cpp
|
||||
|
||||
error_reporter.o: error_reporter.cpp error_reporter.h
|
||||
$(CPP) $(CFLAGS) -c error_reporter.cpp
|
||||
|
||||
|
|
166
stdin_reader.cpp
166
stdin_reader.cpp
|
@ -1,166 +0,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 "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;
|
||||
}
|
|
@ -1,67 +0,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.
|
||||
*/
|
||||
|
||||
#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
|
|
@ -33,13 +33,12 @@
|
|||
|
||||
#include "wave_reader.h"
|
||||
#include "error_reporter.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
using std::ostringstream;
|
||||
using std::exception;
|
||||
using std::cin;
|
||||
|
||||
WaveReader::WaveReader(string filename, bool &forceStop) :
|
||||
filename(filename), fileSize(0)
|
||||
|
@ -50,20 +49,19 @@ WaveReader::WaveReader(string filename, bool &forceStop) :
|
|||
ostringstream oss;
|
||||
|
||||
if (!filename.empty()) {
|
||||
ifs.open(filename.c_str(), ifstream::binary);
|
||||
|
||||
if (!ifs.is_open()) {
|
||||
oss << "Cannot open " << filename << ", file does not exist";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
|
||||
is = &ifs;
|
||||
|
||||
is->seekg(0, is->end);
|
||||
fileSize = is->tellg();
|
||||
is->seekg(0, is->beg);
|
||||
fileDescriptor = open(filename.c_str(), O_RDONLY);
|
||||
} else {
|
||||
is = &cin;
|
||||
fileDescriptor = STDIN_FILENO;
|
||||
}
|
||||
|
||||
if (fileDescriptor == -1) {
|
||||
oss << "Cannot open " << getFilename() << ", file does not exist";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
|
||||
if (!filename.empty()) {
|
||||
fileSize = lseek(fileDescriptor, 0, SEEK_END);
|
||||
lseek(fileDescriptor, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -121,26 +119,26 @@ WaveReader::WaveReader(string filename, bool &forceStop) :
|
|||
headerOffset += bytesToRead;
|
||||
delete data;
|
||||
|
||||
if ((string(header.subchunk2ID, 4) != string("data")) || (header.subchunk2Size + ifs.tellg() < fileSize)) {
|
||||
if ((string(header.subchunk2ID, 4) != string("data")) || (header.subchunk2Size + lseek(fileDescriptor, 0, SEEK_CUR) < fileSize)) {
|
||||
oss << "Error while opening " << getFilename() << ", data corrupted";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
} catch (ErrorReporter &error) {
|
||||
if (!filename.empty()) {
|
||||
ifs.close();
|
||||
close(fileDescriptor);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!filename.empty()) {
|
||||
dataOffset = is->tellg();
|
||||
dataOffset = lseek(fileDescriptor, 0, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
|
||||
WaveReader::~WaveReader()
|
||||
{
|
||||
if (!filename.empty()) {
|
||||
ifs.close();
|
||||
close(fileDescriptor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -151,18 +149,19 @@ vector<char>* WaveReader::readData(unsigned bytesToRead, bool &forceStop, bool c
|
|||
data->resize(bytesToRead);
|
||||
|
||||
while ((bytesRead < bytesToRead) && !forceStop) {
|
||||
if (is->eof()) {
|
||||
int bytes = read(fileDescriptor, &(*data)[0], bytesToRead - bytesRead);
|
||||
if (bytes == -1) {
|
||||
delete data;
|
||||
|
||||
if (closeFileOnException && !filename.empty()) {
|
||||
ifs.close();
|
||||
close(fileDescriptor);
|
||||
}
|
||||
|
||||
ostringstream oss;
|
||||
oss << "Error while reading " << getFilename() << ", data corrupted";
|
||||
oss << "Error while reading " << getFilename() << ", file is corrupted";
|
||||
throw ErrorReporter(oss.str());
|
||||
}
|
||||
bytesRead += is->readsome(&(*data)[0], bytesToRead - bytesRead);
|
||||
bytesRead += bytes;
|
||||
}
|
||||
|
||||
if (forceStop) {
|
||||
|
@ -187,7 +186,9 @@ vector<float>* WaveReader::getFrames(unsigned frameCount, unsigned frameOffset,
|
|||
bytesToRead = bytesLeft - bytesLeft % bytesPerFrame;
|
||||
frameCount = bytesToRead / bytesPerFrame;
|
||||
}
|
||||
is->seekg(dataOffset + frameOffset * bytesPerFrame);
|
||||
if (lseek(fileDescriptor, dataOffset + frameOffset * bytesPerFrame, SEEK_SET) == -1) {
|
||||
throw new ErrorReporter("File is corrupted!");
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -36,15 +36,11 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <istream>
|
||||
#include <fstream>
|
||||
#include "audio_format.h"
|
||||
#include "pcm_wave_header.h"
|
||||
|
||||
using std::vector;
|
||||
using std::string;
|
||||
using std::istream;
|
||||
using std::ifstream;
|
||||
|
||||
class WaveReader
|
||||
{
|
||||
|
@ -59,8 +55,7 @@ class WaveReader
|
|||
string filename;
|
||||
PCMWaveHeader header;
|
||||
unsigned fileSize, dataOffset;
|
||||
ifstream ifs;
|
||||
istream* is;
|
||||
int fileDescriptor;
|
||||
|
||||
vector<char>* readData(unsigned bytesToRead, bool &forceStop, bool closeFileOnException);
|
||||
string getFilename();
|
||||
|
|
Ładowanie…
Reference in New Issue