openMSX
WavWriter.cc
Go to the documentation of this file.
1 #include "WavWriter.hh"
2 #include "MSXException.hh"
3 #include "Math.hh"
4 #include "endian.hh"
5 #include "one_of.hh"
6 #include "vla.hh"
7 #include <cstring>
8 #include <vector>
9 
10 namespace openmsx {
11 
13  unsigned channels, unsigned bits, unsigned frequency)
14  : file(filename, "wb")
15  , bytes(0)
16 {
17  // write wav header
18  struct WavHeader {
19  char chunkID[4]; // + 0 'RIFF'
20  Endian::L32 chunkSize; // + 4 total size
21  char format[4]; // + 8 'WAVE'
22  char subChunk1ID[4]; // +12 'fmt '
23  Endian::L32 subChunk1Size; // +16 = 16 (fixed)
24  Endian::L16 audioFormat; // +20 = 1 (fixed)
25  Endian::L16 numChannels; // +22
26  Endian::L32 sampleRate; // +24
27  Endian::L32 byteRate; // +28
28  Endian::L16 blockAlign; // +32
29  Endian::L16 bitsPerSample; // +34
30  char subChunk2ID[4]; // +36 'data'
31  Endian::L32 subChunk2Size; // +40
32  } header;
33 
34  memcpy(header.chunkID, "RIFF", sizeof(header.chunkID));
35  header.chunkSize = 0; // actual value filled in later
36  memcpy(header.format, "WAVE", sizeof(header.format));
37  memcpy(header.subChunk1ID, "fmt ", sizeof(header.subChunk1ID));
38  header.subChunk1Size = 16;
39  header.audioFormat = 1;
40  header.numChannels = channels;
41  header.sampleRate = frequency;
42  header.byteRate = (channels * frequency * bits) / 8;
43  header.blockAlign = (channels * bits) / 8;
44  header.bitsPerSample = bits;
45  memcpy(header.subChunk2ID, "data", sizeof(header.subChunk2ID));
46  header.subChunk2Size = 0; // actaul value filled in later
47 
48  file.write(&header, sizeof(header));
49 }
50 
52 {
53  try {
54  // data chunk must have an even number of bytes
55  if (bytes & 1) {
56  uint8_t pad = 0;
57  file.write(&pad, 1);
58  }
59 
60  flush(); // write header
61  } catch (MSXException&) {
62  // ignore, can't throw from destructor
63  }
64 }
65 
67 {
68  Endian::L32 totalSize = (bytes + 44 - 8 + 1) & ~1; // round up to even number
69  Endian::L32 wavSize = bytes;
70 
71  file.seek(4);
72  file.write(&totalSize, 4);
73  file.seek(40);
74  file.write(&wavSize, 4);
75  file.seek(file.getSize()); // SEEK_END
76  file.flush();
77 }
78 
79 void Wav8Writer::write(const uint8_t* buffer, unsigned samples)
80 {
81  file.write(buffer, samples);
82  bytes += samples;
83 }
84 
85 void Wav16Writer::write(const int16_t* buffer, unsigned samples)
86 {
87  unsigned size = sizeof(int16_t) * samples;
88  if (OPENMSX_BIGENDIAN) {
89  // Variable length arrays (VLA) are part of c99 but not of c++
90  // (not even c++11). Some compilers (like gcc) do support VLA
91  // in c++ mode, others (like VC++) don't. Still other compilers
92  // (like clang) only support VLA for POD types.
93  // To side-step this issue we simply use a std::vector, this
94  // code is anyway not performance critical.
95  //VLA(Endian::L16, buf, samples); // doesn't work in clang
96  std::vector<Endian::L16> buf(buffer, buffer + samples);
97  file.write(buf.data(), size);
98  } else {
99  file.write(buffer, size);
100  }
101  bytes += size;
102 }
103 
104 static int16_t float2int16(float f)
105 {
106  return Math::clipIntToShort(lrintf(32768.0f * f));
107 }
108 
109 void Wav16Writer::write(const float* buffer, unsigned stereo, unsigned samples,
110  float ampLeft, float ampRight)
111 {
112  assert(stereo == one_of(1u, 2u));
113  std::vector<Endian::L16> buf(samples * stereo);
114  if (stereo == 1) {
115  assert(ampLeft == ampRight);
116  for (unsigned i = 0; i < samples; ++i) {
117  buf[i] = float2int16(buffer[i] * ampLeft);
118  }
119  } else {
120  for (unsigned i = 0; i < samples; ++i) {
121  buf[2 * i + 0] = float2int16(buffer[2 * i + 0] * ampLeft);
122  buf[2 * i + 0] = float2int16(buffer[2 * i + 0] * ampRight);
123  }
124  }
125  unsigned size = sizeof(int16_t) * samples * stereo;
126  file.write(buf.data(), size);
127  bytes += size;
128 }
129 
130 void Wav16Writer::writeSilence(unsigned samples)
131 {
132  VLA(int16_t, buf, samples);
133  unsigned size = sizeof(int16_t) * samples;
134  memset(buf, 0, size);
135  file.write(buf, size);
136  bytes += size;
137 }
138 
139 } // namespace openmsx
one_of.hh
openmsx::WavWriter::flush
void flush()
Flush data to file and update header.
Definition: WavWriter.cc:66
openmsx::DiskImageUtils::format
void format(SectorAccessibleDisk &disk, bool dos1)
Format the given disk (= a single partition).
Definition: DiskImageUtils.cc:182
openmsx::File::getSize
size_t getSize()
Returns the size of this file.
Definition: File.cc:103
utf8::unchecked::size
size_t size(std::string_view utf8)
Definition: utf8_unchecked.hh:227
openmsx::Wav8Writer::write
void write(const uint8_t *buffer, unsigned stereo, unsigned samples)
Definition: WavWriter.hh:44
MSXException.hh
openmsx::MSXException
Definition: MSXException.hh:10
openmsx::WavWriter::~WavWriter
~WavWriter()
Definition: WavWriter.cc:51
vla.hh
openmsx::Wav16Writer::writeSilence
void writeSilence(unsigned stereo, unsigned samples)
Definition: WavWriter.hh:67
openmsx::Wav16Writer::write
void write(const int16_t *buffer, unsigned stereo, unsigned samples)
Definition: WavWriter.hh:61
one_of
Definition: one_of.hh:7
openmsx::File::write
void write(const void *buffer, size_t num)
Write to file.
Definition: File.cc:88
openmsx::filename
constexpr const char *const filename
Definition: FirmwareSwitch.cc:10
WavWriter.hh
openmsx::File::flush
void flush()
Force a write of all buffered data to disk.
Definition: File.cc:123
endian.hh
Endian::EndianT
Definition: endian.hh:71
openmsx::WavWriter::WavWriter
WavWriter(const Filename &filename, unsigned channels, unsigned bits, unsigned frequency)
Definition: WavWriter.cc:12
openmsx::File::seek
void seek(size_t pos)
Move read/write pointer to the specified position.
Definition: File.cc:108
Math::clipIntToShort
int16_t clipIntToShort(int x)
Clip x to range [-32768,32767].
Definition: Math.hh:100
openmsx::WavWriter::bytes
unsigned bytes
Definition: WavWriter.hh:33
openmsx::Filename
This class represents a filename.
Definition: Filename.hh:18
Math.hh
VLA
#define VLA(TYPE, NAME, LENGTH)
Definition: vla.hh:10
openmsx::WavWriter::file
File file
Definition: WavWriter.hh:32
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5