diff --git a/README.md b/README.md index 3e7d857..d6ef8ec 100644 --- a/README.md +++ b/README.md @@ -25,3 +25,11 @@ Implemented are the follwing [Window functions](https://en.wikipedia.org/wiki/Wi Some constants we need +### [pcm.hh](pcm.hh) + +Interface for reading and writing [PCM](https://en.wikipedia.org/wiki/Pulse-code_modulation) data + +### [wav.hh](wav.hh) + +Read and write [WAV](https://en.wikipedia.org/wiki/WAV) files + diff --git a/pcm.hh b/pcm.hh new file mode 100644 index 0000000..dd77247 --- /dev/null +++ b/pcm.hh @@ -0,0 +1,28 @@ +/* +Interface for reading and writing PCM data + +Copyright 2018 Ahmet Inan +*/ + +#ifndef PCM_HH +#define PCM_HH + +namespace DSP { + +template +struct WritePCM +{ + virtual void write(TYPE *, int, int) = 0; + virtual void silence(int) = 0; +}; + +template +struct ReadPCM +{ + virtual void read(TYPE *, int, int) = 0; +}; + +} + +#endif + diff --git a/wav.hh b/wav.hh new file mode 100644 index 0000000..f5ab53e --- /dev/null +++ b/wav.hh @@ -0,0 +1,84 @@ +/* +Read and write WAV files + +Copyright 2018 Ahmet Inan +*/ + +#ifndef WAV_HH +#define WAV_HH + +#include +#include "pcm.hh" + +namespace DSP { + +template +class WriteWAV : public WritePCM +{ + std::ofstream os; + int bytes, channels; + int offset, factor, min, max; + void writeLE(int v, int b) + { + for (int i = 0; i < b; ++i) + os.put(255 & (v >> (8 * i))); + } +public: + WriteWAV(const char *name, int rate, int bytes, int channels) : os(name, std::ios::binary | std::ios::trunc), bytes(bytes), channels(channels) + { + switch (bytes) { + case 1: + offset = 128; + factor = 127; + min = 0; + max = 255; + break; + default: + bytes = 2; + offset = 0; + factor = 32767; + min = -32768; + max = 32767; + } + os.write("RIFF", 4); // ChunkID + writeLE(36, 4); // ChunkSize + os.write("WAVE", 4); // Format + os.write("fmt ", 4); // Subchunk1ID + writeLE(16, 4); // Subchunk1Size + writeLE(1, 2); // AudioFormat + writeLE(channels, 2); // NumChannels + writeLE(rate, 4); // SampleRate + writeLE(rate * channels * bytes, 4); // ByteRate + writeLE(channels * bytes, 2); // BlockAlign + writeLE(8 * bytes, 2); // BitsPerSample + os.write("data", 4); // Subchunk2ID + writeLE(0, 4); // Subchunk2Size + } + ~WriteWAV() + { + int size = int(os.tellp()) - 44; + os.seekp(4); + writeLE(36 + size, 4); // ChunkSize + os.seekp(40); + writeLE(size, 4); // Subchunk2Size + } + void write(TYPE *buf, int num, int stride = 1) + { + for (int n = 0; n < num; ++n) { + for (int c = 0; c < channels; ++c) { + TYPE v = TYPE(offset) + TYPE(factor) * buf[stride * n + c]; + writeLE(std::nearbyint(std::clamp(v, TYPE(min), TYPE(max))), bytes); + } + } + } + void silence(int num) + { + for (int i = 0; i < num * channels; ++i) + writeLE(offset, bytes); + } +}; + +} + +#endif +