load_aiff.c
changeset 617 87116a42526e
parent 601 05123263dab3
child 621 944412baab72
equal deleted inserted replaced
616:7ead8213dfb0 617:87116a42526e
    38 #include "load_aiff.h"
    38 #include "load_aiff.h"
    39 
    39 
    40 /*********************************************/
    40 /*********************************************/
    41 /* Define values for AIFF (IFF audio) format */
    41 /* Define values for AIFF (IFF audio) format */
    42 /*********************************************/
    42 /*********************************************/
    43 #define FORM		0x4d524f46		/* "FORM" */
    43 #define FORM        0x4d524f46      /* "FORM" */
    44 
    44 
    45 #define AIFF		0x46464941		/* "AIFF" */
    45 #define AIFF        0x46464941      /* "AIFF" */
    46 #define SSND		0x444e5353		/* "SSND" */
    46 #define SSND        0x444e5353      /* "SSND" */
    47 #define COMM		0x4d4d4f43		/* "COMM" */
    47 #define COMM        0x4d4d4f43      /* "COMM" */
    48 
    48 
    49 #define _8SVX		0x58565338		/* "8SVX" */
    49 #define _8SVX       0x58565338      /* "8SVX" */
    50 #define VHDR		0x52444856		/* "VHDR" */
    50 #define VHDR        0x52444856      /* "VHDR" */
    51 #define BODY		0x59444F42		/* "BODY" */
    51 #define BODY        0x59444F42      /* "BODY" */
    52 
    52 
    53 /* This function was taken from libsndfile. I don't pretend to fully
    53 /* This function was taken from libsndfile. I don't pretend to fully
    54  * understand it.
    54  * understand it.
    55  */
    55  */
    56 
    56 
    57 static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
    57 static Uint32 SANE_to_Uint32 (Uint8 *sanebuf)
    58 {
    58 {
    59 	/* Is the frequency outside of what we can represent with Uint32? */
    59     /* Is the frequency outside of what we can represent with Uint32? */
    60 	if ( (sanebuf[0] & 0x80) || (sanebuf[0] <= 0x3F) || (sanebuf[0] > 0x40)
    60     if ( (sanebuf[0] & 0x80) || (sanebuf[0] <= 0x3F) || (sanebuf[0] > 0x40)
    61 		|| (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) )
    61         || (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) )
    62 		return 0;
    62         return 0;
    63 
    63 
    64 	return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
    64     return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7)
    65 		| (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
    65         | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
    66 }
    66 }
    67 
    67 
    68 /* This function is based on SDL_LoadWAV_RW(). */
    68 /* This function is based on SDL_LoadWAV_RW(). */
    69 
    69 
    70 SDL_AudioSpec *Mix_LoadAIFF_RW (SDL_RWops *src, int freesrc,
    70 SDL_AudioSpec *Mix_LoadAIFF_RW (SDL_RWops *src, int freesrc,
    71 	SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
    71     SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
    72 {
    72 {
    73 	int was_error;
    73     int was_error;
    74 	int found_SSND;
    74     int found_SSND;
    75 	int found_COMM;
    75     int found_COMM;
    76 	int found_VHDR;
    76     int found_VHDR;
    77 	int found_BODY;
    77     int found_BODY;
    78 	long start = 0;
    78     long start = 0;
    79 
    79 
    80 	Uint32 chunk_type;
    80     Uint32 chunk_type;
    81 	Uint32 chunk_length;
    81     Uint32 chunk_length;
    82 	long next_chunk;
    82     long next_chunk;
    83 
    83 
    84 	/* AIFF magic header */
    84     /* AIFF magic header */
    85 	Uint32 FORMchunk;
    85     Uint32 FORMchunk;
    86 	Uint32 AIFFmagic;
    86     Uint32 AIFFmagic;
    87 
    87 
    88 	/* SSND chunk */
    88     /* SSND chunk */
    89 	Uint32 offset;
    89     Uint32 offset;
    90 	Uint32 blocksize;
    90     Uint32 blocksize;
    91 
    91 
    92 	/* COMM format chunk */
    92     /* COMM format chunk */
    93 	Uint16 channels = 0;
    93     Uint16 channels = 0;
    94 	Uint32 numsamples = 0;
    94     Uint32 numsamples = 0;
    95 	Uint16 samplesize = 0;
    95     Uint16 samplesize = 0;
    96 	Uint8 sane_freq[10];
    96     Uint8 sane_freq[10];
    97 	Uint32 frequency = 0;
    97     Uint32 frequency = 0;
    98 
    98 
    99 	/* Make sure we are passed a valid data source */
    99     /* Make sure we are passed a valid data source */
   100 	was_error = 0;
   100     was_error = 0;
   101 	if ( src == NULL ) {
   101     if ( src == NULL ) {
   102 		was_error = 1;
   102         was_error = 1;
   103 		goto done;
   103         goto done;
   104 	}
   104     }
   105 
   105 
   106 	FORMchunk	= SDL_ReadLE32(src);
   106     FORMchunk   = SDL_ReadLE32(src);
   107 	chunk_length	= SDL_ReadBE32(src);
   107     chunk_length    = SDL_ReadBE32(src);
   108 	if ( chunk_length == AIFF ) { /* The FORMchunk has already been read */
   108     if ( chunk_length == AIFF ) { /* The FORMchunk has already been read */
   109 		AIFFmagic    = chunk_length;
   109         AIFFmagic    = chunk_length;
   110 		chunk_length = FORMchunk;
   110         chunk_length = FORMchunk;
   111 		FORMchunk    = FORM;
   111         FORMchunk    = FORM;
   112 	} else {
   112     } else {
   113 		AIFFmagic    = SDL_ReadLE32(src);
   113         AIFFmagic    = SDL_ReadLE32(src);
   114 	}
   114     }
   115 	if ( (FORMchunk != FORM) || ( (AIFFmagic != AIFF) && (AIFFmagic != _8SVX) ) ) {
   115     if ( (FORMchunk != FORM) || ( (AIFFmagic != AIFF) && (AIFFmagic != _8SVX) ) ) {
   116 		SDL_SetError("Unrecognized file type (not AIFF nor 8SVX)");
   116         SDL_SetError("Unrecognized file type (not AIFF nor 8SVX)");
   117 		was_error = 1;
   117         was_error = 1;
   118 		goto done;
   118         goto done;
   119 	}
   119     }
   120 
   120 
   121 	/* TODO: Better santity-checking. */
   121     /* TODO: Better santity-checking. */
   122 
   122 
   123 	found_SSND = 0;
   123     found_SSND = 0;
   124 	found_COMM = 0;
   124     found_COMM = 0;
   125 	found_VHDR = 0;
   125     found_VHDR = 0;
   126 	found_BODY = 0;
   126     found_BODY = 0;
   127 
   127 
   128 	do {
   128     do {
   129 		chunk_type	= SDL_ReadLE32(src);
   129         chunk_type  = SDL_ReadLE32(src);
   130 		chunk_length	= SDL_ReadBE32(src);
   130         chunk_length    = SDL_ReadBE32(src);
   131 		next_chunk	= SDL_RWtell(src) + chunk_length;
   131         next_chunk  = SDL_RWtell(src) + chunk_length;
   132 		/* Paranoia to avoid infinite loops */
   132         /* Paranoia to avoid infinite loops */
   133 		if (chunk_length == 0)
   133         if (chunk_length == 0)
   134 			break;
   134             break;
   135 
   135 
   136 		switch (chunk_type) {
   136         switch (chunk_type) {
   137 			case SSND:
   137             case SSND:
   138 				found_SSND	= 1;
   138                 found_SSND  = 1;
   139 				offset		= SDL_ReadBE32(src);
   139                 offset      = SDL_ReadBE32(src);
   140 				blocksize	= SDL_ReadBE32(src);
   140                 blocksize   = SDL_ReadBE32(src);
   141 				start		= SDL_RWtell(src) + offset;
   141                 start       = SDL_RWtell(src) + offset;
   142 				break;
   142                 break;
   143 
   143 
   144 			case COMM:
   144             case COMM:
   145 				found_COMM	= 1;
   145                 found_COMM  = 1;
   146 				channels	= SDL_ReadBE16(src);
   146                 channels    = SDL_ReadBE16(src);
   147 				numsamples	= SDL_ReadBE32(src);
   147                 numsamples  = SDL_ReadBE32(src);
   148 				samplesize	= SDL_ReadBE16(src);
   148                 samplesize  = SDL_ReadBE16(src);
   149 				SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
   149                 SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
   150 				frequency	= SANE_to_Uint32(sane_freq);
   150                 frequency   = SANE_to_Uint32(sane_freq);
   151 				if (frequency == 0) {
   151                 if (frequency == 0) {
   152 					SDL_SetError("Bad AIFF sample frequency");
   152                     SDL_SetError("Bad AIFF sample frequency");
   153 					was_error = 1;
   153                     was_error = 1;
   154 					goto done;
   154                     goto done;
   155 				}
   155                 }
   156 				break;
   156                 break;
   157 
   157 
   158 			case VHDR:
   158             case VHDR:
   159 				found_VHDR	= 1;
   159                 found_VHDR  = 1;
   160 				SDL_ReadBE32(src);
   160                 SDL_ReadBE32(src);
   161 				SDL_ReadBE32(src);
   161                 SDL_ReadBE32(src);
   162 				SDL_ReadBE32(src);
   162                 SDL_ReadBE32(src);
   163 				frequency = SDL_ReadBE16(src);
   163                 frequency = SDL_ReadBE16(src);
   164 				channels = 1;
   164                 channels = 1;
   165 				samplesize = 8;
   165                 samplesize = 8;
   166 				break;
   166                 break;
   167 
   167 
   168 			case BODY:
   168             case BODY:
   169 				found_BODY	= 1;
   169                 found_BODY  = 1;
   170 				numsamples	= chunk_length;
   170                 numsamples  = chunk_length;
   171 				start		= SDL_RWtell(src);
   171                 start       = SDL_RWtell(src);
   172 				break;
   172                 break;
   173 
   173 
   174 			default:
   174             default:
   175 				break;
   175                 break;
   176 		}
   176         }
   177 		/* a 0 pad byte can be stored for any odd-length chunk */
   177         /* a 0 pad byte can be stored for any odd-length chunk */
   178 		if (chunk_length&1)
   178         if (chunk_length&1)
   179 			next_chunk++;
   179             next_chunk++;
   180 	} while ( ( ( (AIFFmagic == AIFF) && ( !found_SSND || !found_COMM ) )
   180     } while ( ( ( (AIFFmagic == AIFF) && ( !found_SSND || !found_COMM ) )
   181 		  || ( (AIFFmagic == _8SVX ) && ( !found_VHDR || !found_BODY ) ) )
   181           || ( (AIFFmagic == _8SVX ) && ( !found_VHDR || !found_BODY ) ) )
   182 		  && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != 1 );
   182           && SDL_RWseek(src, next_chunk, RW_SEEK_SET) != 1 );
   183 
   183 
   184 	if ( (AIFFmagic == AIFF) && !found_SSND ) {
   184     if ( (AIFFmagic == AIFF) && !found_SSND ) {
   185 		SDL_SetError("Bad AIFF (no SSND chunk)");
   185         SDL_SetError("Bad AIFF (no SSND chunk)");
   186 		was_error = 1;
   186         was_error = 1;
   187 		goto done;
   187         goto done;
   188 	}
   188     }
   189 
   189 
   190 	if ( (AIFFmagic == AIFF) && !found_COMM ) {
   190     if ( (AIFFmagic == AIFF) && !found_COMM ) {
   191 		SDL_SetError("Bad AIFF (no COMM chunk)");
   191         SDL_SetError("Bad AIFF (no COMM chunk)");
   192 		was_error = 1;
   192         was_error = 1;
   193 		goto done;
   193         goto done;
   194 	}
   194     }
   195 
   195 
   196 	if ( (AIFFmagic == _8SVX) && !found_VHDR ) {
   196     if ( (AIFFmagic == _8SVX) && !found_VHDR ) {
   197 		SDL_SetError("Bad 8SVX (no VHDR chunk)");
   197         SDL_SetError("Bad 8SVX (no VHDR chunk)");
   198 		was_error = 1;
   198         was_error = 1;
   199 		goto done;
   199         goto done;
   200 	}
   200     }
   201 
   201 
   202 	if ( (AIFFmagic == _8SVX) && !found_BODY ) {
   202     if ( (AIFFmagic == _8SVX) && !found_BODY ) {
   203 		SDL_SetError("Bad 8SVX (no BODY chunk)");
   203         SDL_SetError("Bad 8SVX (no BODY chunk)");
   204 		was_error = 1;
   204         was_error = 1;
   205 		goto done;
   205         goto done;
   206 	}
   206     }
   207 
   207 
   208 	/* Decode the audio data format */
   208     /* Decode the audio data format */
   209 	memset(spec, 0, sizeof(*spec));
   209     memset(spec, 0, sizeof(*spec));
   210 	spec->freq = frequency;
   210     spec->freq = frequency;
   211 	switch (samplesize) {
   211     switch (samplesize) {
   212 		case 8:
   212         case 8:
   213 			spec->format = AUDIO_S8;
   213             spec->format = AUDIO_S8;
   214 			break;
   214             break;
   215 		case 16:
   215         case 16:
   216 			spec->format = AUDIO_S16MSB;
   216             spec->format = AUDIO_S16MSB;
   217 			break;
   217             break;
   218 		default:
   218         default:
   219 			SDL_SetError("Unsupported AIFF samplesize");
   219             SDL_SetError("Unsupported AIFF samplesize");
   220 			was_error = 1;
   220             was_error = 1;
   221 			goto done;
   221             goto done;
   222 	}
   222     }
   223 	spec->channels = (Uint8) channels;
   223     spec->channels = (Uint8) channels;
   224 	spec->samples = 4096;		/* Good default buffer size */
   224     spec->samples = 4096;       /* Good default buffer size */
   225 
   225 
   226 	*audio_len = channels * numsamples * (samplesize / 8);
   226     *audio_len = channels * numsamples * (samplesize / 8);
   227 	*audio_buf = (Uint8 *)SDL_malloc(*audio_len);
   227     *audio_buf = (Uint8 *)SDL_malloc(*audio_len);
   228 	if ( *audio_buf == NULL ) {
   228     if ( *audio_buf == NULL ) {
   229 		SDL_SetError("Out of memory");
   229         SDL_SetError("Out of memory");
   230 		return(NULL);
   230         return(NULL);
   231 	}
   231     }
   232 	SDL_RWseek(src, start, RW_SEEK_SET);
   232     SDL_RWseek(src, start, RW_SEEK_SET);
   233 	if ( SDL_RWread(src, *audio_buf, *audio_len, 1) != 1 ) {
   233     if ( SDL_RWread(src, *audio_buf, *audio_len, 1) != 1 ) {
   234 		SDL_SetError("Unable to read audio data");
   234         SDL_SetError("Unable to read audio data");
   235 		return(NULL);
   235         return(NULL);
   236 	}
   236     }
   237 
   237 
   238 	/* Don't return a buffer that isn't a multiple of samplesize */
   238     /* Don't return a buffer that isn't a multiple of samplesize */
   239 	*audio_len &= ~((samplesize / 8) - 1);
   239     *audio_len &= ~((samplesize / 8) - 1);
   240 
   240 
   241 done:
   241 done:
   242 	if ( freesrc && src ) {
   242     if ( freesrc && src ) {
   243 		SDL_RWclose(src);
   243         SDL_RWclose(src);
   244 	}
   244     }
   245 	if ( was_error ) {
   245     if ( was_error ) {
   246 		spec = NULL;
   246         spec = NULL;
   247 	}
   247     }
   248 	return(spec);
   248     return(spec);
   249 }
   249 }
   250 
   250