kopia lustrzana https://github.com/markondej/fm_transmitter
Merge 6dfa17b97f
into 00c1337ab0
commit
d6688a0766
|
@ -95,9 +95,9 @@ int main(int argc, char** argv)
|
||||||
<< bandwidth << " kHz bandwidth" << std::endl;
|
<< bandwidth << " kHz bandwidth" << std::endl;
|
||||||
do {
|
do {
|
||||||
std::string filename = argv[optind++];
|
std::string filename = argv[optind++];
|
||||||
if ((optind == argc) && loop) {
|
if ((optind == argc) && loop)
|
||||||
optind = filesOffset;
|
optind = filesOffset;
|
||||||
}
|
|
||||||
WaveReader reader(filename != "-" ? filename : std::string(), enable, mtx);
|
WaveReader reader(filename != "-" ? filename : std::string(), enable, mtx);
|
||||||
WaveHeader header = reader.GetHeader();
|
WaveHeader header = reader.GetHeader();
|
||||||
std::cout << "Playing: " << reader.GetFilename() << ", "
|
std::cout << "Playing: " << reader.GetFilename() << ", "
|
||||||
|
|
|
@ -169,21 +169,18 @@ class Peripherals
|
||||||
private:
|
private:
|
||||||
Peripherals() {
|
Peripherals() {
|
||||||
int memFd;
|
int memFd;
|
||||||
if ((memFd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
|
if ((memFd = open("/dev/mem", O_RDWR | O_SYNC)) < 0)
|
||||||
throw std::runtime_error("Cannot open /dev/mem file (permission denied)");
|
throw std::runtime_error("Cannot open /dev/mem file (permission denied)");
|
||||||
}
|
|
||||||
|
|
||||||
peripherals = mmap(nullptr, GetSize(), PROT_READ | PROT_WRITE, MAP_SHARED, memFd, GetVirtualBaseAddress());
|
peripherals = mmap(nullptr, GetSize(), PROT_READ | PROT_WRITE, MAP_SHARED, memFd, GetVirtualBaseAddress());
|
||||||
close(memFd);
|
close(memFd);
|
||||||
if (peripherals == MAP_FAILED) {
|
if (peripherals == MAP_FAILED)
|
||||||
throw std::runtime_error("Cannot obtain access to peripherals (mmap error)");
|
throw std::runtime_error("Cannot obtain access to peripherals (mmap error)");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
unsigned GetSize() {
|
unsigned GetSize() {
|
||||||
unsigned size = bcm_host_get_peripheral_size();
|
unsigned size = bcm_host_get_peripheral_size();
|
||||||
if (size == BCM2711_PERI_VIRT_BASE) {
|
if (size == BCM2711_PERI_VIRT_BASE)
|
||||||
size = 0x01000000;
|
size = 0x01000000;
|
||||||
}
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,9 +194,8 @@ class AllocatedMemory
|
||||||
AllocatedMemory(unsigned size) {
|
AllocatedMemory(unsigned size) {
|
||||||
mBoxFd = mbox_open();
|
mBoxFd = mbox_open();
|
||||||
memSize = size;
|
memSize = size;
|
||||||
if (memSize % PAGE_SIZE) {
|
if (memSize % PAGE_SIZE)
|
||||||
memSize = (memSize / PAGE_SIZE + 1) * PAGE_SIZE;
|
memSize = (memSize / PAGE_SIZE + 1) * PAGE_SIZE;
|
||||||
}
|
|
||||||
memHandle = mem_alloc(mBoxFd, size, PAGE_SIZE, (Peripherals::GetVirtualBaseAddress() == BCM2835_PERI_VIRT_BASE) ? BCM2835_MEM_FLAG : BCM2711_MEM_FLAG);
|
memHandle = mem_alloc(mBoxFd, size, PAGE_SIZE, (Peripherals::GetVirtualBaseAddress() == BCM2835_PERI_VIRT_BASE) ? BCM2835_MEM_FLAG : BCM2711_MEM_FLAG);
|
||||||
if (!memHandle) {
|
if (!memHandle) {
|
||||||
mbox_close(mBoxFd);
|
mbox_close(mBoxFd);
|
||||||
|
@ -353,9 +349,8 @@ Transmitter::~Transmitter() {
|
||||||
cv.wait(lock, [&]() -> bool {
|
cv.wait(lock, [&]() -> bool {
|
||||||
return !enable;
|
return !enable;
|
||||||
});
|
});
|
||||||
if (output) {
|
if (output)
|
||||||
delete output;
|
delete output;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transmitter::Transmit(WaveReader &reader, float frequency, float bandwidth, unsigned dmaChannel, bool preserveCarrier)
|
void Transmitter::Transmit(WaveReader &reader, float frequency, float bandwidth, unsigned dmaChannel, bool preserveCarrier)
|
||||||
|
@ -383,15 +378,13 @@ void Transmitter::Transmit(WaveReader &reader, float frequency, float bandwidth,
|
||||||
unsigned clockDivisor = static_cast<unsigned>(round(Peripherals::GetClockFrequency() * (0x01 << 12) / frequency));
|
unsigned clockDivisor = static_cast<unsigned>(round(Peripherals::GetClockFrequency() * (0x01 << 12) / frequency));
|
||||||
unsigned divisorRange = clockDivisor - static_cast<unsigned>(round(Peripherals::GetClockFrequency() * (0x01 << 12) / (frequency + 0.0005f * bandwidth)));
|
unsigned divisorRange = clockDivisor - static_cast<unsigned>(round(Peripherals::GetClockFrequency() * (0x01 << 12) / (frequency + 0.0005f * bandwidth)));
|
||||||
|
|
||||||
if (!output) {
|
if (!output)
|
||||||
output = new ClockOutput(clockDivisor);
|
output = new ClockOutput(clockDivisor);
|
||||||
}
|
|
||||||
|
|
||||||
if (dmaChannel != 0xff) {
|
if (dmaChannel != 0xff)
|
||||||
TxViaDma(reader, header.sampleRate, bufferSize, clockDivisor, divisorRange, dmaChannel);
|
TxViaDma(reader, header.sampleRate, bufferSize, clockDivisor, divisorRange, dmaChannel);
|
||||||
} else {
|
else
|
||||||
TxViaCpu(reader, header.sampleRate, bufferSize, clockDivisor, divisorRange);
|
TxViaCpu(reader, header.sampleRate, bufferSize, clockDivisor, divisorRange);
|
||||||
}
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
finally();
|
finally();
|
||||||
throw;
|
throw;
|
||||||
|
@ -409,16 +402,14 @@ void Transmitter::Stop()
|
||||||
|
|
||||||
void Transmitter::TxViaDma(WaveReader &reader, unsigned sampleRate, unsigned bufferSize, unsigned clockDivisor, unsigned divisorRange, unsigned dmaChannel)
|
void Transmitter::TxViaDma(WaveReader &reader, unsigned sampleRate, unsigned bufferSize, unsigned clockDivisor, unsigned divisorRange, unsigned dmaChannel)
|
||||||
{
|
{
|
||||||
if (dmaChannel > 15) {
|
if (dmaChannel > 15)
|
||||||
throw std::runtime_error("DMA channel number out of range (0 - 15)");
|
throw std::runtime_error("DMA channel number out of range (0 - 15)");
|
||||||
}
|
|
||||||
|
|
||||||
AllocatedMemory allocated(sizeof(uint32_t) * bufferSize + sizeof(DMAControllBlock) * (2 * bufferSize) + sizeof(uint32_t));
|
AllocatedMemory allocated(sizeof(uint32_t) * bufferSize + sizeof(DMAControllBlock) * (2 * bufferSize) + sizeof(uint32_t));
|
||||||
|
|
||||||
std::vector<Sample> samples = reader.GetSamples(bufferSize, enable, mtx);
|
std::vector<Sample> samples = reader.GetSamples(bufferSize, enable, mtx);
|
||||||
if (samples.empty()) {
|
if (samples.empty())
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
bool eof = false;
|
bool eof = false;
|
||||||
if (samples.size() < bufferSize) {
|
if (samples.size() < bufferSize) {
|
||||||
|
@ -461,30 +452,27 @@ void Transmitter::TxViaDma(WaveReader &reader, unsigned sampleRate, unsigned buf
|
||||||
|
|
||||||
auto finally = [&]() {
|
auto finally = [&]() {
|
||||||
dmaCb[(cbOffset < 2 * bufferSize) ? cbOffset : 0].nextCbAddress = 0x00000000;
|
dmaCb[(cbOffset < 2 * bufferSize) ? cbOffset : 0].nextCbAddress = 0x00000000;
|
||||||
while (dma.GetControllBlockAddress() != 0x00000000) {
|
while (dma.GetControllBlockAddress() != 0x00000000)
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
}
|
|
||||||
samples.clear();
|
samples.clear();
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
while (!eof) {
|
while (!eof) {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
if (!enable) {
|
if (!enable)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
samples = reader.GetSamples(bufferSize, enable, mtx);
|
samples = reader.GetSamples(bufferSize, enable, mtx);
|
||||||
if (!samples.size()) {
|
if (!samples.size())
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
cbOffset = 0;
|
cbOffset = 0;
|
||||||
eof = samples.size() < bufferSize;
|
eof = samples.size() < bufferSize;
|
||||||
for (std::size_t i = 0; i < samples.size(); i++) {
|
for (std::size_t i = 0; i < samples.size(); i++) {
|
||||||
float value = samples[i].GetMonoValue();
|
float value = samples[i].GetMonoValue();
|
||||||
while (i == ((dma.GetControllBlockAddress() - allocated.GetPhysicalAddress(dmaCb)) / (2 * sizeof(DMAControllBlock)))) {
|
while (i == ((dma.GetControllBlockAddress() - allocated.GetPhysicalAddress(dmaCb)) / (2 * sizeof(DMAControllBlock))))
|
||||||
std::this_thread::sleep_for(std::chrono::microseconds(BUFFER_TIME / 10));
|
std::this_thread::sleep_for(std::chrono::microseconds(BUFFER_TIME / 10));
|
||||||
}
|
|
||||||
clkDiv[i] = CLK_PASSWORD | (0xffffff & (clockDivisor - static_cast<int>(round(value * divisorRange))));
|
clkDiv[i] = CLK_PASSWORD | (0xffffff & (clockDivisor - static_cast<int>(round(value * divisorRange))));
|
||||||
cbOffset += 2;
|
cbOffset += 2;
|
||||||
}
|
}
|
||||||
|
@ -523,28 +511,28 @@ void Transmitter::TxViaCpu(WaveReader &reader, unsigned sampleRate, unsigned buf
|
||||||
return samples.empty() || !enable || stop;
|
return samples.empty() || !enable || stop;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!enable) {
|
|
||||||
|
if (!enable)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (stop) {
|
if (stop)
|
||||||
throw std::runtime_error("Transmitter thread has unexpectedly exited");
|
throw std::runtime_error("Transmitter thread has unexpectedly exited");
|
||||||
}
|
|
||||||
if (samples.empty()) {
|
if (samples.empty()) {
|
||||||
if (!reader.SetSampleOffset(sampleOffset + (start ? 0 : bufferSize))) {
|
if (!reader.SetSampleOffset(sampleOffset + (start ? 0 : bufferSize)))
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
samples = reader.GetSamples(bufferSize, enable, mtx);
|
samples = reader.GetSamples(bufferSize, enable, mtx);
|
||||||
lock.lock();
|
lock.lock();
|
||||||
if (samples.empty()) {
|
if (samples.empty())
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
eof = samples.size() < bufferSize;
|
eof = samples.size() < bufferSize;
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
cv.notify_all();
|
cv.notify_all();
|
||||||
} else {
|
} else
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
|
||||||
start = false;
|
start = false;
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
@ -567,9 +555,10 @@ void Transmitter::CpuTxThread(unsigned sampleRate, unsigned clockDivisor, unsign
|
||||||
cv.wait(lock, [&]() -> bool {
|
cv.wait(lock, [&]() -> bool {
|
||||||
return !samples->empty() || *stop;
|
return !samples->empty() || *stop;
|
||||||
});
|
});
|
||||||
if (*stop) {
|
|
||||||
|
if (*stop)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
start = current = std::chrono::system_clock::now();
|
start = current = std::chrono::system_clock::now();
|
||||||
*sampleOffset = std::chrono::duration_cast<std::chrono::microseconds>(current - playbackStart).count() * sampleRate / 1000000;
|
*sampleOffset = std::chrono::duration_cast<std::chrono::microseconds>(current - playbackStart).count() * sampleRate / 1000000;
|
||||||
loadedSamples = std::move(*samples);
|
loadedSamples = std::move(*samples);
|
||||||
|
@ -579,9 +568,9 @@ void Transmitter::CpuTxThread(unsigned sampleRate, unsigned clockDivisor, unsign
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (offset >= loadedSamples.size()) {
|
if (offset >= loadedSamples.size())
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
unsigned prevOffset = offset;
|
unsigned prevOffset = offset;
|
||||||
float value = loadedSamples[offset].GetMonoValue();
|
float value = loadedSamples[offset].GetMonoValue();
|
||||||
output->SetDivisor(clockDivisor - static_cast<int>(round(value * divisorRange)));
|
output->SetDivisor(clockDivisor - static_cast<int>(round(value * divisorRange)));
|
||||||
|
|
125
wave_reader.cpp
125
wave_reader.cpp
|
@ -43,21 +43,18 @@
|
||||||
Sample::Sample(uint8_t *data, unsigned channels, unsigned bitsPerChannel)
|
Sample::Sample(uint8_t *data, unsigned channels, unsigned bitsPerChannel)
|
||||||
: value(0.f)
|
: value(0.f)
|
||||||
{
|
{
|
||||||
int sum = 0;
|
int32_t sum = 0;
|
||||||
int16_t *channelValues = new int16_t[channels];
|
|
||||||
for (unsigned i = 0; i < channels; i++) {
|
for (unsigned i = 0; i < channels; i++) {
|
||||||
switch (bitsPerChannel >> 3) {
|
switch (bitsPerChannel >> 3) {
|
||||||
case 2:
|
case 2:
|
||||||
channelValues[i] = (data[((i + 1) << 1) - 1] << 8) | data[((i + 1) << 1) - 2];
|
sum += *reinterpret_cast<int16_t *>(&data[i << 1]);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
channelValues[i] = (static_cast<int16_t>(data[i]) - 0x80) << 8;
|
sum += (static_cast<int16_t>(data[i]) - 0x80) << 8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
sum += channelValues[i];
|
|
||||||
}
|
}
|
||||||
value = 2 * sum / (static_cast<float>(USHRT_MAX) * channels);
|
value = sum / (-static_cast<float>(SHRT_MIN) * channels);
|
||||||
delete[] channelValues;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float Sample::GetMonoValue() const
|
float Sample::GetMonoValue() const
|
||||||
|
@ -66,62 +63,54 @@ float Sample::GetMonoValue() const
|
||||||
}
|
}
|
||||||
|
|
||||||
WaveReader::WaveReader(const std::string &filename, bool &enable, std::mutex &mtx) :
|
WaveReader::WaveReader(const std::string &filename, bool &enable, std::mutex &mtx) :
|
||||||
filename(filename), headerOffset(0), currentDataOffset(0)
|
filename(filename)
|
||||||
{
|
{
|
||||||
if (!filename.empty()) {
|
if (!filename.empty())
|
||||||
fileDescriptor = open(filename.c_str(), O_RDONLY);
|
fileDescriptor = open(filename.c_str(), O_RDONLY);
|
||||||
} else {
|
else {
|
||||||
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK);
|
fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK);
|
||||||
fileDescriptor = STDIN_FILENO;
|
fileDescriptor = STDIN_FILENO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileDescriptor == -1) {
|
if (fileDescriptor == -1)
|
||||||
throw std::runtime_error(std::string("Cannot open ") + GetFilename() + std::string(", file does not exist"));
|
throw std::runtime_error(std::string("Cannot open ") + GetFilename());
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ReadData(sizeof(WaveHeader::chunkID) + sizeof(WaveHeader::chunkSize) + sizeof(WaveHeader::format), true, enable, mtx);
|
ReadData(&header.chunkID, sizeof(WaveHeader::chunkID) + sizeof(WaveHeader::chunkSize) + sizeof(WaveHeader::format), enable, mtx);
|
||||||
if ((std::string(reinterpret_cast<char *>(header.chunkID), 4) != std::string("RIFF")) || (std::string(reinterpret_cast<char *>(header.format), 4) != std::string("WAVE"))) {
|
if ((std::string(reinterpret_cast<char *>(header.chunkID), 4) != std::string("RIFF")) || (std::string(reinterpret_cast<char *>(header.format), 4) != std::string("WAVE")))
|
||||||
throw std::runtime_error(std::string("Error while opening ") + GetFilename() + std::string(", WAVE file expected"));
|
throw std::runtime_error(std::string("Error while opening ") + GetFilename() + std::string(", WAVE file expected"));
|
||||||
}
|
|
||||||
|
|
||||||
ReadData(sizeof(WaveHeader::subchunk1ID) + sizeof(WaveHeader::subchunk1Size), true, enable, mtx);
|
ReadData(&header.subchunk1ID, sizeof(WaveHeader::subchunk1ID) + sizeof(WaveHeader::subchunk1Size), enable, mtx);
|
||||||
unsigned subchunk1MinSize = sizeof(WaveHeader::audioFormat) + sizeof(WaveHeader::channels) +
|
unsigned subchunk1MinSize = sizeof(WaveHeader::audioFormat) + sizeof(WaveHeader::channels) +
|
||||||
sizeof(WaveHeader::sampleRate) + sizeof(WaveHeader::byteRate) + sizeof(WaveHeader::blockAlign) +
|
sizeof(WaveHeader::sampleRate) + sizeof(WaveHeader::byteRate) + sizeof(WaveHeader::blockAlign) +
|
||||||
sizeof(WaveHeader::bitsPerSample);
|
sizeof(WaveHeader::bitsPerSample);
|
||||||
if ((std::string(reinterpret_cast<char *>(header.subchunk1ID), 4) != std::string("fmt ")) || (header.subchunk1Size < subchunk1MinSize)) {
|
if ((std::string(reinterpret_cast<char *>(header.subchunk1ID), 4) != std::string("fmt ")) || (header.subchunk1Size < subchunk1MinSize))
|
||||||
throw std::runtime_error(std::string("Error while opening ") + GetFilename() + std::string(", data corrupted"));
|
throw std::runtime_error(std::string("Error while opening ") + GetFilename() + std::string(", data corrupted"));
|
||||||
}
|
|
||||||
|
|
||||||
ReadData(header.subchunk1Size, true, enable, mtx);
|
ReadData(&header.audioFormat, header.subchunk1Size, enable, mtx);
|
||||||
if ((header.audioFormat != WAVE_FORMAT_PCM) ||
|
if ((header.audioFormat != WAVE_FORMAT_PCM) ||
|
||||||
(header.byteRate != (header.bitsPerSample >> 3) * header.channels * header.sampleRate) ||
|
(header.byteRate != (header.bitsPerSample >> 3) * header.channels * header.sampleRate) ||
|
||||||
(header.blockAlign != (header.bitsPerSample >> 3) * header.channels) ||
|
(header.blockAlign != (header.bitsPerSample >> 3) * header.channels) ||
|
||||||
(((header.bitsPerSample >> 3) != 1) && ((header.bitsPerSample >> 3) != 2))) {
|
(((header.bitsPerSample >> 3) != 1) && ((header.bitsPerSample >> 3) != 2)))
|
||||||
throw std::runtime_error(std::string("Error while opening ") + GetFilename() + std::string(", unsupported WAVE format"));
|
throw std::runtime_error(std::string("Error while opening ") + GetFilename() + std::string(", unsupported WAVE format"));
|
||||||
}
|
|
||||||
|
|
||||||
ReadData(sizeof(WaveHeader::subchunk2ID) + sizeof(WaveHeader::subchunk2Size), true, enable, mtx);
|
ReadData(&header.subchunk2ID, sizeof(WaveHeader::subchunk2ID) + sizeof(WaveHeader::subchunk2Size), enable, mtx);
|
||||||
if (std::string(reinterpret_cast<char *>(header.subchunk2ID), 4) != std::string("data")) {
|
if (std::string(reinterpret_cast<char *>(header.subchunk2ID), 4) != std::string("data"))
|
||||||
throw std::runtime_error(std::string("Error while opening ") + GetFilename() + std::string(", data corrupted"));
|
throw std::runtime_error(std::string("Error while opening ") + GetFilename() + std::string(", data corrupted"));
|
||||||
}
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
if (fileDescriptor != STDIN_FILENO) {
|
if (fileDescriptor != STDIN_FILENO)
|
||||||
close(fileDescriptor);
|
close(fileDescriptor);
|
||||||
}
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileDescriptor != STDIN_FILENO) {
|
if (fileDescriptor != STDIN_FILENO)
|
||||||
dataOffset = lseek(fileDescriptor, 0, SEEK_CUR);
|
dataOffset = lseek(fileDescriptor, 0, SEEK_CUR);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WaveReader::~WaveReader()
|
WaveReader::~WaveReader()
|
||||||
{
|
{
|
||||||
if (fileDescriptor != STDIN_FILENO) {
|
if (fileDescriptor != STDIN_FILENO)
|
||||||
close(fileDescriptor);
|
close(fileDescriptor);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string WaveReader::GetFilename() const
|
std::string WaveReader::GetFilename() const
|
||||||
|
@ -137,96 +126,66 @@ const WaveHeader &WaveReader::GetHeader() const
|
||||||
std::vector<Sample> WaveReader::GetSamples(unsigned quantity, bool &enable, std::mutex &mtx) {
|
std::vector<Sample> WaveReader::GetSamples(unsigned quantity, bool &enable, std::mutex &mtx) {
|
||||||
unsigned bytesPerSample = (header.bitsPerSample >> 3) * header.channels;
|
unsigned bytesPerSample = (header.bitsPerSample >> 3) * header.channels;
|
||||||
unsigned bytesToRead = quantity * bytesPerSample;
|
unsigned bytesToRead = quantity * bytesPerSample;
|
||||||
unsigned bytesLeft = header.subchunk2Size - currentDataOffset;
|
unsigned bytesLeft = (fileDescriptor != STDIN_FILENO) ?
|
||||||
|
header.subchunk2Size - lseek(fileDescriptor, 0, SEEK_CUR) : bytesToRead;
|
||||||
if (bytesToRead > bytesLeft) {
|
if (bytesToRead > bytesLeft) {
|
||||||
bytesToRead = bytesLeft - bytesLeft % bytesPerSample;
|
bytesToRead = bytesLeft - bytesLeft % bytesPerSample;
|
||||||
quantity = bytesToRead / bytesPerSample;
|
quantity = bytesToRead / bytesPerSample;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> data = std::move(ReadData(bytesToRead, false, enable, mtx));
|
std::vector<uint8_t> data(bytesToRead);
|
||||||
if (data.size() < bytesToRead) {
|
data.resize(ReadData(&data[0], bytesToRead, enable, mtx));
|
||||||
|
if (data.size() < bytesToRead)
|
||||||
quantity = data.size() / bytesPerSample;
|
quantity = data.size() / bytesPerSample;
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<Sample> samples;
|
std::vector<Sample> samples;
|
||||||
samples.reserve(quantity);
|
samples.reserve(quantity);
|
||||||
for (unsigned i = 0; i < quantity; i++) {
|
for (unsigned i = 0; i < quantity; i++)
|
||||||
samples.push_back(Sample(&data[bytesPerSample * i], header.channels, header.bitsPerSample));
|
samples.push_back(Sample(&data[bytesPerSample * i], header.channels, header.bitsPerSample));
|
||||||
}
|
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WaveReader::SetSampleOffset(unsigned offset) {
|
bool WaveReader::SetSampleOffset(unsigned offset) {
|
||||||
if (fileDescriptor != STDIN_FILENO) {
|
if (fileDescriptor != STDIN_FILENO)
|
||||||
currentDataOffset = offset * (header.bitsPerSample >> 3) * header.channels;
|
if (lseek(fileDescriptor, dataOffset + offset * (header.bitsPerSample >> 3) * header.channels, SEEK_SET) == -1)
|
||||||
if (lseek(fileDescriptor, dataOffset + currentDataOffset, SEEK_SET) == -1) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> WaveReader::ReadData(unsigned bytesToRead, bool headerBytes, bool &enable, std::mutex &mtx)
|
unsigned WaveReader::ReadData(void *buffer, unsigned bytesToRead, bool &enable, std::mutex &mtx)
|
||||||
{
|
{
|
||||||
unsigned bytesRead = 0;
|
unsigned bytesRead = 0;
|
||||||
std::vector<uint8_t> data;
|
|
||||||
data.resize(bytesToRead);
|
|
||||||
timeval timeout = {
|
timeval timeout = {
|
||||||
.tv_sec = 1,
|
.tv_sec = 1,
|
||||||
};
|
};
|
||||||
fd_set fds;
|
fd_set fds;
|
||||||
|
|
||||||
while (bytesRead < bytesToRead) {
|
while (bytesRead < bytesToRead) {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
std::lock_guard<std::mutex> lock(mtx);
|
||||||
if (!enable) {
|
if (!enable)
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
int bytes = read(fileDescriptor, &data[bytesRead], bytesToRead - bytesRead);
|
int bytes = read(fileDescriptor, &(reinterpret_cast<uint8_t *>(buffer)[bytesRead]), bytesToRead - bytesRead);
|
||||||
if (((bytes == -1) && ((fileDescriptor != STDIN_FILENO) || (errno != EAGAIN))) ||
|
if ((bytes == -1) && ((fileDescriptor != STDIN_FILENO) || (errno != EAGAIN)))
|
||||||
((static_cast<unsigned>(bytes) < bytesToRead) && headerBytes && (fileDescriptor != STDIN_FILENO))) {
|
throw std::runtime_error(std::string("Error while opening ") + GetFilename() + std::string(", cannot read file"));
|
||||||
throw std::runtime_error(std::string("Error while opening ") + GetFilename() + std::string(", data corrupted"));
|
if (bytes == 0)
|
||||||
}
|
break;
|
||||||
if (bytes > 0) {
|
if (bytes > 0)
|
||||||
bytesRead += bytes;
|
bytesRead += bytes;
|
||||||
}
|
|
||||||
if (bytesRead < bytesToRead) {
|
if (bytesRead < bytesToRead) {
|
||||||
if (fileDescriptor != STDIN_FILENO) {
|
if (fileDescriptor != STDIN_FILENO)
|
||||||
data.resize(bytesRead);
|
|
||||||
break;
|
break;
|
||||||
} else {
|
else {
|
||||||
FD_ZERO(&fds);
|
FD_ZERO(&fds);
|
||||||
FD_SET(STDIN_FILENO, &fds);
|
FD_SET(STDIN_FILENO, &fds);
|
||||||
select(STDIN_FILENO + 1, &fds, nullptr, nullptr, &timeout);
|
select(STDIN_FILENO + 1, &fds, nullptr, nullptr, &timeout);
|
||||||
if (FD_ISSET(STDIN_FILENO, &fds)) {
|
if (FD_ISSET(STDIN_FILENO, &fds))
|
||||||
FD_CLR(STDIN_FILENO, &fds);
|
FD_CLR(STDIN_FILENO, &fds);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bytes == 0) {
|
|
||||||
data.resize(bytesRead);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (headerBytes) {
|
return bytesRead;
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
|
||||||
if (!enable) {
|
|
||||||
throw std::runtime_error("Cannot obtain header, program interrupted");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::memcpy(&(reinterpret_cast<uint8_t *>(&header))[headerOffset], data.data(), bytesRead);
|
|
||||||
headerOffset += bytesRead;
|
|
||||||
} else {
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(mtx);
|
|
||||||
if (!enable) {
|
|
||||||
data.resize(bytesRead);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
currentDataOffset += bytesRead;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,10 +79,10 @@ class WaveReader
|
||||||
std::vector<Sample> GetSamples(unsigned quantity, bool &enable, std::mutex &mtx);
|
std::vector<Sample> GetSamples(unsigned quantity, bool &enable, std::mutex &mtx);
|
||||||
bool SetSampleOffset(unsigned offset);
|
bool SetSampleOffset(unsigned offset);
|
||||||
private:
|
private:
|
||||||
std::vector<uint8_t> ReadData(unsigned bytesToRead, bool headerBytes, bool &enable, std::mutex &mtx);
|
unsigned ReadData(void *buffer, unsigned bytesToRead, bool &enable, std::mutex &mtx);
|
||||||
|
|
||||||
std::string filename;
|
std::string filename;
|
||||||
WaveHeader header;
|
WaveHeader header;
|
||||||
unsigned dataOffset, headerOffset, currentDataOffset;
|
unsigned dataOffset;
|
||||||
int fileDescriptor;
|
int fileDescriptor;
|
||||||
};
|
};
|
||||||
|
|
Ładowanie…
Reference in New Issue