flake-0.11/0000755000175000017500000000000010655263114012132 5ustar justinjustinflake-0.11/libflake/0000755000175000017500000000000010655263114013703 5ustar justinjustinflake-0.11/libflake/bitio.h0000644000175000017500000000674110655263114015172 0ustar justinjustin/** * Bitwise File Writer * Copyright (c) 2006-2007 Justin Ruggles * * derived from ffmpeg/libavcodec/bitstream.h * Common bit i/o utils * Copyright (c) 2000, 2001 Fabrice Bellard * Copyright (c) 2002-2004 Michael Niedermayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef BITIO_H #define BITIO_H #include "common.h" #include #include "bswap.h" typedef struct BitWriter { uint32_t bit_buf; int bit_left; uint8_t *buffer, *buf_ptr, *buf_end; int eof; } BitWriter; static inline void bitwriter_init(BitWriter *bw, void *buf, int len) { if(len < 0) { len = 0; buf = NULL; } bw->buffer = buf; bw->buf_end = bw->buffer + len; bw->buf_ptr = bw->buffer; bw->bit_left = 32; bw->bit_buf = 0; bw->eof = 0; } static inline uint32_t bitwriter_count(BitWriter *bw) { // TODO: simplify return ((((bw->buf_ptr - bw->buffer) << 3) + 32 - bw->bit_left) + 7) >> 3; } static inline void bitwriter_flush(BitWriter *bw) { bw->bit_buf <<= bw->bit_left; while(bw->bit_left < 32 && !bw->eof) { if(bw->buf_ptr >= bw->buf_end) { bw->eof = 1; break; } if(bw->buffer != NULL) { *bw->buf_ptr = bw->bit_buf >> 24; } bw->buf_ptr++; bw->bit_buf <<= 8; bw->bit_left += 8; } bw->bit_left = 32; bw->bit_buf = 0; } static inline void bitwriter_writebits(BitWriter *bw, int bits, uint32_t val) { uint32_t bb=0; assert(bits == 32 || val < (1U << bits)); if(bits == 0 || bw->eof) return; if((bw->buf_ptr+3) >= bw->buf_end) { bw->eof = 1; return; } if(bits < bw->bit_left) { bw->bit_buf = (bw->bit_buf << bits) | val; bw->bit_left -= bits; } else { if(bw->bit_left == 32) { assert(bits == 32); bb = val; } else { bb = (bw->bit_buf << bw->bit_left) | (val >> (bits - bw->bit_left)); bw->bit_left += (32 - bits); } if(bw->buffer != NULL) { *(uint32_t *)bw->buf_ptr = be2me_32(bb); } bw->buf_ptr += 4; bw->bit_buf = val; } } static inline void bitwriter_writebits_signed(BitWriter *bw, int bits, int32_t val) { assert(bits >= 0 && bits <= 31); bitwriter_writebits(bw, bits, val & ((1ULL<>31); // write quotient in unary q = (v >> k) + 1; while(q > 31) { bitwriter_writebits(bw, 31, 0); q -= 31; } bitwriter_writebits(bw, q, 1); // write write remainder in binary using 'k' bits bitwriter_writebits(bw, k, v&((1<bw, streaminfo, 38); // metadata header bitwriter_writebits(ctx->bw, 1, last); bitwriter_writebits(ctx->bw, 7, 0); bitwriter_writebits(ctx->bw, 24, 34); if(ctx->params.variable_block_size) { bitwriter_writebits(ctx->bw, 16, 0); } else { bitwriter_writebits(ctx->bw, 16, ctx->params.block_size); } bitwriter_writebits(ctx->bw, 16, ctx->params.block_size); bitwriter_writebits(ctx->bw, 24, 0); bitwriter_writebits(ctx->bw, 24, ctx->max_frame_size); bitwriter_writebits(ctx->bw, 20, ctx->samplerate); bitwriter_writebits(ctx->bw, 3, ctx->channels-1); bitwriter_writebits(ctx->bw, 5, ctx->bps-1); // total samples if(ctx->sample_count > 0) { bitwriter_writebits(ctx->bw, 4, 0); bitwriter_writebits(ctx->bw, 32, ctx->sample_count); } else { bitwriter_writebits(ctx->bw, 4, 0); bitwriter_writebits(ctx->bw, 32, 0); } } /** * Write padding metadata block to byte array. */ static int write_padding(FlacEncodeContext *ctx, uint8_t *padding, int last, int padlen) { bitwriter_init(ctx->bw, padding, 4); // metadata header bitwriter_writebits(ctx->bw, 1, last); bitwriter_writebits(ctx->bw, 7, 1); bitwriter_writebits(ctx->bw, 24, padlen); return padlen + 4; } static const char *vendor_string = FLAKE_IDENT; /** * Write vorbis comment metadata block to byte array. * Just writes the vendor string for now. */ static int write_vorbis_comment(FlacEncodeContext *ctx, uint8_t *comment, int last) { int vendor_len; uint8_t vlen_le[4]; vendor_len = strlen(vendor_string); bitwriter_init(ctx->bw, comment, 4); // metadata header bitwriter_writebits(ctx->bw, 1, last); bitwriter_writebits(ctx->bw, 7, 4); bitwriter_writebits(ctx->bw, 24, vendor_len+8); // vendor string length // note: use me2le_32() vlen_le[0] = vendor_len & 0xFF; vlen_le[1] = (vendor_len >> 8) & 0xFF; vlen_le[2] = (vendor_len >> 16) & 0xFF; vlen_le[3] = (vendor_len >> 24) & 0xFF; memcpy(&comment[4], vlen_le, 4); memcpy(&comment[8], vendor_string, vendor_len); memset(&comment[vendor_len+8], 0, 4); return vendor_len + 12; } /** * Write fLaC stream marker & metadata headers */ static int write_headers(FlacEncodeContext *ctx, uint8_t *header) { int header_size, last; header_size = 0; last = 0; // stream marker header[0] = 0x66; header[1] = 0x4C; header[2] = 0x61; header[3] = 0x43; header_size += 4; // streaminfo write_streaminfo(ctx, &header[header_size], last); header_size += 38; // vorbis comment if(ctx->params.padding_size == 0) last = 1; header_size += write_vorbis_comment(ctx, &header[header_size], last); // padding if(ctx->params.padding_size > 0) { last = 1; header_size += write_padding(ctx, &header[header_size], last, ctx->params.padding_size); } return header_size; } /** * Set blocksize based on samplerate * Chooses the closest predefined blocksize >= time_ms milliseconds */ static int select_blocksize(int samplerate, int time_ms) { int i, target, blocksize; blocksize = flac_blocksizes[1]; target = (samplerate * time_ms) / 1000; for(i=0; i<16; i++) { if(target >= flac_blocksizes[i] && flac_blocksizes[i] > blocksize) { blocksize = flac_blocksizes[i]; } } return blocksize; } int flake_set_defaults(FlakeEncodeParams *params) { int lvl; if(!params) { return -1; } lvl = params->compression; if((lvl < 0 || lvl > 12) && (lvl != 99)) { return -1; } // default to level 5 params params->order_method = FLAKE_ORDER_METHOD_EST; params->stereo_method = FLAKE_STEREO_METHOD_ESTIMATE; params->block_size = 0; params->block_time_ms = 105; params->prediction_type = FLAKE_PREDICTION_LEVINSON; params->min_prediction_order = 1; params->max_prediction_order = 8; params->min_partition_order = 0; params->max_partition_order = 6; params->padding_size = 4096; params->variable_block_size = 0; // differences from level 5 switch(lvl) { case 0: params->stereo_method = FLAKE_STEREO_METHOD_INDEPENDENT; params->block_time_ms = 27; params->prediction_type = FLAKE_PREDICTION_FIXED; params->min_prediction_order = 2; params->max_prediction_order = 2; params->min_partition_order = 4; params->max_partition_order = 4; break; case 1: params->block_time_ms = 27; params->prediction_type = FLAKE_PREDICTION_FIXED; params->min_prediction_order = 2; params->max_prediction_order = 3; params->min_partition_order = 2; params->max_partition_order = 2; break; case 2: params->block_time_ms = 27; params->prediction_type = FLAKE_PREDICTION_FIXED; params->min_prediction_order = 2; params->max_prediction_order = 4; params->min_partition_order = 0; params->max_partition_order = 3; break; case 3: params->max_prediction_order = 6; params->max_partition_order = 3; break; case 4: params->max_partition_order = 3; break; case 5: break; case 6: params->order_method = FLAKE_ORDER_METHOD_2LEVEL; params->max_partition_order = 8; break; case 7: params->order_method = FLAKE_ORDER_METHOD_4LEVEL; params->max_partition_order = 8; break; case 8: params->order_method = FLAKE_ORDER_METHOD_4LEVEL; params->max_prediction_order = 12; params->max_partition_order = 8; break; case 9: params->order_method = FLAKE_ORDER_METHOD_LOG; params->max_prediction_order = 12; params->max_partition_order = 8; break; case 10: params->order_method = FLAKE_ORDER_METHOD_SEARCH; params->max_prediction_order = 12; params->max_partition_order = 8; break; case 11: params->order_method = FLAKE_ORDER_METHOD_LOG; params->max_prediction_order = 32; params->max_partition_order = 8; break; case 12: params->order_method = FLAKE_ORDER_METHOD_SEARCH; params->max_prediction_order = 32; params->max_partition_order = 8; break; case 99: params->order_method = FLAKE_ORDER_METHOD_SEARCH; params->block_time_ms = 186; params->max_prediction_order = 32; params->max_partition_order = 8; params->variable_block_size = 2; break; } return 0; } int flake_validate_params(FlakeContext *s) { int i; int subset = 0; int bs; FlakeEncodeParams *params; if(s == NULL) { return -1; } params = &s->params; if(s->channels < 1 || s->channels > FLAC_MAX_CH) { return -1; } if(s->sample_rate < 1 || s->sample_rate > 655350) { return -1; } for(i=4; i<12; i++) { if(s->sample_rate == flac_samplerates[i]) { break; } } if(i == 12) { subset = 1; } if(s->bits_per_sample < 4 || s->bits_per_sample > 32) { return -1; } for(i=1; i<8; i++) { if(s->bits_per_sample == flac_bitdepths[i]) break; } if(i == 8) { subset = 1; } if((params->compression < 0 || params->compression > 12) && (params->compression != 99)) { return -1; } if(params->order_method < 0 || params->order_method > 6) { return -1; } if(params->stereo_method < 0 || params->stereo_method > 1) { return -1; } if(params->block_time_ms < 0) { return -1; } bs = params->block_size; if(bs == 0) { bs = select_blocksize(s->sample_rate, params->block_time_ms); } if(bs < FLAC_MIN_BLOCKSIZE || bs > FLAC_MAX_BLOCKSIZE) { return -1; } for(i=0; i<15; i++) { if(bs == flac_blocksizes[i]) break; } if(i == 15 || (s->sample_rate <= 48000 && bs > 4608)) { subset = 1; } if(params->prediction_type < 0 || params->prediction_type > 2) { return -1; } if(params->min_prediction_order > params->max_prediction_order) { return -1; } if(params->prediction_type == FLAKE_PREDICTION_FIXED) { if(params->min_prediction_order < 0 || params->min_prediction_order > 4) { return -1; } if(params->max_prediction_order < 0 || params->max_prediction_order > 4) { return -1; } } else { if(params->min_prediction_order < 1 || params->min_prediction_order > 32) { return -1; } if(params->max_prediction_order < 1 || params->max_prediction_order > 32) { return -1; } if(s->sample_rate <= 48000 && params->max_prediction_order > 12) { subset = 1; } } if(params->min_partition_order > params->max_partition_order) { return -1; } if(params->min_partition_order < 0 || params->min_partition_order > 8) { return -1; } if(params->max_partition_order < 0 || params->max_partition_order > 8) { return -1; } if(params->padding_size < 0 || params->padding_size >= (1<<24)) { return -1; } if(params->variable_block_size < 0 || params->variable_block_size > 2) { return -1; } if(params->variable_block_size > 0) { subset = 1; } return subset; } /** * Initialize encoder */ int flake_encode_init(FlakeContext *s) { FlacEncodeContext *ctx; int i, header_len; if(s == NULL) { return -1; } // allocate memory ctx = calloc(1, sizeof(FlacEncodeContext)); s->private_ctx = ctx; if(flake_validate_params(s) < 0) { return -1; } ctx->channels = s->channels; ctx->ch_code = s->channels-1; // find samplerate in table for(i=4; i<12; i++) { if(s->sample_rate == flac_samplerates[i]) { ctx->samplerate = flac_samplerates[i]; ctx->sr_code[0] = i; ctx->sr_code[1] = 0; break; } } // if not in table, samplerate is non-standard if(i == 12) { ctx->samplerate = s->sample_rate; if(ctx->samplerate % 1000 == 0 && ctx->samplerate <= 255000) { ctx->sr_code[0] = 12; ctx->sr_code[1] = ctx->samplerate / 1000; } else if(ctx->samplerate % 10 == 0 && ctx->samplerate <= 655350) { ctx->sr_code[0] = 14; ctx->sr_code[1] = s->sample_rate / 10; } else if(ctx->samplerate < 65535) { ctx->sr_code[0] = 13; ctx->sr_code[1] = ctx->samplerate; } } for(i=1; i<8; i++) { if(s->bits_per_sample == flac_bitdepths[i]) { ctx->bps = flac_bitdepths[i]; ctx->bps_code = i; break; } } if(i == 8) return -1; // FIXME: For now, only 16-bit encoding is supported if(ctx->bps != 16) return -1; ctx->sample_count = s->samples; if(s->params.block_size == 0) { s->params.block_size = select_blocksize(ctx->samplerate, s->params.block_time_ms); } ctx->params = s->params; // select LPC precision based on block size if( ctx->params.block_size <= 192) ctx->lpc_precision = 7; else if(ctx->params.block_size <= 384) ctx->lpc_precision = 8; else if(ctx->params.block_size <= 576) ctx->lpc_precision = 9; else if(ctx->params.block_size <= 1152) ctx->lpc_precision = 10; else if(ctx->params.block_size <= 2304) ctx->lpc_precision = 11; else if(ctx->params.block_size <= 4608) ctx->lpc_precision = 12; else if(ctx->params.block_size <= 8192) ctx->lpc_precision = 13; else if(ctx->params.block_size <= 16384) ctx->lpc_precision = 14; else ctx->lpc_precision = 15; // set maximum encoded frame size (if larger, re-encodes in verbatim mode) if(ctx->channels == 2) { ctx->max_frame_size = 16 + ((ctx->params.block_size * (ctx->bps+ctx->bps+1) + 7) >> 3); } else { ctx->max_frame_size = 16 + ((ctx->params.block_size * ctx->channels * ctx->bps + 7) >> 3); } s->max_frame_size = ctx->max_frame_size; // output header bytes ctx->bw = calloc(sizeof(BitWriter), 1); s->header = calloc(ctx->params.padding_size + 1024, 1); header_len = -1; if(s->header != NULL) { header_len = write_headers(ctx, s->header); } ctx->frame_count = 0; // initialize CRC & MD5 crc_init(); md5_init(&ctx->md5ctx); return header_len; } /** * Initialize the current frame before encoding */ static int init_frame(FlacEncodeContext *ctx) { int i, ch; FlacFrame *frame; frame = &ctx->frame; if(ctx->params.block_time_ms < 0) { return -1; } if(ctx->params.block_size == 0) { ctx->params.block_size = select_blocksize(ctx->samplerate, ctx->params.block_time_ms); } if(ctx->params.block_size < 1 || ctx->params.block_size > FLAC_MAX_BLOCKSIZE) { return -1; } // set maximum encoded frame size (if larger, re-encodes in verbatim mode) if(ctx->channels == 2) { ctx->max_frame_size = 16 + ((ctx->params.block_size * (ctx->bps+ctx->bps+1) + 7) >> 3); } else { ctx->max_frame_size = 16 + ((ctx->params.block_size * ctx->channels * ctx->bps + 7) >> 3); } // get block size codes i = 15; if(!ctx->params.variable_block_size) { for(i=0; i<15; i++) { if(ctx->params.block_size == flac_blocksizes[i]) { frame->blocksize = flac_blocksizes[i]; frame->bs_code[0] = i; frame->bs_code[1] = -1; break; } } } if(i == 15) { frame->blocksize = ctx->params.block_size; if(frame->blocksize <= 256) { frame->bs_code[0] = 6; frame->bs_code[1] = frame->blocksize-1; } else { frame->bs_code[0] = 7; frame->bs_code[1] = frame->blocksize-1; } } // initialize output bps for each channel for(ch=0; chchannels; ch++) { frame->subframes[ch].obits = ctx->bps; } return 0; } /** * Copy channel-interleaved input samples into separate subframes */ static void update_md5_checksum(FlacEncodeContext *ctx, int16_t *samples) { md5_accumulate(&ctx->md5ctx, samples, ctx->channels, ctx->params.block_size); } /** * Copy channel-interleaved input samples into separate subframes */ static void copy_samples(FlacEncodeContext *ctx, int16_t *samples) { int i, j, ch; FlacFrame *frame; frame = &ctx->frame; for(i=0,j=0; iblocksize; i++) { for(ch=0; chchannels; ch++,j++) { frame->subframes[ch].samples[i] = samples[j]; } } } /** * Estimate the best stereo decorrelation mode */ static int calc_decorr_scores(int32_t *left_ch, int32_t *right_ch, int n) { int i, best; int32_t lt, rt; uint64_t sum[4]; uint64_t score[4]; int k; // calculate sum of 2nd order residual for each channel sum[0] = sum[1] = sum[2] = sum[3] = 0; for(i=2; i> 1); sum[3] += abs(lt - rt); sum[0] += abs(lt); sum[1] += abs(rt); } // estimate bit counts for(i=0; i<4; i++) { k = find_optimal_rice_param(2*sum[i], n); sum[i] = rice_encode_count(2*sum[i], n, k); } // calculate score for each mode score[0] = sum[0] + sum[1]; score[1] = sum[0] + sum[3]; score[2] = sum[1] + sum[3]; score[3] = sum[2] + sum[3]; // return mode with lowest score best = 0; for(i=1; i<4; i++) { if(score[i] < score[best]) { best = i; } } switch(best) { case 0: return FLAC_CHMODE_LEFT_RIGHT; case 1: return FLAC_CHMODE_LEFT_SIDE; case 2: return FLAC_CHMODE_RIGHT_SIDE; case 3: return FLAC_CHMODE_MID_SIDE; } return FLAC_CHMODE_LEFT_RIGHT; } /** * Perform stereo channel decorrelation */ static void channel_decorrelation(FlacEncodeContext *ctx) { int i; FlacFrame *frame; int32_t *left, *right; int32_t tmp; frame = &ctx->frame; left = frame->subframes[0].samples; right = frame->subframes[1].samples; if(ctx->channels != 2) { frame->ch_mode = FLAC_CHMODE_NOT_STEREO; return; } if(frame->blocksize <= 32 || ctx->params.stereo_method == FLAKE_STEREO_METHOD_INDEPENDENT) { frame->ch_mode = FLAC_CHMODE_LEFT_RIGHT; return; } // estimate stereo decorrelation type frame->ch_mode = calc_decorr_scores(left, right, frame->blocksize); // perform decorrelation and adjust bits-per-sample if(frame->ch_mode == FLAC_CHMODE_LEFT_RIGHT) { return; } if(frame->ch_mode == FLAC_CHMODE_MID_SIDE) { for(i=0; iblocksize; i++) { tmp = left[i]; left[i] = (left[i] + right[i]) >> 1; right[i] = tmp - right[i]; } frame->subframes[1].obits++; } else if(frame->ch_mode == FLAC_CHMODE_LEFT_SIDE) { for(i=0; iblocksize; i++) { right[i] = left[i] - right[i]; } frame->subframes[1].obits++; } else if(frame->ch_mode == FLAC_CHMODE_RIGHT_SIDE) { for(i=0; iblocksize; i++) { left[i] = left[i] - right[i]; } frame->subframes[0].obits++; } } /** * Write UTF-8 encoded integer value * Used to encode frame number in frame header */ static void write_utf8(BitWriter *bw, uint32_t val) { int bytes, shift; if(val < 0x80){ bitwriter_writebits(bw, 8, val); return; } bytes = (log2i(val)+4) / 5; shift = (bytes - 1) * 6; bitwriter_writebits(bw, 8, (256 - (256>>bytes)) | (val >> shift)); while(shift >= 6){ shift -= 6; bitwriter_writebits(bw, 8, 0x80 | ((val >> shift) & 0x3F)); } } static void output_frame_header(FlacEncodeContext *ctx) { FlacFrame *frame; uint8_t crc; frame = &ctx->frame; bitwriter_writebits(ctx->bw, 16, 0xFFF8); bitwriter_writebits(ctx->bw, 4, frame->bs_code[0]); bitwriter_writebits(ctx->bw, 4, ctx->sr_code[0]); if(frame->ch_mode == FLAC_CHMODE_NOT_STEREO) { bitwriter_writebits(ctx->bw, 4, ctx->ch_code); } else { bitwriter_writebits(ctx->bw, 4, frame->ch_mode); } bitwriter_writebits(ctx->bw, 3, ctx->bps_code); bitwriter_writebits(ctx->bw, 1, 0); write_utf8(ctx->bw, ctx->frame_count); // custom block size if(frame->bs_code[1] >= 0) { if(frame->bs_code[1] < 256) { bitwriter_writebits(ctx->bw, 8, frame->bs_code[1]); } else { bitwriter_writebits(ctx->bw, 16, frame->bs_code[1]); } } // custom sample rate if(ctx->sr_code[1] > 0) { if(ctx->sr_code[1] < 256) { bitwriter_writebits(ctx->bw, 8, ctx->sr_code[1]); } else { bitwriter_writebits(ctx->bw, 16, ctx->sr_code[1]); } } // CRC-8 of frame header bitwriter_flush(ctx->bw); crc = calc_crc8(ctx->bw->buffer, bitwriter_count(ctx->bw)); bitwriter_writebits(ctx->bw, 8, crc); } static void output_residual(FlacEncodeContext *ctx, int ch) { int i, j, p; int k, porder, psize, res_cnt; FlacFrame *frame; FlacSubframe *sub; frame = &ctx->frame; sub = &frame->subframes[ch]; // rice-encoded block bitwriter_writebits(ctx->bw, 2, 0); // partition order porder = sub->rc.porder; psize = frame->blocksize >> porder; assert(porder >= 0); bitwriter_writebits(ctx->bw, 4, porder); res_cnt = psize - sub->order; // residual j = sub->order; for(p=0; p<(1 << porder); p++) { k = sub->rc.params[p]; bitwriter_writebits(ctx->bw, 4, k); if(p == 1) res_cnt = psize; for(i=0; iblocksize; i++, j++) { bitwriter_write_rice_signed(ctx->bw, k, sub->residual[j]); } } } static void output_subframe_constant(FlacEncodeContext *ctx, int ch) { FlacSubframe *sub; sub = &ctx->frame.subframes[ch]; bitwriter_writebits_signed(ctx->bw, sub->obits, sub->residual[0]); } static void output_subframe_verbatim(FlacEncodeContext *ctx, int ch) { int i, n; FlacFrame *frame; FlacSubframe *sub; frame = &ctx->frame; sub = &frame->subframes[ch]; n = frame->blocksize; for(i=0; ibw, sub->obits, sub->residual[i]); } } static void output_subframe_fixed(FlacEncodeContext *ctx, int ch) { int i; FlacFrame *frame; FlacSubframe *sub; frame = &ctx->frame; sub = &frame->subframes[ch]; // warm-up samples for(i=0; iorder; i++) { bitwriter_writebits_signed(ctx->bw, sub->obits, sub->residual[i]); } // residual output_residual(ctx, ch); } static void output_subframe_lpc(FlacEncodeContext *ctx, int ch) { int i, cbits; FlacFrame *frame; FlacSubframe *sub; frame = &ctx->frame; sub = &frame->subframes[ch]; // warm-up samples for(i=0; iorder; i++) { bitwriter_writebits_signed(ctx->bw, sub->obits, sub->residual[i]); } // LPC coefficients cbits = ctx->lpc_precision; bitwriter_writebits(ctx->bw, 4, cbits-1); bitwriter_writebits_signed(ctx->bw, 5, sub->shift); for(i=0; iorder; i++) { bitwriter_writebits_signed(ctx->bw, cbits, sub->coefs[i]); } // residual output_residual(ctx, ch); } static void output_subframes(FlacEncodeContext *ctx) { FlacFrame *frame; int i, ch; frame = &ctx->frame; for(i=0; ichannels; i++) { ch = i; // subframe header bitwriter_writebits(ctx->bw, 1, 0); bitwriter_writebits(ctx->bw, 6, frame->subframes[ch].type_code); bitwriter_writebits(ctx->bw, 1, 0); // subframe switch(frame->subframes[ch].type) { case FLAC_SUBFRAME_CONSTANT: output_subframe_constant(ctx, ch); break; case FLAC_SUBFRAME_VERBATIM: output_subframe_verbatim(ctx, ch); break; case FLAC_SUBFRAME_FIXED: output_subframe_fixed(ctx, ch); break; case FLAC_SUBFRAME_LPC: output_subframe_lpc(ctx, ch); break; } } } static void output_frame_footer(FlacEncodeContext *ctx) { uint16_t crc; bitwriter_flush(ctx->bw); crc = calc_crc16(ctx->bw->buffer, bitwriter_count(ctx->bw)); bitwriter_writebits(ctx->bw, 16, crc); bitwriter_flush(ctx->bw); } int encode_frame(FlakeContext *s, uint8_t *frame_buffer, int16_t *samples) { int i, ch; FlacEncodeContext *ctx; ctx = (FlacEncodeContext *) s->private_ctx; if(ctx == NULL) return -1; ctx->params.block_size = s->params.block_size; if(init_frame(ctx)) { return -1; } s->params.block_size = ctx->params.block_size; if(frame_buffer != NULL) { update_md5_checksum(ctx, samples); } copy_samples(ctx, samples); channel_decorrelation(ctx); for(ch=0; chchannels; ch++) { if(encode_residual(ctx, ch) < 0) { return -1; } } bitwriter_init(ctx->bw, frame_buffer, ctx->max_frame_size); output_frame_header(ctx); output_subframes(ctx); output_frame_footer(ctx); if(ctx->bw->eof) { // frame size too large, reencode in verbatim mode for(i=0; ichannels; i++) { ch = i; reencode_residual_verbatim(ctx, ch); } bitwriter_init(ctx->bw, frame_buffer, ctx->max_frame_size); output_frame_header(ctx); output_subframes(ctx); output_frame_footer(ctx); // if still too large, means my estimate is wrong. assert(!ctx->bw->eof); } if(frame_buffer != NULL) { if(ctx->params.variable_block_size) { ctx->frame_count += s->params.block_size; } else { ctx->frame_count++; } } return bitwriter_count(ctx->bw); } int flake_encode_frame(FlakeContext *s, uint8_t *frame_buffer, int16_t *samples) { int fs; FlacEncodeContext *ctx; ctx = (FlacEncodeContext *) s->private_ctx; fs = -1; if((ctx->params.variable_block_size > 0) && !(s->params.block_size & 7) && s->params.block_size >= 128) { fs = encode_frame_vbs(s, frame_buffer, samples); } else { fs = encode_frame(s, frame_buffer, samples); } return fs; } void flake_encode_close(FlakeContext *s) { FlacEncodeContext *ctx; if(s == NULL) return; if(s->private_ctx == NULL) return; ctx = (FlacEncodeContext *) s->private_ctx; if(ctx) { md5_final(s->md5digest, &ctx->md5ctx); if(ctx->bw) free(ctx->bw); free(ctx); } if(s->header) free(s->header); s->private_ctx = NULL; } flake-0.11/libflake/rice.h0000644000175000017500000000354310655263114015003 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file rice.h * Functions for calculating optimal partition order and Rice parameters */ #ifndef RICE_H #define RICE_H #include "common.h" #define MAX_RICE_PARAM 14 #define MAX_PARTITION_ORDER 8 #define MAX_PARTITIONS (1 << MAX_PARTITION_ORDER) typedef struct RiceContext { int porder; /* partition order */ int params[MAX_PARTITIONS]; /* Rice parameters */ int esc_bps[MAX_PARTITIONS]; /* bps if using escape code */ } RiceContext; #define rice_encode_count(sum, n, k) (((n)*((k)+1))+(((sum)-(n>>1))>>(k))) extern int find_optimal_rice_param(uint32_t sum, int n); extern uint32_t calc_rice_params_fixed(RiceContext *rc, int pmin, int pmax, int32_t *data, int n, int pred_order, int bps); extern uint32_t calc_rice_params_lpc(RiceContext *rc, int pmin, int pmax, int32_t *data, int n, int pred_order, int bps, int precision); #endif /* RICE_H */ flake-0.11/libflake/crc.h0000644000175000017500000000201610655263114014622 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef CRC_H #define CRC_H #include "common.h" extern void crc_init(void); extern uint8_t calc_crc8(const uint8_t *buf, uint32_t len); extern uint16_t calc_crc16(const uint8_t *buf, uint32_t len); #endif /* CRC_H */ flake-0.11/libflake/flake.h0000644000175000017500000001432710655263114015145 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef FLAKE_H #define FLAKE_H #define FLAKE_STRINGIFY(s) FLAKE_TOSTRING(s) #define FLAKE_TOSTRING(s) #s #define FLAKE_VERSION 0.11 #define FLAKE_IDENT "Flake" FLAKE_STRINGIFY(FLAKE_VERSION) #define FLAKE_ORDER_METHOD_MAX 0 #define FLAKE_ORDER_METHOD_EST 1 #define FLAKE_ORDER_METHOD_2LEVEL 2 #define FLAKE_ORDER_METHOD_4LEVEL 3 #define FLAKE_ORDER_METHOD_8LEVEL 4 #define FLAKE_ORDER_METHOD_SEARCH 5 #define FLAKE_ORDER_METHOD_LOG 6 #define FLAKE_STEREO_METHOD_INDEPENDENT 0 #define FLAKE_STEREO_METHOD_ESTIMATE 1 #define FLAKE_PREDICTION_NONE 0 #define FLAKE_PREDICTION_FIXED 1 #define FLAKE_PREDICTION_LEVINSON 2 typedef struct FlakeEncodeParams { // compression quality // set by user prior to calling flake_encode_init // standard values are 0 to 8 // 0 is lower compression, faster encoding // 8 is higher compression, slower encoding // extended values 9 to 12 are slower and/or use // higher prediction orders int compression; // prediction order selection method // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. // valid values are 0 to 5 // 0 = use maximum order only // 1 = use estimation // 2 = 2-level // 3 = 4-level // 4 = 8-level // 5 = full search // 6 = log search int order_method; // stereo decorrelation method // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. // valid values are 0 to 2 // 0 = independent L+R channels // 1 = mid-side encoding int stereo_method; // block size in samples // set by the user prior to calling flake_encode_init // if set to 0, a block size is chosen based on block_time_ms // can also be changed by user before encoding a frame int block_size; // block time in milliseconds // set by the user prior to calling flake_encode_init // used to calculate block_size based on sample rate // can also be changed by user before encoding a frame int block_time_ms; // padding size in bytes // set by the user prior to calling flake_encode_init // if set to less than 0, defaults to 4096 int padding_size; // maximum encoded frame size // this is set by flake_encode_init based on input audio format // it can be used by the user to allocate an output buffer int max_frame_size; // minimum prediction order // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. // valid values are 0 to 4 for fixed prediction and 1 to 32 for non-fixed int min_prediction_order; // maximum prediction order // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. // valid values are 0 to 4 for fixed prediction and 1 to 32 for non-fixed int max_prediction_order; // type of linear prediction // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. // 0 = fixed prediction // 1 = Levinson-Durbin recursion int prediction_type; // minimum partition order // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. // valid values are 0 to 8 int min_partition_order; // maximum partition order // set by user prior to calling flake_encode_init // if set to less than 0, it is chosen based on compression. // valid values are 0 to 8 int max_partition_order; // whether to use variable block sizes // set by user prior to calling flake_encode_init // 0 = fixed block size // 1 = variable block size int variable_block_size; } FlakeEncodeParams; typedef struct FlakeContext { // number of audio channels // set by user prior to calling flake_encode_init // valid values are 1 to 8 int channels; // audio sample rate in Hz // set by user prior to calling flake_encode_init int sample_rate; // sample size in bits // set by user prior to calling flake_encode_init // only 16-bit is currently supported int bits_per_sample; // total stream samples // set by user prior to calling flake_encode_init // if 0, stream length is unknown unsigned int samples; FlakeEncodeParams params; // maximum frame size in bytes // set by flake_encode_init // this can be used to allocate memory for output int max_frame_size; // MD5 digest // set by flake_encode_close; unsigned char md5digest[16]; // header bytes // allocated by flake_encode_init and freed by flake_encode_close unsigned char *header; // encoding context, which is hidden from the user // allocated by flake_encode_init and freed by flake_encode_close void *private_ctx; } FlakeContext; /** * Sets encoding defaults based on compression level * params->compression must be set prior to calling */ extern int flake_set_defaults(FlakeEncodeParams *params); /** * Validates encoding parameters * @return -1 if error. 0 if ok. 1 if ok but non-Subset. */ extern int flake_validate_params(FlakeContext *s); extern int flake_encode_init(FlakeContext *s); extern int flake_encode_frame(FlakeContext *s, unsigned char *frame_buffer, short *samples); extern void flake_encode_close(FlakeContext *s); #endif /* FLAKE_H */ flake-0.11/libflake/crc.c0000644000175000017500000000426410655263114014624 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "common.h" #include "crc.h" static void crc_init_table(uint16_t *table, int bits, int poly) { int i, j, crc; poly = (poly + (1<> (bits - 8)) ^ *data++; assert(v2 < 256); crc = v1 ^ table[v2]; } return crc; } uint8_t calc_crc8(const uint8_t *data, uint32_t len) { uint8_t crc; if(data == NULL) return 0; crc = calc_crc(crc8tab, 8, data, len); return crc; } uint16_t calc_crc16(const uint8_t *data, uint32_t len) { uint16_t crc; if(data == NULL) return 0; crc = calc_crc(crc16tab, 16, data, len); return crc; } flake-0.11/libflake/vbs.h0000644000175000017500000000171510655263114014652 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef VBS_H #define VBS_H #include "common.h" extern int encode_frame_vbs(FlakeContext *s, uint8_t *frame_buffer, int16_t *samples); #endif /* VBS_H */ flake-0.11/libflake/lpc.c0000644000175000017500000001503610655263114014632 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "common.h" #include "flake.h" #include "lpc.h" /** * Apply Welch window function to audio block */ static inline void apply_welch_window(const int32_t *data, int len, double *w_data) { int i; double c; c = (2.0 / (len - 1.0)) - 1.0; for(i=0; i<(len >> 1); i++) { double w = 1.0 - ((c-i) * (c-i)); w_data[i] = data[i] * w; w_data[len-1-i] = data[len-1-i] * w; } } /** * Calculates autocorrelation data from audio samples * A Welch window function is applied before calculation. */ static void compute_autocorr(const int32_t *data, int len, int lag, double *autoc) { int i, j; double *data1; double temp, temp2; data1 = malloc((len+16) * sizeof(double)); apply_welch_window(data, len, data1); data1[len] = 0; for (i=0; i<=lag; ++i) { temp = 1.0; temp2 = 1.0; for (j=0; j<=lag-i; ++j) temp += data1[j+i] * data1[j]; for (j=lag+1; j<=len-1; j+=2) { temp += data1[j] * data1[j-i]; temp2 += data1[j+1] * data1[j+1-i]; } autoc[i] = temp + temp2; } free(data1); } /** * Levinson-Durbin recursion. * Produces LPC coefficients from autocorrelation data. */ static void compute_lpc_coefs(const double *autoc, int max_order, double *ref, double lpc[][MAX_LPC_ORDER]) { int i, j, i2; double r, err, tmp; double lpc_tmp[MAX_LPC_ORDER]; for(i=0; i> 1); lpc_tmp[i] = r; for(j=0; j=0; i--) { if(fabs(ref[i]) > 0.10) { order_est = i+1; break; } } // Levinson recursion compute_lpc_coefs(NULL, order_est, ref, lpc); return order_est; } /** * Quantize LPC coefficients */ static void quantize_lpc_coefs(double *lpc_in, int order, int precision, int32_t *lpc_out, int *shift) { int i; double d, cmax, error; int32_t qmax; int sh, q; // define maximum levels qmax = (1 << (precision - 1)) - 1; // find maximum coefficient value cmax = 0.0; for(i=0; i cmax) cmax = d; } // if maximum value quantizes to zero, return all zeros if(cmax * (1 << 15) < 1.0) { *shift = 0; memset(lpc_out, 0, sizeof(int32_t) * order); return; } // calculate level shift which scales max coeff to available bits sh = 15; while((cmax * (1 << sh) > qmax) && (sh > 0)) { sh--; } // since negative shift values are unsupported in decoder, scale down // coefficients instead if(sh == 0 && cmax > qmax) { double scale = ((double)qmax) / cmax; for(i=0; i qmax) q = qmax; error -= q; lpc_out[i] = q; } *shift = sh; } /** * Calculate LPC coefficients for multiple orders */ int lpc_calc_coefs(const int32_t *samples, int blocksize, int max_order, int precision, int omethod, int32_t coefs[][MAX_LPC_ORDER], int *shift) { double autoc[MAX_LPC_ORDER+1]; double lpc[MAX_LPC_ORDER][MAX_LPC_ORDER]; int i; int opt_order; compute_autocorr(samples, blocksize, max_order+1, autoc); opt_order = max_order; if(omethod == FLAKE_ORDER_METHOD_EST) { opt_order = compute_lpc_coefs_est(autoc, max_order, lpc); } else { compute_lpc_coefs(autoc, max_order, NULL, lpc); } switch(omethod) { case FLAKE_ORDER_METHOD_MAX: case FLAKE_ORDER_METHOD_EST: i = opt_order-1; quantize_lpc_coefs(lpc[i], i+1, precision, coefs[i], &shift[i]); break; default: for(i=0; i #include "flake.h" #include "rice.h" #include "lpc.h" #include "md5.h" #define FLAC_MAX_CH 8 #define FLAC_MIN_BLOCKSIZE 16 #define FLAC_MAX_BLOCKSIZE 65535 #define FLAC_SUBFRAME_CONSTANT 0 #define FLAC_SUBFRAME_VERBATIM 1 #define FLAC_SUBFRAME_FIXED 8 #define FLAC_SUBFRAME_LPC 32 #define FLAC_CHMODE_NOT_STEREO 0 #define FLAC_CHMODE_LEFT_RIGHT 1 #define FLAC_CHMODE_LEFT_SIDE 8 #define FLAC_CHMODE_RIGHT_SIDE 9 #define FLAC_CHMODE_MID_SIDE 10 #define FLAC_STREAM_MARKER 0x664C6143 struct BitWriter; typedef struct FlacSubframe { int type; int type_code; int order; int obits; int32_t coefs[MAX_LPC_ORDER]; int shift; int32_t samples[FLAC_MAX_BLOCKSIZE]; int32_t residual[FLAC_MAX_BLOCKSIZE]; RiceContext rc; } FlacSubframe; typedef struct FlacFrame { int blocksize; int bs_code[2]; int ch_mode; int ch_order[2]; uint8_t crc8; FlacSubframe subframes[FLAC_MAX_CH]; } FlacFrame; typedef struct FlacEncodeContext { int channels; int ch_code; int samplerate; int sr_code[2]; int bps; int bps_code; uint32_t sample_count; FlakeEncodeParams params; int max_frame_size; int lpc_precision; uint32_t frame_count; FlacFrame frame; MD5Context md5ctx; struct BitWriter *bw; } FlacEncodeContext; extern int encode_frame(FlakeContext *s, uint8_t *frame_buffer, int16_t *samples); #endif /* FLAC_H */ flake-0.11/libflake/optimize.c0000644000175000017500000002374210655263114015717 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "common.h" #include "flake.h" #include "optimize.h" #include "encode.h" #include "lpc.h" #include "rice.h" static void encode_residual_verbatim(int32_t res[], int32_t smp[], int n) { memcpy(res, smp, n*sizeof(int32_t)); } static void encode_residual_fixed(int32_t res[], int32_t smp[], int n, int order) { int i; switch(order) { case 0: memcpy(res, smp, n*sizeof(int32_t)); return; case 1: res[0] = smp[0]; for(i=1; i> shift); } } int encode_residual(FlacEncodeContext *ctx, int ch) { int i; FlacFrame *frame; FlacSubframe *sub; int32_t coefs[MAX_LPC_ORDER][MAX_LPC_ORDER]; int shift[MAX_LPC_ORDER]; int n, max_order, opt_order, min_porder, max_porder; int min_order; int32_t *res, *smp; int est_order, omethod; frame = &ctx->frame; sub = &frame->subframes[ch]; res = sub->residual; smp = sub->samples; n = frame->blocksize; // CONSTANT for(i=1; itype = sub->type_code = FLAC_SUBFRAME_CONSTANT; res[0] = smp[0]; return sub->obits; } // VERBATIM if(n < 5 || ctx->params.prediction_type == FLAKE_PREDICTION_NONE) { sub->type = sub->type_code = FLAC_SUBFRAME_VERBATIM; encode_residual_verbatim(res, smp, n); return sub->obits * n; } omethod = ctx->params.order_method; min_order = ctx->params.min_prediction_order; max_order = ctx->params.max_prediction_order; opt_order = max_order; min_porder = ctx->params.min_partition_order; max_porder = ctx->params.max_partition_order; // FIXED if(ctx->params.prediction_type == FLAKE_PREDICTION_FIXED || n <= max_order) { uint32_t bits[5]; if(max_order > 4) max_order = 4; opt_order = min_order; bits[opt_order] = UINT32_MAX; for(i=min_order; i<=max_order; i++) { encode_residual_fixed(res, smp, n, i); bits[i] = calc_rice_params_fixed(&sub->rc, min_porder, max_porder, res, n, i, sub->obits); if(bits[i] < bits[opt_order]) { opt_order = i; } } sub->order = opt_order; sub->type = FLAC_SUBFRAME_FIXED; sub->type_code = sub->type | sub->order; if(sub->order != max_order) { encode_residual_fixed(res, smp, n, sub->order); return calc_rice_params_fixed(&sub->rc, min_porder, max_porder, res, n, sub->order, sub->obits); } return bits[sub->order]; } // LPC est_order = lpc_calc_coefs(smp, n, max_order, ctx->lpc_precision, omethod, coefs, shift); if(omethod == FLAKE_ORDER_METHOD_MAX) { // always use maximum order opt_order = max_order; } else if(omethod == FLAKE_ORDER_METHOD_EST) { // estimated order opt_order = est_order; } else if(omethod == FLAKE_ORDER_METHOD_2LEVEL || omethod == FLAKE_ORDER_METHOD_4LEVEL || omethod == FLAKE_ORDER_METHOD_8LEVEL) { int levels = 1 << (omethod-1); uint32_t bits[8]; int order; int opt_index = levels-1; opt_order = max_order-1; bits[opt_index] = UINT32_MAX; for(i=opt_index; i>=0; i--) { order = min_order + (((max_order-min_order+1) * (i+1)) / levels)-1; if(order < 0) order = 0; encode_residual_lpc(res, smp, n, order+1, coefs[order], shift[order]); bits[i] = calc_rice_params_lpc(&sub->rc, min_porder, max_porder, res, n, order+1, sub->obits, ctx->lpc_precision); if(bits[i] < bits[opt_index]) { opt_index = i; opt_order = order; } } opt_order++; } else if(omethod == FLAKE_ORDER_METHOD_SEARCH) { // brute-force optimal order search uint32_t bits[MAX_LPC_ORDER]; opt_order = 0; bits[0] = UINT32_MAX; for(i=0; irc, min_porder, max_porder, res, n, i+1, sub->obits, ctx->lpc_precision); if(bits[i] < bits[opt_order]) { opt_order = i; } } opt_order++; } else if(omethod == FLAKE_ORDER_METHOD_LOG) { // log search (written by Michael Niedermayer for FFmpeg) uint32_t bits[MAX_LPC_ORDER]; int step; opt_order = min_order - 1 + (max_order-min_order)/3; memset(bits, -1, sizeof(bits)); for(step=16; step>0; step>>=1){ int last = opt_order; for(i=last-step; i<=last+step; i+= step){ if(i=max_order || bits[i] < UINT32_MAX) continue; encode_residual_lpc(res, smp, n, i+1, coefs[i], shift[i]); bits[i] = calc_rice_params_lpc(&sub->rc, min_porder, max_porder, res, n, i+1, sub->obits, ctx->lpc_precision); if(bits[i] < bits[opt_order]) { opt_order = i; } } } opt_order++; } else { return -1; } sub->order = opt_order; sub->type = FLAC_SUBFRAME_LPC; sub->type_code = sub->type | (sub->order-1); sub->shift = shift[sub->order-1]; for(i=0; iorder; i++) { sub->coefs[i] = coefs[sub->order-1][i]; } encode_residual_lpc(res, smp, n, sub->order, sub->coefs, sub->shift); return calc_rice_params_lpc(&sub->rc, min_porder, max_porder, res, n, sub->order, sub->obits, ctx->lpc_precision); } void reencode_residual_verbatim(FlacEncodeContext *ctx, int ch) { FlacFrame *frame; FlacSubframe *sub; frame = &ctx->frame; sub = &frame->subframes[ch]; sub->type = sub->type_code = FLAC_SUBFRAME_VERBATIM; encode_residual_verbatim(sub->residual, sub->samples, frame->blocksize); } flake-0.11/libflake/lpc.h0000644000175000017500000000213510655263114014633 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef LPC_H #define LPC_H #include "common.h" #define MAX_LPC_ORDER 32 extern int lpc_calc_coefs(const int32_t *samples, int blocksize, int max_order, int precision, int omethod, int32_t coefs[][MAX_LPC_ORDER], int *shift); #endif /* LPC_H */ flake-0.11/libflake/md5.h0000644000175000017500000000152710655263114014546 0ustar justinjustin/* * This is an implementation of the RSA Data Security, Inc. * MD5 Message-Digest Algorithm. * * Written by Solar Designer in 2001, and placed * in the public domain. There's absolutely no warranty. * * Modified in 2006 by Justin Ruggles. * Still in the public domain. Still no warranty. */ #ifndef MD5_H #define MD5_H #include "common.h" typedef struct { uint32_t lo, hi; uint32_t a, b, c, d; uint8_t buffer[64]; uint32_t block[16]; } MD5Context; extern void md5_init(MD5Context *ctx); extern void md5_update(MD5Context *ctx, const void *data, uint32_t size); extern void md5_final(uint8_t *result, MD5Context *ctx); extern void md5_accumulate(MD5Context *ctx, const void *signal, int ch, int nsamples); extern void md5_print(uint8_t digest[16]); #endif /* MD5_H */ flake-0.11/libflake/Makefile0000644000175000017500000000224510655263114015346 0ustar justinjustin# # Flake Library Makefile # include ../config.mak CFLAGS=$(OPTFLAGS) -I. -I.. -I$(SRC_PATH)/libflake \ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_ISOC9X_SOURCE \ -DHAVE_CONFIG_H OBJS= crc.o encode.o lpc.o md5.o optimize.o rice.o vbs.o \ HEADERS = flake.h NAME=flake SRC_DIR = $(SRC_PATH)/lib$(NAME) VPATH = $(SRC_DIR) SRCS := $(OBJS:.o=.c) all: $(EXTRADEPS) $(LIB) $(LIB): $(OBJS) rm -f $@ $(AR) rc $@ $^ $(EXTRAOBJS) $(RANLIB) $@ %.o: %.c $(CC) $(CFLAGS) $(LIBOBJFLAGS) -c -o $@ $< depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend dep: depend clean: rm -f *.o *.d *~ *.a *.lib *.def *.exp distclean: clean rm -f .depend install: install-libs install-headers install-libs: $(LIB) install -d "$(libdir)" install -m 644 $(LIB) "$(libdir)" $(LIB_INSTALL_EXTRA_CMD) install-headers: install -d "$(incdir)" install -m 644 $(addprefix "$(SRC_DIR)"/,$(HEADERS)) "$(incdir)" uninstall: uninstall-libs uninstall-headers uninstall-libs: -rm -f "$(libdir)/$(LIB)" uninstall-headers: rm -f "$(addprefix $(incdir)/,$(HEADERS))" ../config.mak: touch ../config.mak # # include dependency files if they exist # ifneq ($(wildcard .depend),) include .depend endif flake-0.11/libflake/md5.c0000644000175000017500000001774110655263114014546 0ustar justinjustin/* * This is an implementation of the RSA Data Security, Inc. * MD5 Message-Digest Algorithm. * * Written by Solar Designer in 2001, and placed * in the public domain. There's absolutely no warranty. * * Modified in 2006 by Justin Ruggles. * Still in the public domain. Still no warranty. */ #include "common.h" #include "md5.h" #include "bswap.h" /* * The basic MD5 functions. * * F is optimized compared to its RFC 1321 definition just like in Colin * Plumb's implementation. */ #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) #define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) #define H(x, y, z) ((x) ^ (y) ^ (z)) #define I(x, y, z) ((y) ^ ((x) | ~(z))) /* * The MD5 transformation for all four rounds. */ #define STEP(f, a, b, c, d, x, t, s) \ (a) += f((b), (c), (d)) + (x) + (t); \ (a) = (((a) << (s)) | (((a) & 0xFFFFFFFF) >> (32 - (s)))); \ (a) += (b); /* * SET reads 4 input bytes in little-endian byte order and stores them * in a properly aligned word in host byte order. */ #define SET(n) \ (ctx->block[(n)] = \ (uint32_t)ptr[(n) * 4] | \ ((uint32_t)ptr[(n) * 4 + 1] << 8) | \ ((uint32_t)ptr[(n) * 4 + 2] << 16) | \ ((uint32_t)ptr[(n) * 4 + 3] << 24)) #define GET(n) \ (ctx->block[(n)]) /* * This processes one or more 64-byte data blocks, but does NOT update * the bit counters. There are no alignment requirements. */ static const void * body(MD5Context *ctx, const void *data, uint32_t size) { const uint8_t *ptr; uint32_t a, b, c, d; uint32_t saved_a, saved_b, saved_c, saved_d; ptr = data; a = ctx->a; b = ctx->b; c = ctx->c; d = ctx->d; do { saved_a = a; saved_b = b; saved_c = c; saved_d = d; // Round 1 STEP(F, a, b, c, d, SET( 0), 0xD76AA478, 7) STEP(F, d, a, b, c, SET( 1), 0xE8C7B756, 12) STEP(F, c, d, a, b, SET( 2), 0x242070DB, 17) STEP(F, b, c, d, a, SET( 3), 0xC1BDCEEE, 22) STEP(F, a, b, c, d, SET( 4), 0xF57C0FAF, 7) STEP(F, d, a, b, c, SET( 5), 0x4787C62A, 12) STEP(F, c, d, a, b, SET( 6), 0xA8304613, 17) STEP(F, b, c, d, a, SET( 7), 0xFD469501, 22) STEP(F, a, b, c, d, SET( 8), 0x698098D8, 7) STEP(F, d, a, b, c, SET( 9), 0x8B44F7AF, 12) STEP(F, c, d, a, b, SET(10), 0xFFFF5BB1, 17) STEP(F, b, c, d, a, SET(11), 0x895CD7BE, 22) STEP(F, a, b, c, d, SET(12), 0x6B901122, 7) STEP(F, d, a, b, c, SET(13), 0xFD987193, 12) STEP(F, c, d, a, b, SET(14), 0xA679438E, 17) STEP(F, b, c, d, a, SET(15), 0x49B40821, 22) // Round 2 STEP(G, a, b, c, d, GET( 1), 0xF61E2562, 5) STEP(G, d, a, b, c, GET( 6), 0xC040B340, 9) STEP(G, c, d, a, b, GET(11), 0x265E5A51, 14) STEP(G, b, c, d, a, GET( 0), 0xE9B6C7AA, 20) STEP(G, a, b, c, d, GET( 5), 0xD62F105D, 5) STEP(G, d, a, b, c, GET(10), 0x02441453, 9) STEP(G, c, d, a, b, GET(15), 0xD8A1E681, 14) STEP(G, b, c, d, a, GET( 4), 0xE7D3FBC8, 20) STEP(G, a, b, c, d, GET( 9), 0x21E1CDE6, 5) STEP(G, d, a, b, c, GET(14), 0xC33707D6, 9) STEP(G, c, d, a, b, GET( 3), 0xF4D50D87, 14) STEP(G, b, c, d, a, GET( 8), 0x455A14ED, 20) STEP(G, a, b, c, d, GET(13), 0xA9E3E905, 5) STEP(G, d, a, b, c, GET( 2), 0xFCEFA3F8, 9) STEP(G, c, d, a, b, GET( 7), 0x676F02D9, 14) STEP(G, b, c, d, a, GET(12), 0x8D2A4C8A, 20) // Round 3 STEP(H, a, b, c, d, GET( 5), 0xFFFA3942, 4) STEP(H, d, a, b, c, GET( 8), 0x8771F681, 11) STEP(H, c, d, a, b, GET(11), 0x6D9D6122, 16) STEP(H, b, c, d, a, GET(14), 0xFDE5380C, 23) STEP(H, a, b, c, d, GET( 1), 0xA4BEEA44, 4) STEP(H, d, a, b, c, GET( 4), 0x4BDECFA9, 11) STEP(H, c, d, a, b, GET( 7), 0xF6BB4B60, 16) STEP(H, b, c, d, a, GET(10), 0xBEBFBC70, 23) STEP(H, a, b, c, d, GET(13), 0x289B7EC6, 4) STEP(H, d, a, b, c, GET( 0), 0xEAA127FA, 11) STEP(H, c, d, a, b, GET( 3), 0xD4EF3085, 16) STEP(H, b, c, d, a, GET( 6), 0x04881D05, 23) STEP(H, a, b, c, d, GET( 9), 0xD9D4D039, 4) STEP(H, d, a, b, c, GET(12), 0xE6DB99E5, 11) STEP(H, c, d, a, b, GET(15), 0x1FA27CF8, 16) STEP(H, b, c, d, a, GET( 2), 0xC4AC5665, 23) // Round 4 STEP(I, a, b, c, d, GET( 0), 0xF4292244, 6) STEP(I, d, a, b, c, GET( 7), 0x432AFF97, 10) STEP(I, c, d, a, b, GET(14), 0xAB9423A7, 15) STEP(I, b, c, d, a, GET( 5), 0xFC93A039, 21) STEP(I, a, b, c, d, GET(12), 0x655B59C3, 6) STEP(I, d, a, b, c, GET( 3), 0x8F0CCC92, 10) STEP(I, c, d, a, b, GET(10), 0xFFEFF47D, 15) STEP(I, b, c, d, a, GET( 1), 0x85845DD1, 21) STEP(I, a, b, c, d, GET( 8), 0x6FA87E4F, 6) STEP(I, d, a, b, c, GET(15), 0xFE2CE6E0, 10) STEP(I, c, d, a, b, GET( 6), 0xA3014314, 15) STEP(I, b, c, d, a, GET(13), 0x4E0811A1, 21) STEP(I, a, b, c, d, GET( 4), 0xF7537E82, 6) STEP(I, d, a, b, c, GET(11), 0xBD3AF235, 10) STEP(I, c, d, a, b, GET( 2), 0x2AD7D2BB, 15) STEP(I, b, c, d, a, GET( 9), 0xEB86D391, 21) a += saved_a; b += saved_b; c += saved_c; d += saved_d; ptr += 64; } while(size -= 64); ctx->a = a; ctx->b = b; ctx->c = c; ctx->d = d; return ptr; } void md5_init(MD5Context *ctx) { ctx->a = 0x67452301; ctx->b = 0xefcdab89; ctx->c = 0x98badcfe; ctx->d = 0x10325476; ctx->lo = 0; ctx->hi = 0; } void md5_update(MD5Context *ctx, const void *data, uint32_t size) { uint32_t saved_lo; uint32_t used, free; saved_lo = ctx->lo; if((ctx->lo = (saved_lo + size) & 0x1FFFFFFF) < saved_lo) ctx->hi++; ctx->hi += size >> 29; used = saved_lo & 0x3f; if(used) { free = 64 - used; if(size < free) { memcpy(&ctx->buffer[used], data, size); return; } memcpy(&ctx->buffer[used], data, free); data = (uint8_t *)data + free; size -= free; body(ctx, ctx->buffer, 64); } if(size >= 64) { data = body(ctx, data, size & ~(uint32_t)0x3f); size &= 0x3f; } memcpy(ctx->buffer, data, size); } void md5_final(uint8_t *result, MD5Context *ctx) { uint32_t used, free; used = ctx->lo & 0x3f; ctx->buffer[used++] = 0x80; free = 64 - used; if(free < 8) { memset(&ctx->buffer[used], 0, free); body(ctx, ctx->buffer, 64); used = 0; free = 64; } memset(&ctx->buffer[used], 0, free - 8); ctx->lo <<= 3; ctx->buffer[56] = ctx->lo; ctx->buffer[57] = ctx->lo >> 8; ctx->buffer[58] = ctx->lo >> 16; ctx->buffer[59] = ctx->lo >> 24; ctx->buffer[60] = ctx->hi; ctx->buffer[61] = ctx->hi >> 8; ctx->buffer[62] = ctx->hi >> 16; ctx->buffer[63] = ctx->hi >> 24; body(ctx, ctx->buffer, 64); result[0] = ctx->a; result[1] = ctx->a >> 8; result[2] = ctx->a >> 16; result[3] = ctx->a >> 24; result[4] = ctx->b; result[5] = ctx->b >> 8; result[6] = ctx->b >> 16; result[7] = ctx->b >> 24; result[8] = ctx->c; result[9] = ctx->c >> 8; result[10] = ctx->c >> 16; result[11] = ctx->c >> 24; result[12] = ctx->d; result[13] = ctx->d >> 8; result[14] = ctx->d >> 16; result[15] = ctx->d >> 24; memset(ctx, 0, sizeof(*ctx)); } /** * Run md5_update on the audio signal byte stream */ void md5_accumulate(MD5Context *ctx, const void *signal, int ch, int nsamples) { int data_bytes = ch * nsamples * 2; #ifdef WORDS_BIGENDIAN int i; uint16_t *sig16 = malloc(data_bytes); memcpy(sig16, signal, data_bytes); for(i=0; i> 3; int64_t res[8]; int layout[8]; int16_t *sptr, *sptr0, *sptr1, *sptr2; // calculate absolute sum of 2nd order residual for(i=0; i<8; i++) { sptr = &samples[i*n*channels]; res[i] = 0; for(ch=0; ch SPLIT_THRESHOLD) { layout[i+1] = 1; } } // generate frame count and frame sizes from layout frames[0] = 0; memset(sizes, 0, 8 * sizeof(int)); for(i=0; i<8; i++) { if(layout[i]) { frames[0]++; } sizes[frames[0]-1] += n; } } static void split_frame_v2(FlakeContext *s, int16_t *samples, int *frames, int sizes[8]) { int fsizes[4][8]; int layout[8]; int i, j, n, ch; FlacEncodeContext *ctx = (FlacEncodeContext *) s->private_ctx; ch = ctx->channels; // encode for each level to get sizes for(i=0; i<4; i++) { int levels, bs; levels = (1<params.block_size /= levels; bs = s->params.block_size; for(j=0; jparams.block_size *= levels; } // initialize layout for(i=0; i<8; i++) layout[i] = 1; // level 3 merge if(fsizes[2][0] < (fsizes[3][0]+fsizes[3][1])) { layout[1] = 0; } if(fsizes[2][1] < (fsizes[3][2]+fsizes[3][3])) { layout[3] = 0; } if(fsizes[2][2] < (fsizes[3][4]+fsizes[3][5])) { layout[5] = 0; } if(fsizes[2][3] < (fsizes[3][6]+fsizes[3][7])) { layout[7] = 0; } // level 2 merge if(layout[1] == 0 && layout[3] == 0) { if(fsizes[1][0] < (fsizes[2][0]+fsizes[2][1])) { layout[2] = 0; } } if(layout[5] == 0 && layout[7] == 0) { if(fsizes[1][1] < (fsizes[2][2]+fsizes[2][3])) { layout[6] = 0; } } // level 1 merge if(layout[2] == 0 && layout[6] == 0) { if(fsizes[0][0] < (fsizes[1][0]+fsizes[1][1])) { layout[4] = 0; } } // generate frame count and frame sizes from layout n = s->params.block_size >> 3; frames[0] = 0; memset(sizes, 0, 8 * sizeof(int)); for(i=0; i<8; i++) { if(layout[i]) { frames[0]++; } sizes[frames[0]-1] += n; } } int encode_frame_vbs(FlakeContext *s, uint8_t *frame_buffer, int16_t *samples) { int fs; int frames; int sizes[8]; FlacEncodeContext *ctx; ctx = (FlacEncodeContext *) s->private_ctx; switch(ctx->params.variable_block_size) { case 1: split_frame_v1(samples, s->channels, s->params.block_size, &frames, sizes); break; case 2: split_frame_v2(s, samples, &frames, sizes); break; default: frames = 1; break; } if(frames > 1) { int i, fpos, spos, bs; fpos = 0; spos = 0; bs = s->params.block_size; for(i=0; iparams.block_size = sizes[i]; fs = encode_frame(s, &frame_buffer[fpos], &samples[spos*ctx->channels]); if(fs < 0) return -1; fpos += fs; spos += sizes[i]; } s->params.block_size = bs; assert(spos == bs); return fpos; } fs = encode_frame(s, frame_buffer, samples); return fs; } flake-0.11/libflake/optimize.h0000644000175000017500000000203710655263114015716 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef OPTIMIZE_H #define OPTIMIZE_H #include "common.h" #include "encode.h" extern int encode_residual(FlacEncodeContext *ctx, int ch); extern void reencode_residual_verbatim(FlacEncodeContext *ctx, int ch); #endif /* OPTIMIZE_H */ flake-0.11/libflake/rice.c0000644000175000017500000001063010655263114014771 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file rice.c * Functions for calculating optimal partition order and Rice parameters */ #include "common.h" #include "rice.h" int find_optimal_rice_param(uint32_t sum, int n) { int k, k_opt; uint32_t nbits[MAX_RICE_PARAM+1]; k_opt = 0; nbits[0] = UINT32_MAX; for(k=0; k<=MAX_RICE_PARAM; k++) { nbits[k] = rice_encode_count(sum, n, k); if(nbits[k] < nbits[k_opt]) { k_opt = k; } } return k_opt; } static uint32_t calc_optimal_rice_params(RiceContext *rc, int porder, uint32_t *sums, int n, int pred_order) { int i; int k, cnt, part; uint32_t all_bits; part = (1 << porder); all_bits = 0; cnt = (n >> porder) - pred_order; for(i=0; i> porder); k = find_optimal_rice_param(sums[i], cnt); rc->params[i] = k; all_bits += rice_encode_count(sums[i], cnt, k); } all_bits += (4 * part); rc->porder = porder; return all_bits; } static void calc_sums(int pmin, int pmax, uint32_t *data, int n, int pred_order, uint32_t sums[][MAX_PARTITIONS]) { int i, j; int parts, cnt; uint32_t *res; // sums for highest level parts = (1 << pmax); res = &data[pred_order]; cnt = (n >> pmax) - pred_order; for(i=0; i> pmax); if(i > 0) res = &data[i*cnt]; sums[pmax][i] = 0; for(j=0; j=pmin; i--) { parts = (1 << i); for(j=0; j= 0 && pmin <= MAX_PARTITION_ORDER); assert(pmax >= 0 && pmax <= MAX_PARTITION_ORDER); assert(pmin <= pmax); udata = malloc(n * sizeof(uint32_t)); for(i=0; i>31); } calc_sums(pmin, pmax, udata, n, pred_order, sums); opt_porder = pmin; bits[pmin] = UINT32_MAX; for(i=pmin; i<=pmax; i++) { bits[i] = calc_optimal_rice_params(&tmp_rc, i, sums[i], n, pred_order); if(bits[i] <= bits[opt_porder]) { opt_porder = i; *rc = tmp_rc; } } free(udata); return bits[opt_porder]; } static int get_max_p_order(int max_porder, int n, int order) { int porder = MIN(max_porder, log2i(n^(n-1))); if(order > 0) porder = MIN(porder, log2i(n/order)); return porder; } uint32_t calc_rice_params_fixed(RiceContext *rc, int pmin, int pmax, int32_t *data, int n, int pred_order, int bps) { uint32_t bits; pmin = get_max_p_order(pmin, n, pred_order); pmax = get_max_p_order(pmax, n, pred_order); bits = pred_order*bps + 6; bits += calc_rice_params(rc, pmin, pmax, data, n, pred_order); return bits; } uint32_t calc_rice_params_lpc(RiceContext *rc, int pmin, int pmax, int32_t *data, int n, int pred_order, int bps, int precision) { uint32_t bits; pmin = get_max_p_order(pmin, n, pred_order); pmax = get_max_p_order(pmax, n, pred_order); bits = pred_order*bps + 4 + 5 + pred_order*precision + 6; bits += calc_rice_params(rc, pmin, pmax, data, n, pred_order); return bits; } flake-0.11/Changelog0000644000175000017500000000140410655263114013743 0ustar justinjustinFlake TODO list --------------- - Apply feature updates from FFmpeg - Shared lib/DLL support - 24-bit/32-bit lossless - Raw audio input - AIFF input - Import FFmpeg's FLAC decoder for verification during encoding - Vorbis Comment tag support - Embedded CUESHEET support Flake Changelog --------------- version 0.11 : 5 July 2007 - Significant speed improvements - Added log search - Added variable block size encoding - Added level 99 high-compression level - Quiet encoding mode (no console output except errors) - Changed output file designation to "-o output.flac" - Changed order method option to "-m #" - Added support for encoding multiple files at once version 0.10 : 11 September 2006 (Initial SVN import) - New configure system - Separate library & console app flake-0.11/README0000644000175000017500000000151410655263114013013 0ustar justinjustin------------------------------------------------------------------------------- Flake: FLAC audio encoder The purpose of Flake is to be an alternative to the FLAC reference encoder with the goal of increasing encoding speed and implementing experimental features. Neither the program nor the library have stable interfaces. Therefore, the commandline options and the library API/ABI may change. After version 1.0 is released, this will become more stable. The FLAC format and reference encoder were created by Josh Coalson and are hosted by the Xiph.org Foundation. Many thanks! ------------------------------------------------------------------------------- Copyright (c) 2006-2007 Justin Ruggles http://flake-enc.sourceforge.net/ ------------------------------------------------------------------------------- flake-0.11/util/0000755000175000017500000000000010655263114013107 5ustar justinjustinflake-0.11/util/wavinfo.c0000644000175000017500000002661210655263114014733 0ustar justinjustin/** * Console WAV File Info Utility * * Copyright (c) 2006 Justin Ruggles */ #include "common.h" #include "wav.h" static char * get_format_name(int id) { if(id < 0x0000 || id > 0xFFFF) return NULL; switch(id) { case 0x0000: return "Microsoft Unknown Wave Format"; case 0x0001: return "Microsoft PCM"; case 0x0002: return "Microsoft ADPCM"; case 0x0003: return "IEEE Float"; case 0x0004: return "Compaq Computer VSELP"; case 0x0005: return "IBM CVSD"; case 0x0006: return "Microsoft A-Law"; case 0x0007: return "Microsoft mu-Law"; case 0x0008: return "Microsoft DTS"; case 0x0009: return "Microsoft DRM Encrypted Audio"; case 0x000A: return "Windows Media Audio 9 Voice"; case 0x000B: return "Windows Media RT Voice"; case 0x0010: return "OKI ADPCM"; case 0x0011: return "Intel DVI/IMA ADPCM"; case 0x0012: return "Videologic MediaSpace ADPCM"; case 0x0013: return "Sierra ADPCM"; case 0x0014: return "Antex G.723 ADPCM"; case 0x0015: return "DSP Solutions DigiSTD"; case 0x0016: return "DSP Solutions DigiFIX"; case 0x0017: return "Dialogic OKI ADPCM"; case 0x0018: return "MediaVision ADPCM"; case 0x0019: return "Hewlett-Packard CU"; case 0x0020: return "Yamaha ADPCM"; case 0x0021: return "Speech Compression Sonarc"; case 0x0022: return "DSP Group TrueSpeech"; case 0x0023: return "Echo Speech EchoSC1"; case 0x0024: return "Audiofile AF36"; case 0x0025: return "Audio Processing Technology APTX"; case 0x0026: return "AudioFile AF10"; case 0x0027: return "Prosody 1612"; case 0x0028: return "LRC"; case 0x0030: return "Dolby AC2"; case 0x0031: return "Microsoft GSM 6.10"; case 0x0032: return "MSNAudio"; case 0x0033: return "Antex ADPCME"; case 0x0034: return "Control Resources VQLPC"; case 0x0035: return "DigiREAL"; case 0x0036: return "DigiADPCM"; case 0x0037: return "Control Resources CR10"; case 0x0038: return "Natural MicroSystems VBXADPCM"; case 0x0039: return "Crystal IMA ADPCM"; case 0x003A: return "EchoSC3"; case 0x003B: return "Rockwell ADPCM"; case 0x003C: return "Rockwell Digit LK"; case 0x003D: return "Xebec"; case 0x0040: return "Antex Electronics G.721 ADPCM"; case 0x0041: return "G.728 CELP"; case 0x0042: return "MS G.723"; case 0x0043: return "MS G.723.1"; case 0x0044: return "MS G.729"; case 0x0045: return "SP G.726"; case 0x0050: return "MPEG Layer-2 or Layer-1"; case 0x0052: return "RT24"; case 0x0053: return "PAC"; case 0x0055: return "MPEG Layer-3"; case 0x0059: return "Lucent G.723"; case 0x0060: return "Cirrus"; case 0x0061: return "ESPCM"; case 0x0062: return "Voxware"; case 0x0063: return "Canopus Atrac"; case 0x0064: return "G.726 ADPCM"; case 0x0065: return "G.722 ADPCM"; case 0x0066: return "DSAT"; case 0x0067: return "DSAT Display"; case 0x0069: return "Voxware Byte Aligned"; case 0x0070: return "Voxware AC8"; case 0x0071: return "Voxware AC10"; case 0x0072: return "Voxware AC16"; case 0x0073: return "Voxware AC20"; case 0x0074: return "Voxware MetaVoice"; case 0x0075: return "Voxware MetaSound"; case 0x0076: return "Voxware RT29HW"; case 0x0077: return "Voxware VR12"; case 0x0078: return "Voxware VR18"; case 0x0079: return "Voxware TQ40"; case 0x0080: return "Softsound"; case 0x0081: return "Voxware TQ60"; case 0x0082: return "MSRT24"; case 0x0083: return "G.729A"; case 0x0084: return "MVI MV12"; case 0x0085: return "DF G.726"; case 0x0086: return "DF GSM610"; case 0x0088: return "ISIAudio"; case 0x0089: return "Onlive"; case 0x0091: return "SBC24"; case 0x0092: return "Dolby AC3 SPDIF"; case 0x0093: return "MediaSonic G.723"; case 0x0094: return "Aculab PLC Prosody 8kbps"; case 0x0097: return "ZyXEL ADPCM"; case 0x0098: return "Philips LPCBB"; case 0x0099: return "Packed"; case 0x00FF: return "AAC"; case 0x0100: return "Rhetorex ADPCM"; case 0x0101: return "IBM mu-law"; case 0x0102: return "IBM A-law"; case 0x0103: return "IBM AVC ADPCM"; case 0x0111: return "Vivo G.723"; case 0x0112: return "Vivo Siren"; case 0x0123: return "Digital G.723"; case 0x0125: return "Sanyo LD ADPCM"; case 0x0130: return "Sipro Lab Telecom ACELP NET / RealAudio 4.0/5.0)"; case 0x0131: return "Sipro Lab Telecom ACELP 4800"; case 0x0132: return "Sipro Lab Telecom ACELP 8V3"; case 0x0133: return "Sipro Lab Telecom G.729"; case 0x0134: return "Sipro Lab Telecom G.729A"; case 0x0135: return "Sipro Lab Telecom Kelvin"; case 0x0140: return "Windows Media Video V8"; case 0x0150: return "Qualcomm PureVoice"; case 0x0151: return "Qualcomm HalfRate"; case 0x0155: return "Ring Zero Systems TUB GSM"; case 0x0160: return "Microsoft Audio 1"; case 0x0161: return "Windows Media 7/8/9"; case 0x0162: return "Windows Media 9 Professional"; case 0x0163: return "Windows Media 9 Lossess"; case 0x0164: return "Windows Media Professional over S/PDIF"; case 0x0180: return "MPEG-2 AAC"; case 0x0190: return "DTS"; case 0x0200: return "Creative Labs ADPCM"; case 0x0202: return "Creative Labs FastSpeech8"; case 0x0203: return "Creative Labs FastSpeech10"; case 0x0210: return "UHER Informatic GmbH ADPCM"; case 0x0215: return "Ulead DV Audio NTSC"; case 0x0216: return "Ulead DV Audio PAL"; case 0x0220: return "Quarterdeck"; case 0x0230: return "I-link Worldwide VC"; case 0x0240: return "Aureal RAW Sport"; case 0x0250: return "Interactive Products HSX"; case 0x0251: return "Interactive Products RPELP"; case 0x0260: return "Consistent Software CS2"; case 0x0270: return "Sony SCX / RealAudio 8.0"; case 0x0271: return "Sony SCY"; case 0x0272: return "Sony ATRAC3"; case 0x0273: return "Sony SPC"; case 0x0300: return "Fujitsu FM Towns Snd"; case 0x0400: return "BTV Digital"; case 0x0401: return "Intel Music Coder"; case 0x0450: return "QDesign Music"; case 0x0680: return "VME VMPCM"; case 0x0681: return "AT&T Labs TPC"; case 0x08AE: return "ClearJump LiteWave"; case 0x1000: return "Olivetti GSM"; case 0x1001: return "Olivetti ADPCM"; case 0x1002: return "Olivetti CELP"; case 0x1003: return "Olivetti SBC"; case 0x1004: return "Olivetti OPR"; case 0x1100: return "L&H Codec"; case 0x1101: return "L&H CELP"; case 0x1102: return "L&H SBC 0x1102"; case 0x1103: return "L&H SBC 0x1103"; case 0x1104: return "L&H SBC 0x1104"; case 0x1400: return "Norris"; case 0x1401: return "AT&T ISIAudio"; case 0x1500: return "Soundspace Music Compression"; case 0x181C: return "VoxWare RT24 Speech"; case 0x1971: return "Sonic Foundry Perfect Clarity Audio (PCA)"; case 0x1FC4: return "NCT Soft ALF2CD"; case 0x2000: return "Dolby AC3"; case 0x2001: return "Dolby DTS"; case 0x2002: return "RealAudio 1.0 (14.4K)"; case 0x2003: return "RealAudio 2.0 (28.8K)"; case 0x2004: return "RealAudio G2 (Cook)"; case 0x2005: return "RealAudio 3.0 (DolbyNet AC3)"; case 0x2006: return "RealAudio 10.0 (LC-AAC)"; case 0x2007: return "RealAudio 10.0 (HE-AAC)"; case 0x2048: return "Sonic"; case 0x4143: return "Divio AAC"; case 0x4201: return "Nokia AMR"; case 0x566F: return "Vorbis"; case 0x5756: return "WavPack"; case 0x674F: return "Ogg Vorbis 1"; case 0x6750: return "Ogg Vorbis 2"; case 0x6751: return "Ogg Vorbis 3"; case 0x676F: return "Ogg Vorbis 1+"; case 0x6770: return "Ogg Vorbis 2+"; case 0x6771: return "Ogg Vorbis 3+"; case 0x7A21: return "Adaptive Multirate"; case 0x7A22: return "Adaptive Multirate w/ silence detection"; case 0x706D: return "AAC"; case 0x77A1: return "TTA"; case 0xA106: return "MPEG-4 AAC"; case 0xA109: return "Speex"; case 0xF1AC: return "FLAC"; case 0xFFFE: return "{ Extensible }"; case 0xFFFF: return "{ Development }"; default: return NULL; } } typedef struct WavInfo { char *fname; WavFile wf; } WavInfo; static void wavinfo_print(WavInfo *wi) { char *type; int samples, leftover; float playtime; WavFile *wf = &wi->wf; type = get_format_name(wf->format); printf("\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"); printf("File:\n"); printf(" Name: %s\n", wi->fname); if(wf->seekable) { printf(" File Size: %d\n", wf->file_size); } else { printf(" File Size: unknown\n"); } printf("Format:\n"); if(type == NULL) { printf(" Type: unknown - 0x%04X\n", wf->format); } else { printf(" Type: %s\n", type); } printf(" Channels: %d\n", wf->channels); printf(" Sample Rate: %d Hz\n", wf->sample_rate); printf(" Avg bytes/sec: %d\n", wf->bytes_per_sec); printf(" Block Align: %d bytes\n", wf->block_align); printf(" Bit Width: %d\n", wf->bit_width); printf("Data:\n"); printf(" Start: %d\n", wf->data_start); printf(" Data Size: %d\n", wf->data_size); leftover = wf->file_size - wf->data_size - wf->data_start; if(leftover < 0) { if(!wf->seekable) { printf(" [ warning! unable to verify true data size ]\n"); } else { printf(" [ warning! reported data size is larger than file size ]\n"); } } else if(leftover > 0) { printf(" Leftover: %d bytes\n", leftover); } if(wf->format == 0x0001 || wf->format == 0x0003) { samples = wf->data_size / wf->block_align; playtime = (float)samples / (float)wf->sample_rate; printf(" Samples: %d\n", samples); printf(" Playing Time: %0.2f sec\n", playtime); } else { printf(" Samples: unknown\n"); printf(" Playing Time: unknown\n"); } printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n"); } static void wavfile_error(char *msg) { if(msg != NULL) { fprintf(stderr, "%s\n", msg); } exit(1); } int main(int argc, char **argv) { FILE *fp; WavInfo wi; WavFile *wf = &wi.wf; // initialize WavInfo to zero memset(&wi, 0, sizeof(WavInfo)); // open file if(argc > 2) { wavfile_error("\nusage: wavinfo [test.wav]\n"); } if(argc == 2) { wi.fname = argv[1]; fp = fopen(wi.fname, "rb"); } else { wi.fname = "[stdin]"; fp = stdin; } if(!fp) wavfile_error("cannot open file"); wavfile_init(wf, fp); // print info wavinfo_print(&wi); fclose(fp); return 0; } flake-0.11/util/all-test.sh0000755000175000017500000000073410655263114015177 0ustar justinjustin#!/bin/sh # change location of binaries if necessary wavinfo="./wavinfo"; wavsize=$($wavinfo $1 | awk '/Data Size/ {print $3}'); playtime=$($wavinfo $1 | awk '/Playing Time/ {print $3}'); # not-as-accurate alternative for 16-bit 44100Hz stereo: #wavsize=$(echo -e "$(stat -c %s $1) - 44" | bc); #playtime=$(echo -e "scale=2\n$wavsize / (44100*4)" | bc)s; echo "$1"; echo "playing time: ${playtime}s"; echo "original audio size: $wavsize"; flac-test.sh $1 flake-test.sh $1 flake-0.11/util/flac-test.sh0000755000175000017500000000207010655263114015327 0ustar justinjustin#!/bin/sh # requirements: flac, time, awk, stat, bc # change location of binaries if necessary flac="flac"; wavinfo="./wavinfo"; enc="$flac -f $1 --no-seektable -o flac-"; dec="$flac -t flac-"; wavsize=$($wavinfo $1 | awk '/Data Size/ {print $3}'); playtime=$($wavinfo $1 | awk '/Playing Time/ {print $3}'); # not-as-accurate alternative for 16-bit 44100Hz stereo: #wavsize=$(echo -e "$(stat -c %s $1) - 44" | bc); #playtime=$(echo -e "scale=2\n$wavsize / (44100*4)" | bc)s; echo ""; echo "flac:"; echo ""; echo "level enc time bytes ratio kbps dec time"; echo "----- --------- -------- ----- ------ ---------"; for i in $(seq 0 8) ; do i0=$(printf "%02d" $i); time=$((time -p ${enc}$i0.flac -$i) 2>&1 | awk '/user/ {print $2}'); csize=$(stat -c %s flac-$i0.flac); ratio=$(echo -e "scale=3\n$csize/$wavsize" | bc); kbps=$(echo -e "scale=1\n$csize*8/($playtime*1000)" | bc); dtime=$((time -p ${dec}$i0.flac) 2>&1 | awk '/user/ {print $2}'); printf "%3d %8ss %8s %5s %6s %8ss\n" $i $time $csize 0$ratio $kbps $dtime; done; flake-0.11/util/flake-test.sh0000755000175000017500000000326110655263114015507 0ustar justinjustin#!/bin/sh # requirements: flac, flake, time, awk, stat, bc # change location of binaries if necessary flac="flac"; flake="../flake/flake"; wavinfo="./wavinfo"; enc="$flake $1 -o flake-"; dec="$flac -t flake-"; wavsize=$($wavinfo $1 | awk '/Data Size/ {print $3}'); playtime=$($wavinfo $1 | awk '/Playing Time/ {print $3}'); # not-as-accurate alternative for 16-bit 44100Hz stereo: #wavsize=$(echo -e "$(stat -c %s $1) - 44" | bc); #playtime=$(echo -e "scale=2\n$wavsize / (44100*4)" | bc)s; echo ""; echo "flake:" echo ""; echo "level enc time bytes ratio kbps dec time"; echo "----- --------- -------- ----- ------ ---------"; for i in $(seq 0 8) ; do i0=$(printf "%02d" $i); time=$((time -p ${enc}$i0.flac -$i) 2>&1 | awk '/user/ {print $2}'); csize=$(stat -c %s flake-$i0.flac); ratio=$(echo -e "scale=3\n$csize/$wavsize" | bc); kbps=$(echo -e "scale=1\n$csize*8/($playtime*1000)" | bc); dtime=$((time -p ${dec}$i0.flac) 2>&1 | awk '/user/ {print $2}'); printf "%3d %8ss %8s %5s %6s %8ss\n" $i $time $csize 0$ratio $kbps $dtime; done; echo ""; echo "flake (extended):"; echo ""; echo "level enc time bytes ratio kbps dec time"; echo "----- --------- -------- ----- ------ ---------"; for i in $(seq 9 12) ; do i0=$(printf "%02d" $i); time=$((time -p ${enc}$i0.flac -$i) 2>&1 | awk '/user/ {print $2}'); csize=$(stat -c %s flake-$i0.flac); ratio=$(echo -e "scale=3\n$csize/$wavsize" | bc); kbps=$(echo -e "scale=1\n$csize*8/($playtime*1000)" | bc); dtime=$((time -p ${dec}$i0.flac) 2>&1 | awk '/user/ {print $2}'); printf "%3d %8ss %8s %5s %6s %8ss\n" $i $time $csize 0$ratio $kbps $dtime; done; flake-0.11/util/Makefile0000644000175000017500000000127210655263114014551 0ustar justinjustin# # Flake Util Makefile # include ../config.mak CFLAGS=$(OPTFLAGS) -I. -I.. -I$(SRC_PATH)/flake \ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_ISOC9X_SOURCE \ -DHAVE_CONFIG_H LDFLAGS+= -g PROGS=wavinfo$(EXESUF) OBJS = wavinfo.o $(SRC_PATH)/flake/wav.o SRCS = $(OBJS:.o=.c) all: $(PROGS) wavinfo$(EXESUF): $(OBJS) $(CC) $(LDFLAGS) -o $@ $(OBJS) $(EXTRALIBS) %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< install: dep: depend depend: .depend .depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend clean: rm -f *.o *~ \ *.d *.a *.lib *.def *.exp \ $(PROGS) distclean: clean rm -f .depend ../config.* ../config.mak: touch ../config.mak ifneq ($(wildcard .depend),) include .depend endif flake-0.11/bswap.h0000644000175000017500000000173210655263114013422 0ustar justinjustin/** * @file bswap.h * byte swap. */ #ifndef BSWAP_H #define BSWAP_H #include "common.h" static inline uint16_t bswap_16(uint16_t x){ return (x>>8) | (x<<8); } static inline uint32_t bswap_32(uint32_t x){ x= ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF); return (x>>16) | (x<<16); } static inline uint64_t bswap_64(uint64_t x) { union { uint64_t ll; uint32_t l[2]; } w, r; w.ll = x; r.l[0] = bswap_32(w.l[1]); r.l[1] = bswap_32(w.l[0]); return r.ll; } // be2me ... BigEndian to MachineEndian // le2me ... LittleEndian to MachineEndian #ifdef WORDS_BIGENDIAN #define be2me_16(x) (x) #define be2me_32(x) (x) #define be2me_64(x) (x) #define le2me_16(x) bswap_16(x) #define le2me_32(x) bswap_32(x) #define le2me_64(x) bswap_64(x) #else #define be2me_16(x) bswap_16(x) #define be2me_32(x) bswap_32(x) #define be2me_64(x) bswap_64(x) #define le2me_16(x) (x) #define le2me_32(x) (x) #define le2me_64(x) (x) #endif #endif /* BSWAP_H */ flake-0.11/Makefile0000644000175000017500000000312110655263114013567 0ustar justinjustin# # Flake Main Makefile # include config.mak VPATH=$(SRC_PATH) CFLAGS=$(OPTFLAGS) -I. -I$(SRC_PATH) -I$(SRC_PATH)/libflake \ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_ISOC9X_SOURCE \ -DHAVE_CONFIG_H LDFLAGS+= -g FLAKE_LIBDIRS = -L./libflake FLAKE_LIBS = -lflake$(BUILDSUF) all: lib progs utils lib: $(MAKE) -C libflake all progs: $(MAKE) -C flake all utils: $(MAKE) -C util all .PHONY: install install: install-progs install-libs install-headers install-progs: progs $(MAKE) -C flake install install-libs: $(MAKE) -C libflake install-libs install-headers: $(MAKE) -C libflake install-headers uninstall: uninstall-progs uninstall-libs uninstall-headers uninstall-progs: $(MAKE) -C flake uninstall-progs uninstall-libs: $(MAKE) -C libflake uninstall-libs uninstall-headers: $(MAKE) -C libflake uninstall-headers dep: depend depend: $(MAKE) -C libflake depend $(MAKE) -C flake depend $(MAKE) -C util depend clean: $(MAKE) -C libflake clean $(MAKE) -C flake clean $(MAKE) -C util clean rm -f *.o *.d *~ distclean: clean $(MAKE) -C libflake distclean $(MAKE) -C flake distclean $(MAKE) -C util distclean rm -f .depend config.* # tar release (use 'make -k tar' on a checkouted tree) FILE=flake-$(shell grep "\#define FLAKE_VERSION " libflake/flake.h | \ cut -d " " -f 3 ) tar: distclean rm -rf /tmp/$(FILE) cp -r . /tmp/$(FILE) (tar --exclude config.mak --exclude .svn -C /tmp -jcvf $(FILE).tar.bz2 $(FILE) ) rm -rf /tmp/$(FILE) config.mak: touch config.mak .PHONY: lib ifneq ($(wildcard .depend),) include .depend endif flake-0.11/common.h0000644000175000017500000000436710655263114013605 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file common.h * Common header file */ #ifndef COMMON_H #define COMMON_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef M_SQRT2 #define M_SQRT2 1.41421356237309504880 #endif #ifndef EMULATE_INTTYPES #include #else #if defined(_WIN32) && defined(_MSC_VER) typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #endif #endif /* EMULATE_INTTYPES */ #define ABS(a) ((a) >= 0 ? (a) : (-(a))) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MIN(a,b) ((a) > (b) ? (b) : (a)) #define CLIP(x,min,max) MAX(MIN((x), (max)), (min)) static inline int log2i(uint32_t v) { int i; int n = 0; if(v & 0xffff0000){ v >>= 16; n += 16; } if(v & 0xff00){ v >>= 8; n += 8; } for(i=2; i<256; i<<=1) { if(v >= i) n++; else break; } return n; } #include // strnlen is a GNU extention. providing implementation if needed. #ifndef HAVE_STRNLEN static inline size_t strnlen(const char *s, size_t maxlen) { size_t i = 0; while((s[i] != '\0') && (i < maxlen)) i++; return i; } #elif !defined(__USE_GNU) extern size_t strnlen(const char *s, size_t maxlen); #endif #endif /* COMMON_H */ flake-0.11/flake/0000755000175000017500000000000010655263114013214 5ustar justinjustinflake-0.11/flake/flake.c0000644000175000017500000005270610655263114014454 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006-2007 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "common.h" #include /* used for binary mode piped i/o on Windows */ #ifdef _WIN32 #include #include #endif #include "bswap.h" #include "wav.h" #include "flake.h" #ifndef PATH_MAX #define PATH_MAX 255 #endif static void print_usage(FILE *out) { fprintf(out, "usage: flake [options] [-o output.flac]\n" "type 'flake -h' for more details.\n\n"); } static void print_help(FILE *out) { fprintf(out, "usage: flake [options] [-o output.flac]\n" "options:\n" " [-h] Print out list of commandline options\n" " [-q] Quiet mode\n" " [-p #] Padding bytes to put in header (default: 4096)\n" " [-0 ... -12] Compression level (default: 5)\n" " 0 = -b 1152 -t 1 -l 2,2 -m 0 -r 4,4 -s 0\n" " 1 = -b 1152 -t 1 -l 3,4 -m 1 -r 2,2 -s 1\n" " 2 = -b 1152 -t 1 -l 2,4 -m 1 -r 3 -s 1\n" " 3 = -b 4608 -t 2 -l 6 -m 1 -r 3 -s 1\n" " 4 = -b 4608 -t 2 -l 8 -m 1 -r 3 -s 1\n" " 5 = -b 4608 -t 2 -l 8 -m 1 -r 6 -s 1\n" " 6 = -b 4608 -t 2 -l 8 -m 2 -r 8 -s 1\n" " 7 = -b 4608 -t 2 -l 8 -m 3 -r 8 -s 1\n" " 8 = -b 4608 -t 2 -l 12 -m 3 -r 8 -s 1\n" " 9 = -b 4608 -t 2 -l 12 -m 6 -r 8 -s 1\n" " 10 = -b 4608 -t 2 -l 12 -m 5 -r 8 -s 1\n" " 11 = -b 4608 -t 2 -l 32 -m 6 -r 8 -s 1\n" " 12 = -b 4608 -t 2 -l 32 -m 5 -r 8 -s 1\n" " [-b #] Block size [16 - 65535] (default: 4608)\n" " [-t #] Prediction type\n" " 0 = no prediction / verbatim\n" " 1 = fixed prediction\n" " 2 = Levinson-Durbin recursion (default)\n" " [-l #[,#]] Prediction order {max} or {min},{max} (default: 1,8)\n" " [-m #] Prediction order selection method\n" " 0 = maximum\n" " 1 = estimate (default)\n" " 2 = 2-level\n" " 3 = 4-level\n" " 4 = 8-level\n" " 5 = full search\n" " 6 = log search\n" " [-r #[,#]] Rice partition order {max} or {min},{max} (default: 0,6)\n" " [-s #] Stereo decorrelation method\n" " 0 = independent L+R channels\n" " 1 = mid-side (default)\n" " [-v #] Variable block size\n" " 0 = fixed (default)\n" " 1 = variable, method 1\n" " 2 = variable, method 2\n" "\n"); } typedef struct FilePair { char *infile; char *outfile; FILE *ifp; FILE *ofp; } FilePair; typedef struct CommandOptions { FilePair *filelist; int input_count; int found_output; int compr; int omethod; int ptype; int omin; int omax; int pomin; int pomax; int bsize; int stmethod; int padding; int vbs; int quiet; } CommandOptions; static int parse_number(char *arg, int max) { int i; int m = 0; int n = 0; int digits; for(i=0; i '9') { fprintf(stderr, "invalid digit: %c (ASCII:0x%02X)\n", arg[i], arg[i]); return -1; } n += (arg[i]-48) * m; m /= 10; } return n; } static int parse_commandline(int argc, char **argv, CommandOptions *opts) { int i; static const char *param_str = "bhlmopqrstv"; int max_digits = 8; int ifc = 0; opts->filelist = NULL; if(argc < 2) { return 1; } opts->filelist = calloc(argc * sizeof(FilePair), 1); opts->input_count = 0; opts->found_output = 0; opts->compr = 5; opts->omethod = -1; opts->ptype = -1; opts->omin = -1; opts->omax = -1; opts->pomin = -1; opts->pomax = -1; opts->bsize = -1; opts->stmethod = -1; opts->padding = -1; opts->vbs = -1; opts->quiet = 0; for(i=1; i= '0' && argv[i][1] <= '9') { if(argv[i][2] != '\0' && argv[i][3] != '\0') { opts->filelist[ifc].infile = argv[i]; ifc++; } else { opts->compr = parse_number(&argv[i][1], max_digits); if(opts->compr < 0) return 1; } } else { // if argument starts with '-' and is more than 1 char, treat // it as a filename if(argv[i][2] != '\0') { opts->filelist[ifc].infile = argv[i]; ifc++; continue; } // check to see if param is valid if(strchr(param_str, argv[i][1]) == NULL) { fprintf(stderr, "invalid option: -%c\n", argv[i][1]); return 1; } // print commandline help if(argv[i][1] == 'h') { return 2; } i++; if(i >= argc) { fprintf(stderr, "incomplete option: -%c\n", argv[i-1][1]); return 1; } switch(argv[i-1][1]) { case 'b': opts->bsize = parse_number(argv[i], max_digits); if(opts->bsize < 0) return 1; break; case 'l': if(strchr(argv[i], ',') == NULL) { opts->omin = 0; opts->omax = parse_number(argv[i], max_digits); if(opts->omax < 0) return 1; } else { char *po = strchr(argv[i], ','); po[0] = '\0'; opts->omin = parse_number(argv[i], max_digits); if(opts->omin < 0) return 1; opts->omax = parse_number(&po[1], max_digits); if(opts->omax < 0) return 1; } // constrain bounds based on prediction type if(opts->ptype == FLAKE_PREDICTION_FIXED) { if(opts->omax > 4) opts->omax = 4; } else if(opts->ptype == FLAKE_PREDICTION_LEVINSON) { if(opts->omin == 0) opts->omin = 1; } break; case 'm': opts->omethod = parse_number(argv[i], max_digits); if(opts->omethod < 0) return 1; break; case 'o': if(opts->found_output) { return 1; } else { int olen = strnlen(argv[i], PATH_MAX) + 1; opts->filelist[0].outfile = calloc(1, olen+5); strncpy(opts->filelist[0].outfile, argv[i], olen); opts->found_output = 1; } break; case 'p': opts->padding = parse_number(argv[i], max_digits); if(opts->padding < 0) return 1; break; case 'q': i--; opts->quiet = 1; break; case 'r': if(strchr(argv[i], ',') == NULL) { opts->pomin = 0; opts->pomax = parse_number(argv[i], max_digits); if(opts->pomax < 0) return 1; } else { char *po = strchr(argv[i], ','); po[0] = '\0'; opts->pomin = parse_number(argv[i], max_digits); if(opts->pomin < 0) return 1; opts->pomax = parse_number(&po[1], max_digits); if(opts->pomax < 0) return 1; } break; case 's': opts->stmethod = parse_number(argv[i], max_digits); if(opts->stmethod < 0) return 1; break; case 't': opts->ptype = parse_number(argv[i], max_digits); if(opts->ptype < 0) return 1; break; case 'v': opts->vbs = parse_number(argv[i], max_digits); if(opts->vbs < 0) return 1; break; } } } else { // if argument does not start with '-' parse as a filename. also, // if the argument is a single '-' treat it as a filename opts->filelist[ifc].infile = argv[i]; ifc++; } } if(!ifc) { fprintf(stderr, "error parsing filenames.\n"); return 1; } if(opts->found_output && ifc > 1) { fprintf(stderr, "cannot specify output file when using multiple input files\n"); return 1; } if(!opts->found_output) { // if no output is specified, use input filename with .flac extension for(i=0; ifilelist[i].infile, PATH_MAX); opts->filelist[i].outfile = calloc(1, ext+6); strncpy(opts->filelist[i].outfile, opts->filelist[i].infile, ext+1); opts->filelist[i].outfile[ext] = '\0'; while(ext > 0 && opts->filelist[i].outfile[ext] != '.') ext--; if(ext >= (PATH_MAX-5)) { fprintf(stderr, "input filename too long\n"); return 1; } strncpy(&opts->filelist[i].outfile[ext], ".flac", 6); } } // disallow infile & outfile with same name except with piping for(i=0; ifilelist[i].infile, "-", 2) && strncmp(opts->filelist[i].outfile, "-", 2)) { if(!strcmp(opts->filelist[i].infile, opts->filelist[i].outfile)) { fprintf(stderr, "output filename cannot match input filename\n"); return 1; } } } opts->input_count = ifc; return 0; } static void print_params(FlakeContext *s) { char *omethod_s, *stmethod_s, *ptype_s, *vbs_s; vbs_s = "ERROR"; switch(s->params.variable_block_size) { case 0: vbs_s = "none"; break; case 1: vbs_s = "method 1"; break; case 2: vbs_s = "method 2"; break; } fprintf(stderr, "variable block size: %s\n", vbs_s); ptype_s = "ERROR"; switch(s->params.prediction_type) { case 0: ptype_s = "none (verbatim mode)"; break; case 1: ptype_s = "fixed"; break; case 2: ptype_s = "levinson-durbin"; break; } fprintf(stderr, "prediction type: %s\n", ptype_s); if(s->params.prediction_type != FLAKE_PREDICTION_NONE) { fprintf(stderr, "prediction order: %d,%d\n", s->params.min_prediction_order, s->params.max_prediction_order); fprintf(stderr, "partition order: %d,%d\n", s->params.min_partition_order, s->params.max_partition_order); omethod_s = "ERROR"; switch(s->params.order_method) { case 0: omethod_s = "maximum"; break; case 1: omethod_s = "estimate"; break; case 2: omethod_s = "2-level"; break; case 3: omethod_s = "4-level"; break; case 4: omethod_s = "8-level"; break; case 5: omethod_s = "full search"; break; case 6: omethod_s = "log search"; break; } fprintf(stderr, "order method: %s\n", omethod_s); } if(s->channels == 2) { stmethod_s = "ERROR"; switch(s->params.stereo_method) { case 0: stmethod_s = "independent"; break; case 1: stmethod_s = "mid-side"; break; } fprintf(stderr, "stereo method: %s\n", stmethod_s); } fprintf(stderr, "header padding: %d\n", s->params.padding_size); } static int encode_file(CommandOptions *opts, FilePair *files, int first_file) { FlakeContext s; WavFile wf; int header_size, subset, bs_zero; uint8_t *frame; int16_t *wav; int percent; uint32_t nr, fs, samplecount, bytecount; int t0, t1; float kb, sec, kbps, wav_bytes; if(wavfile_init(&wf, files->ifp)) { fprintf(stderr, "invalid input file: %s\n", files->infile); return 1; } wf.read_format = WAV_SAMPLE_FMT_S16; // set parameters from input audio s.channels = wf.channels; s.sample_rate = wf.sample_rate; s.bits_per_sample = 16; s.samples = wf.samples; // set parameters from commandline s.params.compression = opts->compr; if(flake_set_defaults(&s.params)) { return 1; } if(opts->bsize >= 0) s.params.block_size = opts->bsize; if(opts->omethod >= 0) s.params.order_method = opts->omethod; if(opts->stmethod >= 0) s.params.stereo_method = opts->stmethod; if(opts->ptype >= 0) s.params.prediction_type = opts->ptype; if(opts->omin >= 0) s.params.min_prediction_order = opts->omin; if(opts->omax >= 0) s.params.max_prediction_order = opts->omax; if(opts->pomin >= 0) s.params.min_partition_order = opts->pomin; if(opts->pomax >= 0) s.params.max_partition_order = opts->pomax; if(opts->padding >= 0) s.params.padding_size = opts->padding; if(opts->vbs >= 0) s.params.variable_block_size = opts->vbs; subset = flake_validate_params(&s); if(subset < 0) { fprintf(stderr, "Error: invalid encoding parameters.\n"); return 1; } bs_zero = (s.params.block_size == 0); // initialize encoder header_size = flake_encode_init(&s); if(header_size < 0) { flake_encode_close(&s); fprintf(stderr, "Error initializing encoder.\n"); return 1; } fwrite(s.header, 1, header_size, files->ofp); // print encoding parameters if(first_file && !opts->quiet) { if(subset == 1) { fprintf(stderr,"=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n" " WARNING! The chosen encoding options are\n" " not FLAC Subset compliant. Therefore, the\n" " encoded file(s) may not work properly with\n" " some FLAC players and decoders.\n" "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n"); } if(bs_zero) { fprintf(stderr, "block time: %dms\n", s.params.block_time_ms); } else { fprintf(stderr, "block size: %d\n", s.params.block_size); } print_params(&s); } if(!opts->quiet) { fprintf(stderr, "\n"); fprintf(stderr, "input file: \"%s\"\n", files->infile); fprintf(stderr, "output file: \"%s\"\n", files->outfile); wavfile_print(stderr, &wf); if(wf.bit_width != 16) { fprintf(stderr, "WARNING! converting to 16-bit (not lossless)\n"); } if(wf.samples > 0) { int64_t tms; int th, tm, ts; tms = (int64_t)(wf.samples * 1000.0 / wf.sample_rate); ts = tms / 1000; tms = tms % 1000; tm = ts / 60; ts = ts % 60; th = tm / 60; tm = tm % 60; fprintf(stderr, "samples: %u (", wf.samples); if(th) fprintf(stderr, "%dh", th); fprintf(stderr, "%dm", tm); fprintf(stderr, "%d.%03ds)\n", ts, (int)tms); } else { fprintf(stderr, "samples: unknown\n"); } if(bs_zero) { fprintf(stderr, "block size: %d\n", s.params.block_size); } } frame = malloc(s.max_frame_size); wav = malloc(s.params.block_size * wf.channels * sizeof(int16_t)); samplecount = t0 = percent = 0; wav_bytes = 0; bytecount = header_size; nr = wavfile_read_samples(&wf, wav, s.params.block_size); while(nr > 0) { s.params.block_size = nr; fs = flake_encode_frame(&s, frame, wav); if(fs < 0) { fprintf(stderr, "Error encoding frame\n"); } else if(fs > 0) { fwrite(frame, 1, fs, files->ofp); samplecount += s.params.block_size; bytecount += fs; t1 = samplecount / s.sample_rate; if(t1 > t0) { kb = ((bytecount * 8.0) / 1000.0); sec = ((float)samplecount) / ((float)s.sample_rate); if(samplecount > 0) kbps = kb / sec; else kbps = kb; if(s.samples > 0) { percent = ((samplecount * 100.5) / s.samples); } wav_bytes = samplecount*wf.block_align; if(!opts->quiet) { fprintf(stderr, "\rprogress: %3d%% | ratio: %1.3f | " "bitrate: %4.1f kbps ", percent, (bytecount / wav_bytes), kbps); } } t0 = t1; } nr = wavfile_read_samples(&wf, wav, s.params.block_size); } if(!opts->quiet) { fprintf(stderr, "| bytes: %d \n\n", bytecount); } flake_encode_close(&s); // if seeking is possible, rewrite sample count and MD5 checksum if(!fseek(files->ofp, 22, SEEK_SET)) { uint32_t sc = be2me_32(samplecount); fwrite(&sc, 4, 1, files->ofp); fwrite(s.md5digest, 1, 16, files->ofp); } free(wav); free(frame); return 0; } static int open_files(FilePair *files) { if(!strncmp(files->infile, "-", 2)) { #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif files->ifp = stdin; } else { files->ifp = fopen(files->infile, "rb"); if(!files->ifp) { fprintf(stderr, "error opening input file: %s\n", files->infile); return 1; } } if(!strncmp(files->outfile, "-", 2)) { #ifdef _WIN32 _setmode(_fileno(stdout), _O_BINARY); #endif files->ofp = stdout; } else { files->ofp = fopen(files->outfile, "wb"); if(!files->ofp) { fprintf(stderr, "error opening output file: %s\n", files->outfile); return 1; } } return 0; } static void filelist_cleanup(CommandOptions *opts) { int i; if(opts->filelist) { for(i=0; iinput_count; i++) { if(opts->filelist[i].outfile) free(opts->filelist[i].outfile); } free(opts->filelist); } } int main(int argc, char **argv) { CommandOptions opts; int i, err; memset(&opts, 0, sizeof(CommandOptions)); err = parse_commandline(argc, argv, &opts); if(!opts.quiet) { fprintf(stderr, "\nFlake: FLAC audio encoder\n" "version "FLAKE_STRINGIFY(FLAKE_VERSION)"\n" "(c) 2006-2007 Justin Ruggles\n\n"); } if(err == 2) { print_help(stdout); filelist_cleanup(&opts); return 0; } else if(err) { print_usage(stderr); filelist_cleanup(&opts); return 1; } for(i=0; ifp = fp; // attempt to get file size wf->file_size = 0; wf->seekable = !fseek(fp, 0, SEEK_END); if(wf->seekable) { wf->file_size = ftell(fp); fseek(fp, 0, SEEK_SET); } wf->filepos = 0; id = read4le(fp); wf->filepos += 4; if(id != RIFF_ID) return -1; read4le(fp); wf->filepos += 4; id = read4le(fp); wf->filepos += 4; if(id != WAVE_ID) return -1; found_data = found_fmt = 0; while(!found_data) { id = read4le(fp); wf->filepos += 4; chunksize = read4le(fp); wf->filepos += 4; if(id == 0 || chunksize == 0) return -1; switch(id) { case FMT__ID: if(chunksize < 16) return -1; wf->format = read2le(fp); wf->channels = read2le(fp); wf->sample_rate = read4le(fp); read4le(fp); wf->block_align = read2le(fp); wf->bit_width = read2le(fp); wf->filepos += 16; if(!wf->channels || !wf->sample_rate || !wf->block_align || !wf->bit_width) { return -1; } chunksize -= 16; // WAVE_FORMAT_EXTENSIBLE data wf->ch_mask = 0; if(wf->format == WAVE_FORMAT_EXTENSIBLE && chunksize >= 10) { read4le(fp); // skip CbSize and ValidBitsPerSample wf->ch_mask = read4le(fp); wf->format = read2le(fp); wf->filepos += 10; chunksize -= 10; } if(wf->format == WAVE_FORMAT_PCM || wf->format == WAVE_FORMAT_IEEEFLOAT) { wf->block_align = ((wf->bit_width + 7) >> 3) * wf->channels; } // make up channel mask if not using WAVE_FORMAT_EXTENSIBLE // or if ch_mask is set to zero (unspecified configuration) // TODO: select default configurations for >6 channels if(wf->ch_mask == 0) { switch(wf->channels) { case 1: wf->ch_mask = 0x04; break; case 2: wf->ch_mask = 0x03; break; case 3: wf->ch_mask = 0x07; break; case 4: wf->ch_mask = 0x107; break; case 5: wf->ch_mask = 0x37; break; case 6: wf->ch_mask = 0x3F; break; } } while(chunksize-- > 0) { fgetc(fp); wf->filepos++; } found_fmt = 1; break; case DATA_ID: if(!found_fmt) return -1; wf->data_size = chunksize; wf->data_start = wf->filepos; wf->samples = (wf->data_size / wf->block_align); found_data = 1; break; default: if(wf->seekable) { fseek(fp, chunksize, SEEK_CUR); } else { while(chunksize-- > 0) { fgetc(fp); } } wf->filepos += chunksize; } } wf->source_format = WAV_SAMPLE_FMT_UNKNOWN; wf->read_format = wf->source_format; if(wf->format == WAVE_FORMAT_PCM || wf->format == WAVE_FORMAT_IEEEFLOAT) { switch(wf->bit_width) { case 8: wf->source_format = WAV_SAMPLE_FMT_U8; break; case 16: wf->source_format = WAV_SAMPLE_FMT_S16; break; case 20: wf->source_format = WAV_SAMPLE_FMT_S20; break; case 24: wf->source_format = WAV_SAMPLE_FMT_S24; break; case 32: if(wf->format == WAVE_FORMAT_IEEEFLOAT) { wf->source_format = WAV_SAMPLE_FMT_FLT; } else if(wf->format == WAVE_FORMAT_PCM) { wf->source_format = WAV_SAMPLE_FMT_S32; } break; case 64: if(wf->format == WAVE_FORMAT_IEEEFLOAT) { wf->source_format = WAV_SAMPLE_FMT_DBL; } break; } } return 0; } static void fmt_convert_to_u8(uint8_t *dest, void *src_v, int n, enum WavSampleFormat fmt) { int i, v; if(fmt == WAV_SAMPLE_FMT_U8) { memcpy(dest, src_v, n); } else if(fmt == WAV_SAMPLE_FMT_S16) { int16_t *src = src_v; for(i=0; i> 8) + 128; } } else if(fmt == WAV_SAMPLE_FMT_S20) { int32_t *src = src_v; for(i=0; i> 12) + 128; } } else if(fmt == WAV_SAMPLE_FMT_S24) { int32_t *src = src_v; for(i=0; i> 16) + 128; } } else if(fmt == WAV_SAMPLE_FMT_S32) { int32_t *src = src_v; for(i=0; i> 24) + 128; } } else if(fmt == WAV_SAMPLE_FMT_FLT) { float *src = src_v; for(i=0; i> 4); } } else if(fmt == WAV_SAMPLE_FMT_S24) { int32_t *src = src_v; for(i=0; i> 8); } } else if(fmt == WAV_SAMPLE_FMT_S32) { int32_t *src = src_v; for(i=0; i> 16); } } else if(fmt == WAV_SAMPLE_FMT_FLT) { float *src = src_v; for(i=0; i> 4); } } else if(fmt == WAV_SAMPLE_FMT_S32) { int32_t *src = src_v; for(i=0; i> 12); } } else if(fmt == WAV_SAMPLE_FMT_FLT) { float *src = src_v; for(i=0; i> 8); } } else if(fmt == WAV_SAMPLE_FMT_FLT) { float *src = src_v; for(i=0; ifp == NULL || output == NULL) return -1; if(wf->block_align <= 0) return -1; read_size = wf->block_align * num_samples; if((wf->filepos + read_size) >= (wf->data_start + wf->data_size)) { read_size = (wf->data_start + wf->data_size) - wf->filepos; num_samples = read_size / wf->block_align; } if(num_samples < 0) return -1; if(num_samples == 0) return 0; convert = (wf->read_format != wf->source_format); if(convert) { buffer = calloc(read_size, 1); } else { buffer = output; } nr = fread(buffer, wf->block_align, num_samples, wf->fp); wf->filepos += nr * wf->block_align; nsmp = nr * wf->channels; bps = wf->block_align / wf->channels; if(bps == 1) { if(wf->source_format != WAV_SAMPLE_FMT_U8) return -1; if(convert) { fmt_convert(wf->read_format, output, wf->source_format, buffer, nsmp); } } else if(bps == 2) { #ifdef WORDS_BIGENDIAN uint16_t *buf16 = (uint16_t *)buffer; for(i=0; isource_format != WAV_SAMPLE_FMT_S16) return -1; if(convert) { fmt_convert(wf->read_format, output, wf->source_format, (int16_t *)buffer, nsmp); } } else if(bps == 3) { int32_t *input = calloc(nsmp, sizeof(int32_t)); for(i=0,j=0; ibit_width == 20) { if(v >= (1<<19)) v -= (1<<20); } else if(wf->bit_width == 24) { if(v >= (1<<23)) v -= (1<<24); } else { fprintf(stderr, "unsupported bit width: %d\n", wf->bit_width); return -1; } input[j] = v; } if(wf->source_format != WAV_SAMPLE_FMT_S20 && wf->source_format != WAV_SAMPLE_FMT_S24) { return -1; } if(convert) { fmt_convert(wf->read_format, output, wf->source_format, input, nsmp); } free(input); } else if(bps == 4) { #ifdef WORDS_BIGENDIAN uint32_t *buf32 = (uint32_t *)buffer; for(i=0; iformat == WAVE_FORMAT_IEEEFLOAT) { if(wf->source_format != WAV_SAMPLE_FMT_FLT) return -1; if(convert) { fmt_convert(wf->read_format, output, wf->source_format, (float *)buffer, nsmp); } } else { if(wf->source_format != WAV_SAMPLE_FMT_S32) return -1; if(convert) { fmt_convert(wf->read_format, output, wf->source_format, (int32_t *)buffer, nsmp); } } } else if(wf->format == WAVE_FORMAT_IEEEFLOAT && bps == 8) { #ifdef WORDS_BIGENDIAN uint64_t *buf64 = (uint64_t *)buffer; for(i=0; isource_format != WAV_SAMPLE_FMT_DBL) return -1; if(convert) { fmt_convert(wf->read_format, output, wf->source_format, (double *)buffer, nsmp); } } if(convert) { free(buffer); } return nr; } int wavfile_seek_samples(WavFile *wf, int32_t offset, int whence) { int byte_offset, pos, cur; if(wf == NULL || wf->fp == NULL) return -1; if(wf->block_align <= 0) return -1; if(wf->data_start == 0 || wf->data_size == 0) return -1; byte_offset = offset * wf->block_align; pos = wf->data_start; switch(whence) { case WAV_SEEK_SET: pos = wf->data_start + byte_offset; break; case WAV_SEEK_CUR: cur = wf->filepos; while(cur < wf->data_start) { fgetc(wf->fp); cur++; wf->filepos++; } pos = cur + byte_offset; case WAV_SEEK_END: pos = (wf->data_start+wf->data_size) - byte_offset; break; default: return -1; } if(pos < wf->data_start) { pos = 0; } if(pos >= wf->data_start+wf->data_size) { pos = wf->data_start+wf->data_size-1; } if(!wf->seekable) { if(pos < wf->filepos) return -1; while(wf->filepos < pos) { fgetc(wf->fp); wf->filepos++; } } else { if(fseek(wf->fp, pos, SEEK_SET)) return -1; } return 0; } int wavfile_seek_time_ms(WavFile *wf, int32_t offset, int whence) { int32_t samples; if(wf == NULL || wf->sample_rate == 0) return -1; samples = (offset * wf->sample_rate) / 1000; return wavfile_seek_samples(wf, samples, whence); } int wavfile_position(WavFile *wf) { int cur; if(wf == NULL) return 0; if(wf->data_start == 0 || wf->data_size == 0) return 0; cur = (wf->filepos - wf->data_start) / wf->block_align; if(cur <= 0) return 0; cur /= wf->block_align; return cur; } void wavfile_print(FILE *st, WavFile *wf) { char *type, *chan; if(st == NULL || wf == NULL) return; if(wf->format == WAVE_FORMAT_PCM) { if(wf->bit_width > 8) type = "Signed"; else type = "Unsigned"; } else if(wf->format == WAVE_FORMAT_IEEEFLOAT) { type = "Floating-point"; } else { type = "[unsupported type]"; } switch(wf->channels) { case 1: chan = "mono"; break; case 2: chan = "stereo"; break; case 3: chan = "3-channel"; break; case 4: chan = "4-channel"; break; case 5: chan = "5-channel"; break; case 6: chan = "6-channel"; break; default: chan = "multi-channel"; break; } fprintf(st, "%s %d-bit %d Hz %s\n", type, wf->bit_width, wf->sample_rate, chan); } flake-0.11/flake/wav.h0000644000175000017500000000416510655263114014170 0ustar justinjustin/** * Flake: FLAC audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file wav.h * WAV decoder header */ #ifndef WAV_H #define WAV_H #include "common.h" #define WAVE_FORMAT_PCM 0x0001 #define WAVE_FORMAT_IEEEFLOAT 0x0003 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE #define WAV_SEEK_SET 0 #define WAV_SEEK_CUR 1 #define WAV_SEEK_END 2 enum WavSampleFormat { WAV_SAMPLE_FMT_UNKNOWN = -1, WAV_SAMPLE_FMT_U8 = 0, WAV_SAMPLE_FMT_S16, WAV_SAMPLE_FMT_S20, WAV_SAMPLE_FMT_S24, WAV_SAMPLE_FMT_S32, WAV_SAMPLE_FMT_FLT, WAV_SAMPLE_FMT_DBL, }; typedef struct WavFile { FILE *fp; uint32_t filepos; int seekable; uint32_t file_size; uint32_t data_start; uint32_t data_size; uint32_t samples; int format; int channels; uint32_t ch_mask; int sample_rate; int bytes_per_sec; int block_align; int bit_width; enum WavSampleFormat source_format; // set by wavfile_init enum WavSampleFormat read_format; // set by user } WavFile; extern int wavfile_init(WavFile *wf, FILE *fp); extern int wavfile_read_samples(WavFile *wf, void *buffer, int num_samples); extern int wavfile_seek_samples(WavFile *wf, int32_t offset, int whence); extern int wavfile_seek_time_ms(WavFile *wf, int32_t offset, int whence); extern int wavfile_position(WavFile *wf); extern void wavfile_print(FILE *st, WavFile *wf); #endif /* WAV_H */ flake-0.11/flake/Makefile0000644000175000017500000000223210655263114014653 0ustar justinjustin# # Flake Program Makefile # include ../config.mak CFLAGS=$(OPTFLAGS) -I. -I.. -I$(SRC_PATH)/libflake \ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_ISOC9X_SOURCE \ -DHAVE_CONFIG_H LDFLAGS+= -g DEP_LIBS=$(SRC_PATH)/libflake/$(LIBPREF)flake$(LIBSUF) PROGS_G=flake_g$(EXESUF) PROGS=flake$(EXESUF) OBJS = flake.o wav.o SRCS = $(OBJS:.o=.c) FLAKE_LIBDIRS = -L$(SRC_PATH)/libflake FLAKE_LIBS = -lflake$(BUILDSUF) all: $(PROGS_G) $(PROGS) flake_g$(EXESUF): flake.o wav.o $(DEP_LIBS) $(CC) $(FLAKE_LIBDIRS) $(LDFLAGS) -o $@ flake.o wav.o $(FLAKE_LIBS) $(EXTRALIBS) cp -p flake_g$(EXESUF) flake$(EXESUF) $(STRIP) flake$(EXESUF) %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< install: install-progs install-progs: $(PROGS) install -d "$(bindir)" install -c $(INSTALLSTRIP) -m 755 $(PROGS) "$(bindir)" uninstall: uninstall-progs uninstall-progs: rm -f $(addprefix $(bindir)/, $(PROGS)) dep: depend depend: .depend .depend: $(SRCS) $(CC) -MM $(CFLAGS) $^ 1>.depend clean: rm -f *.o *.d *~ *.a *.lib *.def *.exp \ $(PROGS) $(PROGS_G) distclean: clean rm -f .depend ../config.* ../config.mak: touch ../config.mak ifneq ($(wildcard .depend),) include .depend endif flake-0.11/configure0000755000175000017500000005003710655263114014046 0ustar justinjustin#!/bin/sh # # Flake configure script # # based on ffmpeg configure script (c) 2000, 2001, 2002 Fabrice Bellard # # make sure we are running under a compatible shell unset foo (: ${foo%%bar}) 2>/dev/null && ! (: ${foo?}) 2>/dev/null if test "$?" != 0; then if test "x$FLAKE_CONFIGURE_EXEC" = x; then FLAKE_CONFIGURE_EXEC=1 export FLAKE_CONFIGURE_EXEC exec bash "$0" "$@" exec ksh "$0" "$@" exec /usr/xpg4/bin/sh "$0" "$@" fi echo "No compatible shell script interpreter found." exit 1 fi show_help(){ echo "Usage: configure [options]" echo "Options: [defaults in brackets after descriptions]" echo echo "Standard options:" echo " --help print this message" echo " --log[=FILE|yes|no] log tests and output to FILE [config.err]" echo " --prefix=PREFIX install in PREFIX [$PREFIX]" echo " --libdir=DIR install libs in DIR [PREFIX/lib]" echo " --incdir=DIR install includes in DIR [PREFIX/include/ffmpeg]" echo " --enable-mingw32 enable MinGW native/cross Windows compile" echo " --enable-mingwce enable MinGW native/cross WinCE compile" echo "" echo "Advanced options (experts only):" echo " --source-path=PATH path to source code [$source_path]" echo " --cross-prefix=PREFIX use PREFIX for compilation tools [$cross_prefix]" echo " --cross-compile assume a cross-compiler is used" echo " --cc=CC use C compiler CC [$cc]" echo " --make=MAKE use specified make [$make]" echo " --ar=AR use specified ar [$ar]" echo " --ranlib=RANLIB use specified ranlib [$ranlib]" echo " --strip=STRIP use specified ranlib [$strip]" echo " --extra-cflags=ECFLAGS add ECFLAGS to CFLAGS [$CFLAGS]" echo " --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS [$LDFLAGS]" echo " --extra-libs=ELIBS add ELIBS [$ELIBS]" echo " --build-suffix=SUFFIX suffix for application specific build []" echo " --cpu=CPU force cpu to CPU [$cpu]" echo " --tune=CPU tune code for a particular CPU" echo " (may fail or perform badly on other CPUs)" echo " --disable-altivec disable AltiVec usage" echo " --enable-gprof enable profiling with gprof [$gprof]" echo " --disable-debug disable debugging symbols" echo " --disable-opts disable compiler optimizations" echo " --enable-small optimize for size instead of speed" echo " --disable-strip disable stripping of executables" echo "" echo "NOTE: Object files are built at the place where configure is launched." exit 1 } log(){ echo "$@" >>$logfile } log_file(){ log BEGIN $1 cat -n $1 >>$logfile log END $1 } echolog(){ log "$@" echo "$@" } die(){ echolog "$@" cat </dev/null } save_flags(){ flags_saved && return SAVE_CFLAGS="$CFLAGS" SAVE_LDFLAGS="$LDFLAGS" SAVE_extralibs="$extralibs" } restore_flags(){ CFLAGS="$SAVE_CFLAGS" LDFLAGS="$SAVE_LDFLAGS" extralibs="$SAVE_extralibs" unset SAVE_CFLAGS unset SAVE_LDFLAGS unset SAVE_extralibs } append(){ var=$1 shift flags_saved && eval "SAVE_$var=\"\$SAVE_$var $*\"" eval "$var=\"\$$var $*\"" } add_cflags(){ append CFLAGS "$@" } add_ldflags(){ append LDFLAGS "$@" } add_extralibs(){ append extralibs "$@" } check_cmd(){ log "$@" "$@" >>$logfile 2>&1 } check_cc(){ log check_cc "$@" cat >$TMPC log_file $TMPC check_cmd $cc $CFLAGS "$@" -c -o $TMPO $TMPC } check_cpp(){ log check_cpp "$@" cat >$TMPC log_file $TMPC check_cmd $cc $CFLAGS "$@" -E -o $TMPO $TMPC } check_ld(){ log check_ld "$@" check_cc || return check_cmd $cc $LDFLAGS "$@" -o $TMPE $TMPO $extralibs } check_cflags(){ log check_cflags "$@" check_cc "$@" < int x; EOF } check_exec(){ check_ld "$@" && { test "$cross_compile" = yes || $TMPE >>$logfile 2>&1; } } # set temporary file name if test ! -z "$TMPDIR" ; then TMPDIR1="${TMPDIR}" elif test ! -z "$TEMPDIR" ; then TMPDIR1="${TEMPDIR}" elif test ! -z "$TEMP" ; then TMPDIR1="${TEMP}" else TMPDIR1="/tmp" fi TMPC="${TMPDIR1}/flake-conf-${RANDOM}-$$-${RANDOM}.c" TMPO="${TMPDIR1}/flake-conf-${RANDOM}-$$-${RANDOM}.o" TMPE="${TMPDIR1}/flake-conf-${RANDOM}-$$-${RANDOM}" TMPS="${TMPDIR1}/flake-conf-${RANDOM}-$$-${RANDOM}.S" TMPH="${TMPDIR1}/flake-conf-${RANDOM}-$$-${RANDOM}.h" # default parameters logging="yes" logfile="config.err" PREFIX="/usr/local" libdir='${PREFIX}/lib' incdir='${PREFIX}/include' bindir='${PREFIX}/bin' cross_prefix="" cross_compile="no" cc="gcc" ar="ar" ranlib="ranlib" make="make" strip="strip" cpu=`uname -m` tune="generic" altivec="default" case "$cpu" in i386|i486|i586|i686|i86pc|BePC) cpu="x86" ;; x86_64|amd64) cpu="x86" canon_arch="`$cc -dumpmachine | sed -e 's,\([^-]*\)-.*,\1,'`" if [ x"$canon_arch" = x"x86_64" -o x"$canon_arch" = x"amd64" ]; then if [ -z "`echo $CFLAGS | grep -- -m32`" ]; then cpu="x86_64" fi fi ;; # armv4l is a subset of armv5tel armv4l|armv5tel) cpu="armv4l" ;; alpha) cpu="alpha" ;; "Power Macintosh"|ppc|ppc64|powerpc) cpu="powerpc" ;; mips|mipsel|IP*) cpu="mips" ;; sun4u|sparc64) cpu="sparc64" ;; sparc) cpu="sparc" ;; sh4) cpu="sh4" ;; parisc|parisc64) cpu="parisc" ;; s390|s390x) cpu="s390" ;; m68k) cpu="m68k" ;; ia64) cpu="ia64" ;; bfin) cpu="bfin" ;; *) cpu="unknown" ;; esac gprof="no" mingw32="no" mingwce="no" os2="no" optimize="yes" debug="yes" dostrip="yes" installstrip="-s" extralibs="-lm" bigendian="no" inttypes="yes" LIBOBJFLAGS="" PROJLDFLAGS=-Wl,--warn-common LDCONFIG="ldconfig" LIBPREF="lib" LIBSUF=".a" LIB='$(LIBPREF)$(NAME)$(LIBSUF)' EXESUF="" BUILDSUF="" LIB_INSTALL_EXTRA_CMD='$(RANLIB) "$(libdir)/$(LIB)"' # OS specific targetos=`uname -s` case $targetos in BeOS) PREFIX="/boot/home/config" add_cflags "-DPIC -fomit-frame-pointer" # 3 gcc releases known for BeOS, each with ugly bugs gcc_version="`$cc -v 2>&1 | grep version | cut -d ' ' -f3-`" case "$gcc_version" in 2.9-beos-991026*|2.9-beos-000224*) echo "R5/GG gcc" ;; *20010315*) echo "BeBits gcc" add_cflags "-fno-expensive-optimizations" ;; esac ;; SunOS) make="gmake" PROJLDFLAGS="" ;; NetBSD) make="gmake" ;; OpenBSD) make="gmake" LIBOBJFLAGS="\$(PIC)" ;; FreeBSD) make="gmake" add_cflags "-pthread" ;; GNU/kFreeBSD) add_cflags "-pthread" ;; BSD/OS) extralibs="-lpoll -lgnugetopt -lm" make="gmake" strip="strip -d" installstrip="" ;; Darwin) cc="cc" extralibs="" strip="strip -x" installstrip="" PROJLDFLAGS="-Wl,-dynamic,-search_paths_first" LIB_INSTALL_EXTRA_CMD='$(RANLIB) "$(libdir)/$(LIB)"' ;; MINGW32*) # Note: the rest of the mingw32 config is done afterwards as mingw32 # can be forced on the command line for Linux cross compilation. mingw32="yes" ;; CYGWIN*) targetos=CYGWIN extralibs="" EXESUF=".exe" ;; Linux) ;; IRIX*) targetos=IRIX ranlib="echo ignoring ranlib" make="gmake" ;; OS/2) TMPE=$TMPE".exe" ar="emxomfar -p128" ranlib="echo ignoring ranlib" strip="echo ignoring strip" add_cflags "-Zomf" PROJLDFLAGS="-Zomf -Zstack 16384 -s" LIBPREF="" LIBSUF=".lib" EXESUF=".exe" extralibs="" os2="yes" ;; *) targetos="${targetos}-UNKNOWN" ;; esac # find source path source_path="`dirname $0`" source_path_used="yes" if test -z "$source_path" -o "$source_path" = "." ; then source_path=`pwd` source_path_used="no" else source_path="`cd \"$source_path\"; pwd`" fi if test x"$1" = x"-h" -o x"$1" = x"--help" ; then show_help fi FLAKE_CONFIGURATION=" " for opt do FLAKE_CONFIGURATION="$FLAKE_CONFIGURATION""$opt " done for opt do optval="${opt#*=}" case "$opt" in --log) ;; --log=*) logging="$optval" ;; --prefix=*) PREFIX="$optval"; force_prefix=yes ;; --libdir=*) libdir="$optval"; force_libdir=yes ;; --incdir=*) incdir="$optval" ;; --source-path=*) source_path="$optval" ;; --cross-prefix=*) cross_prefix="$optval" ;; --cross-compile) cross_compile=yes ;; --cc=*) cc="$optval" ;; --make=*) make="$optval" ;; --ar=*) ar="$optval" ;; --ranlib=*) ranlib="$optval" ;; --strip=*) strip="$optval" ;; --extra-cflags=*) add_cflags "$optval" ;; --extra-ldflags=*) EXTRALDFLAGS="$optval" ;; --extra-libs=*) extralibs="$optval" ;; --build-suffix=*) BUILDSUF="$optval" ;; --cpu=*) cpu="$optval" ;; --tune=*) tune="$optval" ;; --disable-altivec) altivec="no" ;; --enable-gprof) gprof="yes" ;; --enable-mingw32) mingw32="yes" ;; --enable-mingwce) mingwce="yes" ;; --disable-debug) debug="no" ;; --disable-opts) optimize="no" ;; --enable-small) optimize="small" ;; --disable-strip) dostrip="no" ;; --help) show_help ;; *) echo "Unknown option \"$opt\"." echo "See $0 --help for available options." exit 1 ;; esac done if test "$logging" != no; then test "$logging" = yes || logfile="$logging" echo "# $0 $@" >$logfile set >>$logfile else logfile=/dev/null fi if test "$mingw32" = "yes" -o "$mingwce" = "yes"; then EXESUF=".exe" if test "$force_prefix" != yes; then PREFIX="$PROGRAMFILES/Flake"; fi if test "$force_libdir" != yes; then bindir='${PREFIX}'; fi fi # Combine PROFLDFLAGS, EXTRALDFLAGS and the LDFLAGS environment variable. LDFLAGS="$PROJLDFLAGS $EXTRALDFLAGS $LDFLAGS" test -n "$cross_prefix" && cross_compile=yes cc="${cross_prefix}${cc}" ar="${cross_prefix}${ar}" ranlib="${cross_prefix}${ranlib}" strip="${cross_prefix}${strip}" #Darwin CC versions needmdynamicnopic="no" if test $targetos = Darwin; then if test -n "`$cc -v 2>&1 | grep xlc`"; then add_cflags "-qpdf2 -qlanglvl=extc99 -qmaxmem=-1 -qarch=auto -qtune=auto" else gcc_version="`$cc -v 2>&1 | grep version | cut -d ' ' -f3-`" case "$gcc_version" in *2.95*) add_cflags "-no-cpp-precomp -pipe" ;; *[34].*) add_cflags "-no-cpp-precomp -pipe -force_cpusubtype_ALL -Wno-sign-compare" needmdynamicnopic="yes" ;; *) add_cflags "-no-cpp-precomp -pipe" needmdynamicnopic="yes" ;; esac fi if test $optimize != "no"; then add_cflags "-fomit-frame-pointer" fi fi # Can only do AltiVec on PowerPC if test $altivec = "default"; then if test $cpu = "powerpc"; then altivec="yes" else altivec="no" fi fi # Add processor-specific flags TUNECPU="generic" POWERPCMODE="32bits" if test $tune != "generic"; then case $tune in 601|ppc601|PowerPC601) add_cflags "-mcpu=601" if test $altivec = "yes"; then echo "WARNING: Tuning for PPC601 but AltiVec enabled!"; fi TUNECPU=ppc601 ;; 603*|ppc603*|PowerPC603*) add_cflags "-mcpu=603" if test $altivec = "yes"; then echo "WARNING: Tuning for PPC603 but AltiVec enabled!"; fi TUNECPU=ppc603 ;; 604*|ppc604*|PowerPC604*) add_cflags "-mcpu=604" if test $altivec = "yes"; then echo "WARNING: Tuning for PPC604 but AltiVec enabled!"; fi TUNECPU=ppc604 ;; G3|g3|75*|ppc75*|PowerPC75*) add_cflags "-mcpu=750 -mtune=750 -mpowerpc-gfxopt" if test $altivec = "yes"; then echo "WARNING: Tuning for PPC75x but AltiVec enabled!"; fi TUNECPU=ppc750 ;; G4|g4|745*|ppc745*|PowerPC745*) add_cflags "-mcpu=7450 -mtune=7450 -mpowerpc-gfxopt" if test $altivec = "no"; then echo "WARNING: Tuning for PPC745x but AltiVec disabled!"; fi TUNECPU=ppc7450 ;; 74*|ppc74*|PowerPC74*) add_cflags "-mcpu=7400 -mtune=7400 -mpowerpc-gfxopt" if test $altivec = "no"; then echo "WARNING: Tuning for PPC74xx but AltiVec disabled!"; fi TUNECPU=ppc7400 ;; G5|g5|970|ppc970|PowerPC970|power4*|Power4*) add_cflags "-mcpu=970 -mtune=970 -mpowerpc-gfxopt -mpowerpc64" if test $altivec = "no"; then echo "WARNING: Tuning for PPC970 but AltiVec disabled!"; fi TUNECPU=ppc970 POWERPCMODE="64bits" ;; power5*|Power5*) add_cflags "-mcpu=power5 -mtune=power5 -mpowerpc-gfxopt -mpowerpc64" if test $altivec = "no"; then echo "WARNING: Tuning for POWER5 but AltiVec disabled!"; fi TUNECPU=power5 POWERPCMODE="64bits" ;; i[3456]86|pentium|pentiumpro|pentium-mmx|pentium[234]|prescott|k6|k6-[23]|athlon|athlon-tbird|athlon-4|athlon-[mx]p|winchip-c6|winchip2|c3|nocona|athlon64|k8|opteron|athlon-fx) add_cflags "-march=$tune" ;; ev4|ev45|ev5|ev56|ev6|ev67|21064|21164|21164a|21164pc|21164PC|21264|21264a) add_cflags "-mcpu=$tune" ;; sparc64) add_cflags "-mcpu=v9 -mtune=v9" ;; *) echo "WARNING: Unknown CPU \"$tune\", ignored." ;; esac fi # compiler sanity check check_exec <&1 | grep version | grep Apple`"; then add_cflags "-faltivec" else add_cflags "-maltivec -mabi=altivec" fi fi fi # --- # big/little-endian test if test "$cross_compile" = "no"; then check_ld < int main(int argc, char ** argv){ volatile uint32_t i=0x01234567; return (*((uint8_t*)(&i))) == 0x67; } EOF else # programs cannot be launched if cross compiling, so make a static guess if test "$cpu" = "powerpc" -o "$cpu" = "mips" ; then bigendian="yes" fi fi # --- # *inttypes.h* test check_header inttypes.h || inttypes=no # test for lrintf in math.h check_exec < int main( void ) { return (lrintf(3.999f) > 0)?0:1; } EOF # test for strnlen in string.h check_exec < int main( void ) { return (strnlen("help", 6) == 4)?0:1; } EOF if enabled debug; then add_cflags -g else add_cflags -DNDEBUG fi # add some useful compiler flags if supported check_cflags -Wdeclaration-after-statement check_cflags -Wall check_cflags -Wno-switch check_cflags -Wdisabled-optimization check_cflags -Wpointer-arith check_cflags -Wredundant-decls check_cflags -Winline # not all compilers support -Os test "$optimize" = "small" && check_cflags -Os if enabled optimize; then if test -n "`$cc -v 2>&1 | grep xlc`"; then add_cflags "-O5" add_ldflags "-O5" else add_cflags "-O3" fi fi if test "$gprof" = "yes" ; then add_cflags "-p" add_ldflags "-p" fi echo "install prefix $PREFIX" echo "source path $source_path" echo "C compiler $cc" echo "make $make" echo "CPU $cpu ($tune)" if test "$BUILDSUF" != ""; then echo "build suffix $BUILDSUF" fi echo "big-endian $bigendian" echo "inttypes.h $inttypes" echo "lrintf() $have_lrintf" echo "strnlen() $have_strnlen" if test $cpu = "powerpc"; then echo "AltiVec enabled $altivec" fi echo "gprof enabled $gprof" echo "debug symbols $debug" echo "strip symbols $dostrip" echo "optimize $optimize" echo "Creating config.mak and config.h..." date >> config.log echo " $0 $FLAKE_CONFIGURATION" >> config.log echo "# Automatically generated by configure - do not modify!" > config.mak echo "/* Automatically generated by configure - do not modify! */" > $TMPH echo "#define FLAKE_CONFIGURATION "'"'"$FLAKE_CONFIGURATION"'"' >> $TMPH echo "PREFIX=$PREFIX" >> config.mak echo "prefix=\$(DESTDIR)\${PREFIX}" >> config.mak echo "libdir=\$(DESTDIR)$libdir" >> config.mak echo "incdir=\$(DESTDIR)$incdir" >> config.mak echo "bindir=\$(DESTDIR)$bindir" >> config.mak echo "MAKE=$make" >> config.mak echo "CC=$cc" >> config.mak echo "AR=$ar" >> config.mak echo "RANLIB=$ranlib" >> config.mak if test "$dostrip" = "yes" ; then echo "STRIP=$strip" >> config.mak echo "INSTALLSTRIP=$installstrip" >> config.mak else echo "STRIP=echo ignoring strip" >> config.mak echo "INSTALLSTRIP=" >> config.mak fi test "$needmdynamicnopic" = yes && add_cflags -mdynamic-no-pic echo "OPTFLAGS=$CFLAGS" >> config.mak echo "LDFLAGS=$LDFLAGS" >> config.mak echo "LDCONFIG=$LDCONFIG" >> config.mak echo "LIBOBJFLAGS=$LIBOBJFLAGS" >> config.mak echo "BUILDSUF=$BUILDSUF" >> config.mak echo "LIBPREF=$LIBPREF" >> config.mak echo "LIBSUF=\${BUILDSUF}$LIBSUF" >> config.mak echo "LIB=$LIB" >> config.mak echo "EXESUF=\${BUILDSUF}$EXESUF" >> config.mak echo "#define TUNECPU $TUNECPU" >> $TMPH if test "$bigendian" = "yes" ; then echo "WORDS_BIGENDIAN=yes" >> config.mak echo "#define WORDS_BIGENDIAN 1" >> $TMPH fi if test "$inttypes" != "yes" ; then echo "#define EMULATE_INTTYPES 1" >> $TMPH fi if test "$have_lrintf" = "yes" ; then echo "#define HAVE_LRINTF 1" >> $TMPH fi if test "$have_strnlen" = "yes" ; then echo "#define HAVE_STRNLEN 1" >> $TMPH fi libflake_version=`grep '#define FLAKE_VERSION ' "$source_path/libflake/flake.h" | sed 's/[^0-9\.]//g'` echo "LIB_INSTALL_EXTRA_CMD=${LIB_INSTALL_EXTRA_CMD}" >> config.mak echo "EXTRALIBS=$extralibs" >> config.mak if test "$mingw32" = "yes" ; then echo "#ifndef __MINGW32__" >> $TMPH echo "#define __MINGW32__ 1" >> $TMPH echo "#endif" >> $TMPH fi if test "$mingwce" = "yes" ; then echo "#define CONFIG_WINCE 1" >> $TMPH echo "#ifndef __MINGW32__" >> $TMPH echo "#define __MINGW32__ 1" >> $TMPH echo "#endif" >> $TMPH fi if test "$os2" = "yes" ; then echo "#define CONFIG_OS2 1" >> $TMPH fi if test "$targetos" = "SunOS" ; then echo "#define CONFIG_SUNOS 1" >> $TMPH fi if test "$targetos" = "Darwin"; then echo "#define CONFIG_DARWIN 1" >> $TMPH fi # build tree in object directory if source path is different from current one if test "$source_path_used" = "yes" ; then DIRS="\ libflake \ flake \ util \ " FILES="\ Makefile \ libflake/Makefile \ flake/Makefile \ util/Makefile \ " for dir in $DIRS ; do mkdir -p $dir done for f in $FILES ; do ln -sf "$source_path/$f" $f done fi echo "SRC_PATH=$source_path" >> config.mak echo "BUILD_ROOT=$PWD" >> config.mak # Do not overwrite config.h if unchanged to avoid superfluous rebuilds. diff $TMPH config.h >/dev/null 2>&1 if test "$?" != "0" ; then mv -f $TMPH config.h else echo "config.h is unchanged" fi rm -f $TMPO $TMPC $TMPE $TMPS $TMPH flake-0.11/COPYING0000644000175000017500000006347410655263114013203 0ustar justinjustin GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it!