#ifndef __STREAMOUTPUT_H_ #define __STREAMOUTPUT_H_ #ifdef __cplusplus #include "icsneo/communication/message/callback/messagecallback.h" #include #include #include #include #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> 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()) { if(initialize()) { initialized = true; } } bool initialize() { return !(!stream->read(reinterpret_cast(&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 f) : MessageCallback(cb, f), stream(&os, [](std::ostream*){}) {} StreamOutput(const char* filename, fn_messageCallback cb, std::shared_ptr f) : MessageCallback(cb, f), stream( new std::ofstream(filename, std::ios::binary), std::default_delete() ) {} StreamOutput(const char* filename) : MessageCallback([](std::shared_ptr) {}), stream( new std::ofstream(filename, std::ios::binary), std::default_delete() ) {} StreamOutput(std::ostream& os) : MessageCallback([](std::shared_ptr) {}), stream(&os, [](std::ostream*){}) {} protected: std::unique_ptr> stream; }; } #endif // __cplusplus #endif