📄 aiff.c
字号:
/*** Copyright (C) 1999-2004 Erik de Castro Lopo <erikd@mega-nerd.com>**** This program is free software; you can redistribute it and/or modify** it under the terms of the GNU Lesser General Public License as published by** the Free Software Foundation; either version 2.1 of the License, or** (at your option) any later version.**** This program is distributed in the hope that it will be useful,** but WITHOUT ANY WARRANTY; without even the implied warranty of** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the** GNU Lesser General Public License for more details.**** You should have received a copy of the GNU Lesser General Public License** along with this program; if not, write to the Free Software** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*/#include "config.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <ctype.h>#include "sndfile.h"#include "sfendian.h"#include "common.h"/*------------------------------------------------------------------------------ * Macros to handle big/little endian issues. */#define FORM_MARKER (MAKE_MARKER ('F', 'O', 'R', 'M'))#define AIFF_MARKER (MAKE_MARKER ('A', 'I', 'F', 'F'))#define AIFC_MARKER (MAKE_MARKER ('A', 'I', 'F', 'C'))#define COMM_MARKER (MAKE_MARKER ('C', 'O', 'M', 'M'))#define SSND_MARKER (MAKE_MARKER ('S', 'S', 'N', 'D'))#define MARK_MARKER (MAKE_MARKER ('M', 'A', 'R', 'K'))#define INST_MARKER (MAKE_MARKER ('I', 'N', 'S', 'T'))#define APPL_MARKER (MAKE_MARKER ('A', 'P', 'P', 'L'))#define c_MARKER (MAKE_MARKER ('(', 'c', ')', ' '))#define NAME_MARKER (MAKE_MARKER ('N', 'A', 'M', 'E'))#define AUTH_MARKER (MAKE_MARKER ('A', 'U', 'T', 'H'))#define ANNO_MARKER (MAKE_MARKER ('A', 'N', 'N', 'O'))#define COMT_MARKER (MAKE_MARKER ('C', 'O', 'M', 'T'))#define FVER_MARKER (MAKE_MARKER ('F', 'V', 'E', 'R'))#define SFX_MARKER (MAKE_MARKER ('S', 'F', 'X', '!'))#define PEAK_MARKER (MAKE_MARKER ('P', 'E', 'A', 'K'))#define basc_MARKER (MAKE_MARKER ('b', 'a', 's', 'c'))/* Supported AIFC encodings.*/#define NONE_MARKER (MAKE_MARKER ('N', 'O', 'N', 'E'))#define sowt_MARKER (MAKE_MARKER ('s', 'o', 'w', 't'))#define twos_MARKER (MAKE_MARKER ('t', 'w', 'o', 's'))#define raw_MARKER (MAKE_MARKER ('r', 'a', 'w', ' '))#define in32_MARKER (MAKE_MARKER ('i', 'n', '3', '2'))#define ni32_MARKER (MAKE_MARKER ('2', '3', 'n', 'i'))#define fl32_MARKER (MAKE_MARKER ('f', 'l', '3', '2'))#define FL32_MARKER (MAKE_MARKER ('F', 'L', '3', '2'))#define fl64_MARKER (MAKE_MARKER ('f', 'l', '6', '4'))#define FL64_MARKER (MAKE_MARKER ('F', 'L', '6', '4'))#define ulaw_MARKER (MAKE_MARKER ('u', 'l', 'a', 'w'))#define ULAW_MARKER (MAKE_MARKER ('U', 'L', 'A', 'W'))#define alaw_MARKER (MAKE_MARKER ('a', 'l', 'a', 'w'))#define ALAW_MARKER (MAKE_MARKER ('A', 'L', 'A', 'W'))#define DWVW_MARKER (MAKE_MARKER ('D', 'W', 'V', 'W'))#define GSM_MARKER (MAKE_MARKER ('G', 'S', 'M', ' '))#define ima4_MARKER (MAKE_MARKER ('i', 'm', 'a', '4'))/* Unsupported AIFC encodings.*/#define MAC3_MARKER (MAKE_MARKER ('M', 'A', 'C', '3'))#define MAC6_MARKER (MAKE_MARKER ('M', 'A', 'C', '6'))#define ADP4_MARKER (MAKE_MARKER ('A', 'D', 'P', '4'))/* Predfined chunk sizes. */#define SIZEOF_AIFF_COMM 18#define SIZEOF_AIFC_COMM_MIN 22#define SIZEOF_AIFC_COMM 24#define SIZEOF_SSND_CHUNK 8#define SIZEOF_INST_CHUNK 20/* Is it constant? */#define SIZEOF_basc_CHUNK 0x54#define SIZEOF_basc_CHUNK_PADDING 66/* AIFC/IMA4 defines. */#define AIFC_IMA4_BLOCK_LEN 34#define AIFC_IMA4_SAMPLES_PER_BLOCK 64/*------------------------------------------------------------------------------ * Typedefs for file chunks. */enum{ HAVE_FORM = 0x01, HAVE_AIFF = 0x02, HAVE_COMM = 0x04, HAVE_SSND = 0x08} ;typedef struct{ unsigned int size ; short numChannels ; unsigned int numSampleFrames ; short sampleSize ; unsigned char sampleRate [10] ; unsigned int encoding ; char zero_bytes [2] ;} COMM_CHUNK ;typedef struct{ unsigned int offset ; unsigned int blocksize ;} SSND_CHUNK ;typedef struct{ short playMode ; unsigned short beginLoop ; unsigned short endLoop ;} INST_LOOP ;typedef struct{ char baseNote ; /* all notes are MIDI note numbers */ char detune ; /* cents off, only -50 to +50 are significant */ char lowNote ; char highNote ; char lowVelocity ; /* 1 to 127 */ char highVelocity ; /* 1 to 127 */ short gain ; /* in dB, 0 is normal */ INST_LOOP sustain_loop ; INST_LOOP release_loop ;} INST_CHUNK ;enum{ basc_SCALE_MINOR = 1, basc_SCALE_MAJOR, basc_SCALE_NEITHER, basc_SCALE_BOTH,} ;enum{ basc_TYPE_LOOP = 0, basc_TYPE_ONE_SHOT,} ;typedef struct{ unsigned int version ; unsigned int numBeats ; unsigned short rootNote ; unsigned short scaleType ; unsigned short sigNumerator ; unsigned short sigDenominator ; unsigned short loopType ; char zero_bytes [SIZEOF_basc_CHUNK_PADDING] ;} basc_CHUNK ;/*------------------------------------------------------------------------------ * Private static functions. */static int aiff_close (SF_PRIVATE *psf) ;static int tenbytefloat2int (unsigned char *bytes) ;static void uint2tenbytefloat (unsigned int num, unsigned char *bytes) ;static int aiff_read_comm_chunk (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt) ;static int aiff_read_header (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt) ;static int aiff_write_header (SF_PRIVATE *psf, int calc_length) ;static int aiff_write_tailer (SF_PRIVATE *psf) ;static void aiff_write_strings (SF_PRIVATE *psf, int location) ;static int aiff_command (SF_PRIVATE *psf, int command, void *data, int datasize) ;static const char *get_loop_mode_str (short mode) ;static int aiff_read_basc_chunk (SF_PRIVATE * psf) ;/*------------------------------------------------------------------------------** Public function.*/intaiff_open (SF_PRIVATE *psf){ COMM_CHUNK comm_fmt ; int error, subformat ; subformat = psf->sf.format & SF_FORMAT_SUBMASK ; if (psf->mode == SFM_READ || (psf->mode == SFM_RDWR && psf->filelength > 0)) { if ((error = aiff_read_header (psf, &comm_fmt))) return error ; psf_fseek (psf, psf->dataoffset, SEEK_SET) ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { if (psf->is_pipe) return SFE_NO_PIPE_WRITE ; if ((psf->sf.format & SF_FORMAT_TYPEMASK) != SF_FORMAT_AIFF) return SFE_BAD_OPEN_FORMAT ; if (psf->mode == SFM_WRITE && (subformat == SF_FORMAT_FLOAT || subformat == SF_FORMAT_DOUBLE)) { psf->pchunk = calloc (1, sizeof (PEAK_CHUNK) * psf->sf.channels * sizeof (PEAK_POS)) ; if (psf->pchunk == NULL) return SFE_MALLOC_FAILED ; psf->has_peak = SF_TRUE ; psf->peak_loc = SF_PEAK_START ; } ; if (psf->mode != SFM_RDWR || psf->filelength < 40) { psf->filelength = 0 ; psf->datalength = 0 ; psf->dataoffset = 0 ; psf->sf.frames = 0 ; } ; psf->str_flags = SF_STR_ALLOW_START | SF_STR_ALLOW_END ; if ((error = aiff_write_header (psf, SF_FALSE))) return error ; psf->write_header = aiff_write_header ; } ; psf->close = aiff_close ; psf->command = aiff_command ; psf->blockwidth = psf->sf.channels * psf->bytewidth ; switch (psf->sf.format & SF_FORMAT_SUBMASK) { case SF_FORMAT_PCM_U8 : error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_S8 : error = pcm_init (psf) ; break ; case SF_FORMAT_PCM_16 : case SF_FORMAT_PCM_24 : case SF_FORMAT_PCM_32 : error = pcm_init (psf) ; break ; case SF_FORMAT_ULAW : error = ulaw_init (psf) ; break ; case SF_FORMAT_ALAW : error = alaw_init (psf) ; break ; /* Lite remove start */ case SF_FORMAT_FLOAT : error = float32_init (psf) ; break ; case SF_FORMAT_DOUBLE : error = double64_init (psf) ; break ; case SF_FORMAT_DWVW_12 : error = dwvw_init (psf, 12) ; break ; case SF_FORMAT_DWVW_16 : error = dwvw_init (psf, 16) ; break ; case SF_FORMAT_DWVW_24 : error = dwvw_init (psf, 24) ; break ; case SF_FORMAT_DWVW_N : if (psf->mode != SFM_READ) { error = SFE_DWVW_BAD_BITWIDTH ; break ; } ; if (comm_fmt.sampleSize >= 8 && comm_fmt.sampleSize < 24) { error = dwvw_init (psf, comm_fmt.sampleSize) ; psf->sf.frames = comm_fmt.numSampleFrames ; break ; } ; psf_log_printf (psf, "AIFC/DWVW : Bad bitwidth %d\n", comm_fmt.sampleSize) ; error = SFE_DWVW_BAD_BITWIDTH ; break ; case SF_FORMAT_IMA_ADPCM : /* ** IMA ADPCM encoded AIFF files always have a block length ** of 34 which decodes to 64 samples. */ error = aiff_ima_init (psf, AIFC_IMA4_BLOCK_LEN, AIFC_IMA4_SAMPLES_PER_BLOCK) ; break ; /* Lite remove end */ case SF_FORMAT_GSM610 : error = gsm610_init (psf) ; break ; default : return SFE_UNIMPLEMENTED ; } ; if (psf->mode == SFM_READ) psf->blockwidth = psf->sf.channels * psf->bytewidth ; return error ;} /* aiff_open *//*==========================================================================================** Private functions.*/static intaiff_read_header (SF_PRIVATE *psf, COMM_CHUNK *comm_fmt){ SSND_CHUNK ssnd_fmt ; int marker, dword, bytesread, k ; int FORMsize, SSNDsize ; int filetype, found_chunk = 0, done = 0, error = 0 ; char *cptr, byte ; /* Set position to start of file to begin reading header. */ psf_binheader_readf (psf, "p", 0) ; memset (comm_fmt, 0, sizeof (COMM_CHUNK)) ; /* Until recently AIF* file were all BIG endian. */ psf->endian = SF_ENDIAN_BIG ; /* AIFF files can apparently have their chunks in any order. However, they ** must have a FORM chunk. Approach here is to read all the chunks one by ** one and then check for the mandatory chunks at the end. */ while (! done) { psf_binheader_readf (psf, "m", &marker) ; if (psf->mode == SFM_RDWR && (found_chunk & HAVE_SSND)) return SFE_AIFF_RW_SSND_NOT_LAST ; switch (marker) { case FORM_MARKER : if (found_chunk) return SFE_AIFF_NO_FORM ; psf_binheader_readf (psf, "E4", &FORMsize) ; if (psf->fileoffset > 0 && psf->filelength > FORMsize + 8) { /* Set file length. */ psf->filelength = FORMsize + 8 ; psf_log_printf (psf, "FORM : %u\n", FORMsize) ; } else if (FORMsize != psf->filelength - 2 * SIGNED_SIZEOF (dword)) { dword = psf->filelength - 2 * sizeof (dword) ; psf_log_printf (psf, "FORM : %u (should be %u)\n", FORMsize, dword) ; FORMsize = dword ; } else psf_log_printf (psf, "FORM : %u\n", FORMsize) ; found_chunk |= HAVE_FORM ; break ; case AIFC_MARKER : case AIFF_MARKER : if (! (found_chunk & HAVE_FORM)) return SFE_AIFF_AIFF_NO_FORM ; filetype = marker ; psf_log_printf (psf, " %M\n", marker) ; found_chunk |= HAVE_AIFF ; break ; case COMM_MARKER : error = aiff_read_comm_chunk (psf, comm_fmt) ; psf->sf.samplerate = tenbytefloat2int (comm_fmt->sampleRate) ; psf->sf.frames = comm_fmt->numSampleFrames ; psf->sf.channels = comm_fmt->numChannels ; psf->bytewidth = BITWIDTH2BYTES (comm_fmt->sampleSize) ; if (error) return error ; found_chunk |= HAVE_COMM ; break ; case PEAK_MARKER : /* Must have COMM chunk before PEAK chunk. */ if ((found_chunk & (HAVE_FORM | HAVE_AIFF | HAVE_COMM)) != (HAVE_FORM | HAVE_AIFF | HAVE_COMM)) return SFE_AIFF_PEAK_B4_COMM ; psf_binheader_readf (psf, "E4", &dword) ; psf_log_printf (psf, "%M : %d\n", marker, dword) ; if (dword != SIGNED_SIZEOF (PEAK_CHUNK) + psf->sf.channels * SIGNED_SIZEOF (PEAK_POS)) { psf_binheader_readf (psf, "j", dword) ; psf_log_printf (psf, "*** File PEAK chunk bigger than sizeof (PEAK_CHUNK).\n") ; return SFE_WAV_BAD_PEAK ; } ; psf->pchunk = calloc (1, sizeof (PEAK_CHUNK) * psf->sf.channels * sizeof (PEAK_POS)) ; if (psf->pchunk == NULL) return SFE_MALLOC_FAILED ; /* read in rest of PEAK chunk. */ psf_binheader_readf (psf, "E44", &(psf->pchunk->version), &(psf->pchunk->timestamp)) ; if (psf->pchunk->version != 1) psf_log_printf (psf, " version : %d *** (should be version 1)\n", psf->pchunk->version) ; else psf_log_printf (psf, " version : %d\n", psf->pchunk->version) ; psf_log_printf (psf, " time stamp : %d\n", psf->pchunk->timestamp) ; psf_log_printf (psf, " Ch Position Value\n") ; cptr = psf->u.scbuf ; for (dword = 0 ; dword < psf->sf.channels ; dword++) { psf_binheader_readf (psf, "Ef4", &(psf->pchunk->peaks [dword].value), &(psf->pchunk->peaks [dword].position)) ; LSF_SNPRINTF (cptr, sizeof (psf->u.scbuf), " %2d %-12d %g\n", dword, psf->pchunk->peaks [dword].position, psf->pchunk->peaks [dword].value) ; cptr [sizeof (psf->u.scbuf) - 1] = 0 ; psf_log_printf (psf, cptr) ; } ; psf->has_peak = SF_TRUE ; /* Found PEAK chunk. */ break ; case SSND_MARKER : psf_binheader_readf (psf, "E444", &SSNDsize, &(ssnd_fmt.offset), &(ssnd_fmt.blocksize)) ; psf->datalength = SSNDsize - sizeof (ssnd_fmt) ; psf->dataoffset = psf_ftell (psf) ; if (psf->datalength > psf->filelength - psf->dataoffset || psf->datalength < 0) { psf_log_printf (psf, " SSND : %u (should be %D)\n", SSNDsize, psf->filelength - psf->dataoffset + sizeof (SSND_CHUNK)) ; psf->datalength = psf->filelength - psf->dataoffset ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -