/* MP3 support for SoX * * Uses libmad for MP3 decoding * libmp3lame for MP3 encoding * and libtwolame for MP2 encoding * * Written by Fabrizio Gennari <fabrizio.ge@tiscali.it> * * The decoding part is based on the decoder-tutorial program madlld * written by Bertrand Petit <madlld@phoe.fmug.org>, */ #include "sox_i.h"#include <string.h> #if defined(HAVE_LAME_LAME_H) || defined(HAVE_LAME_H) || defined(DL_LAME)#define HAVE_LAME 1#endif #if defined(HAVE_TWOLAME_H) || defined(DL_TWOLAME) #define HAVE_TWOLAME 1#endif #if defined(HAVE_MAD_H) || defined(HAVE_LAME) || defined(HAVE_TWOLAME) #ifdef HAVE_MAD_H#include <mad.h>#endif #if defined(HAVE_LAME_LAME_H)#include <lame/lame.h>#elif defined(HAVE_LAME_H)#include <lame.h>#elif defined(DL_LAME)typedef struct lame_global_struct lame_global_flags;typedef enum { vbr_off=0, vbr_default=4} vbr_mode;#endif #if defined(HAVE_ID3TAG) && (defined(HAVE_IO_H) || defined(HAVE_UNISTD_H))#define USING_ID3TAG 1#endif #ifdef USING_ID3TAG #include <id3tag.h> #include "id3.h"#if defined(HAVE_UNISTD_H) #include <unistd.h>#elif defined(HAVE_IO_H) #include <io.h>#endif#else #define ID3_TAG_FLAG_FOOTERPRESENT 0x10#endif #ifdef HAVE_TWOLAME_H #include <twolame.h>#endif /* Under Windows, importing data from DLLs is a dicey proposition. This is true * when using dlopen, but also true if linking directly against the DLL if the * header does not mark the data as __declspec(dllexport), which mad.h does not. * Sidestep the issue by defining our own mad_timer_zero. This is needed because * mad_timer_zero is used in some of the mad.h macros. */#ifdef HAVE_MAD_H#define mad_timer_zero mad_timer_zero_stubstatic mad_timer_t const mad_timer_zero_stub = {0, 0};#endif #define MAXFRAMESIZE 2880#define ID3PADDING 128 /* LAME takes float values as input. */#define MP3_LAME_PRECISION 24 /* MAD returns values with MAD_F_FRACBITS (28) bits of precision, though it's not certain that all of them are meaningful. Default to 16 bits to align with most users expectation of output file should be 16 bits. */#define MP3_MAD_PRECISION 16 static const char* const mad_library_names[] ={#ifdef DL_MAD "libmad", "libmad-0", "cygmad-0",#endif NULL}; #ifdef DL_MAD #define MAD_FUNC LSX_DLENTRY_DYNAMIC#else #define MAD_FUNC LSX_DLENTRY_STATIC#endif #define MAD_FUNC_ENTRIES(f,x) \ MAD_FUNC(f,x, void, mad_stream_buffer, (struct mad_stream *, unsigned char const *, unsigned long)) \ MAD_FUNC(f,x, void, mad_stream_skip, (struct mad_stream *, unsigned long)) \ MAD_FUNC(f,x, int, mad_stream_sync, (struct mad_stream *)) \ MAD_FUNC(f,x, void, mad_stream_init, (struct mad_stream *)) \ MAD_FUNC(f,x, void, mad_frame_init, (struct mad_frame *)) \ MAD_FUNC(f,x, void, mad_synth_init, (struct mad_synth *)) \ MAD_FUNC(f,x, int, mad_frame_decode, (struct mad_frame *, struct mad_stream *)) \ MAD_FUNC(f,x, void, mad_timer_add, (mad_timer_t *, mad_timer_t)) \ MAD_FUNC(f,x, void, mad_synth_frame, (struct mad_synth *, struct mad_frame const *)) \ MAD_FUNC(f,x, char const *, mad_stream_errorstr, (struct mad_stream const *)) \ MAD_FUNC(f,x, void, mad_frame_finish, (struct mad_frame *)) \ MAD_FUNC(f,x, void, mad_stream_finish, (struct mad_stream *)) \ MAD_FUNC(f,x, unsigned long, mad_bit_read, (struct mad_bitptr *, unsigned int)) \ MAD_FUNC(f,x, int, mad_header_decode, (struct mad_header *, struct mad_stream *)) \ MAD_FUNC(f,x, void, mad_header_init, (struct mad_header *)) \ MAD_FUNC(f,x, signed long, mad_timer_count, (mad_timer_t, enum mad_units)) \ MAD_FUNC(f,x, void, mad_timer_multiply, (mad_timer_t *, signed long)) static const char* const lame_library_names[] ={#ifdef DL_LAME "libmp3lame", "libmp3lame-0", "lame-enc", "cygmp3lame-0",#endif NULL}; #ifdef DL_LAME #define LAME_FUNC LSX_DLENTRY_DYNAMIC#else /* DL_LAME */ #define LAME_FUNC LSX_DLENTRY_STATIC#endif /* DL_LAME */ #define LAME_FUNC_ENTRIES(f,x) \ LAME_FUNC(f,x, lame_global_flags*, lame_init, (void)) \ LAME_FUNC(f,x, int, lame_set_errorf, (lame_global_flags *, void (*)(const char *, va_list))) \ LAME_FUNC(f,x, int, lame_set_debugf, (lame_global_flags *, void (*)(const char *, va_list))) \ LAME_FUNC(f,x, int, lame_set_msgf, (lame_global_flags *, void (*)(const char *, va_list))) \ LAME_FUNC(f,x, int, lame_set_num_samples, (lame_global_flags *, unsigned long)) \ LAME_FUNC(f,x, int, lame_get_num_channels, (const lame_global_flags *)) \ LAME_FUNC(f,x, int, lame_set_num_channels, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_set_in_samplerate, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_set_out_samplerate, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_set_bWriteVbrTag, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_set_brate, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_set_quality, (lame_global_flags *, int)) \ LAME_FUNC(f,x, vbr_mode, lame_get_VBR, (const lame_global_flags *)) \ LAME_FUNC(f,x, int, lame_set_VBR, (lame_global_flags *, vbr_mode)) \ LAME_FUNC(f,x, int, lame_set_VBR_q, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_init_params, (lame_global_flags *)) \ LAME_FUNC(f,x, int, lame_encode_buffer_float, (lame_global_flags *, const float[], const float[], const int, unsigned char *, const int)) \ LAME_FUNC(f,x, int, lame_encode_flush, (lame_global_flags *, unsigned char *, int)) \ LAME_FUNC(f,x, int, lame_close, (lame_global_flags *)) \ LAME_FUNC(f,x, size_t, lame_get_lametag_frame, (const lame_global_flags *, unsigned char*, size_t)) \ LAME_FUNC(f,x, void, id3tag_init, (lame_global_flags *)) \ LAME_FUNC(f,x, void, id3tag_set_title, (lame_global_flags *, const char* title)) \ LAME_FUNC(f,x, void, id3tag_set_artist, (lame_global_flags *, const char* artist)) \ LAME_FUNC(f,x, void, id3tag_set_album, (lame_global_flags *, const char* album)) \ LAME_FUNC(f,x, void, id3tag_set_year, (lame_global_flags *, const char* year)) \ LAME_FUNC(f,x, void, id3tag_set_comment, (lame_global_flags *, const char* comment)) \ LAME_FUNC(f,x, int, id3tag_set_track, (lame_global_flags *, const char* track)) \ LAME_FUNC(f,x, int, id3tag_set_genre, (lame_global_flags *, const char* genre)) \ LAME_FUNC(f,x, size_t, id3tag_set_pad, (lame_global_flags *, size_t)) \ LAME_FUNC(f,x, size_t, lame_get_id3v2_tag, (lame_global_flags *, unsigned char*, size_t)) \ LAME_FUNC(f,x, int, id3tag_set_fieldvalue, (lame_global_flags *, const char *)) #ifdef HAVE_TWOLAMEstatic const char* const twolame_library_names[] ={#ifdef DL_TWOLAME "libtwolame", "libtwolame-0",#endif NULL};#endif #ifdef DL_TWOLAME #define TWOLAME_FUNC LSX_DLENTRY_DYNAMIC#else #define TWOLAME_FUNC LSX_DLENTRY_STATIC#endif #define TWOLAME_FUNC_ENTRIES(f,x) \ TWOLAME_FUNC(f,x, twolame_options*, twolame_init, (void)) \ TWOLAME_FUNC(f,x, int, twolame_get_num_channels, (twolame_options*)) \ TWOLAME_FUNC(f,x, int, twolame_set_num_channels, (twolame_options*, int)) \ TWOLAME_FUNC(f,x, int, twolame_set_in_samplerate, (twolame_options *, int)) \ TWOLAME_FUNC(f,x, int, twolame_set_out_samplerate, (twolame_options *, int)) \ TWOLAME_FUNC(f,x, int, twolame_set_brate, (twolame_options *, int)) \ TWOLAME_FUNC(f,x, int, twolame_init_params, (twolame_options *)) \ TWOLAME_FUNC(f,x, int, twolame_encode_buffer_float32_interleaved, (twolame_options *, const float [], int, unsigned char *, int)) \ TWOLAME_FUNC(f,x, int, twolame_encode_flush, (twolame_options *, unsigned char *, int)) \ TWOLAME_FUNC(f,x, void, twolame_close, (twolame_options **)) /* Private data */typedef struct mp3_priv_t { unsigned char *mp3_buffer; size_t mp3_buffer_size; #ifdef HAVE_MAD_H struct mad_stream Stream; struct mad_frame Frame; struct mad_synth Synth; mad_timer_t Timer; ptrdiff_t cursamp; size_t FrameCount; LSX_DLENTRIES_TO_PTRS(MAD_FUNC_ENTRIES, mad_dl);#endif /*HAVE_MAD_H*/ #if defined(HAVE_LAME) || defined(HAVE_TWOLAME) float *pcm_buffer; size_t pcm_buffer_size; char mp2;#endif #ifdef HAVE_LAME lame_global_flags *gfp; uint64_t num_samples; int vbr_tag; LSX_DLENTRIES_TO_PTRS(LAME_FUNC_ENTRIES, lame_dl);#endif #ifdef HAVE_TWOLAME twolame_options *opt; LSX_DLENTRIES_TO_PTRS(TWOLAME_FUNC_ENTRIES, twolame_dl);#endif} priv_t; #ifdef HAVE_MAD_H /* This function merges the functions tagtype() and id3_tag_query() from MAD's libid3tag, so we don't have to link to it Returns 0 if the frame is not an ID3 tag, tag length if it is */ static int tagtype(const unsigned char *data, size_t length){ if (length >= 3 && data[0] == 'T' && data[1] == 'A' && data[2] == 'G') { return 128; /* ID3V1 */ } if (length >= 10 && (data[0] == 'I' && data[1] == 'D' && data[2] == '3') && data[3] < 0xff && data[4] < 0xff && data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80) { /* ID3V2 */ unsigned char flags; unsigned int size; flags = data[5]; size = 10 + (data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9]; if (flags & ID3_TAG_FLAG_FOOTERPRESENT) size += 10; for (; size < length && !data[size]; ++size); /* Consume padding */ return size; } return 0;} #endif /*HAVE_MAD_H*/ #include "mp3-util.h" #ifdef HAVE_MAD_H /* * (Re)fill the stream buffer that is to be decoded. If any data * still exists in the buffer then they are first shifted to be * front of the stream buffer. */static int sox_mp3_input(sox_format_t * ft){ priv_t *p = (priv_t *) ft->priv; size_t bytes_read; size_t remaining; remaining = p->Stream.bufend - p->Stream.next_frame; /* libmad does not consume all the buffer it's given. Some * data, part of a truncated frame, is left unused at the * end of the buffer. That data must be put back at the * beginning of the buffer and taken in account for * refilling the buffer. This means that the input buffer * must be large enough to hold a complete frame at the * highest observable bit-rate (currently 448 kb/s). * TODO: Is 2016 bytes the size of the largest frame? * (448000*(1152/32000))/8 */ memmove(p->mp3_buffer, p->Stream.next_frame, remaining); bytes_read = lsx_readbuf(ft, p->mp3_buffer+remaining, p->mp3_buffer_size-remaining); if (bytes_read == 0) { return SOX_EOF; } p->mad_stream_buffer(&p->Stream, p->mp3_buffer, bytes_read+remaining); p->Stream.error = 0; return SOX_SUCCESS;} /* Attempts to read an ID3 tag at the current location in stream and * consume it all. Returns SOX_EOF if no tag is found. Its up to * caller to recover. * */static int sox_mp3_inputtag(sox_format_t * ft){ priv_t *p = (priv_t *) ft->priv; int rc = SOX_EOF; size_t remaining; size_t tagsize; /* FIXME: This needs some more work if we are to ever * look at the ID3 frame. This is because the Stream * may not be able to hold the complete ID3 frame. * We should consume the whole frame inside tagtype() * instead of outside of tagframe(). That would support * recovering when Stream contains less then 8-bytes (header) * and also when ID3v2 is bigger then Stream buffer size. * Need to pass in stream so that buffer can be * consumed as well as letting additional data to be * read in. */ remaining = p->Stream.bufend - p->Stream.next_frame; if ((tagsize = tagtype(p->Stream.this_frame, remaining))) { p->mad_stream_skip(&p->Stream, tagsize); rc = SOX_SUCCESS; } /* We know that a valid frame hasn't been found yet * so help libmad out and go back into frame seek mode. * This is true whether an ID3 tag was found or not. */ p->mad_stream_sync(&p->Stream); return rc;} static sox_bool sox_mp3_vbrtag(sox_format_t *ft){ priv_t *p = ft->priv; struct mad_bitptr *anc = &p->Stream.anc_ptr; if (p->Frame.header.layer != MAD_LAYER_III) return sox_false; if (p->Stream.anc_bitlen < 32) return sox_false; if (!memcmp(anc->byte, "Xing", 4) || !memcmp(anc->byte, "Info", 4)) return sox_true; return sox_false;} static int startread(sox_format_t * ft){ priv_t *p = (priv_t *) ft->priv; size_t ReadSize; sox_bool ignore_length = ft->signal.length == SOX_IGNORE_LENGTH; int open_library_result; LSX_DLLIBRARY_OPEN( p, mad_dl, MAD_FUNC_ENTRIES, "MAD decoder library", mad_library_names, open_library_result); if (open_library_result) return SOX_EOF; p->mp3_buffer_size = sox_globals.bufsiz; p->mp3_buffer = lsx_malloc(p->mp3_buffer_size); ft->signal.length = SOX_UNSPEC; if (ft->seekable) {#ifdef USING_ID3TAG lsx_id3_read_tag(ft, sox_true); lsx_rewind(ft); if (!ft->signal.length)#endif if (!ignore_length) ft->signal.length = mp3_duration(ft); } p->mad_stream_init(&p->Stream); p->mad_frame_init(&p->Frame); p->mad_synth_init(&p->Synth); mad_timer_reset(&p->Timer); ft->encoding.encoding = SOX_ENCODING_MP3; /* Decode at least one valid frame to find out the input * format. The decoded frame will be saved off so that it * can be processed later. */ ReadSize = lsx_readbuf(ft, p->mp3_buffer, p->mp3_buffer_size); if (ReadSize != p->mp3_buffer_size && lsx_error(ft)) return SOX_EOF; p->mad_stream_buffer(&p->Stream, p->mp3_buffer, ReadSize); /* Find a valid frame before starting up. This makes sure * that we have a valid MP3 and also skips past ID3v2 tags * at the beginning of the audio file. */ p->Stream.error = 0; while (p->mad_frame_decode(&p->Frame,&p->Stream)) { /* check whether input buffer needs a refill */ if (p->Stream.error == MAD_ERROR_BUFLEN) { if (sox_mp3_input(ft) == SOX_EOF) return SOX_EOF; continue; } /* Consume any ID3 tags */ sox_mp3_inputtag(ft); /* FIXME: We should probably detect when we've read * a bunch of non-ID3 data and still haven't found a * frame. In that case we can abort early without * scanning the whole file. */ p->Stream.error = 0; } if (p->Stream.error) { lsx_fail_errno(ft,SOX_EOF,"No valid MP3 frame found"); return SOX_EOF; } switch(p->Frame.header.mode) { case MAD_MODE_SINGLE_CHANNEL: case MAD_MODE_DUAL_CHANNEL: case MAD_MODE_JOINT_STEREO: case MAD_MODE_STEREO: ft->signal.channels = MAD_NCHANNELS(&p->Frame.header); break; default: lsx_fail_errno(ft, SOX_EFMT, "Cannot determine number of channels"); return SOX_EOF; } ft->signal.precision = MP3_MAD_PRECISION; ft->signal.rate=p->Frame.header.samplerate; if (ignore_length) ft->signal.length = SOX_UNSPEC; else { ft->signal.length *= ft->signal.channels; /* Keep separate from line above! */ } if (!sox_mp3_vbrtag(ft)) p->Stream.next_frame = p->Stream.this_frame; p->mad_frame_init(&p->Frame); sox_mp3_input(ft); p->cursamp = 0; return SOX_SUCCESS;} /* * Read up to len samples from p->Synth * If needed, read some more MP3 data, decode them and synth them * Place in buf[]. * Return number of samples read. */static size_t sox_mp3read(sox_format_t * ft, sox_sample_t *buf, size_t len){ priv_t *p = (priv_t *) ft->priv; size_t donow,i,done=0; mad_fixed_t sample; size_t chan; do { size_t x = (p->Synth.pcm.length - p->cursamp)*ft->signal.channels; donow=min(len, x); i=0; while(i<donow){ for(chan=0;chan<ft->signal.channels;chan++){ sample=p->Synth.pcm.samples[chan][p->cursamp]; if (sample < -MAD_F_ONE) sample=-MAD_F_ONE; else if (sample >= MAD_F_ONE) sample=MAD_F_ONE-1;Lines 1–500 of 1299. Load more
/* MP3 support for SoX * * Uses libmad for MP3 decoding * libmp3lame for MP3 encoding * and libtwolame for MP2 encoding * * Written by Fabrizio Gennari <fabrizio.ge@tiscali.it> * * The decoding part is based on the decoder-tutorial program madlld * written by Bertrand Petit <madlld@phoe.fmug.org>, */ #include "sox_i.h" #include <string.h> #if defined(HAVE_LAME_LAME_H) || defined(HAVE_LAME_H) || defined(DL_LAME) #define HAVE_LAME 1 #endif #if defined(HAVE_TWOLAME_H) || defined(DL_TWOLAME) #define HAVE_TWOLAME 1 #endif #if defined(HAVE_MAD_H) || defined(HAVE_LAME) || defined(HAVE_TWOLAME) #ifdef HAVE_MAD_H #include <mad.h> #endif #if defined(HAVE_LAME_LAME_H) #include <lame/lame.h> #elif defined(HAVE_LAME_H) #include <lame.h> #elif defined(DL_LAME) typedef struct lame_global_struct lame_global_flags; typedef enum { vbr_off=0, vbr_default=4 } vbr_mode; #endif #if defined(HAVE_ID3TAG) && (defined(HAVE_IO_H) || defined(HAVE_UNISTD_H)) #define USING_ID3TAG 1 #endif #ifdef USING_ID3TAG #include <id3tag.h> #include "id3.h" #if defined(HAVE_UNISTD_H) #include <unistd.h> #elif defined(HAVE_IO_H) #include <io.h> #endif #else #define ID3_TAG_FLAG_FOOTERPRESENT 0x10 #endif #ifdef HAVE_TWOLAME_H #include <twolame.h> #endif /* Under Windows, importing data from DLLs is a dicey proposition. This is true * when using dlopen, but also true if linking directly against the DLL if the * header does not mark the data as __declspec(dllexport), which mad.h does not. * Sidestep the issue by defining our own mad_timer_zero. This is needed because * mad_timer_zero is used in some of the mad.h macros. */ #ifdef HAVE_MAD_H #define mad_timer_zero mad_timer_zero_stub static mad_timer_t const mad_timer_zero_stub = {0, 0}; #endif #define MAXFRAMESIZE 2880 #define ID3PADDING 128 /* LAME takes float values as input. */ #define MP3_LAME_PRECISION 24 /* MAD returns values with MAD_F_FRACBITS (28) bits of precision, though it's not certain that all of them are meaningful. Default to 16 bits to align with most users expectation of output file should be 16 bits. */ #define MP3_MAD_PRECISION 16 static const char* const mad_library_names[] = { #ifdef DL_MAD "libmad", "libmad-0", "cygmad-0", #endif NULL }; #ifdef DL_MAD #define MAD_FUNC LSX_DLENTRY_DYNAMIC #else #define MAD_FUNC LSX_DLENTRY_STATIC #endif #define MAD_FUNC_ENTRIES(f,x) \ MAD_FUNC(f,x, void, mad_stream_buffer, (struct mad_stream *, unsigned char const *, unsigned long)) \ MAD_FUNC(f,x, void, mad_stream_skip, (struct mad_stream *, unsigned long)) \ MAD_FUNC(f,x, int, mad_stream_sync, (struct mad_stream *)) \ MAD_FUNC(f,x, void, mad_stream_init, (struct mad_stream *)) \ MAD_FUNC(f,x, void, mad_frame_init, (struct mad_frame *)) \ MAD_FUNC(f,x, void, mad_synth_init, (struct mad_synth *)) \ MAD_FUNC(f,x, int, mad_frame_decode, (struct mad_frame *, struct mad_stream *)) \ MAD_FUNC(f,x, void, mad_timer_add, (mad_timer_t *, mad_timer_t)) \ MAD_FUNC(f,x, void, mad_synth_frame, (struct mad_synth *, struct mad_frame const *)) \ MAD_FUNC(f,x, char const *, mad_stream_errorstr, (struct mad_stream const *)) \ MAD_FUNC(f,x, void, mad_frame_finish, (struct mad_frame *)) \ MAD_FUNC(f,x, void, mad_stream_finish, (struct mad_stream *)) \ MAD_FUNC(f,x, unsigned long, mad_bit_read, (struct mad_bitptr *, unsigned int)) \ MAD_FUNC(f,x, int, mad_header_decode, (struct mad_header *, struct mad_stream *)) \ MAD_FUNC(f,x, void, mad_header_init, (struct mad_header *)) \ MAD_FUNC(f,x, signed long, mad_timer_count, (mad_timer_t, enum mad_units)) \ MAD_FUNC(f,x, void, mad_timer_multiply, (mad_timer_t *, signed long)) static const char* const lame_library_names[] = { #ifdef DL_LAME "libmp3lame", "libmp3lame-0", "lame-enc", "cygmp3lame-0", #endif NULL }; #ifdef DL_LAME #define LAME_FUNC LSX_DLENTRY_DYNAMIC #else /* DL_LAME */ #define LAME_FUNC LSX_DLENTRY_STATIC #endif /* DL_LAME */ #define LAME_FUNC_ENTRIES(f,x) \ LAME_FUNC(f,x, lame_global_flags*, lame_init, (void)) \ LAME_FUNC(f,x, int, lame_set_errorf, (lame_global_flags *, void (*)(const char *, va_list))) \ LAME_FUNC(f,x, int, lame_set_debugf, (lame_global_flags *, void (*)(const char *, va_list))) \ LAME_FUNC(f,x, int, lame_set_msgf, (lame_global_flags *, void (*)(const char *, va_list))) \ LAME_FUNC(f,x, int, lame_set_num_samples, (lame_global_flags *, unsigned long)) \ LAME_FUNC(f,x, int, lame_get_num_channels, (const lame_global_flags *)) \ LAME_FUNC(f,x, int, lame_set_num_channels, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_set_in_samplerate, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_set_out_samplerate, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_set_bWriteVbrTag, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_set_brate, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_set_quality, (lame_global_flags *, int)) \ LAME_FUNC(f,x, vbr_mode, lame_get_VBR, (const lame_global_flags *)) \ LAME_FUNC(f,x, int, lame_set_VBR, (lame_global_flags *, vbr_mode)) \ LAME_FUNC(f,x, int, lame_set_VBR_q, (lame_global_flags *, int)) \ LAME_FUNC(f,x, int, lame_init_params, (lame_global_flags *)) \ LAME_FUNC(f,x, int, lame_encode_buffer_float, (lame_global_flags *, const float[], const float[], const int, unsigned char *, const int)) \ LAME_FUNC(f,x, int, lame_encode_flush, (lame_global_flags *, unsigned char *, int)) \ LAME_FUNC(f,x, int, lame_close, (lame_global_flags *)) \ LAME_FUNC(f,x, size_t, lame_get_lametag_frame, (const lame_global_flags *, unsigned char*, size_t)) \ LAME_FUNC(f,x, void, id3tag_init, (lame_global_flags *)) \ LAME_FUNC(f,x, void, id3tag_set_title, (lame_global_flags *, const char* title)) \ LAME_FUNC(f,x, void, id3tag_set_artist, (lame_global_flags *, const char* artist)) \ LAME_FUNC(f,x, void, id3tag_set_album, (lame_global_flags *, const char* album)) \ LAME_FUNC(f,x, void, id3tag_set_year, (lame_global_flags *, const char* year)) \ LAME_FUNC(f,x, void, id3tag_set_comment, (lame_global_flags *, const char* comment)) \ LAME_FUNC(f,x, int, id3tag_set_track, (lame_global_flags *, const char* track)) \ LAME_FUNC(f,x, int, id3tag_set_genre, (lame_global_flags *, const char* genre)) \ LAME_FUNC(f,x, size_t, id3tag_set_pad, (lame_global_flags *, size_t)) \ LAME_FUNC(f,x, size_t, lame_get_id3v2_tag, (lame_global_flags *, unsigned char*, size_t)) \ LAME_FUNC(f,x, int, id3tag_set_fieldvalue, (lame_global_flags *, const char *)) #ifdef HAVE_TWOLAME static const char* const twolame_library_names[] = { #ifdef DL_TWOLAME "libtwolame", "libtwolame-0", #endif NULL }; #endif #ifdef DL_TWOLAME #define TWOLAME_FUNC LSX_DLENTRY_DYNAMIC #else #define TWOLAME_FUNC LSX_DLENTRY_STATIC #endif #define TWOLAME_FUNC_ENTRIES(f,x) \ TWOLAME_FUNC(f,x, twolame_options*, twolame_init, (void)) \ TWOLAME_FUNC(f,x, int, twolame_get_num_channels, (twolame_options*)) \ TWOLAME_FUNC(f,x, int, twolame_set_num_channels, (twolame_options*, int)) \ TWOLAME_FUNC(f,x, int, twolame_set_in_samplerate, (twolame_options *, int)) \ TWOLAME_FUNC(f,x, int, twolame_set_out_samplerate, (twolame_options *, int)) \ TWOLAME_FUNC(f,x, int, twolame_set_brate, (twolame_options *, int)) \ TWOLAME_FUNC(f,x, int, twolame_init_params, (twolame_options *)) \ TWOLAME_FUNC(f,x, int, twolame_encode_buffer_float32_interleaved, (twolame_options *, const float [], int, unsigned char *, int)) \ TWOLAME_FUNC(f,x, int, twolame_encode_flush, (twolame_options *, unsigned char *, int)) \ TWOLAME_FUNC(f,x, void, twolame_close, (twolame_options **)) /* Private data */ typedef struct mp3_priv_t { unsigned char *mp3_buffer; size_t mp3_buffer_size; #ifdef HAVE_MAD_H struct mad_stream Stream; struct mad_frame Frame; struct mad_synth Synth; mad_timer_t Timer; ptrdiff_t cursamp; size_t FrameCount; LSX_DLENTRIES_TO_PTRS(MAD_FUNC_ENTRIES, mad_dl); #endif /*HAVE_MAD_H*/ #if defined(HAVE_LAME) || defined(HAVE_TWOLAME) float *pcm_buffer; size_t pcm_buffer_size; char mp2; #endif #ifdef HAVE_LAME lame_global_flags *gfp; uint64_t num_samples; int vbr_tag; LSX_DLENTRIES_TO_PTRS(LAME_FUNC_ENTRIES, lame_dl); #endif #ifdef HAVE_TWOLAME twolame_options *opt; LSX_DLENTRIES_TO_PTRS(TWOLAME_FUNC_ENTRIES, twolame_dl); #endif } priv_t; #ifdef HAVE_MAD_H /* This function merges the functions tagtype() and id3_tag_query() from MAD's libid3tag, so we don't have to link to it Returns 0 if the frame is not an ID3 tag, tag length if it is */ static int tagtype(const unsigned char *data, size_t length) { if (length >= 3 && data[0] == 'T' && data[1] == 'A' && data[2] == 'G') { return 128; /* ID3V1 */ } if (length >= 10 && (data[0] == 'I' && data[1] == 'D' && data[2] == '3') && data[3] < 0xff && data[4] < 0xff && data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80) { /* ID3V2 */ unsigned char flags; unsigned int size; flags = data[5]; size = 10 + (data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9]; if (flags & ID3_TAG_FLAG_FOOTERPRESENT) size += 10; for (; size < length && !data[size]; ++size); /* Consume padding */ return size; } return 0; } #endif /*HAVE_MAD_H*/ #include "mp3-util.h" #ifdef HAVE_MAD_H /* * (Re)fill the stream buffer that is to be decoded. If any data * still exists in the buffer then they are first shifted to be * front of the stream buffer. */ static int sox_mp3_input(sox_format_t * ft) { priv_t *p = (priv_t *) ft->priv; size_t bytes_read; size_t remaining; remaining = p->Stream.bufend - p->Stream.next_frame; /* libmad does not consume all the buffer it's given. Some * data, part of a truncated frame, is left unused at the * end of the buffer. That data must be put back at the * beginning of the buffer and taken in account for * refilling the buffer. This means that the input buffer * must be large enough to hold a complete frame at the * highest observable bit-rate (currently 448 kb/s). * TODO: Is 2016 bytes the size of the largest frame? * (448000*(1152/32000))/8 */ memmove(p->mp3_buffer, p->Stream.next_frame, remaining); bytes_read = lsx_readbuf(ft, p->mp3_buffer+remaining, p->mp3_buffer_size-remaining); if (bytes_read == 0) { return SOX_EOF; } p->mad_stream_buffer(&p->Stream, p->mp3_buffer, bytes_read+remaining); p->Stream.error = 0; return SOX_SUCCESS; } /* Attempts to read an ID3 tag at the current location in stream and * consume it all. Returns SOX_EOF if no tag is found. Its up to * caller to recover. * */ static int sox_mp3_inputtag(sox_format_t * ft) { priv_t *p = (priv_t *) ft->priv; int rc = SOX_EOF; size_t remaining; size_t tagsize; /* FIXME: This needs some more work if we are to ever * look at the ID3 frame. This is because the Stream * may not be able to hold the complete ID3 frame. * We should consume the whole frame inside tagtype() * instead of outside of tagframe(). That would support * recovering when Stream contains less then 8-bytes (header) * and also when ID3v2 is bigger then Stream buffer size. * Need to pass in stream so that buffer can be * consumed as well as letting additional data to be * read in. */ remaining = p->Stream.bufend - p->Stream.next_frame; if ((tagsize = tagtype(p->Stream.this_frame, remaining))) { p->mad_stream_skip(&p->Stream, tagsize); rc = SOX_SUCCESS; } /* We know that a valid frame hasn't been found yet * so help libmad out and go back into frame seek mode. * This is true whether an ID3 tag was found or not. */ p->mad_stream_sync(&p->Stream); return rc; } static sox_bool sox_mp3_vbrtag(sox_format_t *ft) { priv_t *p = ft->priv; struct mad_bitptr *anc = &p->Stream.anc_ptr; if (p->Frame.header.layer != MAD_LAYER_III) return sox_false; if (p->Stream.anc_bitlen < 32) return sox_false; if (!memcmp(anc->byte, "Xing", 4) || !memcmp(anc->byte, "Info", 4)) return sox_true; return sox_false; } static int startread(sox_format_t * ft) { priv_t *p = (priv_t *) ft->priv; size_t ReadSize; sox_bool ignore_length = ft->signal.length == SOX_IGNORE_LENGTH; int open_library_result; LSX_DLLIBRARY_OPEN( p, mad_dl, MAD_FUNC_ENTRIES, "MAD decoder library", mad_library_names, open_library_result); if (open_library_result) return SOX_EOF; p->mp3_buffer_size = sox_globals.bufsiz; p->mp3_buffer = lsx_malloc(p->mp3_buffer_size); ft->signal.length = SOX_UNSPEC; if (ft->seekable) { #ifdef USING_ID3TAG lsx_id3_read_tag(ft, sox_true); lsx_rewind(ft); if (!ft->signal.length) #endif if (!ignore_length) ft->signal.length = mp3_duration(ft); } p->mad_stream_init(&p->Stream); p->mad_frame_init(&p->Frame); p->mad_synth_init(&p->Synth); mad_timer_reset(&p->Timer); ft->encoding.encoding = SOX_ENCODING_MP3; /* Decode at least one valid frame to find out the input * format. The decoded frame will be saved off so that it * can be processed later. */ ReadSize = lsx_readbuf(ft, p->mp3_buffer, p->mp3_buffer_size); if (ReadSize != p->mp3_buffer_size && lsx_error(ft)) return SOX_EOF; p->mad_stream_buffer(&p->Stream, p->mp3_buffer, ReadSize); /* Find a valid frame before starting up. This makes sure * that we have a valid MP3 and also skips past ID3v2 tags * at the beginning of the audio file. */ p->Stream.error = 0; while (p->mad_frame_decode(&p->Frame,&p->Stream)) { /* check whether input buffer needs a refill */ if (p->Stream.error == MAD_ERROR_BUFLEN) { if (sox_mp3_input(ft) == SOX_EOF) return SOX_EOF; continue; } /* Consume any ID3 tags */ sox_mp3_inputtag(ft); /* FIXME: We should probably detect when we've read * a bunch of non-ID3 data and still haven't found a * frame. In that case we can abort early without * scanning the whole file. */ p->Stream.error = 0; } if (p->Stream.error) { lsx_fail_errno(ft,SOX_EOF,"No valid MP3 frame found"); return SOX_EOF; } switch(p->Frame.header.mode) { case MAD_MODE_SINGLE_CHANNEL: case MAD_MODE_DUAL_CHANNEL: case MAD_MODE_JOINT_STEREO: case MAD_MODE_STEREO: ft->signal.channels = MAD_NCHANNELS(&p->Frame.header); break; default: lsx_fail_errno(ft, SOX_EFMT, "Cannot determine number of channels"); return SOX_EOF; } ft->signal.precision = MP3_MAD_PRECISION; ft->signal.rate=p->Frame.header.samplerate; if (ignore_length) ft->signal.length = SOX_UNSPEC; else { ft->signal.length *= ft->signal.channels; /* Keep separate from line above! */ } if (!sox_mp3_vbrtag(ft)) p->Stream.next_frame = p->Stream.this_frame; p->mad_frame_init(&p->Frame); sox_mp3_input(ft); p->cursamp = 0; return SOX_SUCCESS; } /* * Read up to len samples from p->Synth * If needed, read some more MP3 data, decode them and synth them * Place in buf[]. * Return number of samples read. */ static size_t sox_mp3read(sox_format_t * ft, sox_sample_t *buf, size_t len) { priv_t *p = (priv_t *) ft->priv; size_t donow,i,done=0; mad_fixed_t sample; size_t chan; do { size_t x = (p->Synth.pcm.length - p->cursamp)*ft->signal.channels; donow=min(len, x); i=0; while(i<donow){ for(chan=0;chan<ft->signal.channels;chan++){ sample=p->Synth.pcm.samples[chan][p->cursamp]; if (sample < -MAD_F_ONE) sample=-MAD_F_ONE; else if (sample >= MAD_F_ONE) sample=MAD_F_ONE-1;