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