1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 /*
3 bqaudiostream
4
5 A small library wrapping various audio file read/write
6 implementations in C++.
7
8 Copyright 2007-2015 Particular Programs Ltd.
9
10 Permission is hereby granted, free of charge, to any person
11 obtaining a copy of this software and associated documentation
12 files (the "Software"), to deal in the Software without
13 restriction, including without limitation the rights to use, copy,
14 modify, merge, publish, distribute, sublicense, and/or sell copies
15 of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
25 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
29 Except as contained in this notice, the names of Chris Cannam and
30 Particular Programs Ltd shall not be used in advertising or
31 otherwise to promote the sale, use or other dealings in this
32 Software without prior written authorization.
33 */
34
35 #include "SimpleWavFileWriteStream.h"
36
37 #if ! (defined(HAVE_LIBSNDFILE) || defined(HAVE_SNDFILE))
38
39 #include "Exceptions.h"
40 #include <iostream>
41
42 using namespace std;
43
44 namespace breakfastquay
45 {
46
getOpusExtensions()47 static vector<string> extensions() {
48 vector<string> ee;
49 ee.push_back("wav");
50 return ee;
51 }
52
53 static
54 AudioWriteStreamBuilder<SimpleWavFileWriteStream>
55 simplewavbuilder(
56 string("http://breakfastquay.com/rdf/turbot/audiostream/SimpleWavFileWriteStream"),
57 extensions()
58 );
59
60 SimpleWavFileWriteStream::SimpleWavFileWriteStream(Target target) :
61 AudioWriteStream(target),
62 m_bitDepth(24),
63 m_file(0)
D()64 {
65 m_file = new ofstream(getPath().c_str(), ios::out | std::ios::binary);
66
67 if (!*m_file) {
68 delete m_file;
69 m_file = 0;
70 cerr << "SimpleWavFileWriteStream: Failed to open output file for writing" << endl;
71 m_error = string("Failed to open audio file '") +
72 getPath() + "' for writing";
73 throw FailedToWriteFile(getPath());
74 }
75
76 writeFormatChunk();
77 }
78
79 SimpleWavFileWriteStream::~SimpleWavFileWriteStream()
80 {
81 if (!m_file) {
82 return;
83 }
84
85 m_file->seekp(0, ios::end);
86 unsigned int totalSize = m_file->tellp();
87
88 // seek to first length position
89 m_file->seekp(4, ios::beg);
90
91 // write complete file size minus 8 bytes to here
92 putBytes(int2le(totalSize - 8, 4));
93
94 // reseek from start forward 40
95 m_file->seekp(40, ios::beg);
96
97 // write the data chunk size to end
98 putBytes(int2le(totalSize - 44, 4));
99
100 m_file->close();
101
102 delete m_file;
103 m_file = 0;
104 }
105
106 void
107 SimpleWavFileWriteStream::putBytes(string s)
108 {
109 if (!m_file) return;
110 for (unsigned int i = 0; i < s.length(); i++) {
111 *m_file << (unsigned char)s[i];
112 }
113 }
114
115 void
getFrames(size_t count,float * frames)116 SimpleWavFileWriteStream::putBytes(const unsigned char *buffer, size_t n)
117 {
118 if (!m_file) return;
119 m_file->write((const char *)buffer, n);
120 }
121
122 string
123 SimpleWavFileWriteStream::int2le(unsigned int value, unsigned int length)
124 {
125 string r;
126
127 do {
128 r += (unsigned char)((long)((value >> (8 * r.length())) & 0xff));
129 } while (r.length() < length);
130
131 return r;
132 }
133
134 void
135 SimpleWavFileWriteStream::writeFormatChunk()
136 {
137 if (!m_file) return;
138
139 string outString;
140
141 outString += "RIFF";
142 outString += "0000";
143 outString += "WAVE";
144 outString += "fmt ";
145
146 // length
147 outString += int2le(0x10, 4);
148
149 // 1 for PCM, 3 for float
150 outString += int2le(0x01, 2);
151
152 // channels
153 outString += int2le(getChannelCount(), 2);
154
155 // sample rate
156 outString += int2le(getSampleRate(), 4);
157
158 // bytes per second
159 outString += int2le((m_bitDepth / 8) * getChannelCount() * getSampleRate(), 4);
160
161 // bytes per frame
162 outString += int2le((m_bitDepth / 8) * getChannelCount(), 2);
163
164 // bits per sample
165 outString += int2le(m_bitDepth, 2);
166
167 outString += "data";
168 outString += "0000";
169
170 putBytes(outString);
171 }
172
173 void
174 SimpleWavFileWriteStream::putInterleavedFrames(size_t count, float *frames)
175 {
176 if (count == 0) return;
177
178 for (size_t i = 0; i < count; ++i) {
179 for (size_t c = 0; c < getChannelCount(); ++c) {
180
181 double f = frames[i * getChannelCount() + c];
182 unsigned int u = 0;
183 unsigned char ubuf[4];
184 if (f < -1.0) f = -1.0;
185 if (f > 1.0) f = 1.0;
186
187 switch (m_bitDepth) {
188
189 case 24:
190 f = f * 2147483647.0;
191 u = (unsigned int)(int(f));
192 u >>= 8;
193 ubuf[0] = (u & 0xff);
194 u >>= 8;
195 ubuf[1] = (u & 0xff);
196 u >>= 8;
197 ubuf[2] = (u & 0xff);
198 break;
199
200 default:
201 ubuf[0] = ubuf[1] = ubuf[2] = ubuf[3] = '\0';
202 break;
203 }
204
205 putBytes(ubuf, m_bitDepth / 8);
206 }
207 }
208 }
209
~OpusReadStream()210 }
211
212 #endif
213