Well, I sent this earlier this week, but I guess it's stuck in the spam filter,
so I'll send it again split up in several
parts. First the full source, if this one arrives I'll reply with the patch.
Ok, so I ended up creating 2 versions of this. The first one is what I
mentioned earlier, pretty much a line-for-line
translation of the original example. The c++-style casts made the
(already ugly) lines with casts even uglier by
the way...
/* example_cpp_encode_file - Simple FLAC file encoder using libFLAC
* Copyright (C) 2007,2008,2009 Josh Coalson
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* 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 General Public License for more details.
*
* You should have received a copy of the GNU 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.
*/
/*
* This example shows how to use libFLAC++ to encode a WAVE file to a FLAC
* file. It only supports 16-bit stereo files in canonical WAVE format.
*
* Complete API documentation can be found at:
* http://flac.sourceforge.net/api/
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <iostream>
#include <fstream>
#include <cstring>
#define __STDC_FORMAT_MACROS
#include "FLAC++/metadata.h"
#include "FLAC++/encoder.h"
class OurEncoder: public FLAC::Encoder::File {
unsigned total_samples;
public:
OurEncoder(unsigned samples): FLAC::Encoder::File(), total_samples(samples) { }
protected:
virtual void progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate);
};
#define READSIZE 1024
int main(int argc, char *argv[])
{
if(argc != 3) {
std::cerr << "usage: " << argv[0] << " infile.wav outfile.flac" << std::endl;
return 1;
}
std::ifstream fin(argv[1]);
if(!fin.is_open()) {
std::cerr << "ERROR: opening " << argv[1] << " for output" << std::endl;
return 1;
}
/* read wav header and validate it */
FLAC__byte buffer[READSIZE/*samples*/ * 2/*bytes_per_sample*/ * 2/*channels*/]; /* we read the WAVE data into here */
if(
!fin.read(reinterpret_cast<char *>(buffer), 44) ||
memcmp(buffer, "RIFF", 4) ||
memcmp(buffer+8, "WAVEfmt \020\000\000\000\001\000\002\000", 16) ||
memcmp(buffer+32, "\004\000\020\000data", 8)
) {
std::cerr << "ERROR: invalid/unsupported WAVE file, only 16bps stereo WAVE in canonical form allowed" << std::endl;
return 1;
}
unsigned sample_rate = (((((static_cast<unsigned>(buffer[27]) << 8) | buffer[26]) << 8) | buffer[25]) << 8) | buffer[24];
unsigned channels = 2;
unsigned bps = 16;
unsigned total_samples = ((((((static_cast<unsigned>(buffer[43]) << 8) | buffer[42]) << 8) | buffer[41]) << 8) | buffer[40]) / 4;
/* check the encoder */
OurEncoder encoder(total_samples);
if(!encoder) {
std::cerr << "ERROR: allocating encoder" << std::endl;
return 1;
}
bool ok = encoder.set_verify(true);
ok &= encoder.set_compression_level(5);
ok &= encoder.set_channels(channels);
ok &= encoder.set_bits_per_sample(bps);
ok &= encoder.set_sample_rate(sample_rate);
ok &= encoder.set_total_samples_estimate(total_samples);
/* now add some metadata; we'll add some tags and a padding block */
FLAC::Metadata::Prototype *metadata[2];
if(ok) {
FLAC::Metadata::VorbisComment::Entry entry;
if(
!(metadata[0] = new FLAC::Metadata::VorbisComment) ||
!(metadata[1] = new FLAC::Metadata::Padding(1234)) ||
/* there are many tag (vorbiscomment) functions but these are convenient for this particular use: */
!(entry = FLAC::Metadata::VorbisComment::Entry("ARTIST", "Some Artist")).is_valid() ||
!reinterpret_cast<FLAC::Metadata::VorbisComment *>(metadata[0])->append_comment(entry) || /* copy=false: let metadata object take control of entry's allocated string */
!(entry = FLAC::Metadata::VorbisComment::Entry("YEAR", "1984")).is_valid() ||
!reinterpret_cast<FLAC::Metadata::VorbisComment *>(metadata[0])->append_comment(entry)
) {
std::cerr << "ERROR: out of memory or tag error" << std::endl;
ok = false;
}
ok = encoder.set_metadata(metadata, 2);
}
/* initialize encoder */
if(ok) {
FLAC__StreamEncoderInitStatus init_status = encoder.init(argv[2]);
if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
std::cerr << "ERROR: initializing encoder: " << FLAC__StreamEncoderInitStatusString[init_status] << std::endl;
ok = false;
}
}
/* read blocks of samples from WAVE file and feed to encoder */
if(ok) {
size_t left = static_cast<size_t>(total_samples);
FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];
while(ok && left) {
size_t need = (left>READSIZE? static_cast<size_t>(READSIZE) :static_cast<size_t> (left));
if (!fin.read(reinterpret_cast<char *>(buffer), need*channels*(bps/8))) {
std::cerr << "ERROR: reading from WAVE file" << std::endl;
ok = false;
}
else {
/* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */
for(size_t i = 0; i < need*channels; ++i) {
/* inefficient but simple and works on big- or little-endian machines */
pcm[i] = static_cast<FLAC__int32>((static_cast<FLAC__int16>(static_cast<FLAC__int8>(buffer[2*i+1])) << 8) |
static_cast<FLAC__int16>(buffer[2*i]));
}
/* feed samples to encoder */
ok = encoder.process_interleaved(pcm, need);
}
left -= need;
}
}
ok &= encoder.finish();
std::cerr << "encoding: " << (ok? "succeeded" : "FAILED") << std::endl;
std::cerr << " state: " << encoder.get_state().resolved_as_cstring(encoder) << std::endl;
/* now that encoding is finished, the metadata can be freed */
delete metadata[0];
delete metadata[1];
return 0;
}
void OurEncoder::progress_callback(FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate)
{
std::cerr << "wrote " << bytes_written << " bytes, " << samples_written << "/" << total_samples << " samples, "
<< frames_written << "/" << total_frames_estimate << " frames" << std::endl;
}
_______________________________________________
flac-dev mailing list
flac-dev@xiph.org
http://lists.xiph.org/mailman/listinfo/flac-dev