1/* example_cpp_decode_file - Simple FLAC file decoder using libFLAC 2 * Copyright (C) 2007 Josh Coalson 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 */ 18 19/* 20 * This example shows how to use libFLAC++ to decode a FLAC file to a WAVE 21 * file. It only supports 16-bit stereo files. 22 * 23 * Complete API documentation can be found at: 24 * http://flac.sourceforge.net/api/ 25 */ 26 27#if HAVE_CONFIG_H 28# include <config.h> 29#endif 30 31#include <stdio.h> 32#include <stdlib.h> 33#include "FLAC++/decoder.h" 34 35static FLAC__uint64 total_samples = 0; 36static unsigned sample_rate = 0; 37static unsigned channels = 0; 38static unsigned bps = 0; 39 40static bool write_little_endian_uint16(FILE *f, FLAC__uint16 x) 41{ 42 return 43 fputc(x, f) != EOF && 44 fputc(x >> 8, f) != EOF 45 ; 46} 47 48static bool write_little_endian_int16(FILE *f, FLAC__int16 x) 49{ 50 return write_little_endian_uint16(f, (FLAC__uint16)x); 51} 52 53static bool write_little_endian_uint32(FILE *f, FLAC__uint32 x) 54{ 55 return 56 fputc(x, f) != EOF && 57 fputc(x >> 8, f) != EOF && 58 fputc(x >> 16, f) != EOF && 59 fputc(x >> 24, f) != EOF 60 ; 61} 62 63class OurDecoder: public FLAC::Decoder::File { 64public: 65 OurDecoder(FILE *f_): FLAC::Decoder::File(), f(f_) { } 66protected: 67 FILE *f; 68 69 virtual ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]); 70 virtual void metadata_callback(const ::FLAC__StreamMetadata *metadata); 71 virtual void error_callback(::FLAC__StreamDecoderErrorStatus status); 72}; 73 74int main(int argc, char *argv[]) 75{ 76 bool ok = true; 77 FILE *fout; 78 79 if(argc != 3) { 80 fprintf(stderr, "usage: %s infile.flac outfile.wav\n", argv[0]); 81 return 1; 82 } 83 84 if((fout = fopen(argv[2], "wb")) == NULL) { 85 fprintf(stderr, "ERROR: opening %s for output\n", argv[2]); 86 return 1; 87 } 88 89 OurDecoder decoder(fout); 90 91 if(!decoder) { 92 fprintf(stderr, "ERROR: allocating decoder\n"); 93 fclose(fout); 94 return 1; 95 } 96 97 (void)decoder.set_md5_checking(true); 98 99 FLAC__StreamDecoderInitStatus init_status = decoder.init(argv[1]); 100 if(init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) { 101 fprintf(stderr, "ERROR: initializing decoder: %s\n", FLAC__StreamDecoderInitStatusString[init_status]); 102 ok = false; 103 } 104 105 if(ok) { 106 ok = decoder.process_until_end_of_stream(); 107 fprintf(stderr, "decoding: %s\n", ok? "succeeded" : "FAILED"); 108 fprintf(stderr, " state: %s\n", decoder.get_state().resolved_as_cstring(decoder)); 109 } 110 111 fclose(fout); 112 113 return 0; 114} 115 116::FLAC__StreamDecoderWriteStatus OurDecoder::write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) 117{ 118 const FLAC__uint32 total_size = (FLAC__uint32)(total_samples * channels * (bps/8)); 119 size_t i; 120 121 if(total_samples == 0) { 122 fprintf(stderr, "ERROR: this example only works for FLAC files that have a total_samples count in STREAMINFO\n"); 123 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; 124 } 125 if(channels != 2 || bps != 16) { 126 fprintf(stderr, "ERROR: this example only supports 16bit stereo streams\n"); 127 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; 128 } 129 130 /* write WAVE header before we write the first frame */ 131 if(frame->header.number.sample_number == 0) { 132 if( 133 fwrite("RIFF", 1, 4, f) < 4 || 134 !write_little_endian_uint32(f, total_size + 36) || 135 fwrite("WAVEfmt ", 1, 8, f) < 8 || 136 !write_little_endian_uint32(f, 16) || 137 !write_little_endian_uint16(f, 1) || 138 !write_little_endian_uint16(f, (FLAC__uint16)channels) || 139 !write_little_endian_uint32(f, sample_rate) || 140 !write_little_endian_uint32(f, sample_rate * channels * (bps/8)) || 141 !write_little_endian_uint16(f, (FLAC__uint16)(channels * (bps/8))) || /* block align */ 142 !write_little_endian_uint16(f, (FLAC__uint16)bps) || 143 fwrite("data", 1, 4, f) < 4 || 144 !write_little_endian_uint32(f, total_size) 145 ) { 146 fprintf(stderr, "ERROR: write error\n"); 147 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; 148 } 149 } 150 151 /* write decoded PCM samples */ 152 for(i = 0; i < frame->header.blocksize; i++) { 153 if( 154 !write_little_endian_int16(f, (FLAC__int16)buffer[0][i]) || /* left channel */ 155 !write_little_endian_int16(f, (FLAC__int16)buffer[1][i]) /* right channel */ 156 ) { 157 fprintf(stderr, "ERROR: write error\n"); 158 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; 159 } 160 } 161 162 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; 163} 164 165void OurDecoder::metadata_callback(const ::FLAC__StreamMetadata *metadata) 166{ 167 /* print some stats */ 168 if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { 169 /* save for later */ 170 total_samples = metadata->data.stream_info.total_samples; 171 sample_rate = metadata->data.stream_info.sample_rate; 172 channels = metadata->data.stream_info.channels; 173 bps = metadata->data.stream_info.bits_per_sample; 174 175 fprintf(stderr, "sample rate : %u Hz\n", sample_rate); 176 fprintf(stderr, "channels : %u\n", channels); 177 fprintf(stderr, "bits per sample: %u\n", bps); 178#ifdef _MSC_VER 179 fprintf(stderr, "total samples : %I64u\n", total_samples); 180#else 181 fprintf(stderr, "total samples : %llu\n", total_samples); 182#endif 183 } 184} 185 186void OurDecoder::error_callback(::FLAC__StreamDecoderErrorStatus status) 187{ 188 fprintf(stderr, "Got error callback: %s\n", FLAC__StreamDecoderErrorStatusString[status]); 189} 190