mirror of
https://github.com/aicodix/dsp.git
synced 2026-04-27 14:30:36 +00:00
added WAV file writer
This commit is contained in:
parent
b08665e8d9
commit
52b16be64a
3 changed files with 120 additions and 0 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
28
pcm.hh
Normal file
28
pcm.hh
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
Interface for reading and writing PCM data
|
||||
|
||||
Copyright 2018 Ahmet Inan <inan@aicodix.de>
|
||||
*/
|
||||
|
||||
#ifndef PCM_HH
|
||||
#define PCM_HH
|
||||
|
||||
namespace DSP {
|
||||
|
||||
template <typename TYPE>
|
||||
struct WritePCM
|
||||
{
|
||||
virtual void write(TYPE *, int, int) = 0;
|
||||
virtual void silence(int) = 0;
|
||||
};
|
||||
|
||||
template <typename TYPE>
|
||||
struct ReadPCM
|
||||
{
|
||||
virtual void read(TYPE *, int, int) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
84
wav.hh
Normal file
84
wav.hh
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
Read and write WAV files
|
||||
|
||||
Copyright 2018 Ahmet Inan <inan@aicodix.de>
|
||||
*/
|
||||
|
||||
#ifndef WAV_HH
|
||||
#define WAV_HH
|
||||
|
||||
#include <fstream>
|
||||
#include "pcm.hh"
|
||||
|
||||
namespace DSP {
|
||||
|
||||
template <typename TYPE>
|
||||
class WriteWAV : public WritePCM<TYPE>
|
||||
{
|
||||
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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue