/sf/tags/RELEASE_0_1_1/src/sndlib/headers.c
C | 1622 lines | 1185 code | 78 blank | 359 comment | 294 complexity | 4a9d04c3a2ccb7a170b31d62775e2807 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0
Large files files are truncated, but you can click here to view the full file
- /* readers/writers for various sound file headers
- *
- * TODO: avi, asf, and soundfont code seriously incomplete
- * avr doesn't match actual files
- * quicktime is just a guess
- * esignal not tackled yet
- * check resource info on Mac (for SoundEdit)
- *
- * --------------------------------
- * int c_read_header (char *name): reads file's header
- * int c_write_header (char *name, int type, int in_srate, int in_chans, int loc, int size, int format, char *comment, int len): writes file's header
- * int c_update_header (char *name, int type, int size, int srate, int format, int chans, int loc): update file's header (unset fields should be 0)
- * void create_header_buffer (void): initialize (allocate) various buffers -- should be called before using c_read_header and others
- *
- * Once c_read_header has been called, the data in it can be accessed through:
- *
- * int c_snd_header_data_size (void): samples
- * int c_snd_header_data_location (void) location of data (bytes)
- * int c_snd_header_chans (void) channels
- * int c_snd_header_srate (void) srate
- * int c_snd_header_type (void) header type (i.e. aiff, wave, etc) (see sndlib.h)
- * int c_snd_header_format (void) data format (see sndlib.h)
- * int c_snd_header_distributed (void) true if header info is scattered around in the file
- * int c_snd_header_comment_start (void) comment start location (if any) (bytes)
- * int c_snd_header_comment_end (void) comment end location
- * int c_snd_header_aux_comment_start (int n) if multiple comments, nth start location
- * int c_snd_header_aux_comment_end (int n) if multiple comments, nth end location
- * int c_snd_header_type_specifier (void) original (header-specific) type ID
- * int c_snd_header_bits_per_sample (void) sample width in bits
- * int c_true_file_length (void) true (lseek) file length
- * int c_snd_header_datum_size (void) sample width in bytes
- * --------------------------------
- *
- * "Linear" below means 2's complement integer.
- *
- * Currently supported read/write (in standard data formats):
- * NeXT/Sun/DEC/AFsp
- * AIFF/AIFC
- * RIFF (microsoft wave)
- * IRCAM (old style)
- * no header
- *
- * Currently supported read-only (in selected data formats):
- * 8SVX (IFF), IRCAM Vax float, EBICSF, INRS, ESPS, SPPACK, ADC (OGI), NIST-SPHERE, AVR, VOC,
- * Sound Tools, Turtle Beach SMP, SoundFont 2.0, Sound Designer I and II, PSION alaw, MAUD,
- * Tandy DeskMate new and old style, Gravis Ultrasound, Comdisco SPW, Goldwave sample, OMF,
- * Sonic Foundry, SBStudio II, Delusion digital, Digiplayer ST3, Farandole Composer WaveSample,
- * Ultratracker WaveSample, Sample Dump exchange, Yamaha SY85 and SY99 (buggy), Yamaha TX16,
- * Covox v8, SPL, AVI, Kurzweil 2000
- *
- * for a few of these I'm still trying to get documentation -- best sources of info
- * are ftp.cwi.nl:pub/audio (info files), the AFsp sources, and the SOX sources.
- * sox and gsm are at ftp.cwi.nl, AFsp is from kabal@Polaris.EE.McGill.CA (Peter Kabal) as
- * ftp.TSP.EE.McGill.CA:/pub/AFsp/AFsp-V3R2.tar.Z. The Sound Designer formats are described
- * in the "Developer Documentation" from Digidesign. Other useful sources can be found at
- * ftp.x.org:/contrib/audio/nas, svr-ftp.eng.cam.ac.uk:/comp.speech/tools, and
- * at http://www.wotsit.demon.co.uk/music.htm. I put many of my test cases in
- * ccrma-ftp.stanford.edu:/pub/Lisp/sf.tar.gz. The RIFF format is described in the
- * Microsoft Multimedia Programmer's Reference Manual at ftp.microsoft.com:/SoftLib/MSLFILES/MDRK.EXE.
- * AVI format is described in http://www.rahul.net/jfm/avi.html.
- *
- * The main problem with compressed sound files is that you can't do reliable
- * random access to the data, can't easily read backwards, and most of the compression
- * schemes are proprietary (and appalling), but to translate Mus10/Sam, HCOM, IEEE text,
- * IBM CVSD, MIDI sample dumps, various adpcm cases, NIST shortpack files, and AVI see snd-trans.c
- * in the sound editor (snd.tar.gz).
- *
- * If anyone has information on any other header or data formats, I would be most interested in it,
- * but only if it can be included in this file.
- */
- #if defined(HAVE_CONFIG_H)
- #include "config.h"
- #endif
- #include <math.h>
- #include <stdio.h>
- #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_FCNTL_H))
- #include <fcntl.h>
- #endif
- #include <signal.h>
- #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_LIMITS_H))
- #include <limits.h>
- #endif
- #include <errno.h>
- #include <stdlib.h>
- #if (defined(NEXT) || (defined(HAVE_LIBC_H) && (!defined(HAVE_UNISTD_H))))
- #include <libc.h>
- #else
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #endif
- #include "sndlib.h"
- static int hdrbuf_is_inited = 0;
- #define HDRBUFSIZ 256
- #ifndef MACOS
- static unsigned char *hdrbuf;
- #else
- static char *hdrbuf;
- #endif
- #define INITIAL_READ_SIZE 32
- /* AIFF files can have any number of ANNO chunks, so we'll grab at least 4 of them */
- /* if AUX_COMMENTS is changed, remember to change aux-comments in headers.lisp */
- #define AUX_COMMENTS 4
- static int *aux_comment_start = NULL, *aux_comment_end = NULL;
- #define LOOPS 2
- static int *loop_modes = NULL,*loop_starts = NULL,*loop_ends = NULL;
- static int markers = 0;
- static int *marker_ids = NULL,*marker_positions = NULL;
- #ifdef MCL_PPC
- void reset_hdrbuf(void) {hdrbuf_is_inited = 0; markers = 0;}
- #endif
- void create_header_buffer (void)
- {
- if (hdrbuf_is_inited == 0)
- {
- hdrbuf_is_inited = 1;
- #ifndef MACOS
- hdrbuf = (unsigned char *)CALLOC(HDRBUFSIZ,sizeof(unsigned char));
- #else
- hdrbuf = (char *)CALLOC(HDRBUFSIZ,sizeof(unsigned char));
- #endif
- aux_comment_start = (int *)CALLOC(AUX_COMMENTS,sizeof(int));
- aux_comment_end = (int *)CALLOC(AUX_COMMENTS,sizeof(int));
- if ((hdrbuf == NULL) || (aux_comment_start == NULL) || (aux_comment_end == NULL))
- clm_printf("header buffer allocation trouble");
- loop_modes = (int *)CALLOC(LOOPS,sizeof(int));
- loop_starts = (int *)CALLOC(LOOPS,sizeof(int));
- loop_ends = (int *)CALLOC(LOOPS,sizeof(int));
- }
- }
- static const unsigned char I_DSND[4] = {'.','s','n','d'}; /* NeXT/Sun/Dec/SGI/AFsp first word */
- static const unsigned char I_FORM[4] = {'F','O','R','M'}; /* AIFF first word */
- static const unsigned char I_AIFF[4] = {'A','I','F','F'}; /* AIFF second word */
- static const unsigned char I_AIFC[4] = {'A','I','F','C'}; /* ditto but might be compressed data */
- static const unsigned char I_COMM[4] = {'C','O','M','M'};
- static const unsigned char I_COMT[4] = {'C','O','M','T'};
- static const unsigned char I_INFO[4] = {'I','N','F','O'};
- static const unsigned char I_INST[4] = {'I','N','S','T'};
- static const unsigned char I_inst[4] = {'i','n','s','t'}; /* RIFF wants lower case, just to be different */
- static const unsigned char I_MARK[4] = {'M','A','R','K'};
- static const unsigned char I_SSND[4] = {'S','S','N','D'};
- static const unsigned char I_FVER[4] = {'F','V','E','R'};
- static const unsigned char I_NONE[4] = {'N','O','N','E'};
- static const unsigned char I_ULAW[4] = {'U','L','A','W'}; /* AIFC compression types that we can handle */
- static const unsigned char I_ulaw[4] = {'u','l','a','w'}; /* or maybe it's lowercase ... */
- static const unsigned char I_ima4[4] = {'i','m','a','4'}; /* AIFC IMA adpcm apparently */
- static const unsigned char I_ALAW[4] = {'A','L','A','W'};
- static const unsigned char I_APPL[4] = {'A','P','P','L'};
- static const unsigned char I_CLM_[4] = {'C','L','M',' '}; /* I hereby claim this AIFF chunk name */
- static const unsigned char I_RIFF[4] = {'R','I','F','F'}; /* RIFF first word */
- static const unsigned char I_RIFX[4] = {'R','I','F','X'}; /* RIFX first word (big-endian RIFF file) */
- static const unsigned char I_WAVE[4] = {'W','A','V','E'};
- static const unsigned char I_fmt_[4] = {'f','m','t',' '};
- static const unsigned char I_data[4] = {'d','a','t','a'};
- static const unsigned char I_fact[4] = {'f','a','c','t'}; /* used by compressed RIFF files */
- static const unsigned char I_clm_[4] = {'c','l','m',' '};
- static const unsigned char I_NIST[4] = {'N','I','S','T'}; /* first word of NIST SPHERE files */
- static const unsigned char I_8SVX[4] = {'8','S','V','X'}; /* AIFF other choice */
- static const unsigned char I_dcdt[4] = {'.','c','d','t'}; /* no-ffi CLM data file */
- static const unsigned char I_VOC0[4] = {'C','r','e','a'}; /* Actual text is "Creative Voice File" */
- static const unsigned char I_VOC1[4] = {'t','i','v','e'};
- static const unsigned char I_SOUN[4] = {'S','O','U','N'}; /* Sound Tools first word="SOUND" -- not unique as SMP files start with "SOUND SAMPLE" */
- static const unsigned char I_SMP1[4] = {'D',' ','S','A'};
- static const unsigned char I_SMP2[4] = {'M','P','L','E'};
- static const unsigned char I_BODY[4] = {'B','O','D','Y'}; /* next 4 for 8svx chunk names */
- static const unsigned char I_VHDR[4] = {'V','H','D','R'};
- static const unsigned char I_CHAN[4] = {'C','H','A','N'};
- static const unsigned char I_ANNO[4] = {'A','N','N','O'};
- static const unsigned char I_NAME[4] = {'N','A','M','E'};
- static const unsigned char I_AVR_[4] = {'2','B','I','T'}; /* first word of AVR files */
- static const unsigned char I_HCOM[4] = {'H','C','O','M'};
- static const unsigned char I_FSSD[4] = {'F','S','S','D'};
- static const unsigned char I_SPIB[4] = {'%','/','/','\n'}; /* first word of IEEE spib text sound files */
- static const unsigned char I_S___[4] = {'%','-','-','-'}; /* first word of other IEEE spib text sound files */
- static const unsigned char I_ALaw[4] = {'A','L','a','w'}; /* first word of PSION alaw files */
- static const unsigned char I_Soun[4] = {'S','o','u','n'}; /* second */
- static const unsigned char I_MAUD[4] = {'M','A','U','D'}; /* MAUD specialization of AIFF */
- static const unsigned char I_MHDR[4] = {'M','H','D','R'};
- static const unsigned char I_MDAT[4] = {'M','D','A','T'};
- static const unsigned char I_mdat[4] = {'m','d','a','t'}; /* quicktime */
- static const unsigned char I_AFsp[4] = {'A','F','s','p'};
- static const unsigned char I_MThd[4] = {'M','T','h','d'}; /* sigh -- the M word */
- static const unsigned char I_DVSM[4] = {'D','V','S','M'}; /* first word of DVSM files */
- static const unsigned char I_DECN[4] = {'.','s','d','\0'}; /* first word of DEC files (?) */
- static const unsigned char I_Esig[4] = {'E','s','i','g'}; /* first word of Esignal files */
- static const unsigned char I_nalc[4] = {'n','a','l','\n'}; /* second word of Esignal files */
- static const unsigned char I_sfbk[4] = {'s','f','b','k'}; /* SoundFont 2.0 */
- static const unsigned char I_sdta[4] = {'s','d','t','a'};
- static const unsigned char I_shdr[4] = {'s','h','d','r'};
- static const unsigned char I_smpl[4] = {'s','m','p','l'};
- static const unsigned char I_pdta[4] = {'p','d','t','a'};
- static const unsigned char I_LIST[4] = {'L','I','S','T'};
- static const unsigned char I_GF1P[4] = {'G','F','1','P'}; /* first word of Gravis Ultrsound patch files */
- static const unsigned char I_ATCH[4] = {'A','T','C','H'}; /* second word */
- static const unsigned char I_DSIG[4] = {'$','S','I','G'}; /* first word of Comdisco SPW file */
- static const unsigned char I_NAL_[4] = {'N','A','L','_'}; /* second word */
- static const unsigned char I_GOLD[4] = {'G','O','L','D'}; /* first word Goldwave(?) sample file */
- static const unsigned char I__WAV[4] = {' ','S','A','M'}; /* second word */
- static const unsigned char I_SRFS[4] = {'S','R','F','S'}; /* first word Sonic Resource Foundry file(?) */
- static const unsigned char I_Diam[4] = {'D','i','a','m'}; /* first word DiamondWare file */
- static const unsigned char I_ondW[4] = {'o','n','d','W'}; /* second word */
- static const unsigned char I_Drat[4] = {'.','r','a','\xfd'}; /* first word real audio file */
- static const unsigned char I_CSRE[4] = {'C','S','R','E'}; /* adf first word -- second starts with "40" */
- static const unsigned char I_SND_[4] = {'S','N','D',' '}; /* SBStudio II */
- static const unsigned char I_SNIN[4] = {'S','N','I','N'};
- static const unsigned char I_SNDT[4] = {'S','N','D','T'};
- static const unsigned char I_DDSF[4] = {'D','D','S','F'}; /* Delusion Digital Sound File */
- static const unsigned char I_FSMt[4] = {'F','S','M','\376'}; /* Farandole Composer WaveSample */
- static const unsigned char I_SDXc[4] = {'S','D','X',':'}; /* Sample dump exchange format */
- static const unsigned char I_UWFD[4] = {'U','W','F','D'}; /* Ultratracker Wavesample */
- static const unsigned char I_LM89[4] = {'L','M','8','9'}; /* Yamaha TX-16 */
- static const unsigned char I_SY80[4] = {'S','Y','8','0'}; /* Yamaha SY-99 */
- static const unsigned char I_SY85[4] = {'S','Y','8','5'}; /* Yamaha SY-85 */
- static const unsigned char I_SCRS[4] = {'S','C','R','S'}; /* Digiplayer ST3 */
- static const unsigned char I_covox[4] = {'\377','\125','\377','\252'};
- static const unsigned char I_DSPL[4] = {'D','S','P','L'}; /* Digitracker SPL (now obsolete) */
- static const unsigned char I_AVI_[4] = {'A','V','I',' '}; /* RIFF AVI */
- static const unsigned char I_strf[4] = {'s','t','r','f'};
- static const unsigned char I_movi[4] = {'m','o','v','i'};
- static const unsigned char I_PRAM[4] = {'P','R','A','M'}; /* Kurzweil 2000 */
- static const unsigned char I_ones[4] = {'\377','\377','\377','\377'};
- static const unsigned char I_zeros[4] = {'\0','\0','\0','\0'};
- static const unsigned char I_asf0[4] = {'\321','\051','\342','\326'};
- static const unsigned char I_asf1[4] = {'\332','\065','\321','\021'};
- static const unsigned char I_asf2[4] = {'\220','\064','\000','\240'};
- static const unsigned char I_asf3[4] = {'\311','\003','\111','\276'};
- #define I_IRCAM_VAX 0x0001a364
- #define I_IRCAM_SUN 0x0002a364
- #define I_IRCAM_MIPS 0x0003a364
- #define I_IRCAM_NEXT 0x0004a364
- #define NINRS 7
- static const unsigned int I_INRS[NINRS]={0xcb460020,0xd0465555,0xfa460000,0x1c470040,0x3b470080,0x7a470000,0x9c470040};
- static int data_size=0, data_location=0, srate=0, chans=0, header_type=0, sound_format=0, original_sound_format=0, true_file_length=0;
- static int comment_start=0, comment_end=0, header_distributed=0, type_specifier=0, bits_per_sample=0, fact_samples=0, block_align=0;
- static int base_detune = 0, base_note = 0;
- int c_snd_header_data_size (void) {return(data_size);}
- int c_snd_header_data_location (void) {return(data_location);}
- int c_snd_header_chans (void) {return(chans);}
- int c_snd_header_srate (void) {return(srate);}
- int c_snd_header_type (void) {return(header_type);}
- int c_snd_header_format (void) {return(sound_format);}
- int c_snd_header_distributed (void) {return(header_distributed);}
- int c_snd_header_comment_start (void) {return(comment_start);}
- int c_snd_header_comment_end (void) {return(comment_end);}
- int c_snd_header_aux_comment_start (int n) {return(aux_comment_start[n]);}
- int c_snd_header_aux_comment_end (int n) {return(aux_comment_end[n]);}
- int c_snd_header_type_specifier (void) {return(type_specifier);}
- int c_snd_header_bits_per_sample (void) {return(bits_per_sample);}
- int c_snd_header_fact_samples (void) {return(fact_samples);}
- int c_snd_header_block_align (void) {return(block_align);}
- int c_true_file_length (void) {return(true_file_length);}
- int c_snd_header_original_format (void) {return(original_sound_format);}
- int c_snd_header_loop_mode(int which) {if (loop_modes) return(loop_modes[which]); else return(-1);}
- int c_snd_header_loop_start(int which) {if (loop_starts) return(loop_starts[which]); else return(-1);}
- int c_snd_header_loop_end(int which) {if (loop_ends) return(loop_ends[which]); else return(-1);}
- int c_snd_header_mark_position(int id) {int i; for (i=0;i<markers;i++) {if (marker_ids[i] == id) return(marker_positions[i]);} return(-1);}
- int c_snd_header_base_detune(void) {return(base_detune);}
- int c_snd_header_base_note(void) {return(base_note);}
- int c_snd_datum_size (int format)
- {
- switch (format)
- {
- case snd_8_linear: return(1); break;
- case snd_16_linear: return(2); break;
- case snd_8_unsigned: return(1); break;
- case snd_8_mulaw: return(1); break;
- case snd_8_alaw: return(1); break;
- case snd_32_linear: return(4); break;
- case snd_32_float: return(4); break;
- case snd_24_linear: return(3); break;
- case snd_64_double: return(8); break;
- case snd_16_linear_little_endian: return(2); break;
- case snd_32_linear_little_endian: return(4); break;
- case snd_32_float_little_endian: return(4); break;
- case snd_64_double_little_endian: return(8); break;
- case snd_24_linear_little_endian: return(3); break;
- case snd_16_unsigned: return(2); break;
- case snd_16_unsigned_little_endian: return(2); break;
- case snd_32_vax_float: return(4); break;
- default: return(1); break; /* we divide by this number, so 0 is not safe */
- }
- }
- void c_set_snd_header (int in_srate, int in_chans, int in_format)
- {
- srate = in_srate;
- chans = in_chans;
- sound_format = in_format;
- data_size = c_snd_samples(in_format,true_file_length);
- }
- int c_snd_header_datum_size (void) {return(c_snd_datum_size(sound_format));}
- int c_snd_bytes (int format, int size) {return(size*(c_snd_datum_size(format)));}
- int c_snd_samples (int format, int size) {return((int)(size/(c_snd_datum_size(format))));}
- static int equal_big_or_little_endian(int n1, int n2)
- {
- return ((n1 == big_endian_int(n2)) || (n1 == little_endian_int(n2)));
- }
- static short big_or_little_endian_short (short n, int little)
- {
- if (little) return(little_endian_short(n));
- return(big_endian_short(n));
- }
- static int big_or_little_endian_int (int n, int little)
- {
- if (little) return(little_endian_int(n));
- return(big_endian_int(n));
- }
- static float big_or_little_endian_float (unsigned char *n, int little)
- {
- if (little) return(little_endian_float(n));
- return(big_endian_float(n));
- }
- int match_four_chars(unsigned char *head, const unsigned char *match)
- {
- int i;
- for (i=0;i<4;i++) if (head[i] != match[i]) return(0);
- return(1);
- }
-
- static void write_four_chars(unsigned char *head, const unsigned char *match)
- {
- int i;
- for (i=0;i<4;i++) head[i] = match[i];
- }
- static void read_bicsf_header (int chan);
- /* ------------------------------------ NeXT (or Sun) --------------------------------
- *
- * 0: ".snd"
- * 4: data_location (bytes) (not necessarily word aligned on Sun)
- * 8: data_size (bytes) -- sometimes incorrect ("advisory")
- * 12: data format indicator -- see below
- * 16: srate (int)
- * 20: chans
- * 24: comment start
- *
- * in an AFsp file, the first 4 bytes of the comment are "AFsp",
- * see headers.lisp for readers/writers of AFsp fields
- * for bicsf, the integer at 28 is 107364 or 107415
- *
- * on NeXTStep, always big-endian. ".snd"==0x2e736e64 on big-endian machines.
- *
- * formats are:
- * 0 unspecified, 1 mulaw_8, 2 linear_8, 3 linear_16, 4 linear_24, 5 linear_32, 6 float,
- * 7 double, 8 indirect, 9 nested, 10 dsp_core, 11 dsp_data_8, 12 dsp_data_16, 13 dsp_data_24,
- * 14 dsp_data_32, 16 display, 17 mulaw_squelch, 18 emphasized, 19 compressed, 20 compressed_emphasized
- * 21 dsp_commands, 22 dsp_commands_samples, 23 adpcm_g721, 24 adpcm_g722, 25 adpcm_g723,
- * 26 adpcm_g723_5, 27 alaw_8, 28 aes, 29 delat_mulaw_8 {internal Snd-secret format: 30=linear_32_little_endian}
- *
- */
- static void read_next_header (int chan)
- {
- int maybe_bicsf;
- type_specifier = (*((int *)(hdrbuf)));
- data_location = big_endian_int((*((int *)(hdrbuf+4))));
- data_size = big_endian_int((*((int *)(hdrbuf+8))));
- /* can be bogus -- fixup if possible */
- true_file_length = lseek(chan,0L,2);
- if (data_size <= 24) data_size = (true_file_length-data_location);
- original_sound_format = big_endian_int((*((int *)(hdrbuf+12))));
- switch (original_sound_format)
- { /* defined in /usr/include/sound/soundstruct.h */
- /* see headers.lisp for a table of all known format names */
- case 1: sound_format = snd_8_mulaw; break;
- case 2: sound_format = snd_8_linear; break;
- case 3: sound_format = snd_16_linear; break;
- case 4: sound_format = snd_24_linear; break;
- case 5: sound_format = snd_32_linear; break;
- case 6: sound_format = snd_32_float; break;
- case 7: sound_format = snd_64_double; break;
- case 18: sound_format = snd_16_linear; break;
- /* "emphasized": Xavier Serra's de-emphasis filter: y(n) = x(n) + .9 y(n-1) */
- case 27: sound_format = snd_8_alaw; break;
- case 30: sound_format = snd_32_linear_little_endian; break; /* this is for Snd's internal benefit -- it is not used elsewhere */
- default: sound_format = snd_unsupported; break;
- }
- srate = big_endian_int((*((int *)(hdrbuf+16))));
- chans = big_endian_int((*((int *)(hdrbuf+20))));
- comment_start = 24;
- comment_end = data_location - 1;
- if (comment_end < comment_start) comment_end = comment_start;
- if (match_four_chars((unsigned char *)(hdrbuf+24),I_AFsp)) header_distributed = 1; else header_distributed = 0;
- maybe_bicsf = big_endian_int((*((int *)(hdrbuf+28))));
- if (maybe_bicsf == 107364) read_bicsf_header(chan);
- data_size = c_snd_samples(sound_format,data_size);
- }
- void write_next_header (int chan, int srate, int chans, int loc, int siz, int format, char *comment, int len)
- {
- int i,j;
- char *str;
- write_four_chars((unsigned char *)hdrbuf,I_DSND); /* ".snd" */
- i = len/4;
- j = 24 + (4 * (i+1));
- if (loc < j) loc = j;
- (*((int *)(hdrbuf+4))) = big_endian_int(loc);
- (*((int *)(hdrbuf+8))) = big_endian_int(siz);
- switch (format)
- {
- case snd_8_mulaw: (*((int *)(hdrbuf+12))) = big_endian_int(1); break;
- case snd_8_linear: (*((int *)(hdrbuf+12))) = big_endian_int(2); break;
- case snd_16_linear: (*((int *)(hdrbuf+12))) = big_endian_int(3); break;
- case snd_24_linear: (*((int *)(hdrbuf+12))) = big_endian_int(4); break;
- case snd_32_linear: (*((int *)(hdrbuf+12))) = big_endian_int(5); break;
- case snd_32_float: (*((int *)(hdrbuf+12))) = big_endian_int(6); break;
- case snd_64_double: (*((int *)(hdrbuf+12))) = big_endian_int(7); break;
- case snd_32_linear_little_endian: (*((int *)(hdrbuf+12))) = big_endian_int(30); break; /* see above */
- case snd_8_alaw: (*((int *)(hdrbuf+12))) = big_endian_int(27); break;
- default:
- str=(char *)CALLOC(256,sizeof(char));
- sprintf(str,"CLM/NeXT unsupported sound data format type: %d\n",format);
- clm_printf(str);
- FREE(str);
- break;
- }
- (*((int *)(hdrbuf+16))) = big_endian_int(srate);
- (*((int *)(hdrbuf+20))) = big_endian_int(chans);
- write(chan,hdrbuf,24);
- j = 0;
- for (i=0;i<len;i++)
- {
- hdrbuf[j]=comment[i];
- j++;
- if (j == HDRBUFSIZ)
- {
- write(chan,hdrbuf,HDRBUFSIZ);
- j = 0;
- }
- }
- for (i=0;i<(loc-(len+24));i++) /* now fill left over bytes with nulls */
- {
- hdrbuf[j]=0;
- j++;
- if (j == HDRBUFSIZ)
- {
- write(chan,hdrbuf,HDRBUFSIZ);
- j = 0;
- }
- }
- if (j != 0) write(chan,hdrbuf,j);
- data_location = loc;
- }
- static void update_next_header (int chan, int siz)
- {
- lseek(chan,8L,0);
- (*((int *)(hdrbuf))) = big_endian_int(siz);
- write(chan,hdrbuf,4);
- }
- static void update_next_header_comment (int chan, int loc, char *comment, int len)
- {
- int i,j;
- lseek(chan,(long)(loc-4),0);
- read(chan,hdrbuf,4);
- lseek(chan,(long)(loc-4),0);
- for (j=0;j<4;j++) if (hdrbuf[j]==0) hdrbuf[j] = 32;
- j = 4;
- for (i=0;i<len;i++)
- {
- hdrbuf[j]=comment[i];
- j++;
- if (j == HDRBUFSIZ)
- {
- write(chan,hdrbuf,HDRBUFSIZ);
- j = 0;
- }
- }
- if (j != 0) write(chan,hdrbuf,j);
- }
- /* ------------------------------------ AIFF ------------------------------------
- *
- * 0: "FORM"
- * 4: size (bytes)
- * 8: "AIFF" or "AIFC" -- the latter includes compressed formats
- *
- * Thereafter the file is organized into "chunks", each chunk being
- * a 4-byte identifer followed by an int (4-bytes) giving the chunk size
- * not including the 8-byte header. AIFF data is signed. If the chunk
- * size is odd, an extra (unaccounted-for) null byte is added at the end.
- *
- * The chunks we want are "COMM", "SSND", and "APPL".
- *
- * COMM: 0: chans
- * 2: frames
- * 6: bits per sample
- * 8: srate as 80-bit IEEE float
- * then if AIFC (not AIFF), 4 bytes giving compression id ("NONE"=not compressed)
- * followed by Pascal string giving long name of compression type
- *
- * SSND: 0: data location (offset within SSND chunk)
- *
- * Other chunks include: ANNO: a comment, INST: loop control, MARK: marker, MIDI: midi,
- * COMT: comment (max 65536 chars), NAME: sound name, AUTH: author's name
- * (c), AESD: recording data, APPL: application specific stuff
- * "MARK" size short-#marks {marks} -- latter are short-ID long-position pstring-name.
- * "INST" size chars[baseNote detune lowNote highNote lowVelocity HighVelocity] short-gain loops[sustain release]
- * loop: short-playMode marker-begin marker-end (signed?) shorts)
- * playMode: 0 no loop, 1 forward loop, 2 forward/backward loop
- * chars are MIDI data (detune is in cents)
- * "MIDI" size MIDI-data...
- * "AESD" size AES Channel Status Data (24 bytes as specified by AES)
- * see "AES: Guidelines for the use of the AES3 interface"
- * byte 0: bit 0: 0=consumer, 1=pro
- * bit 1: 0=audio, 1=non-audio
- * bits 2:4: emphasis: 0:none, 4:none, 6:CD, 7:CCITT J17
- * bits 6:7: srate: 00=48KHz, 01=48, 10=44.1, 11=32
- * byte 1: bits 0:3: chans: 2:mono, else stereo
- * byte 2 for word size stuff (always ends up 16-bit): bits 3-5=sample length where 4=16-bit
- * byte 3: multi-channels modes, 4: AES sync ref, 5:unused, 6-9:ASCII source ID, 10-13:ASCII destination ID
- * byte 14-17:local sample addr, 18-21:time of day addr, then CRC checks
- * "APPL" size signature data
- * "COMT" size short-#comments {comments} -- the latter are long-time marker short-text-length char-text
- * time is in seconds since 1-Jan-1904
- * "NAME"/"AUTH"/"(c) "/"ANNO" size char-name
- * "FVER" size(4) AIFC-format-version -- currently always 0xA2805140
- * "SAXL" -- a desperate kludge to get around Apple's own compression schemes!
- *
- * always big-endian
- * There was also (briefly) an AIFS file, now deprecated.
- */
- /* ieee-80 conversions -- design by committee! */
- /* this code taken from CSound sources -- apparently originally written by Malcolm Slaney at Apple */
- #define ULPOW2TO31 ((unsigned int)0x80000000)
- #define DPOW2TO31 ((double)2147483648.0) /* 2^31 */
- static double myUlongToDouble(unsigned int ul)
- {
- double val;
- if(ul & ULPOW2TO31) val = DPOW2TO31 + (ul & (~ULPOW2TO31));
- else val = ul;
- return val;
- }
- static unsigned int myDoubleToUlong(double val)
- {
- unsigned int ul;
- if(val < DPOW2TO31) ul = (unsigned int)val;
- else ul = ULPOW2TO31 | (unsigned int)(val-DPOW2TO31);
- return ul;
- }
- static double ieee_80_to_double(unsigned char *p)
- {
- unsigned char sign;
- short exp = 0;
- unsigned int mant1 = 0;
- unsigned int mant0 = 0;
- double val;
- exp = *p++; exp <<= 8; exp |= *p++; sign = (exp & 0x8000) ? 1 : 0; exp &= 0x7FFF;
- mant1 = *p++; mant1 <<= 8; mant1 |= *p++; mant1 <<= 8; mant1 |= *p++; mant1 <<= 8; mant1 |= *p++;
- mant0 = *p++; mant0 <<= 8; mant0 |= *p++; mant0 <<= 8; mant0 |= *p++; mant0 <<= 8; mant0 |= *p++;
- if(mant1 == 0 && mant0 == 0 && exp == 0 && sign == 0)
- return 0.0;
- else
- {
- val = myUlongToDouble(mant0) * pow(2.0,-63.0);
- val += myUlongToDouble(mant1) * pow(2.0,-31.0);
- val *= pow(2.0,((double) exp) - 16383.0);
- return sign ? -val : val;
- }
- }
- static void double_to_ieee_80(double val, unsigned char *p)
- {
- unsigned char sign = 0;
- short exp = 0;
- unsigned int mant1 = 0;
- unsigned int mant0 = 0;
- if(val < 0.0) { sign = 1; val = -val; }
- if(val != 0.0) /* val identically zero -> all elements zero */
- {
- exp = (short)(log(val)/log(2.0) + 16383.0);
- val *= pow(2.0, 31.0+16383.0-(double)exp);
- mant1 = myDoubleToUlong(val);
- val -= myUlongToDouble(mant1);
- val *= pow(2.0, 32.0);
- mant0 = myDoubleToUlong(val);
- }
- *p++ = ((sign<<7)|(exp>>8)); *p++ = 0xFF & exp;
- *p++ = 0xFF & (mant1>>24); *p++ = 0xFF & (mant1>>16); *p++ = 0xFF & (mant1>> 8); *p++ = 0xFF & (mant1);
- *p++ = 0xFF & (mant0>>24); *p++ = 0xFF & (mant0>>16); *p++ = 0xFF & (mant0>> 8); *p++ = 0xFF & (mant0);
- }
- static int update_form_size, update_frames_location, update_ssnd_location;
- static int seek_and_read(int chan, unsigned char *buf, int offset, int nbytes)
- {
- if (offset < 0) return(-1);
- lseek(chan, offset, 0);
- #ifndef MACOS
- return(read(chan,buf,nbytes));
- #else
- return(read(chan,(char *)buf,nbytes));
- #endif
- }
- static int read_aiff_marker(int m, int offset, unsigned char *buf)
- {
- unsigned char *hb;
- int psize;
- hb = (unsigned char *)(buf+offset);
- marker_ids[m] = big_endian_short(*(short *)hb);
- marker_positions[m] = big_endian_int(*(int *)(hb+2));
- psize = (int)hb[6] + 1;
- if (psize & 1) psize++;
- return(psize+6);
- }
- static void read_aiff_header (int chan, int overall_offset)
- {
- /* we know we have checked for FORM xxxx AIFF|AIFC when we arrive here */
- /* as far as I can tell, the COMM block has the header data we seek, and the SSND block has the sound data */
- /* everything else will be ignored -- apparently we can depend on seeing a "chunk" name, then size */
- int chunksize,offset,frames,chunkloc,happy,i,j,num_marks,m,moff,msize;
- type_specifier = (*((int *)(hdrbuf+8+overall_offset)));
- update_ssnd_location = 0;
- chunkloc = 12 + overall_offset;
- offset = 0;
- comment_start = 0;
- comment_end = 0;
- for (i=0;i<AUX_COMMENTS;i++) aux_comment_start[i] = 0;
- sound_format = snd_16_linear;
- header_distributed = 1;
- srate = 0;
- chans = 0;
- happy = 1;
- data_size = 0;
- if (loop_modes)
- {
- loop_modes[0] = 0;
- loop_modes[1] = 0;
- }
- true_file_length = lseek(chan,0L,2);
- update_form_size = big_endian_int((*(int *)(hdrbuf+4+overall_offset))); /* should be file-size-8 unless there are multiple forms */
- while (happy)
- {
- offset += chunkloc;
- if (seek_and_read(chan,(unsigned char *)hdrbuf,offset,32) <= 0)
- {
- clm_printf("error reading header");
- return;
- }
- chunksize = big_endian_int((*(int *)(hdrbuf+4)));
- if (match_four_chars((unsigned char *)hdrbuf,I_COMM))
- {
- chans = big_endian_short((*(short *)(hdrbuf+8)));
- frames = big_endian_int((*(int *)(hdrbuf+10)));
- update_frames_location = 10+offset;
- original_sound_format = big_endian_short((*(short *)(hdrbuf+14)));
- if ((original_sound_format%8) != 0)
- {
- /* weird sizes are legal --
- * these samples are left-justified (and zero padded on the right), so
- * we can handle any bit size by rounding up to the nearest byte.
- */
- original_sound_format=8*(1+(original_sound_format>>3));
- }
- if (original_sound_format == 8) sound_format = snd_8_linear;
- else if (original_sound_format == 16) sound_format = snd_16_linear;
- else if (original_sound_format == 24) sound_format = snd_24_linear;
- else if (original_sound_format == 32) sound_format = snd_32_linear;
- else sound_format = snd_unsupported;
- data_size = (frames*c_snd_datum_size(sound_format)*chans);
- srate = (int)ieee_80_to_double((unsigned char *)(hdrbuf+16));
- /* if AIFC, compression type over-rides (possibly bogus) original_sound_format */
- if (type_specifier == (*(int *)I_AIFC))
- {
- /* some aifc files assume the compression field is a new and very weird chunk!! -- surely a bug? */
- /* AIFF spec says COMM size is always 18, but this is amended in the newer AIFC spec */
- if (chunksize == 18) chunksize += (5+((int)hdrbuf[30])); /* 5=chunk header length in this case */
- if (!(match_four_chars((unsigned char *)(hdrbuf+26),I_NONE)))
- {
- original_sound_format = (*(int *)(hdrbuf+26));
- if (match_four_chars((unsigned char *)(hdrbuf+26),I_ALAW)) sound_format = snd_8_alaw;
- else if ((match_four_chars((unsigned char *)(hdrbuf+26),I_ULAW)) ||
- (match_four_chars((unsigned char *)(hdrbuf+26),I_ulaw)))
- sound_format = snd_8_mulaw;
- else
- {
- if (match_four_chars((unsigned char *)(hdrbuf+26),I_ima4))
- {
- block_align = 34;
- original_sound_format = AIFF_IMA_ADPCM;
- }
- sound_format = snd_unsupported;
- }
- }
- }
- }
- else
- {
- if (match_four_chars((unsigned char *)hdrbuf,I_SSND))
- {
- update_ssnd_location = offset+4;
- data_location = big_endian_int((*(int *)(hdrbuf+8))) + offset + 16; /* Baroque! */
- /* offset is where the hdrbuf is positioned in the file, the sound data offset itself is at loc+8 and the */
- /* 0-based location of the sound data is at the end of the chunk = 16 (8=header+4=offset+4=blocksize) */
- /* the next int can be the block size if the data is block-aligned */
- /* only one SSND per AIFF is allowed */
- }
- else
- {
- if ((match_four_chars((unsigned char *)hdrbuf,I_ANNO)) || (match_four_chars((unsigned char *)hdrbuf,I_COMT)))
- {
- j=0;
- for (i=0;i<AUX_COMMENTS;i++) if (aux_comment_start[i] == 0) {j=i; break;}
- if (j >= AUX_COMMENTS) {clm_printf("ran out of auxiliary comment space"); j=0;}
- aux_comment_start[j] = offset+8;
- if (match_four_chars((unsigned char *)hdrbuf,I_COMT)) aux_comment_start[j] += 8; /* skip time stamp and markerId (not ID, I assume!) */
- aux_comment_end[j] = offset+7+chunksize;
- }
- else
- {
- if (match_four_chars((unsigned char *)hdrbuf,I_APPL))
- {
- if (match_four_chars((unsigned char *)(hdrbuf+8),I_CLM_))
- {
- /* my own chunk has the arbitrary length comment I use (actually the ASCII */
- /* representation of a lisp program evaluated in the CLM package) to handle mix et al. */
- /* It is nothing more than the actual string -- remember to pad to even length here. */
- comment_start = offset + 12;
- comment_end = comment_start + chunksize - 5;
- }
- }
- else
- {
- if (match_four_chars((unsigned char *)hdrbuf,I_INST))
- {
- base_note = hdrbuf[8];
- base_detune = hdrbuf[9];
- loop_modes[0] = big_endian_short((*(short *)(hdrbuf+16)));
- loop_starts[0] = big_endian_short((*(short *)(hdrbuf+18)));
- loop_ends[0] = big_endian_short((*(short *)(hdrbuf+20)));
- loop_modes[1] = big_endian_short((*(short *)(hdrbuf+22)));
- loop_starts[1] = big_endian_short((*(short *)(hdrbuf+24)));
- loop_ends[1] = big_endian_short((*(short *)(hdrbuf+26)));
- /* these are mark numbers */
- }
- else
- {
- if (match_four_chars((unsigned char *)hdrbuf,I_MARK))
- {
- /* unsigned short #marks, each mark: id pos name (pstring damn it) */
- num_marks = big_endian_unsigned_short(*(unsigned short *)(hdrbuf+8));
- if (num_marks > markers)
- {
- if (markers > 0) {if (marker_ids) FREE(marker_ids); if (marker_positions) FREE(marker_positions);}
- markers = num_marks;
- marker_ids = (int *)CALLOC(markers,sizeof(int));
- marker_positions = (int *)CALLOC(markers,sizeof(int));
- }
- moff = 10;
- for (m=0;m<num_marks;m++)
- {
- msize = read_aiff_marker(m,moff,(unsigned char *)hdrbuf);
- moff += msize;
- }
- }
- }
- }
- }
- }
- }
- chunkloc = (8+chunksize);
- if (chunksize&1) chunkloc++; /* extra null appended to odd-length chunks */
- if ((offset+chunkloc) >= update_form_size) happy=0;
- }
- if (true_file_length < data_size) data_size = true_file_length - data_location;
- data_size = c_snd_samples(sound_format,data_size);
- }
- static void write_aiff_header (int chan, int srate, int chans, int siz, int format, char *comment, int len)
- {
- /* we write the simplest possible AIFF header: AIFF | COMM | APPL-CLM_ if needed | SSND eof. */
- /* the assumption being that we're going to be appending sound data once the header is out */
- /* INST and MARK chunks added Jul-95 for various programs that expect them (MixView). */
- int i,j,lenhdr,curend,extra,aifc;
- char *str;
- lenhdr=0;
- extra=0;
- curend=0;
- if ((format == snd_8_mulaw) || (format == snd_8_alaw)) aifc=1; else aifc=0;
- if (len != 0)
- {
- lenhdr = 12;
- if ((len % 4) != 0)
- extra = (4 - (len % 4));
- }
- write_four_chars((unsigned char *)hdrbuf,I_FORM);
- if (aifc==1) (*(int *)(hdrbuf+4)) = big_endian_int(len+30+16+38+siz+lenhdr+extra+12+10);
- else (*(int *)(hdrbuf+4)) = big_endian_int(len+30+16+38+siz+lenhdr+extra);
- /*
- * comment length + 4 for AIFF 18+8 for I_COMM info + 16 for I_SSND info + 38 for INST and MARK +
- * siz for data + 12 for comment header if any + padding == total size - 8 (i.e. FORM header).
- * INST+MARK (38) added 3-Jul-95 for Notam software compatibility
- *
- * if necessary, AIFC is used instead with the FVER and compression-name info: 12 for FVER, 10 for xLAW+size+xLAW+nul
- */
- if (aifc==1)
- {
- write_four_chars((unsigned char *)(hdrbuf+8),I_AIFC);
- write(chan,hdrbuf,12);
- curend=12;
- write_four_chars((unsigned char *)hdrbuf,I_FVER);
- (*(int *)(hdrbuf+4)) = big_endian_int(4);
- (*(int *)(hdrbuf+8)) = big_endian_int(0xA2805140);
- }
- else write_four_chars((unsigned char *)(hdrbuf+8),I_AIFF);
- write_four_chars((unsigned char *)(hdrbuf+12),I_COMM);
- if (aifc==1) (*(int *)(hdrbuf+16)) = big_endian_int(18+10); else (*(int *)(hdrbuf+16)) = big_endian_int(18);
- (*(short *)(hdrbuf+20)) = big_endian_short((short)chans);
- (*(int *)(hdrbuf+22)) = big_endian_int((int)(siz / (chans*c_snd_datum_size(format))));
- switch (format)
- {
- case snd_16_linear: (*(short *)(hdrbuf+26)) = big_endian_short(16); break;
- case snd_24_linear: (*(short *)(hdrbuf+26)) = big_endian_short(24); break;
- case snd_32_linear: (*(short *)(hdrbuf+26)) = big_endian_short(32); break;
- case snd_8_linear: (*(short *)(hdrbuf+26)) = big_endian_short(8); break;
- case snd_8_mulaw: (*(short *)(hdrbuf+26)) = big_endian_short(8); break;
- case snd_8_alaw: (*(short *)(hdrbuf+26)) = big_endian_short(8); break;
- default:
- str=(char *)CALLOC(256,sizeof(char));
- sprintf(str,"CLM/AIFF unsupported sound data format type: %d\n",format);
- clm_printf(str);
- FREE(str);
- break;
- }
- double_to_ieee_80((double)srate,(unsigned char *)(hdrbuf+28));
- if (aifc==1)
- {
- if (format == snd_8_mulaw)
- write_four_chars((unsigned char *)(hdrbuf+38),I_ULAW);
- else write_four_chars((unsigned char *)(hdrbuf+38),I_ALAW);
- (*(unsigned char *)(hdrbuf+42)) = 4; /* final pad null not accounted-for */
- if (format == snd_8_mulaw)
- write_four_chars((unsigned char *)(hdrbuf+43),I_ULAW);
- else write_four_chars((unsigned char *)(hdrbuf+43),I_ALAW);
- (*(unsigned char *)(hdrbuf+47)) = 0;
- i=48;
- }
- else i = 38;
- if (len != 0)
- {
- if (aifc==1)
- {
- /* this dumb looking code made necessary by SGI C compiler's stupidity */
- write_four_chars((unsigned char *)(hdrbuf+48),I_APPL);
- (*(int *)(hdrbuf+52)) = big_endian_int(len+4+extra);
- write_four_chars((unsigned char *)(hdrbuf+56),I_CLM_);
- i = 60;
- }
- else
- {
- write_four_chars((unsigned char *)(hdrbuf+38),I_APPL);
- (*(int *)(hdrbuf+42)) = big_endian_int(len+4+extra);
- write_four_chars((unsigned char *)(hdrbuf+46),I_CLM_);
- i = 50;
- }
- for (j=0;j<len;j++)
- {
- if (i == HDRBUFSIZ)
- {
- curend += HDRBUFSIZ;
- write(chan,hdrbuf,HDRBUFSIZ);
- i=0;
- }
- hdrbuf[i]=comment[j];
- i++;
- }
- if (extra != 0)
- {
- if ((i+extra) > HDRBUFSIZ)
- {
- curend += i;
- write(chan,hdrbuf,i);
- i=0;
- }
- for (j=0;j<extra;j++)
- {
- hdrbuf[i] = 0;
- i++;
- }
- }
- }
- curend += i;
- write(chan,hdrbuf,i);
- write_four_chars((unsigned char *)hdrbuf,I_MARK); /* SoundHack includes a blank MARK chunk for some reason */
- (*(int *)(hdrbuf+4)) = big_endian_int(2);
- (*(short *)(hdrbuf+8)) = 0;
- write_four_chars((unsigned char *)(hdrbuf+10),I_INST);
- (*(int *)(hdrbuf+14)) = big_endian_int(20);
- (*(int *)(hdrbuf+18)) = big_endian_int(0x3c00007f); /* base-note=middle C, detune=0, lownote=0, highnote=0x7f */
- (*(int *)(hdrbuf+22)) = big_endian_int(0x017f0000); /* lowvelocity=1, highvelocity=0x7f, gain=0 */
- (*(int *)(hdrbuf+26)) = 0; /* no loops */
- (*(int *)(hdrbuf+30)) = 0;
- (*(int *)(hdrbuf+34)) = 0;
- write_four_chars((unsigned char *)(hdrbuf+38),I_SSND);
- (*(int *)(hdrbuf+38+4)) = big_endian_int(siz+8);
- (*(int *)(hdrbuf+38+8)) = 0; /* "offset" */
- (*(int *)(hdrbuf+38+12)) = 0; /* "blocksize " */
- data_location = 38+16+curend;
- write(chan,hdrbuf,38+16);
- }
- static void update_aiff_header (int chan, int siz)
- {
- /* we apparently have to make sure the form size and the data size are correct
- * assumed here that we'll only be updating our own AIFF files
- * There are 3 such locations -- the 2nd word of the file which is the overall form size,
- * the frames variable in the COMM chunk, and the chunk-size variable in the SSND chunk
- * an unexpected hassle for CLM is that we can open/close the output file many times if running mix,
- * so we have to update the various size fields taking into account the old size
- */
- read(chan,hdrbuf,INITIAL_READ_SIZE);
- read_aiff_header(chan,0);
- lseek(chan,4L,0);
- (*(int *)hdrbuf) = big_endian_int(siz+update_form_size-c_snd_bytes(sound_format,data_size));
- /* cancel old data_size from previous possible write */
- write(chan,hdrbuf,4);
- lseek(chan,update_frames_location,0);
- (*(int *)hdrbuf) = big_endian_int(siz/(chans*c_snd_datum_size(sound_format)));
- write(chan,hdrbuf,4);
- lseek(chan,update_ssnd_location,0);
- (*(int *)hdrbuf) = big_endian_int(siz+8);
- write(chan,hdrbuf,4);
- }
- static void update_aiff_header_comment (int chan, char *comment, int len)
- {
- /* save-stats in CLM appends a comment after the sound data has been written */
- int i,j,true_len,old_len;
- if (len&1) true_len = len+1; else true_len=len;
- lseek(chan,0L,2);
- write_four_chars((unsigned char *)hdrbuf,I_ANNO);
- (*(int *)(hdrbuf+4)) = big_endian_int(len);
- for (i=0,j=8;i<len;i++,j++) hdrbuf[j]=comment[i];
- write(chan,hdrbuf,8+true_len);
- lseek(chan,4L,0);
- read(chan,hdrbuf,4);
- old_len = big_endian_int(*((int *)hdrbuf));
- (*(int *)hdrbuf) = big_endian_int(old_len+true_len+8);
- lseek(chan,4L,0);
- write(chan,hdrbuf,4);
- }
- /* ------------------------------------ RIFF (wave) ------------------------------------
- *
- * see ftp.microsoft.com:/SoftLib/MSLFILES/MDRK.EXE (also MMSYSTEM.H and MMREG.H)
- *
- * 0: "RIFF" (little-endian) or "RIFX" (big-endian)
- * 4: size
- * 8: "WAVE" ("RMID" = midi data, others are AVI, CPPO, ACON etc)
- * AVI chunk can include audio data
- *
- * rest very similar to AIFF (odd-sized chunks are padded)
- *
- * fmt 0: format code (see below)
- * 2: chans
- * 4: srate (long)
- * 8: average rate "for buffer estimation"
- * 12: alignment "block size"
- * 14: data size (bits per sample) (PCM only)
- * 16: count (bytes) of extra info in the header (i.e. trailing info added to this basic header)
- * 20: samples per block (short) in dvi_adpcm
- *
- * formats are: 0: unknown, 1: PCM, 2: ADPCM, 3: IEEE float, 4: VSELP, 5: IBM_CVSD, 6: alaw, 7: mulaw
- * 0x10: OKI_ADPCM, 0x11: DVI_ADPCM, 0x12: MediaSpace_ADPCM,
- * 0x13: Sierra_ADPCM, 0x14: G723_ADPCM, 0x15: DIGISTD, 0x16: DIGIFIX, 0x17: Dialogic ADPCM,
- * 0x18: Mediavision ADPCM, 0x19: HP cu codec,
- * 0x20: Yamaha_ADPCM, 0x21: SONARC, 0x22: DSPGroup_TrueSpeech
- * 0x23: EchoSC1, 0x24: AudioFile_AF36, 0x25: APTX, 0x26: AudioFile_AF10
- * 0x27: prosody 1612, 0x28: lrc,
- * 0x30: Dolby_Ac2, 0x31: GSM610, 0x32: MSN audio codec, 0x33: Antext_ADPCM, 0x34: Control_res_vqlpc,
- * 0x35: DIGIREAL, 0x36: DIGIADPCM, 0x37: Control_res_cr10, 0x38: NMS_VBXADPCM, 0x39:Roland rdac,
- * 0x3a: echo sc3, 0x3b: Rockwell adpcm, 0x3c: Rockwell digitalk codec, 0x3d: Xebec,
- * 0x40: G721_ADPCM, 0x41: G728 CELP, 0x42: MS G723, 0x50: MPEG,
- * 0x52: RT24, 0x53: PAC, 0x55: Mpeg layer 3, 0x59: Lucent G723, 0x60: Cirrus,
- * 0x61: ESS Tech pcm, 0x62: voxware (obsolete), 0x63: canopus atrac,
- * 0x64: G726, 0x65: G722, 0x66: DSAT, 0x67: DSAT display,
- * 0x69: voxware (obsolete), 0x70: voxware ac8 (obsolete), 0x71: voxware ac10 (obsolete),
- * 0x72: voxware ac16 (obsolete), 0x73: voxware ac20 (obsolete), 0x74: voxware rt24,
- * 0x75: voxware rt29, 0x76: voxware rt29hw (obsolete), 0x77: voxware vr12 (obsolete),
- * 0x78: voxware vr18 (obsolete), 0x79: voxware tq40 (obsolete),
- * 0x80: softsound, 0x81: voxware tq60 (obsolete), 0x82: MS RT24, 0x83: G729A,
- * 0x84: MVI_MVI2, 0x85: DF G726, 0x86: DF GSM610, 0x88: isaudio, 0x89: onlive,
- * 0x91: sbc24, 0x92: dolby ac3 spdif, 0x97: zyxel adpcm, 0x98: philips lpcbb,
- * 0x99: packed, 0x100: rhetorex adpcm,
- * 0x101: Irat, 0x102: IBM_alaw?, 0x103: IBM_ADPCM?,
- * 0x111: vivo G723, 0x112: vivo siren, 0x123: digital g273
- * 0x200: Creative_ADPCM, 0x202: Creative fastspeech 8, 0x203: Creative fastspeech 10,
- * 0x220: quarterdeck, 0x300: FM_TOWNS_SND, 0x400: BTV digital, 0x680: VME vmpcm,
- * 0x1000: OLIGSM, 0x1001: OLIADPCM, 0x1002: OLICELP, 0x1003: OLISBC, 0x1004: OLIOPR
- * 0x1100: LH codec, 0x1400: Norris, 0x1401: isaudio, 0x1500: Soundspace musicompression, 0x2000: DVM
- * (see http://www.microsoft.com/asf/resources/draft-ietf-fleischman-codec-subtree-00.txt)
- *
- * RIFF and LIST chunks have nested chunks. Registered chunk names include:
- * LIST with subchunks, one of which can be:
- * INFO itself containing:
- * IARL: archival location, IART: artist, ICMS: commissioned, ICMT: comment, ICOP: copyright, ICRD: creation date,
- * ICRP: uh...cropped, IDIM: dimensions, IDPI: dpi, IENG: engineer, IGNR: genre, IKEY: keywords, ILGT: lightness,
- * IMED: medium, INAM: name, IPLT: palette, IPRD: product, ISBJ: subject, ISFT: software, ISHP: sharpness,
- * ISRC: source, ISRF: source form, ITCH: technician, ISMP: SMPTE time code, IDIT: digitization time
- *
- * data chunk has the samples
- * other (currently ignored) chunks are wavl = waveform data, fact, cues of some sort, slnt = silence,
- * plst = playlist, adtl = associated data list, labl = cue label, note = cue comments,
- * ltxt = text associated with data segment (cue), file, DISP = displayable object,
- * JUNK = outdated info, PAD = padding, etc
- * fact chunk generally has number of samples (used in compressed files)
- */
- static void read_riff_header (int chan)
- {
- /* we know we have checked for RIFF xxxx WAVE when we arrive here */
- int chunksize,offset,chunkloc,happy,little;
- little = 1;
- if (match_four_chars((unsigned char *)hdrbuf,I_RIFX)) little=0; /* big-endian data in this case, but I've never seen one */
- type_specifier = (*((int *)(hdrbuf+8)));
- chunkloc = 12;
- offset = 0;
- comment_start = 0;
- comment_end = 0;
- header_distributed = 1;
- sound_format = snd_unsupported;
- srate = 0;
- chans = 0;
- happy = 1;
- data_size = 0;
- fact_samples = 0;
- bits_per_sample = 0;
- true_file_length = lseek(chan,0L,2);
- update_form_size = big_or_little_endian_int((*(int *)(hdrbuf+4)),little);
- while (happy)
- {
- offset += chunkloc;
- if (seek_and_read(chan,(unsigned char *)hdrbuf,offset,32) <= 0)
- {
- clm_printf("error reading header");
- return;
- }
- chunksize = big_or_little_endian_int((*(int *)(hdrbuf+4)),little);
- if (match_four_chars((unsigned char *)hdrbuf,I_fmt_))
- {
- /*
- * 8: short format code --1=PCM for example
- * 10: short chans --1
- * 12: long rate --48000 (0xbb80)
- * 16: long ave rate --65655 (0x10077)
- * 20: short align --2
- * 22: short data size (bits) --16
- * 24: bytes of extra
- * ... some extra data dependent on format
- *
- * R I F F # # # # W A V E f m t sp
- * 5249 4646 f851 0500 5741 5645 666d 7420
- * e40f 0000 0100 0100 80bb 0000 0077 0100
- * 0200 1000 0000 0000 0000 0000 0000 0000
- *
- * #x000551f8 = 348664 = size in bytes - 8
- * #x00000fe4 = 4068 [fmt_ chunk size?]
- */
- original_sound_format = big_or_little_endian_short(((*(short *)(hdrbuf+8))),little);
- chans = big_or_little_endian_short((*(short *)(hdrbuf+10)),little);
- srate = big_or_little_endian_int((*(int *)(hdrbuf+12)),little);
- block_align = big_or_little_endian_short((*(short *)(hdrbuf+20)),little);
- bits_per_sample = big_or_little_endian_short((*(short *)(hdrbuf+22)),little);
- if (bits_per_sample == 16)
- {
- if (little) sound_format = snd_16_linear_little_endian; else sound_format = snd_16_linear;
- }
- else
- if ((original_sound_format == 6) && (bits_per_sample == 8)) sound_format = snd_8_alaw; else
- if ((original_sound_format == 7) && (bits_per_sample == 8)) sound_format = snd_8_mulaw; else
- if (original_sound_format == 1)
- {
- if (bits_per_sample == 8) sound_format = snd_8_unsigned; else
- if (bits_per_sample == 32)
- {
- if (little) sound_format = snd_32_linear_little_endian; else sound_format = snd_32_linear;
- }
- }
- else
- /* IBM mulaw follows G711 specs like other versions (this info direct from IBM) */
- if (original_sound_format == 0x102) sound_format = snd_8_alaw; else
- if (original_sound_format == 0x101) sound_format = snd_8_mulaw;
- }
- else
- {
- if (match_four_chars((unsigned char *)hdrbuf,I_data))
- {
- update_ssnd_location = offset+4;
- data_location = offset + 8;
- data_size = big_or_little_endian_int((*(int *)…
Large files files are truncated, but you can click here to view the full file