(Metux) autogen.sh: not running ./configure anymore (breaks certain distro builders)
[mirror-ossqm-audiofile.git] / libaudiofile / aiffwrite.c
blob19b7227b13136c841737997ac031a5420d4476f2
1 /*
2 Audio File Library
3 Copyright (C) 1998-2000, Michael Pruett <michael@68k.org>
4 Copyright (C) 2000-2001, Silicon Graphics, Inc.
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with this library; if not, write to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307 USA.
23 aiffwrite.c
25 This file contains routines for writing AIFF and AIFF-C format
26 sound files.
29 #ifdef HAVE_CONFIG_H
30 #include <config.h>
31 #endif
33 #include <assert.h>
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
38 #include "extended.h"
39 #include "afinternal.h"
40 #include "audiofile.h"
41 #include "aiff.h"
42 #include "byteorder.h"
43 #include "util.h"
44 #include "setup.h"
46 status _af_aiff_update (AFfilehandle file);
48 static status WriteCOMM (AFfilehandle file);
49 static status WriteSSND (AFfilehandle file);
50 static status WriteMARK (AFfilehandle file);
51 static status WriteINST (AFfilehandle file);
52 static status WriteFVER (AFfilehandle file);
53 static status WriteAESD (AFfilehandle file);
54 static status WriteMiscellaneous (AFfilehandle file);
56 static _AIFFInfo *aiffinfo_new (void)
58 _AIFFInfo *aiff = _af_malloc(sizeof (_AIFFInfo));
60 aiff->miscellaneousPosition = 0;
61 aiff->FVER_offset = 0;
62 aiff->COMM_offset = 0;
63 aiff->MARK_offset = 0;
64 aiff->INST_offset = 0;
65 aiff->AESD_offset = 0;
66 aiff->SSND_offset = 0;
68 return aiff;
71 status _af_aiff_write_init (AFfilesetup setup, AFfilehandle file)
73 uint32_t fileSize = 0;
75 assert(file);
76 assert(file->fileFormat == AF_FILE_AIFF ||
77 file->fileFormat == AF_FILE_AIFFC);
79 if (_af_filesetup_make_handle(setup, file) == AF_FAIL)
80 return AF_FAIL;
82 file->formatSpecific = aiffinfo_new();
84 af_fwrite("FORM", 4, 1, file->fh);
85 af_write_uint32_be(&fileSize, file->fh);
87 if (file->fileFormat == AF_FILE_AIFF)
88 af_fwrite("AIFF", 4, 1, file->fh);
89 else if (file->fileFormat == AF_FILE_AIFFC)
90 af_fwrite("AIFC", 4, 1, file->fh);
92 if (file->fileFormat == AF_FILE_AIFFC)
93 WriteFVER(file);
95 WriteCOMM(file);
96 WriteMARK(file);
97 WriteINST(file);
98 WriteAESD(file);
99 WriteMiscellaneous(file);
100 WriteSSND(file);
102 return AF_SUCCEED;
105 status _af_aiff_update (AFfilehandle file)
107 _Track *track;
108 uint32_t length;
110 assert(file);
112 track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
114 #ifdef DEBUG
115 printf("_af_aiff_update called.\n");
116 #endif
118 /* Get the length of the file. */
119 length = af_flength(file->fh);
120 length -= 8;
122 /* Set the length of the FORM chunk. */
123 af_fseek(file->fh, 4, SEEK_SET);
124 af_write_uint32_be(&length, file->fh);
126 if (file->fileFormat == AF_FILE_AIFFC)
127 WriteFVER(file);
129 WriteCOMM(file);
130 WriteMARK(file);
131 WriteINST(file);
132 WriteAESD(file);
133 WriteMiscellaneous(file);
134 WriteSSND(file);
136 return AF_SUCCEED;
139 static status WriteCOMM (const AFfilehandle file)
141 _Track *track;
142 uint32_t chunkSize;
143 _AIFFInfo *aiff;
144 bool isAIFFC;
146 uint16_t sb;
147 uint32_t lb;
148 unsigned char eb[10];
150 uint8_t compressionTag[4];
151 /* Pascal strings can occupy only 255 bytes (+ a size byte). */
152 char compressionName[256];
154 isAIFFC = file->fileFormat == AF_FILE_AIFFC;
156 aiff = file->formatSpecific;
159 If COMM_offset hasn't been set yet, set it to the
160 current offset.
162 if (aiff->COMM_offset == 0)
163 aiff->COMM_offset = af_ftell(file->fh);
164 else
165 af_fseek(file->fh, aiff->COMM_offset, SEEK_SET);
167 track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
169 if (isAIFFC)
171 if (track->f.compressionType == AF_COMPRESSION_NONE)
173 if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP)
175 memcpy(compressionTag, "NONE", 4);
176 strcpy(compressionName, "not compressed");
178 else if (track->f.sampleFormat == AF_SAMPFMT_FLOAT)
180 memcpy(compressionTag, "fl32", 4);
181 strcpy(compressionName, "32-bit Floating Point");
183 else if (track->f.sampleFormat == AF_SAMPFMT_DOUBLE)
185 memcpy(compressionTag, "fl64", 4);
186 strcpy(compressionName, "64-bit Floating Point");
189 We disallow unsigned sample data for
190 AIFF files in _af_aiff_complete_setup,
191 so the next condition should never be
192 satisfied.
194 else if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED)
196 _af_error(AF_BAD_SAMPFMT,
197 "AIFF/AIFF-C format does not support unsigned data");
198 assert(0);
199 return AF_FAIL;
202 else if (track->f.compressionType == AF_COMPRESSION_G711_ULAW)
204 memcpy(compressionTag, "ulaw", 4);
205 strcpy(compressionName, "CCITT G.711 u-law");
207 else if (track->f.compressionType == AF_COMPRESSION_G711_ALAW)
209 memcpy(compressionTag, "alaw", 4);
210 strcpy(compressionName, "CCITT G.711 A-law");
214 af_fwrite("COMM", 4, 1, file->fh);
217 For AIFF-C files, the length of the COMM chunk is 22
218 plus the length of the compression name plus the size
219 byte. If the length of the data is an odd number of
220 bytes, add a zero pad byte at the end, but don't
221 include the pad byte in the chunk's size.
223 if (isAIFFC)
224 chunkSize = 22 + strlen(compressionName) + 1;
225 else
226 chunkSize = 18;
227 af_write_uint32_be(&chunkSize, file->fh);
229 /* number of channels, 2 bytes */
230 sb = track->f.channelCount;
231 af_write_uint16_be(&sb, file->fh);
233 /* number of sample frames, 4 bytes */
234 lb = track->totalfframes;
235 af_write_uint32_be(&lb, file->fh);
237 /* sample size, 2 bytes */
238 sb = track->f.sampleWidth;
239 af_write_uint16_be(&sb, file->fh);
241 /* sample rate, 10 bytes */
242 _af_convert_to_ieee_extended(track->f.sampleRate, eb);
243 af_fwrite(eb, 10, 1, file->fh);
245 if (file->fileFormat == AF_FILE_AIFFC)
247 af_fwrite(compressionTag, 4, 1, file->fh);
249 af_write_pstring(compressionName, file->fh);
252 return AF_SUCCEED;
256 The AESD chunk contains information pertinent to audio recording
257 devices.
259 static status WriteAESD (const AFfilehandle file)
261 _Track *track;
262 uint32_t size = 24;
263 _AIFFInfo *aiff;
265 assert(file);
267 aiff = file->formatSpecific;
269 track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
271 if (!track->hasAESData)
272 return AF_SUCCEED;
274 if (aiff->AESD_offset == 0)
275 aiff->AESD_offset = af_ftell(file->fh);
276 else
277 af_fseek(file->fh, aiff->AESD_offset, SEEK_SET);
279 if (af_fwrite("AESD", 4, 1, file->fh) < 1)
280 return AF_FAIL;
282 if (af_write_uint32_be(&size, file->fh) == AF_FAIL)
283 return AF_FAIL;
285 if (af_fwrite(track->aesData, 24, 1, file->fh) < 1)
286 return AF_FAIL;
288 return AF_SUCCEED;
291 static status WriteSSND (AFfilehandle file)
293 _Track *track;
294 uint32_t chunkSize, zero = 0;
295 _AIFFInfo *aiff;
297 assert(file);
298 assert(file->fh);
300 aiff = file->formatSpecific;
302 track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK);
304 if (aiff->SSND_offset == 0)
305 aiff->SSND_offset = af_ftell(file->fh);
306 else
307 af_fseek(file->fh, aiff->SSND_offset, SEEK_SET);
309 chunkSize = (int) _af_format_frame_size(&track->f, false) *
310 track->totalfframes + 8;
312 af_fwrite("SSND", 4, 1, file->fh);
313 af_write_uint32_be(&chunkSize, file->fh);
315 /* data offset */
316 af_write_uint32_be(&zero, file->fh);
317 /* block size */
318 af_write_uint32_be(&zero, file->fh);
320 if (track->fpos_first_frame == 0)
321 track->fpos_first_frame = af_ftell(file->fh);
323 return AF_SUCCEED;
326 static status WriteINST (AFfilehandle file)
328 uint32_t length;
329 struct _INST instrumentdata;
331 length = 20;
333 instrumentdata.sustainLoopPlayMode =
334 afGetLoopMode(file, AF_DEFAULT_INST, 1);
335 instrumentdata.sustainLoopBegin =
336 afGetLoopStart(file, AF_DEFAULT_INST, 1);
337 instrumentdata.sustainLoopEnd =
338 afGetLoopEnd(file, AF_DEFAULT_INST, 1);
340 instrumentdata.releaseLoopPlayMode =
341 afGetLoopMode(file, AF_DEFAULT_INST, 2);
342 instrumentdata.releaseLoopBegin =
343 afGetLoopStart(file, AF_DEFAULT_INST, 2);
344 instrumentdata.releaseLoopEnd =
345 afGetLoopEnd(file, AF_DEFAULT_INST, 2);
347 af_fwrite("INST", 4, 1, file->fh);
348 af_write_uint32_be(&length, file->fh);
350 instrumentdata.baseNote =
351 afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_BASENOTE);
352 af_write_uint8(&instrumentdata.baseNote, file->fh);
353 instrumentdata.detune =
354 afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMCENTS_DETUNE);
355 af_write_uint8(&instrumentdata.detune, file->fh);
356 instrumentdata.lowNote =
357 afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LONOTE);
358 af_write_uint8(&instrumentdata.lowNote, file->fh);
359 instrumentdata.highNote =
360 afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HINOTE);
361 af_write_uint8(&instrumentdata.highNote, file->fh);
362 instrumentdata.lowVelocity =
363 afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_LOVELOCITY);
364 af_write_uint8(&instrumentdata.lowVelocity, file->fh);
365 instrumentdata.highVelocity =
366 afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_MIDI_HIVELOCITY);
367 af_write_uint8(&instrumentdata.highVelocity, file->fh);
369 instrumentdata.gain =
370 afGetInstParamLong(file, AF_DEFAULT_INST, AF_INST_NUMDBS_GAIN);
371 af_write_uint16_be(&instrumentdata.gain, file->fh);
373 af_write_uint16_be(&instrumentdata.sustainLoopPlayMode, file->fh);
374 af_write_uint16_be(&instrumentdata.sustainLoopBegin, file->fh);
375 af_write_uint16_be(&instrumentdata.sustainLoopEnd, file->fh);
377 af_write_uint16_be(&instrumentdata.releaseLoopPlayMode, file->fh);
378 af_write_uint16_be(&instrumentdata.releaseLoopBegin, file->fh);
379 af_write_uint16_be(&instrumentdata.releaseLoopEnd, file->fh);
381 return AF_SUCCEED;
384 static status WriteMARK (AFfilehandle file)
386 AFfileoffset chunkStartPosition, chunkEndPosition;
387 uint32_t length = 0;
388 uint16_t numMarkers;
389 int i, *markids;
390 _AIFFInfo *aiff;
392 assert(file);
394 numMarkers = afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL);
395 if (numMarkers == 0)
396 return AF_SUCCEED;
398 aiff = file->formatSpecific;
400 if (aiff->MARK_offset == 0)
401 aiff->MARK_offset = af_ftell(file->fh);
402 else
403 af_fseek(file->fh, aiff->MARK_offset, SEEK_SET);
405 af_fwrite("MARK", 4, 1, file->fh);
406 af_write_uint32_be(&length, file->fh);
408 chunkStartPosition = af_ftell(file->fh);
410 markids = _af_calloc(numMarkers, sizeof (int));
411 assert(markids);
412 afGetMarkIDs(file, AF_DEFAULT_TRACK, markids);
414 af_write_uint16_be(&numMarkers, file->fh);
416 for (i=0; i<numMarkers; i++)
418 uint8_t namelength, zero = 0;
419 uint16_t id;
420 uint32_t position;
421 char *name;
423 id = markids[i];
424 position = afGetMarkPosition(file, AF_DEFAULT_TRACK, markids[i]);
426 af_write_uint16_be(&id, file->fh);
427 af_write_uint32_be(&position, file->fh);
429 name = afGetMarkName(file, AF_DEFAULT_TRACK, markids[i]);
430 assert(name);
432 /* Write the name as a Pascal-style string. */
433 af_write_pstring(name, file->fh);
436 free(markids);
438 chunkEndPosition = af_ftell(file->fh);
439 length = chunkEndPosition - chunkStartPosition;
441 #ifdef DEBUG
442 printf(" end: %d\n", chunkEndPosition);
443 printf(" length: %d\n", length);
444 #endif
446 af_fseek(file->fh, chunkStartPosition - 4, SEEK_SET);
448 af_write_uint32_be(&length, file->fh);
449 af_fseek(file->fh, chunkEndPosition, SEEK_SET);
451 return AF_SUCCEED;
455 The FVER chunk, if present, is always the first chunk in the file.
457 static status WriteFVER (AFfilehandle file)
459 uint32_t chunkSize, timeStamp;
460 _AIFFInfo *aiff;
462 assert(file->fileFormat == AF_FILE_AIFFC);
464 aiff = file->formatSpecific;
466 if (aiff->FVER_offset == 0)
467 aiff->FVER_offset = af_ftell(file->fh);
468 else
469 af_fseek(file->fh, aiff->FVER_offset, SEEK_SET);
471 af_fwrite("FVER", 4, 1, file->fh);
473 chunkSize = 4;
474 af_write_uint32_be(&chunkSize, file->fh);
476 timeStamp = AIFC_VERSION_1;
477 af_write_uint32_be(&timeStamp, file->fh);
479 return AF_SUCCEED;
483 WriteMiscellaneous writes all the miscellaneous data chunks in a
484 file handle structure to an AIFF or AIFF-C file.
486 static status WriteMiscellaneous (AFfilehandle file)
488 _AIFFInfo *aiff;
489 int i;
491 aiff = (_AIFFInfo *) file->formatSpecific;
493 if (aiff->miscellaneousPosition == 0)
494 aiff->miscellaneousPosition = af_ftell(file->fh);
495 else
496 af_fseek(file->fh, aiff->miscellaneousPosition, SEEK_SET);
498 for (i=0; i<file->miscellaneousCount; i++)
500 _Miscellaneous *misc = &file->miscellaneous[i];
501 uint32_t chunkType, chunkSize;
502 uint8_t padByte = 0;
504 #ifdef DEBUG
505 printf("WriteMiscellaneous: %d, type %d\n", i, misc->type);
506 #endif
508 switch (misc->type)
510 case AF_MISC_NAME:
511 memcpy(&chunkType, "NAME", 4); break;
512 case AF_MISC_AUTH:
513 memcpy(&chunkType, "AUTH", 4); break;
514 case AF_MISC_COPY:
515 memcpy(&chunkType, "(c) ", 4); break;
516 case AF_MISC_ANNO:
517 memcpy(&chunkType, "ANNO", 4); break;
518 case AF_MISC_MIDI:
519 memcpy(&chunkType, "MIDI", 4); break;
520 case AF_MISC_APPL:
521 memcpy(&chunkType, "APPL", 4); break;
525 af_fwrite(&chunkType, 4, 1, file->fh);
527 chunkSize = misc->size;
528 af_write_uint32_be(&chunkSize, file->fh);
530 Write the miscellaneous buffer and then a pad byte
531 if necessary. If the buffer is null, skip the space
532 for now.
534 if (misc->buffer != NULL)
535 af_fwrite(misc->buffer, misc->size, 1, file->fh);
536 else
537 af_fseek(file->fh, misc->size, SEEK_CUR);
539 if (misc->size % 2 != 0)
540 af_write_uint8(&padByte, file->fh);
543 return AF_SUCCEED;