/** * Play a WAV file. * If the channel is playing, it's stopped before. * The file is automatically closed if no error is reported. * \param channel Channel to use. * \param file File to play. * \param loop If loop the playing. */ adv_error mixer_play_file_wav(unsigned channel, adv_fz* file, adv_bool loop) { unsigned rate; unsigned bit; unsigned nchannel; unsigned size; mixer_channel_abort(channel); if (wave_read(file, &nchannel, &bit, &size, &rate) != 0) { return -1; } mixer_channel_alloc(channel, mixer_raw_file, loop); mixer_channel_set(channel, rate, nchannel, bit); mixer_map[channel].file = file; mixer_map[channel].start = fztell(file); mixer_map[channel].end = mixer_map[channel].start + size; mixer_map[channel].pos = mixer_map[channel].start; return 0; }
int wave_open(int id, int mode, void *args) { struct wave_file *w = &wave[id]; struct wave_args *wa = args; int result; /* wave already opened? */ if( w->file ) wave_close(id); w->file = wa->file; w->mode = mode; w->fill_wave = wa->fill_wave; w->smpfreq = wa->smpfreq; w->display = wa->display; if( w->mode ) { w->resolution = 16; w->samples = w->smpfreq; w->length = w->samples * w->resolution / 8; w->data = malloc(w->length); if( !w->data ) { logerror("WAVE malloc(%d) failed\n", w->length); memset(w, 0, sizeof(struct wave_file)); return WAVE_ERR; } return INIT_OK; } else { result = wave_read(id); if( result == WAVE_OK ) { /* return sample frequency in the user supplied structure */ wa->smpfreq = w->smpfreq; w->offset = 0; return INIT_OK; } if( result == WAVE_FMT ) { UINT8 *data; int bytes, pos, length; /* User supplied fill_wave function? */ if( w->fill_wave == NULL ) { logerror("WAVE no fill_wave callback, failing now\n"); return WAVE_ERR; } logerror("WAVE creating wave using fill_wave() callback\n"); /* sanity check: default chunk size is one byte */ if( wa->chunk_size == 0 ) { wa->chunk_size = 1; logerror("WAVE chunk_size defaults to %d\n", wa->chunk_size); } if( wa->smpfreq == 0 ) { wa->smpfreq = 11025; logerror("WAVE smpfreq defaults to %d\n", w->smpfreq); } /* allocate a buffer for the binary data */ data = malloc(wa->chunk_size); if( !data ) { free(w->data); /* zap the wave structure */ memset(&wave[id], 0, sizeof(struct wave_file)); return WAVE_ERR; } /* determine number of samples */ length = wa->header_samples + ((osd_fsize(w->file) + wa->chunk_size - 1) / wa->chunk_size) * wa->chunk_samples + wa->trailer_samples; w->smpfreq = wa->smpfreq; w->resolution = 16; w->samples = length; w->length = length * 2; /* 16 bits per sample */ w->data = malloc(w->length); if( !w->data ) { logerror("WAVE failed to malloc %d bytes\n", w->length); /* zap the wave structure */ memset(&wave[id], 0, sizeof(struct wave_file)); return WAVE_ERR; } logerror("WAVE creating max %d:%02d samples (%d) at %d Hz\n", (w->samples/w->smpfreq)/60, (w->samples/w->smpfreq)%60, w->samples, w->smpfreq); pos = 0; /* if there has to be a header */ if( wa->header_samples > 0 ) { length = (*w->fill_wave)((INT16 *)w->data + pos, w->samples - pos, CODE_HEADER); if( length < 0 ) { logerror("WAVE conversion aborted at header\n"); free(w->data); /* zap the wave structure */ memset(&wave[id], 0, sizeof(struct wave_file)); return WAVE_ERR; } logerror("WAVE header %d samples\n", length); pos += length; } /* convert the file data to samples */ bytes = 0; osd_fseek(w->file, 0, SEEK_SET); while( pos < w->samples ) { length = osd_fread(w->file, data, wa->chunk_size); if( length == 0 ) break; bytes += length; length = (*w->fill_wave)((INT16 *)w->data + pos, w->samples - pos, data); if( length < 0 ) { logerror("WAVE conversion aborted at %d bytes (%d samples)\n", bytes, pos); free(w->data); /* zap the wave structure */ memset(&wave[id], 0, sizeof(struct wave_file)); return WAVE_ERR; } pos += length; } logerror("WAVE converted %d data bytes to %d samples\n", bytes, pos); /* if there has to be a trailer */ if( wa->trailer_samples ) { if( pos < w->samples ) { length = (*w->fill_wave)((INT16 *)w->data + pos, w->samples - pos, CODE_TRAILER); if( length < 0 ) { logerror("WAVE conversion aborted at trailer\n"); free(w->data); /* zap the wave structure */ memset(&wave[id], 0, sizeof(struct wave_file)); return WAVE_ERR; } logerror("WAVE trailer %d samples\n", length); pos += length; } } if( pos < w->samples ) { /* what did the fill_wave() calls really fill into the buffer? */ w->samples = pos; w->length = pos * 2; /* 16 bits per sample */ w->data = realloc(w->data, w->length); /* failure in the last step? how sad... */ if( !w->data ) { logerror("WAVE realloc(%d) failed\n", w->length); /* zap the wave structure */ memset(&wave[id], 0, sizeof(struct wave_file)); return WAVE_ERR; } } logerror("WAVE %d samples - %d:%02d\n", w->samples, (w->samples/w->smpfreq)/60, (w->samples/w->smpfreq)%60); /* hooray! :-) */ return INIT_OK; } } return WAVE_ERR; }