/** * Write callback. Called when decoder has decoded a single audio frame. * * @param decoder Decoder instance * @param frame Decoded frame * @param buffer Array of pointers to decoded channels of data * @param client_data Client data set at initilisation * * @return Read status */ FLAC__StreamDecoderWriteStatus write_callback(const FLAC__StreamDecoder* decoder, const FLAC__Frame* frame, const FLAC__int32* const buffer[], void* client_data) { //TODO write to I2S #ifdef TO_PORT FILE *f = (FILE*)client_data; const FLAC__uint32 total_size = (FLAC__uint32)(total_samples * channels * (bps/8)); size_t i; (void)decoder; if(total_samples == 0) { fprintf(stderr, "ERROR: this example only works for FLAC files that have a total_samples count in STREAMINFO\n"); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } if(channels != 2 || bps != 16) { fprintf(stderr, "ERROR: this example only supports 16bit stereo streams\n"); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } /* write WAVE header before we write the first frame */ if(frame->header.number.sample_number == 0) { if( fwrite("RIFF", 1, 4, f) < 4 || !write_little_endian_uint32(f, total_size + 36) || fwrite("WAVEfmt ", 1, 8, f) < 8 || !write_little_endian_uint32(f, 16) || !write_little_endian_uint16(f, 1) || !write_little_endian_uint16(f, (FLAC__uint16)channels) || !write_little_endian_uint32(f, sample_rate) || !write_little_endian_uint32(f, sample_rate * channels * (bps/8)) || !write_little_endian_uint16(f, (FLAC__uint16)(channels * (bps/8))) || /* block align */ !write_little_endian_uint16(f, (FLAC__uint16)bps) || fwrite("data", 1, 4, f) < 4 || !write_little_endian_uint32(f, total_size) ) { fprintf(stderr, "ERROR: write error\n"); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } } /* write decoded PCM samples */ for(i = 0; i < frame->header.blocksize; i++) { if( !write_little_endian_int16(f, (FLAC__int16)buffer[0][i]) || /* left channel */ !write_little_endian_int16(f, (FLAC__int16)buffer[1][i]) /* right channel */ ) { fprintf(stderr, "ERROR: write error\n"); return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; } } #endif return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; }
/* @@@ not used (yet) */ static FLAC__bool write_little_endian_int32(FILE *f, FLAC__int32 x) { return write_little_endian_uint32(f, (FLAC__uint32)x); }
static FLAC__bool generate_wav(const char *filename, unsigned sample_rate, unsigned channels, unsigned bps, unsigned samples, FLAC__bool strict) { const FLAC__bool waveformatextensible = strict && (channels > 2 || (bps%8)); /* ^^^^^^^ * (bps%8) allows 24 bps which is technically supposed to be WAVEFORMATEXTENSIBLE but we * write 24bps as WAVEFORMATEX since it's unambiguous and matches how flac writes it */ const unsigned true_size = channels * ((bps+7)/8) * samples; const unsigned padded_size = (true_size + 1) & (~1u); const unsigned shift = (bps%8)? 8 - (bps%8) : 0; FILE *f; unsigned i; if(0 == (f = fopen(filename, mode))) return false; if(fwrite("RIFF", 1, 4, f) < 4) goto foo; if(!write_little_endian_uint32(f, padded_size + (waveformatextensible?60:36))) goto foo; if(fwrite("WAVEfmt ", 1, 8, f) < 8) goto foo; if(!write_little_endian_uint32(f, waveformatextensible?40:16)) goto foo; if(!write_little_endian_uint16(f, (FLAC__uint16)(waveformatextensible?65534:1))) goto foo; if(!write_little_endian_uint16(f, (FLAC__uint16)channels)) goto foo; if(!write_little_endian_uint32(f, sample_rate)) goto foo; if(!write_little_endian_uint32(f, sample_rate * channels * ((bps+7)/8))) goto foo; if(!write_little_endian_uint16(f, (FLAC__uint16)(channels * ((bps+7)/8)))) /* block align */ goto foo; if(!write_little_endian_uint16(f, (FLAC__uint16)(bps+shift))) goto foo; if(waveformatextensible) { if(!write_little_endian_uint16(f, (FLAC__uint16)22)) /* cbSize */ goto foo; if(!write_little_endian_uint16(f, (FLAC__uint16)bps)) /* validBitsPerSample */ goto foo; if(!write_little_endian_uint32(f, 0)) /* channelMask */ goto foo; /* GUID = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}} */ if(fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xaa\x00\x38\x9b\x71", 1, 16, f) != 16) goto foo; } if(fwrite("data", 1, 4, f) < 4) goto foo; if(!write_little_endian_uint32(f, true_size)) goto foo; for(i = 0; i < true_size; i++) if(fputc(GET_RANDOM_BYTE<<shift, f) == EOF) goto foo; for( ; i < padded_size; i++) if(fputc(0, f) == EOF) goto foo; fclose(f); return true; foo: fclose(f); return false; }