146 lines
4.1 KiB
C++
146 lines
4.1 KiB
C++
#ifndef __STREAMOUTPUT_H_
|
|
#define __STREAMOUTPUT_H_
|
|
|
|
#ifdef __cplusplus
|
|
|
|
#include "icsneo/communication/message/callback/messagecallback.h"
|
|
#include <memory>
|
|
#include <functional>
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
#define WAV_SAMPLE_RATE_44100 44100
|
|
#define WAV_SAMPLE_RATE_48000 48000
|
|
|
|
namespace icsneo {
|
|
|
|
#pragma pack(push, 1)
|
|
struct WAVHeader {
|
|
|
|
static constexpr uint32_t WAV_CHUNK_ID = 0x46464952; // "RIFF"
|
|
static constexpr uint32_t WAV_FORMAT = 0x45564157; // "WAV"
|
|
static constexpr uint32_t WAV_SUBCHUNK1_ID = 0x20746d66; // "fmt "
|
|
static constexpr uint32_t WAV_SUBCHUNK2_ID = 0x61746164; // "data"
|
|
static constexpr uint16_t WAV_SUBCHUNK1_SIZE = 16;
|
|
static constexpr uint16_t WAV_AUDIO_FORMAT_PCM = 1;
|
|
static constexpr uint32_t WAV_DEFAULT_SIZE = 0; // Default size for streamed wav
|
|
|
|
uint32_t chunkId = WAV_CHUNK_ID; // "RIFF"
|
|
uint32_t chunkSize = WAV_DEFAULT_SIZE; // number of bytes to follow
|
|
uint32_t format = WAV_FORMAT; // "WAV"
|
|
uint32_t subchunk1Id = WAV_SUBCHUNK1_ID; // "fmt "
|
|
uint32_t subchunk1Size = WAV_SUBCHUNK1_SIZE; // number of bytes in *this* subchunk (always 16)
|
|
uint16_t audioFormat = WAV_AUDIO_FORMAT_PCM; // 1 for PCM
|
|
uint16_t numChannels; // number of channels
|
|
uint32_t sampleRate; // sample rate in Hz
|
|
uint32_t byteRate; // bytes per second of audio: sampleRate * numChannels * (bitsPerSample / 8)
|
|
uint16_t blockAlign; // alignment of each block in bytes: numChannels * (bitsPerSample / 8)
|
|
uint16_t bitsPerSample; // number of bits in each sample
|
|
uint32_t subchunk2Id = WAV_SUBCHUNK2_ID; // "data"
|
|
uint32_t subchunk2Size = WAV_DEFAULT_SIZE; // number of bytes to follow
|
|
|
|
WAVHeader() = default;
|
|
|
|
WAVHeader(uint16_t nChannels, uint32_t sRate, uint16_t bps, uint32_t nSamples = 0) {
|
|
setHeader(nChannels, sRate, bps, nSamples);
|
|
}
|
|
|
|
void setHeader(uint16_t newNumChannels, uint32_t newSampleRate, uint16_t newBitsPerSample, uint32_t numSamples = 0) {
|
|
numChannels = newNumChannels;
|
|
sampleRate = newSampleRate;
|
|
bitsPerSample = newBitsPerSample;
|
|
blockAlign = numChannels * (bitsPerSample / 8);
|
|
byteRate = sampleRate * numChannels * (bitsPerSample / 8);
|
|
if(numSamples != 0) {
|
|
setNumSamples(numSamples);
|
|
}
|
|
}
|
|
|
|
void setNumSamples(uint32_t numSamples) {
|
|
subchunk2Size = numSamples * numChannels * (bitsPerSample / 8);
|
|
chunkSize = subchunk2Size + 36;
|
|
}
|
|
};
|
|
|
|
#pragma pack(pop)
|
|
|
|
class IWAVStream {
|
|
private:
|
|
std::unique_ptr<std::istream, std::function<void(std::istream*)>> stream;
|
|
bool initialized = false;
|
|
public:
|
|
WAVHeader header;
|
|
|
|
IWAVStream(std::istream& WAVInput)
|
|
: stream(&WAVInput, [](std::istream*){}) {
|
|
|
|
if(initialize()) {
|
|
initialized = true;
|
|
}
|
|
}
|
|
|
|
IWAVStream(const char* filename)
|
|
: stream(new std::ifstream(filename, std::ios::in | std::ios::binary), std::default_delete<std::istream>()) {
|
|
|
|
if(initialize()) {
|
|
initialized = true;
|
|
}
|
|
}
|
|
|
|
bool initialize() {
|
|
return !(!stream->read(reinterpret_cast<char*>(&header), sizeof(WAVHeader)));
|
|
}
|
|
|
|
operator bool() const {
|
|
return initialized && stream && stream->good();
|
|
}
|
|
|
|
bool read(char* into, std::streamsize num) {
|
|
return !(!stream->read(into, num));
|
|
}
|
|
|
|
/**
|
|
* Set stream immediately after WAV header
|
|
*/
|
|
void reset() {
|
|
if(!(*this)) {
|
|
return;
|
|
}
|
|
|
|
stream->clear();
|
|
stream->seekg(sizeof(icsneo::WAVHeader), std::ios::beg);
|
|
}
|
|
};
|
|
|
|
class StreamOutput : public MessageCallback {
|
|
public:
|
|
StreamOutput(std::ostream& os, fn_messageCallback cb, std::shared_ptr<MessageFilter> f)
|
|
: MessageCallback(cb, f), stream(&os, [](std::ostream*){}) {}
|
|
|
|
StreamOutput(const char* filename, fn_messageCallback cb, std::shared_ptr<MessageFilter> f)
|
|
:
|
|
MessageCallback(cb, f),
|
|
stream(
|
|
new std::ofstream(filename, std::ios::binary),
|
|
std::default_delete<std::ostream>()
|
|
) {}
|
|
|
|
StreamOutput(const char* filename) :
|
|
MessageCallback([](std::shared_ptr<Message>) {}),
|
|
stream(
|
|
new std::ofstream(filename, std::ios::binary),
|
|
std::default_delete<std::ostream>()
|
|
) {}
|
|
|
|
StreamOutput(std::ostream& os) : MessageCallback([](std::shared_ptr<Message>) {}), stream(&os, [](std::ostream*){}) {}
|
|
|
|
protected:
|
|
std::unique_ptr<std::ostream, std::function<void(std::ostream*)>> stream;
|
|
};
|
|
|
|
}
|
|
|
|
#endif // __cplusplus
|
|
|
|
#endif
|