1 /*
2 Audio File Library
3 Copyright (C) 2013 Michael Pruett <michael@68k.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301 USA
19 */
20
21 #include "config.h"
22 #include "ALAC.h"
23
24 #include "Buffer.h"
25 #include "Compiler.h"
26 #include "File.h"
27 #include "FileModule.h"
28 #include "PacketTable.h"
29 #include "SimpleModule.h"
30 #include "Track.h"
31 #include "afinternal.h"
32 #include "audiofile.h"
33 #include "byteorder.h"
34 #include "compression.h"
35 #include "units.h"
36 #include "util.h"
37
38 #include "../alac/ALACBitUtilities.h"
39 #include "../alac/ALACDecoder.h"
40 #include "../alac/ALACEncoder.h"
41
42 #include <assert.h>
43 #include <string.h>
44
45 enum
46 {
47 kALACFormatFlag_16BitSourceData = 1,
48 kALACFormatFlag_20BitSourceData = 2,
49 kALACFormatFlag_24BitSourceData = 3,
50 kALACFormatFlag_32BitSourceData = 4
51 };
52
53 class ALAC : public FileModule
54 {
55 public:
56 static ALAC *createDecompress(Track *, File *, bool canSeek,
57 bool headerless, AFframecount *chunkFrames);
58 static ALAC *createCompress(Track *, File *, bool canSeek,
59 bool headerless, AFframecount *chunkFrames);
60
61 virtual ~ALAC();
62
name() const63 virtual const char *name() const OVERRIDE
64 {
65 return mode() == Compress ? "alac_compress" : "alac_decompress";
66 }
67 virtual void describe() OVERRIDE;
68 virtual void runPull() OVERRIDE;
69 virtual void reset1() OVERRIDE;
70 virtual void reset2() OVERRIDE;
71 virtual void runPush() OVERRIDE;
72 virtual void sync1() OVERRIDE;
73 virtual void sync2() OVERRIDE;
74 virtual int bufferSize() const OVERRIDE;
75
76 private:
77 AFframecount m_framesToIgnore;
78 AFfileoffset m_savedPositionNextFrame;
79 AFframecount m_savedNextFrame;
80
81 SharedPtr<Buffer> m_codecData;
82 ALACDecoder *m_decoder;
83 ALACEncoder *m_encoder;
84 int m_currentPacket;
85
86 ALAC(Mode mode, Track *track, File *fh, bool canSeek, Buffer *codecData);
87 void initDecoder();
88 void initEncoder();
89
90 AudioFormatDescription outputFormat() const;
91 };
92
ALAC(Mode mode,Track * track,File * fh,bool canSeek,Buffer * codecData)93 ALAC::ALAC(Mode mode, Track *track, File *fh, bool canSeek, Buffer *codecData) :
94 FileModule(mode, track, fh, canSeek),
95 m_savedPositionNextFrame(-1),
96 m_savedNextFrame(-1),
97 m_codecData(codecData),
98 m_decoder(NULL),
99 m_encoder(NULL),
100 m_currentPacket(0)
101 {
102 if (mode == Decompress)
103 initDecoder();
104 else
105 initEncoder();
106 }
107
~ALAC()108 ALAC::~ALAC()
109 {
110 delete m_decoder;
111 delete m_encoder;
112 }
113
initDecoder()114 void ALAC::initDecoder()
115 {
116 m_decoder = new ALACDecoder();
117 m_decoder->Init(m_codecData->data(), m_codecData->size());
118 }
119
initEncoder()120 void ALAC::initEncoder()
121 {
122 m_encoder = new ALACEncoder();
123 m_encoder->SetFrameSize(m_track->f.framesPerPacket);
124 m_encoder->InitializeEncoder(outputFormat());
125
126 uint32_t cookieSize = m_encoder->GetMagicCookieSize(m_track->f.channelCount);
127 assert(cookieSize == m_codecData->size());
128 m_encoder->GetMagicCookie(m_codecData->data(), &cookieSize);
129
130 void *v = NULL;
131 _af_pv_getptr(m_track->f.compressionParams, _AF_CODEC_DATA, &v);
132 ::memcpy(v, m_codecData->data(), cookieSize);
133 }
134
outputFormat() const135 AudioFormatDescription ALAC::outputFormat() const
136 {
137 AudioFormatDescription outputFormat;
138 outputFormat.mSampleRate = m_track->f.sampleRate;
139 outputFormat.mFormatID = kALACFormatAppleLossless;
140 switch (m_track->f.sampleWidth)
141 {
142 case 16:
143 outputFormat.mFormatFlags = kALACFormatFlag_16BitSourceData; break;
144 case 20:
145 outputFormat.mFormatFlags = kALACFormatFlag_20BitSourceData; break;
146 case 24:
147 outputFormat.mFormatFlags = kALACFormatFlag_24BitSourceData; break;
148 case 32:
149 outputFormat.mFormatFlags = kALACFormatFlag_32BitSourceData; break;
150 default:
151 outputFormat.mFormatFlags = 0; break;
152 }
153 outputFormat.mFramesPerPacket = m_track->f.framesPerPacket;
154 outputFormat.mChannelsPerFrame = m_track->f.channelCount;
155 outputFormat.mBytesPerPacket = 0;
156 outputFormat.mBytesPerFrame = 0;
157 outputFormat.mBitsPerChannel = 0;
158 outputFormat.mReserved = 0;
159 return outputFormat;
160 }
161
describe()162 void ALAC::describe()
163 {
164 m_outChunk->f.byteOrder = _AF_BYTEORDER_NATIVE;
165 m_outChunk->f.compressionType = AF_COMPRESSION_NONE;
166 m_outChunk->f.compressionParams = AU_NULL_PVLIST;
167 }
168
createDecompress(Track * track,File * fh,bool canSeek,bool headerless,AFframecount * chunkFrames)169 ALAC *ALAC::createDecompress(Track *track, File *fh,
170 bool canSeek, bool headerless, AFframecount *chunkFrames)
171 {
172 assert(fh->tell() == track->fpos_first_frame);
173
174 AUpvlist pv = (AUpvlist) track->f.compressionParams;
175 long codecDataSize;
176 if (!_af_pv_getlong(pv, _AF_CODEC_DATA_SIZE, &codecDataSize))
177 {
178 _af_error(AF_BAD_CODEC_CONFIG, "codec data size not set");
179 return NULL;
180 }
181
182 SharedPtr<Buffer> codecData = new Buffer(codecDataSize);
183
184 void *data;
185 if (!_af_pv_getptr(pv, _AF_CODEC_DATA, &data))
186 {
187 _af_error(AF_BAD_CODEC_CONFIG, "codec data not set");
188 return NULL;
189 }
190
191 memcpy(codecData->data(), data, codecDataSize);
192
193 *chunkFrames = track->f.framesPerPacket;
194
195 return new ALAC(Decompress, track, fh, canSeek, codecData.get());
196 }
197
createCompress(Track * track,File * fh,bool canSeek,bool headerless,AFframecount * chunkFrames)198 ALAC *ALAC::createCompress(Track *track, File *fh,
199 bool canSeek, bool headerless, AFframecount *chunkFrames)
200 {
201 assert(fh->tell() == track->fpos_first_frame);
202
203 AUpvlist pv = (AUpvlist) track->f.compressionParams;
204 long codecDataSize;
205 if (!_af_pv_getlong(pv, _AF_CODEC_DATA_SIZE, &codecDataSize))
206 {
207 _af_error(AF_BAD_CODEC_CONFIG, "codec data size not set");
208 return NULL;
209 }
210
211 SharedPtr<Buffer> codecData = new Buffer(codecDataSize);
212
213 void *data;
214 if (!_af_pv_getptr(pv, _AF_CODEC_DATA, &data))
215 {
216 _af_error(AF_BAD_CODEC_CONFIG, "codec data not set");
217 return NULL;
218 }
219
220 memcpy(codecData->data(), data, codecDataSize);
221
222 *chunkFrames = track->f.framesPerPacket;
223
224 return new ALAC(Compress, track, fh, canSeek, codecData.get());
225 }
226
runPull()227 void ALAC::runPull()
228 {
229 SharedPtr<PacketTable> packetTable = m_track->m_packetTable;
230 if (m_currentPacket >= static_cast<int>(packetTable->numPackets()))
231 {
232 m_outChunk->frameCount = 0;
233 return;
234 }
235 assert(m_currentPacket < static_cast<int>(packetTable->numPackets()));
236
237 ssize_t bytesPerPacket = packetTable->bytesPerPacket(m_currentPacket);
238 assert(bytesPerPacket <= bufferSize());
239
240 if (read(m_inChunk->buffer, bytesPerPacket) < bytesPerPacket)
241 {
242 reportReadError(0, m_track->f.framesPerPacket);
243 return;
244 }
245
246 BitBuffer bitBuffer;
247 BitBufferInit(&bitBuffer, static_cast<uint8_t *>(m_inChunk->buffer),
248 bytesPerPacket);
249
250 uint32_t numFrames;
251 m_decoder->Decode(&bitBuffer, static_cast<uint8_t *>(m_outChunk->buffer),
252 m_track->f.framesPerPacket, m_track->f.channelCount, &numFrames);
253 m_outChunk->frameCount = numFrames;
254
255 m_currentPacket++;
256 }
257
reset1()258 void ALAC::reset1()
259 {
260 AFframecount nextFrame = m_track->nextfframe;
261 m_currentPacket = nextFrame / m_track->f.framesPerPacket;
262 m_track->nextfframe = m_currentPacket * m_track->f.framesPerPacket;
263 m_framesToIgnore = nextFrame - m_track->nextfframe;
264 }
265
reset2()266 void ALAC::reset2()
267 {
268 m_track->fpos_next_frame = m_track->fpos_first_frame +
269 m_track->m_packetTable->startOfPacket(m_currentPacket);
270 m_track->frames2ignore += m_framesToIgnore;
271 }
272
bufferSize() const273 int ALAC::bufferSize() const
274 {
275 return m_track->f.framesPerPacket * m_track->f.channelCount *
276 ((10 + m_track->f.sampleWidth) / 8) + 1;
277 }
278
runPush()279 void ALAC::runPush()
280 {
281 AudioFormatDescription inputFormat;
282 inputFormat.mSampleRate = m_track->f.sampleRate;
283 inputFormat.mFormatID = kALACFormatLinearPCM;
284 inputFormat.mFormatFlags = kALACFormatFlagsNativeEndian;
285 inputFormat.mBytesPerPacket = _af_format_frame_size_uncompressed(&m_track->f, false);
286 inputFormat.mFramesPerPacket = 1;
287 inputFormat.mBytesPerFrame = _af_format_frame_size_uncompressed(&m_track->f, false);
288 inputFormat.mChannelsPerFrame = m_track->f.channelCount;
289 inputFormat.mBitsPerChannel = m_track->f.sampleWidth;
290 inputFormat.mReserved = 0;
291
292 int32_t numBytes = m_inChunk->frameCount * inputFormat.mBytesPerFrame;
293 int32_t result = m_encoder->Encode(inputFormat, outputFormat(),
294 static_cast<uint8_t *>(m_inChunk->buffer),
295 static_cast<uint8_t *>(m_outChunk->buffer),
296 &numBytes);
297 if (result)
298 {
299 _af_error(AF_BAD_CODEC_STATE, "error encoding ALAC audio data");
300 m_track->filemodhappy = false;
301 return;
302 }
303
304 assert(numBytes <= bufferSize());
305
306 ssize_t bytesWritten = write(m_outChunk->buffer, numBytes);
307 if (bytesWritten != numBytes)
308 {
309 reportWriteError(0, m_track->f.framesPerPacket);
310 return;
311 }
312
313 PacketTable *packetTable = m_track->m_packetTable.get();
314
315 packetTable->append(numBytes);
316
317 packetTable->setNumValidFrames(packetTable->numValidFrames() +
318 m_inChunk->frameCount);
319 }
320
sync1()321 void ALAC::sync1()
322 {
323 m_savedPositionNextFrame = m_track->fpos_next_frame;
324 m_savedNextFrame = m_track->nextfframe;
325 }
326
sync2()327 void ALAC::sync2()
328 {
329 assert(!canSeek() || (tell() == m_track->fpos_next_frame));
330
331 m_track->fpos_after_data = tell();
332
333 m_track->fpos_next_frame = m_savedPositionNextFrame;
334 m_track->nextfframe = m_savedNextFrame;
335 }
336
_af_alac_format_ok(AudioFormat * f)337 bool _af_alac_format_ok (AudioFormat *f)
338 {
339 if (f->channelCount > kALACMaxChannels)
340 {
341 _af_error(AF_BAD_CHANNELS,
342 "ALAC compression supports a maximum of 8 channels");
343 return false;
344 }
345
346 if (f->sampleFormat != AF_SAMPFMT_TWOSCOMP)
347 {
348 _af_error(AF_BAD_COMPRESSION,
349 "ALAC compression requires signed integer audio data");
350 return false;
351 }
352
353 if (f->sampleWidth != 16 &&
354 f->sampleWidth != 20 &&
355 f->sampleWidth != 24 &&
356 f->sampleWidth != 32)
357 {
358 _af_error(AF_BAD_WIDTH,
359 "ALAC compression requires 16, 20, 24, or 32 bits per sample");
360 return false;
361 }
362
363 if (f->byteOrder != _AF_BYTEORDER_NATIVE)
364 {
365 _af_error(AF_BAD_COMPRESSION,
366 "ALAC compression requires native-endian format");
367 f->byteOrder = _AF_BYTEORDER_NATIVE;
368 }
369
370 return true;
371 }
372
_af_alac_init_decompress(Track * track,File * fh,bool canSeek,bool headerless,AFframecount * chunkFrames)373 FileModule *_af_alac_init_decompress (Track *track, File *fh,
374 bool canSeek, bool headerless, AFframecount *chunkFrames)
375 {
376 return ALAC::createDecompress(track, fh, canSeek, headerless, chunkFrames);
377 }
378
_af_alac_init_compress(Track * track,File * fh,bool canSeek,bool headerless,AFframecount * chunkFrames)379 FileModule *_af_alac_init_compress (Track *track, File *fh,
380 bool canSeek, bool headerless, AFframecount *chunkFrames)
381 {
382 return ALAC::createCompress(track, fh, canSeek, headerless, chunkFrames);
383 }
384