/*
* Get Audio routines source file
*
* Copyright (c) 1999 Albert L Faber
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* $Id: get_audio.c,v 1.102 2005/05/25 14:17:51 takehiro Exp $ */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#ifdef HAVE_LIMITS_H
# include <limits.h>
#endif
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <string.h>
#else
# ifndef HAVE_STRCHR
# define strchr index
# define strrchr rindex
# endif
char *strchr(), *strrchr();
# ifndef HAVE_MEMCPY
# define memcpy(d, s, n) bcopy ((s), (d), (n))
# define memmove(d, s, n) bcopy ((s), (d), (n))
# endif
#endif
#define MAX_U_32_NUM 0xFFFFFFFF
#include <math.h>
#include <sys/stat.h>
#ifdef __sun__
/* woraround for SunOS 4.x, it has SEEK_* defined here */
#include <unistd.h>
#endif
#include "lame.h"
#include "main.h"
#include "get_audio.h"
#include "portableio.h"
#include "timestatus.h"
#include "lametime.h"
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif
/* global data for get_audio.c. */
int count_samples_carefully;
int pcmbitwidth;
int pcmswapbytes = 0;
unsigned int num_samples_read;
FILE *musicin;
#ifdef AMIGA_MPEGA
int lame_decode_initfile(const char *fullname,
mp3data_struct * const mp3data);
#else
int lame_decode_initfile(FILE * fd, mp3data_struct * mp3data);
#endif
/* read mp3 file until mpglib returns one frame of PCM data */
int lame_decode_fromfile(FILE * fd, short int pcm_l[], short int pcm_r[],
mp3data_struct * mp3data);
static int read_samples_pcm(FILE * musicin, int sample_buffer[2304],
int frame_size, int samples_to_read);
static int read_samples_mp3(lame_global_flags * const gfp, FILE * const musicin,
short int mpg123pcm[2][1152], int num_chan);
void CloseSndFile(sound_file_format input, FILE * musicin);
FILE *OpenSndFile(lame_global_flags * gfp, char *);
/* Replacement for forward fseek(,,SEEK_CUR), because fseek() fails on pipes */
static int
fskip(FILE * fp, long offset, int whence)
{
#ifndef PIPE_BUF
char buffer[4096];
#else
char buffer[PIPE_BUF];
#endif
int read;
if (0 == fseek(fp, offset, whence))
return 0;
if (whence != SEEK_CUR || offset < 0) {
if( silent < 10 ) {
fprintf(stderr,
"fskip problem: Mostly the return status of functions is not evaluate so it is more secure to polute <stderr>.\n");
}
return -1;
}
while (offset > 0) {
read = offset > sizeof(buffer) ? sizeof(buffer) : offset;
if ((read = fread(buffer, 1, read, fp)) <= 0)
return -1;
offset -= read;
}
return 0;
}
FILE *
init_outfile(char *outPath, int decode)
{
FILE *outf;
#ifdef __riscos__
char *p;
#endif
/* open the output file */
if (0 == strcmp(outPath, "-")) {
lame_set_stream_binary_mode(outf = stdout);
}
else {
if ((outf = fopen(outPath, "wb+")) == NULL)
return NULL;
#ifdef __riscos__
/* Assign correct file type */
for (p = outPath; *p; p++) /* ugly, ugly to modify a string */
switch (*p) {
case '.':
*p = '/';
break;
case '/':
*p = '.';
break;
}
SetFiletype(outPath, decode ? 0xFB1 /*WAV*/ : 0x1AD /*AMPEG*/);
#endif
}
return outf;
}
void
init_infile(lame_global_flags * gfp, char *inPath)
{
/* open the input file */
count_samples_carefully = 0;
num_samples_read=0;
pcmbitwidth=in_bitwidth;
pcmswapbytes=swapbytes;
musicin = OpenSndFile(gfp, inPath);
}
void
close_infile(void)
{
CloseSndFile(input_format, musicin);
}
void
SwapBytesInWords(short *ptr, int short_words)
{ /* Some speedy code */
unsigned long val;
unsigned long *p = (unsigned long *) ptr;
#ifndef lint
# if defined(CHAR_BIT)
# if CHAR_BIT != 8
# error CHAR_BIT != 8
# endif
# else
# error can not determine number of bits in a char
# endif
#endif /* lint */
assert(sizeof(short) == 2);
#if defined(SIZEOF_UNSIGNED_LONG) && SIZEOF_UNSIGNED_LONG == 4
for (; short_words >= 2; short_words -= 2, p++) {
val = *p;
*p = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0x00FF00FF);
}
ptr = (short *) p;
for (; short_words >= 1; short_words -= 1, ptr++) {
val = *ptr;
*ptr = ((val << 8) & 0xFF00) | ((val >> 8) & 0x00FF);
}
#elif defined(SIZEOF_UNSIGNED_LONG) && SIZEOF_UNSIGNED_LONG == 8
for (; short_words >= 4; short_words -= 4, p++) {
val = *p;
*p =
((val << 8) & 0xFF00FF00FF00FF00) | ((val >> 8) &
0x00FF00FF00FF00FF);
}
ptr = (short *) p;
for (; short_words >= 1; short_words -= 1, ptr++) {
val = *ptr;
*ptr = ((val << 8) & 0xFF00) | ((val >> 8) & 0x00FF);
}
#else
# ifdef SIZEOF_UNSIGNED_LONG
# warning Using unoptimized SwapBytesInWords().
# endif
for (; short_words >= 1; short_words -= 1, ptr++) {
val = *ptr;
*ptr = ((val << 8) & 0xFF00) | ((val >> 8) & 0x00FF);
}
#endif
assert(short_words == 0);
}
static int
get_audio_common( lame_global_flags * const gfp,
int buffer[2][1152], short buffer16[2][1152] );
/************************************************************************
*
* get_audio()
*
* PURPOSE: reads a frame of audio data from a file to the buffer,
* aligns the data for future processing, and separates the
* left and right channels
*
************************************************************************/
int
get_audio( lame_global_flags * const gfp, int buffer[2][1152] )
{
return( get_audio_common( gfp, buffer, NULL ) );
}
/*
get_audio16 - behave as the original get_audio function, with a limited
16 bit per sample output
*/
int
get_audio16( lame_global_flags * const gfp, short buffer[2][1152] )
{
return( get_audio_common( gfp, NULL, buffer ) );
}
/************************************************************************
get_audio_common - central functionality of get_audio*
in: gfp
buffer output to the int buffer or 16-bit buffer
out: buffer int output (if buffer != NULL)
buffer16 16-bit output (if buffer == NULL)
returns: samples read
note: either buffer or buffer16 must be allocated upon call
*/
static int
get_audio_common( lame_global_flags * const gfp,
int buffer[2][1152], short buffer16[2][1152] )
{
int num_channels = lame_get_num_channels( gfp );
int insamp[2 * 1152];
short buf_tmp16[2][1152];
int samples_read;
int framesize;
int samples_to_read;
unsigned int remaining, tmp_num_samples;
int i;
int *p;
/*
* NOTE: LAME can now handle arbritray size input data packets,
* so there is no reason to read the input data in chuncks of
* size "framesize". EXCEPT: the LAME graphical frame analyzer
* will get out of sync if we read more than framesize worth of data.
*/
samples_to_read = framesize = lame_get_framesize(gfp);
assert(framesize <= 1152);
/* get num_samples */
tmp_num_samples = lame_get_num_samples( gfp );
/* if this flag has been set, then we are carefull to read
* exactly num_samples and no more. This is useful for .wav and .aiff
* files which have id3 or other tags at the end. Note that if you
* are using LIBSNDFILE, this is not necessary
*/
if (count_samples_carefully) {
remaining = tmp_num_samples - Min(tmp_num_samples, num_samples_read);
if (remaining < framesize && 0 != tmp_num_samples)
/* in case the input is a FIFO (at least it's reproducible with
a FIFO) tmp_num_samples may be 0 and therefore remaining
would be 0, but we need to read some samples, so don't
change samples_to_read to the wrong value in this case */
samples_to_read = remaining;
}
switch (input_format) {
case sf_mp1:
case sf_mp2:
case sf_mp3:
if( buffer != NULL )
samples_read = read_samples_mp3( gfp, musicin,
buf_tmp16, num_channels );
else
samples_read = read_samples_mp3( gfp, musicin,
buffer16, num_channels );
break;
default:
samples_read =
read_samples_pcm(musicin, insamp, num_channels * framesize,
num_channels * samples_to_read);
p = insamp + samples_read;
samples_read /= num_channels;
if( buffer != NULL ) { /* output to int buffer */
if( num_channels == 2 ) {
for( i = samples_read; --i >= 0; ) {
buffer[1][i] = *--p;
buffer[0][i] = *--p;
}
} else if( num_channels == 1 ) {
memset( buffer[1], 0, samples_read * sizeof(int) );
for( i = samples_read; --i >= 0; ) {
buffer[0][i] = *--p;
}
} else
assert(0);
} else { /* convert from int; output to 16-bit buffer */
if( num_channels == 2 ) {
for( i = samples_read; --i >= 0; ) {
buffer16[1][i] = *--p >> (8 * sizeof(int) - 16);
buffer16[0][i] = *--p >> (8 * sizeof(int) - 16);
}
} else if( num_channels == 1 ) {
memset( buffer16[1], 0, samples_read * sizeof(short) );
for( i = samples_read; --i >= 0; ) {
buffer16[0][i] = *--p >> (8 * sizeof(int) - 16);
}
} else
assert(0);
}
}
/* LAME mp3 output 16bit - convert to int, if necessary */
if( input_format == sf_mp1 || input_format == sf_mp2 ||
input_format == sf_mp3) {
if( buffer != NULL ) {
for( i = samples_read; --i >= 0; )
buffer[0][i] = buf_tmp16[0][i] << (8 * sizeof(int) - 16);
if( num_channels == 2 ) {
for( i = samples_read; --i >= 0; )
buffer[1][i] = buf_tmp16[1][i] << (8 * sizeof(int) - 16);
} else if( num_channels == 1 ) {
memset( buffer[1], 0, samples_read * sizeof(int) );
} else
assert(0);
}
}
/* if num_samples = MAX_U_32_NUM, then it is considered infinitely long.
Don't count the samples */
if ( tmp_num_samples != MAX_U_32_NUM )
num_samples_read += samples_read;
return samples_read;
}
int
read_samples_mp3(lame_global_flags * const gfp,
FILE * const musicin, short int mpg123pcm[2][1152], int stereo)
{
int out;
#if defined(AMIGA_MPEGA) || defined(HAVE_MPGLIB)
static const char type_name[] = "MP3 file";
out =
lame_decode_fromfile(musicin, mpg123pcm[0], mpg123pcm[1],
&mp3input_data);
/*
* out < 0: error, probably EOF
* out = 0: not possible with lame_decode_fromfile() ???
* out > 0: number of output samples
*/
if (out < 0) {
memset(mpg123pcm, 0, sizeof(**mpg123pcm) * 2 * 1152);
return 0;
}
if ( lame_get_num_channels( gfp ) != mp3input_data.stereo )
if( silent < 10 ) {
fprintf(stderr,
"Error: number of channels has changed in %s - not supported\n",
type_name);
}
if ( lame_get_in_samplerate( gfp ) != mp3input_data.samplerate )
if( silent < 10 ) {
fprintf(stderr,
"Error: sample frequency has changed in %s - not supported\n",
type_name);
}
#else
out = -1;
#endif
return out;
}
int
WriteWaveHeader(FILE * const fp, const int pcmbytes,
const int freq, const int channels, const int bits)
{
int bytes = (bits + 7) / 8;
/* quick and dirty, but documented */
fwrite("RIFF", 1, 4, fp); /* label */
Write32BitsLowHigh(fp, pcmbytes + 44 - 8); /* length in bytes without header */
fwrite("WAVEfmt ", 2, 4, fp); /* 2 labels */
Write32BitsLowHigh(fp, 2 + 2 + 4 + 4 + 2 + 2); /* length of PCM format declaration area */
Write16BitsLowHigh(fp, 1); /* is PCM? */
Write16BitsLowHigh(fp, channels); /* number of channels */
Write32BitsLowHigh(fp, freq); /* sample frequency in [Hz] */
Write32BitsLowHigh(fp, freq * channels * bytes); /* bytes per second */
Write16BitsLowHigh(fp, channels * bytes); /* bytes per sample time */
Write16BitsLowHigh(fp, bits); /* bits per sample */
fwrite("data", 1, 4, fp); /* label */
Write32BitsLowHigh(fp, pcmbytes); /* length in bytes of raw PCM data */
return ferror(fp) ? -1 : 0;
}
#if defined(LIBSNDFILE)
/*
** Copyright (C) 1999 Albert Faber
**
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
void
CloseSndFile(sound_file_format input, FILE * musicin)
{
SNDFILE *gs_pSndFileIn = (SNDFILE *) musicin;
if (input == sf_mp1 || input == sf_mp2 || input == sf_mp3) {
#ifndef AMIGA_MPEGA
if (fclose(musicin) != 0) {
if( silent < 10 ) {
fprintf(stderr, "Could not close audio input file\n");
}
exit(2);
}
#endif
}
else {
if (gs_pSndFileIn) {
if (sf_close(gs_pSndFileIn) != 0) {
if( silent < 10 ) {
fprintf(stderr, "Could not close sound file \n");
}
exit(2);
}
}
}
}
FILE *
OpenSndFile(lame_global_flags * gfp, char *inPath)
{
char *lpszFileName = inPath;
FILE *musicin;
SNDFILE *gs_pSndFileIn;
SF_INFO gs_wfInfo;
if (input_format == sf_mp1 ||
input_format == sf_mp2 || input_format == sf_mp3) {
#ifdef AMIGA_MPEGA
if (-1 == lame_decode_initfile(lpszFileName, &mp3input_data)) {
if( silent < 10 ) {
fprintf(stderr, "Error reading headers in mp3 input file %s.\n",
lpszFileName);
}
exit(1);
}
#endif
#ifdef HAVE_MPGLIB
if ((musicin = fopen(lpszFileName, "rb")) == NULL) {
if( silent < 10 ) {
fprintf(stderr, "Could not find \"%s\".\n", lpszFileName);
}
exit(1);
}
if (-1 == lame_decode_initfile(musicin, &mp3input_data)) {
if( silent < 10 ) {
fprintf(stderr, "Error reading headers in mp3 input file %s.\n",
lpszFileName);
}
exit(1);
}
#endif
if( -1 == lame_set_num_channels( gfp, mp3input_data.stereo ) ) {
if( silent < 10 ) {
fprintf( stderr,
"Unsupported number of channels: %ud\n",
mp3input_data.stereo );
}
exit( 1 );
}
(void) lame_set_in_samplerate( gfp, mp3input_data.samplerate );
(void) lame_set_num_samples( gfp, mp3input_data.nsamp );
}
else if (input_format == sf_ogg) {
if( silent < 10 ) {
fprintf(stderr, "sorry, vorbis support in LAME is deprecated.\n");
}
exit(1);
}
else {
/* Try to open the sound file */
/* set some defaults incase input is raw PCM */
gs_wfInfo.seekable = (input_format != sf_raw); /* if user specified -r, set to not seekable */
gs_wfInfo.samplerate = lame_get_in_samplerate( gfp );
gs_wfInfo.pcmbitwidth = in_bitwidth;
gs_wfInfo.channels = lame_get_num_channels( gfp );
if (in_bitwidth == 8) {
if (in_signed)
gs_wfInfo.format = SF_FORMAT_RAW_S8;
else
gs_wfInfo.format = SF_FORMAT_RAW_U8;
} else {
if (!in_signed) {
fputs("Unsigned input only supported with bitwidth 8\n", stderr);
exit(1);
}
if (in_endian != order_unknown) {
if (in_endian == order_littleEndian)
gs_wfInfo.format = SF_FORMAT_RAW_LE;
else
gs_wfInfo.format = SF_FORMAT_RAW_BE;
} else {
#ifndef WORDS_BIGENDIAN
/* little endian */
if (swapbytes)
gs_wfInfo.format = SF_FORMAT_RAW_BE;
else
gs_wfInfo.format = SF_FORMAT_RAW_LE;
#else
if (swapbytes)
gs_wfInfo.format = SF_FORMAT_RAW_LE;
else
gs_wfInfo.format = SF_FORMAT_RAW_BE;
#endif
}
}
gs_pSndFileIn = sf_open_read(lpszFileName, &gs_wfInfo);
musicin = (SNDFILE *) gs_pSndFileIn;
/* Check result */
if (gs_pSndFileIn == NULL) {
sf_perror(gs_pSndFileIn);
if( silent < 10 ) {
fprintf(stderr, "Could not open sound file \"%s\".\n",
lpszFileName);
}
exit(1);
}
if ((gs_wfInfo.format == SF_FORMAT_RAW_LE) ||
(gs_wfInfo.format == SF_FORMAT_RAW_BE) ||
(gs_wfInfo.format == SF_FORMAT_RAW_S8) ||
(gs_wfInfo.format == SF_FORMAT_RAW_U8))
input_format = sf_raw;
#ifdef _DEBUG_SND_FILE
DEBUGF("\n\nSF_INFO structure\n");
DEBUGF("samplerate :%d\n", gs_wfInfo.samplerate);
DEBUGF("samples :%d\n", gs_wfInfo.samples);
DEBUGF("channels :%d\n", gs_wfInfo.channels);
DEBUGF("pcmbitwidth :%d\n", gs_wfInfo.pcmbitwidth);
DEBUGF("format :");
/* new formats from sbellon@sbellon.de 1/2000 */
switch (gs_wfInfo.format & SF_FORMAT_TYPEMASK) {
case SF_FORMAT_WAV:
DEBUGF("Microsoft WAV format (big endian). ");
break;
case SF_FORMAT_AIFF:
DEBUGF("Apple/SGI AIFF format (little endian). ");
break;
case SF_FORMAT_AU:
DEBUGF("Sun/NeXT AU format (big endian). ");
break;
case SF_FORMAT_AULE:
DEBUGF("DEC AU format (little endian). ");
break;
case SF_FORMAT_RAW:
DEBUGF("RAW PCM data. ");
break;
case SF_FORMAT_PAF:
DEBUGF("Ensoniq PARIS file format. ");
break;
case SF_FORMAT_SVX:
DEBUGF("Amiga IFF / SVX8 / SV16 format. ");
break;
case SF_FORMAT_NIST:
DEBUGF("Sphere NIST format. ");
break;
default:
assert(0);
break;
}
switch (gs_wfInfo.format & SF_FORMAT_SUBMASK) {
case SF_FORMAT_PCM:
DEBUGF("PCM data in 8, 16, 24 or 32 bits.");
break;
case SF_FORMAT_FLOAT:
DEBUGF("32 bit Intel x86 floats.");
break;
case SF_FORMAT_ULAW:
DEBUGF("U-Law encoded.");
break;
case SF_FORMAT_ALAW:
DEBUGF("A-Law encoded.");
break;
case SF_FORMAT_IMA_ADPCM:
DEBUGF("IMA ADPCM.");
break;
case SF_FORMAT_MS_ADPCM:
DEBUGF("Microsoft ADPCM.");
break;
case SF_FORMAT_PCM_BE:
DEBUGF("Big endian PCM data.");
break;
case SF_FORMAT_PCM_LE:
DEBUGF("Little endian PCM data.");
break;
case SF_FORMAT_PCM_S8:
DEBUGF("Signed 8 bit PCM.");
break;
case SF_FORMAT_PCM_U8:
DEBUGF("Unsigned 8 bit PCM.");
break;
case SF_FORMAT_SVX_FIB:
DEBUGF("SVX Fibonacci Delta encoding.");
break;
case SF_FORMAT_SVX_EXP:
DEBUGF("SVX Exponential Delta encoding.");
break;
default:
assert(0);
break;
}
DEBUGF("\n");
DEBUGF("pcmbitwidth :%d\n", gs_wfInfo.pcmbitwidth);
DEBUGF("sections :%d\n", gs_wfInfo.sections);
DEBUGF("seekable :\n", gs_wfInfo.seekable);
#endif
(void) lame_set_num_samples( gfp, gs_wfInfo.samples );
if( -1 == lame_set_num_channels( gfp, gs_wfInfo.channels ) ) {
if( silent < 10 ) {
fprintf( stderr,
"Unsupported number of channels: %ud\n",
gs_wfInfo.channels );
}
exit( 1 );
}
(void) lame_set_in_samplerate( gfp, gs_wfInfo.samplerate );
pcmbitwidth = gs_wfInfo.pcmbitwidth;
}
if (lame_get_num_samples( gfp ) == MAX_U_32_NUM) {
/* try to figure out num_samples */
double flen = lame_get_file_size( lpszFileName );
if (flen >= 0) {
/* try file size, assume 2 bytes per sample */
if (input_format == sf_mp1 ||
input_format == sf_mp2 || input_format == sf_mp3) {
if (mp3input_data.bitrate>0) {
double totalseconds =
(flen * 8.0 / (1000.0 * mp3input_data.bitrate));
unsigned long tmp_num_samples =
totalseconds * lame_get_in_samplerate( gfp );
(void) lame_set_num_samples( gfp, tmp_num_samples );
mp3input_data.nsamp = tmp_num_samples;
}
}
else {
lame_set_num_samples( gfp,
flen / (2 * lame_get_num_channels( gfp )) );
}
}
}
return musicin;
}
/************************************************************************
*
* read_samples()
*
* PURPOSE: reads the PCM samples from a file to the buffer
*
* SEMANTICS:
* Reads #samples_read# number of shorts from #musicin# filepointer
* into #sample_buffer[]#. Returns the number of samples read.
*
************************************************************************/
static int
read_samples_pcm(FILE * const musicin, int sample_buffer[2304],
int frame_size /* unused */ , int samples_to_read)
{
int i;
int samples_read;
samples_read =
sf_read_int((SNDFILE *) musicin, sample_buffer, samples_to_read);
switch (pcmbitwidth) {
case 8:
for (i = 0; i < samples_read; i++)
sample_buffer[i] <<= (8 * sizeof(int) - 8);
break;
case 16:
for (i = 0; i < samples_read; i++)
sample_buffer[i] <<= (8 * sizeof(int) - 16);
break;
case 24:
for (i = 0; i < samples_read; i++)
sample_buffer[i] <<= (8 * sizeof(int) - 24);
break;
case 32:
break;
default:
if( silent < 10 ) {
fprintf(stderr, "Only 8, 16, 24 and 32 bit input files supported \n");
}
exit(1);
}
return samples_read;
}
#else /* defined(LIBSNDFILE) */
/************************************************************************
************************************************************************
************************************************************************
************************************************************************
************************************************************************
************************************************************************
*
* OLD ISO/LAME routines follow. Used if you dont have LIBSNDFILE
* or for stdin/stdout support
*
************************************************************************
************************************************************************
************************************************************************
************************************************************************
************************************************************************
************************************************************************/
/************************************************************************
unpack_read_samples - read and unpack signed low-to-high byte or unsigned
single byte input. (used for read_samples function)
Output integers are stored in the native byte order
(little or big endian). -jd
in: samples_to_read
bytes_per_sample
swap_order - set for high-to-low byte order input stream
i/o: pcm_in
out: sample_buffer (must be allocated up to samples_to_read upon call)
returns: number of samples read
*/
static int
unpack_read_samples( const int samples_to_read, const int bytes_per_sample,
const int swap_order, int *sample_buffer, FILE *pcm_in )
{
int samples_read;
int i;
int *op; /* output pointer */
unsigned char *ip = (unsigned char *) sample_buffer; /* input pointer */
const int b = sizeof(int) * 8;
#define GA_URS_IFLOOP( ga_urs_bps ) \
if( bytes_per_sample == ga_urs_bps ) \
for( i = samples_read * bytes_per_sample; (i -= bytes_per_sample) >=0;)
samples_read = fread( sample_buffer, bytes_per_sample,
samples_to_read, pcm_in);
op = sample_buffer + samples_read;
GA_URS_IFLOOP( 1 )
*--op = (ip[i] ^ 0x80)<<(b-8) | 0x7f<<(b-16);/* convert from unsigned*/
if( swap_order == 0 ) {
GA_URS_IFLOOP( 2 )
*--op = ip[i]<<(b-16) | ip[i+1]<<(b-8);
GA_URS_IFLOOP( 3 )
*--op = ip[i]<<(b-24) | ip[i+1]<<(b-16) | ip[i+2]<<(b-8);
GA_URS_IFLOOP( 4 )
*--op = ip[i]<<(b-32) | ip[i+1]<<(b-24) | ip[i+2]<<(b-16) | ip[i+3] << (b-8);
} else {
GA_URS_IFLOOP( 2 )
*--op = ip[i]<<(b-8) | ip[i+1]<<(b-16);
GA_URS_IFLOOP( 3 )
*--op = ip[i]<<(b-8) | ip[i+1]<<(b-16) | ip[i+2]<<(b-24);
GA_URS_IFLOOP( 4 )
*--op = ip[i]<<(b-8) | ip[i+1]<<(b-16) | ip[i+2]<<(b-24) | ip[i+3]<<(b-32);
}
#undef GA_URS_IFLOOP
return( samples_read );
}
/************************************************************************
*
* read_samples()
*
* PURPOSE: reads the PCM samples from a file to the buffer
*
* SEMANTICS:
* Reads #samples_read# number of shorts from #musicin# filepointer
* into #sample_buffer[]#. Returns the number of samples read.
*
************************************************************************/
int
read_samples_pcm(FILE * musicin, int sample_buffer[2304], int frame_size,
int samples_to_read)
{
int samples_read;
int iswav = (input_format == sf_wave);
int hi_lo_order; /* byte order of input stream */
if( (32 == pcmbitwidth) || (24 == pcmbitwidth) || (16 == pcmbitwidth) ) {
/* assume only recognized wav files are */
/* in little endian byte order */
hi_lo_order = (!iswav == !pcmswapbytes);
samples_read = unpack_read_samples(samples_to_read, pcmbitwidth/8,
hi_lo_order,sample_buffer, musicin );
} else if( 8 == pcmbitwidth ) {
samples_read = unpack_read_samples( samples_to_read, 1, 0,
sample_buffer, musicin );
} else {
if( silent < 10 ) {
fprintf(stderr, "Only 8, 16, 24 and 32 bit input files supported \n");
}
exit(1);
}
if (ferror(musicin)) {
if( silent < 10 ) {
fprintf(stderr, "Error reading input file\n");
}
exit(1);
}
return samples_read;
}
/* AIFF Definitions */
#define IFF_ID_FORM 0x464f524d /* "FORM" */
#define IFF_ID_AIFF 0x41494646 /* "AIFF" */
#define IFF_ID_AIFC 0x41494643 /* "AIFC" */
#define IFF_ID_COMM 0x434f4d4d /* "COMM" */
#define IFF_ID_SSND 0x53534e44 /* "SSND" */
#define IFF_ID_MPEG 0x4d504547 /* "MPEG" */
#define IFF_ID_NONE 0x4e4f4e45 /* "NONE" */ /* AIFF-C data format */
#define IFF_ID_2CBE 0x74776f73 /* "twos" */ /* AIFF-C data format */
#define IFF_ID_2CLE 0x736f7774 /* "sowt" */ /* AIFF-C data format */
#define WAV_ID_RIFF 0x52494646 /* "RIFF" */
#define WAV_ID_WAVE 0x57415645 /* "WAVE" */
#define WAV_ID_FMT 0x666d7420 /* "fmt " */
#define WAV_ID_DATA 0x64617461 /* "data" */
/*****************************************************************************
*
* Read Microsoft Wave headers
*
* By the time we get here the first 32-bits of the file have already been
* read, and we're pretty sure that we're looking at a WAV file.
*
*****************************************************************************/
static int
parse_wave_header(lame_global_flags * gfp, FILE * sf)
{
int format_tag = 0;
int channels = 0;
int block_align = 0;
int bits_per_sample = 0;
int samples_per_sec = 0;
int avg_bytes_per_sec = 0;
int is_wav = 0;
long data_length = 0, file_length, subSize = 0;
int loop_sanity = 0;
file_length = Read32BitsHighLow(sf);
if (Read32BitsHighLow(sf) != WAV_ID_WAVE)
return 0;
for (loop_sanity = 0; loop_sanity < 20; ++loop_sanity) {
int type = Read32BitsHighLow(sf);
if (type == WAV_ID_FMT) {
subSize = Read32BitsLowHigh(sf);
if (subSize < 16) {
/*DEBUGF(
"'fmt' chunk too short (only %ld bytes)!", subSize); */
return 0;
}
format_tag = Read16BitsLowHigh(sf);
subSize -= 2;
channels = Read16BitsLowHigh(sf);
subSize -= 2;
samples_per_sec = Read32BitsLowHigh(sf);
subSize -= 4;
avg_bytes_per_sec = Read32BitsLowHigh(sf);
subSize -= 4;
block_align = Read16BitsLowHigh(sf);
subSize -= 2;
bits_per_sample = Read16BitsLowHigh(sf);
subSize -= 2;
/* DEBUGF(" skipping %d bytes\n", subSize); */
if (subSize > 0) {
if (fskip(sf, (long) subSize, SEEK_CUR) != 0)
return 0;
};
}
else if (type == WAV_ID_DATA) {
subSize = Read32BitsLowHigh(sf);
data_length = subSize;
is_wav = 1;
/* We've found the audio data. Read no further! */
break;
}
else {
subSize = Read32BitsLowHigh(sf);
if (fskip(sf, (long) subSize, SEEK_CUR) != 0)
return 0;
}
}
if (format_tag != 1) {
return 0; /* oh no! non-supported format */
}
if (is_wav) {
/* make sure the header is sane */
if( -1 == lame_set_num_channels( gfp, channels ) ) {
if( silent < 10 ) {
fprintf( stderr,
"Unsupported number of channels: %ud\n",
channels );
}
exit( 1 );
}
(void) lame_set_in_samplerate( gfp, samples_per_sec );
pcmbitwidth = bits_per_sample;
(void) lame_set_num_samples( gfp,
data_length / (channels * ((bits_per_sample+7) / 8)) );
}
return is_wav;
}
/************************************************************************
* aiff_check2
*
* PURPOSE: Checks AIFF header information to make sure it is valid.
* returns 0 on success, 1 on errors
************************************************************************/
int
aiff_check2(const char *file_name, IFF_AIFF * const pcm_aiff_data)
{
if (pcm_aiff_data->sampleType != IFF_ID_SSND) {
if( silent < 10 ) {
fprintf(stderr, "Sound data is not PCM in '%s'\n", file_name);
}
return 1;
}
if (pcm_aiff_data->sampleSize != sizeof(short) * CHAR_BIT) {
if( silent < 10 ) {
fprintf(stderr, "Sound data is not %i bits in '%s'\n",
sizeof(short) * CHAR_BIT, file_name);
}
return 1;
}
if (pcm_aiff_data->numChannels != 1 && pcm_aiff_data->numChannels != 2) {
if( silent < 10 ) {
fprintf(stderr, "Sound data is not mono or stereo in '%s'\n",
file_name);
}
return 1;
}
if (pcm_aiff_data->blkAlgn.blockSize != 0) {
if( silent < 10 ) {
fprintf(stderr, "Block size is not 0 bytes in '%s'\n", file_name);
}
return 1;
}
/* A bug, since we correctly skip the offset earlier in the code.
if (pcm_aiff_data->blkAlgn.offset != 0) {
fprintf(stderr, "Block offset is not 0 bytes in '%s'\n", file_name);
return 1;
} */
return 0;
}
/*****************************************************************************
*
* Read Audio Interchange File Format (AIFF) headers.
*
* By the time we get here the first 32 bits of the file have already been
* read, and we're pretty sure that we're looking at an AIFF file.
*
*****************************************************************************/
static int
parse_aiff_header(lame_global_flags * gfp, FILE * sf)
{
int is_aiff = 0;
long chunkSize = 0, subSize = 0, typeID = 0, dataType = 0;
IFF_AIFF aiff_info;
memset(&aiff_info, 0, sizeof(aiff_info));
chunkSize = Read32BitsHighLow(sf);
typeID = Read32BitsHighLow(sf);
if ((typeID != IFF_ID_AIFF)&&(typeID != IFF_ID_AIFC))
return 0;
while (chunkSize > 0) {
int type = Read32BitsHighLow(sf);
chunkSize -= 4;
/* DEBUGF(
"found chunk type %08x '%4.4s'\n", type, (char*)&type); */
/* don't use a switch here to make it easier to use 'break' for SSND */
if (type == IFF_ID_COMM) {
subSize = Read32BitsHighLow(sf);
chunkSize -= subSize;
aiff_info.numChannels = Read16BitsHighLow(sf);
subSize -= 2;
aiff_info.numSampleFrames = Read32BitsHighLow(sf);
subSize -= 4;
aiff_info.sampleSize = Read16BitsHighLow(sf);
subSize -= 2;
aiff_info.sampleRate = ReadIeeeExtendedHighLow(sf);
subSize -= 10;
if (typeID == IFF_ID_AIFC) {
dataType = Read32BitsHighLow(sf);
subSize -= 4;
if ((dataType != IFF_ID_2CLE) &&
(dataType != IFF_ID_2CBE) &&
(dataType != IFF_ID_NONE))
return 0;
if (aiff_info.sampleSize == 16)
pcmswapbytes = (!swapbytes == (dataType == IFF_ID_2CLE));
}
if (fskip(sf, (long) subSize, SEEK_CUR) != 0)
return 0;
}
else if (type == IFF_ID_SSND) {
subSize = Read32BitsHighLow(sf);
chunkSize -= subSize;
aiff_info.blkAlgn.offset = Read32BitsHighLow(sf);
subSize -= 4;
aiff_info.blkAlgn.blockSize = Read32BitsHighLow(sf);
subSize -= 4;
if (fskip(sf, (long) aiff_info.blkAlgn.offset, SEEK_CUR) != 0)
return 0;
aiff_info.sampleType = IFF_ID_SSND;
is_aiff = 1;
/* We've found the audio data. Read no further! */
break;
}
else {
subSize = Read32BitsHighLow(sf);
chunkSize -= subSize;
if (fskip(sf, (long) subSize, SEEK_CUR) != 0)
return 0;
}
}
/* DEBUGF("Parsed AIFF %d\n", is_aiff); */
if (is_aiff) {
/* make sure the header is sane */
if (0 != aiff_check2("name" /*???????????? */ , &aiff_info))
return 0;
if( -1 == lame_set_num_channels( gfp, aiff_info.numChannels ) ) {
if( silent < 10 ) {
fprintf( stderr,
"Unsupported number of channels: %ud\n",
aiff_info.numChannels );
}
exit( 1 );
}
(void) lame_set_in_samplerate( gfp, (int)aiff_info.sampleRate );
pcmbitwidth = aiff_info.sampleSize;
(void) lame_set_num_samples( gfp, aiff_info.numSampleFrames );
}
return is_aiff;
}
/************************************************************************
*
* parse_file_header
*
* PURPOSE: Read the header from a bytestream. Try to determine whether
* it's a WAV file or AIFF without rewinding, since rewind
* doesn't work on pipes and there's a good chance we're reading
* from stdin (otherwise we'd probably be using libsndfile).
*
* When this function returns, the file offset will be positioned at the
* beginning of the sound data.
*
************************************************************************/
void
parse_file_header(lame_global_flags * gfp, FILE * sf)
{
int type = Read32BitsHighLow(sf);
/*
DEBUGF(
"First word of input stream: %08x '%4.4s'\n", type, (char*) &type);
*/
count_samples_carefully = 0;
input_format = sf_raw;
if (type == WAV_ID_RIFF) {
/* It's probably a WAV file */
if (parse_wave_header(gfp, sf)) {
input_format = sf_wave;
count_samples_carefully = 1;
} else {
if( silent < 10 ) {
fprintf( stderr, "Warning: corrupt or unsupported WAVE format\n");
}
}
}
else if (type == IFF_ID_FORM) {
/* It's probably an AIFF file */
if (parse_aiff_header(gfp, sf)) {
input_format = sf_aiff;
count_samples_carefully = 1;
}
}
if (input_format == sf_raw) {
/*
** Assume it's raw PCM. Since the audio data is assumed to begin
** at byte zero, this will unfortunately require seeking.
*/
if (fseek(sf, 0L, SEEK_SET) != 0) {
/* ignore errors */
}
input_format = sf_raw;
}
}
void
CloseSndFile(sound_file_format input, FILE * musicin)
{
if (fclose(musicin) != 0) {
if( silent < 10 ) {
fprintf(stderr, "Could not close audio input file\n");
}
exit(2);
}
}
FILE *
OpenSndFile(lame_global_flags * gfp, char *inPath)
{
FILE *musicin;
/* set the defaults from info incase we cannot determine them from file */
lame_set_num_samples( gfp, MAX_U_32_NUM );
if (!strcmp(inPath, "-")) {
lame_set_stream_binary_mode(musicin = stdin); /* Read from standard input. */
}
else {
if ((musicin = fopen(inPath, "rb")) == NULL) {
if( silent < 10 ) {
fprintf(stderr, "Could not find \"%s\".\n", inPath);
}
exit(1);
}
}
if (input_format == sf_mp1 ||
input_format == sf_mp2 || input_format == sf_mp3) {
#ifdef AMIGA_MPEGA
if (-1 == lame_decode_initfile(inPath, &mp3input_data)) {
if( silent < 10 ) {
fprintf(stderr, "Error reading headers in mp3 input file %s.\n",
inPath);
}
exit(1);
}
#endif
#ifdef HAVE_MPGLIB
if (-1 == lame_decode_initfile(musicin, &mp3input_data)) {
if( silent < 10 ) {
fprintf(stderr, "Error reading headers in mp3 input file %s.\n",
inPath);
}
exit(1);
}
#endif
if( -1 == lame_set_num_channels( gfp, mp3input_data.stereo ) ) {
if( silent < 10 ) {
fprintf( stderr,
"Unsupported number of channels: %ud\n",
mp3input_data.stereo );
}
exit( 1 );
}
(void) lame_set_in_samplerate( gfp, mp3input_data.samplerate );
(void) lame_set_num_samples( gfp, mp3input_data.nsamp );
}
else if (input_format == sf_ogg) {
if( silent < 10 ) {
fprintf(stderr, "sorry, vorbis support in LAME is deprecated.\n");
}
exit(1);
}
else {
if (input_format != sf_raw) {
parse_file_header(gfp, musicin);
}
if (input_format == sf_raw) {
/* assume raw PCM */
if( silent < 10 ) {
fprintf(stderr, "Assuming raw pcm input file");
if (swapbytes)
fprintf(stderr, " : Forcing byte-swapping\n");
else
fprintf(stderr, "\n");
}
pcmswapbytes = swapbytes;
}
}
if (lame_get_num_samples( gfp ) == MAX_U_32_NUM && musicin != stdin) {
double flen = lame_get_file_size(inPath); /* try to figure out num_samples */
if (flen >= 0) {
/* try file size, assume 2 bytes per sample */
if (input_format == sf_mp1 ||
input_format == sf_mp2 || input_format == sf_mp3) {
if (mp3input_data.bitrate > 0) {
double totalseconds =
(flen * 8.0 / (1000.0 * mp3input_data.bitrate));
unsigned long tmp_num_samples =
(unsigned long) (totalseconds * lame_get_in_samplerate( gfp ));
(void) lame_set_num_samples( gfp, tmp_num_samples );
mp3input_data.nsamp = tmp_num_samples;
}
}
else {
(void) lame_set_num_samples( gfp,
(unsigned long)(flen / (2 * lame_get_num_channels( gfp ))) );
}
}
}
return musicin;
}
#endif /* defined(LIBSNDFILE) */
#if defined(HAVE_MPGLIB)
static int
check_aid(const unsigned char *header)
{
return 0 == memcmp(header, "AiD\1", 4);
}
/*
* Please check this and don't kill me if there's a bug
* This is a (nearly?) complete header analysis for a MPEG-1/2/2.5 Layer I, II or III
* data stream
*/
static int
is_syncword_mp123(const void *const headerptr)
{
const unsigned char *const p = headerptr;
static const char abl2[16] =
{ 0, 7, 7, 7, 0, 7, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8 };
if ((p[0] & 0xFF) != 0xFF)
return 0; /* first 8 bits must be '1' */
if ((p[1] & 0xE0) != 0xE0)
return 0; /* next 3 bits are also */
if ((p[1] & 0x18) == 0x08)
return 0; /* no MPEG-1, -2 or -2.5 */
if ((p[1] & 0x06) == 0x00)
return 0; /* no Layer I, II and III */
#ifndef USE_LAYER_1
if ((p[1] & 0x06) == 0x03*2)
return 0; /* layer1 is not supported */
#endif
#ifndef USE_LAYER_2
if ((p[1] & 0x06) == 0x02*2)
return 0; /* layer1 is not supported */
#endif
if (!(((p[1] & 0x06) == 0x03*2 && input_format == sf_mp1)
|| ((p[1] & 0x06) == 0x02*2 && input_format == sf_mp2)
|| ((p[1] & 0x06) == 0x01*2 && input_format == sf_mp3)))
return 0; /* imcompatible layer with input file format */
if ((p[2] & 0xF0) == 0xF0)
return 0; /* bad bitrate */
if ((p[2] & 0x0C) == 0x0C)
return 0; /* no sample frequency with (32,44.1,48)/(1,2,4) */
if ((p[1] & 0x18) == 0x18 && (p[1] & 0x06) == 0x04
&& abl2[p[2] >> 4] & (1 << (p[3] >> 6)))
return 0;
if ((p[3] & 3) == 2)
return 0; /* reserved enphasis mode */
return 1;
}
int
lame_decode_initfile(FILE * fd, mp3data_struct * mp3data)
{
/* VBRTAGDATA pTagData; */
/* int xing_header,len2,num_frames; */
unsigned char buf[100];
int ret;
int len, aid_header;
short int pcm_l[1152], pcm_r[1152];
int freeformat = 0;
memset(mp3data, 0, sizeof(mp3data_struct));
lame_decode_init();
len = 4;
if (fread(buf, 1, len, fd) != len)
return -1; /* failed */
if (buf[0] == 'I' && buf[1] == 'D' && buf[2] == '3') {
if( silent < 10 ) {
fprintf(stderr, "ID3v2 found. "
"Be aware that the ID3 tag is currently lost when transcoding.\n");
}
len = 6;
if (fread(&buf, 1, len, fd) != len)
return -1; /* failed */
buf[2] &= 127; buf[3] &= 127; buf[4] &= 127; buf[5] &= 127;
len = (((((buf[2] << 7) + buf[3]) << 7) + buf[4]) << 7) + buf[5];
fskip(fd, len, SEEK_CUR);
len = 4;
if (fread(&buf, 1, len, fd) != len)
return -1; /* failed */
}
aid_header = check_aid(buf);
if (aid_header) {
if (fread(&buf, 1, 2, fd) != 2)
return -1; /* failed */
aid_header = (unsigned char) buf[0] + 256 * (unsigned char) buf[1];
if( silent < 10 ) {
fprintf(stderr, "Album ID found. length=%i \n", aid_header);
}
/* skip rest of AID, except for 6 bytes we have already read */
fskip(fd, aid_header - 6, SEEK_CUR);
/* read 4 more bytes to set up buffer for MP3 header check */
if (fread(&buf, 1, len, fd) != len)
return -1; /* failed */
}
len = 4;
while (!is_syncword_mp123(buf)) {
int i;
for (i = 0; i < len - 1; i++)
buf[i] = buf[i + 1];
if (fread(buf + len - 1, 1, 1, fd) != 1)
return -1; /* failed */
}
if ((buf[2] & 0xf0)==0) {
if( silent < 10 ) {
fprintf(stderr,"Input file is freeformat.\n");
}
freeformat = 1;
}
/* now parse the current buffer looking for MP3 headers. */
/* (as of 11/00: mpglib modified so that for the first frame where */
/* headers are parsed, no data will be decoded. */
/* However, for freeformat, we need to decode an entire frame, */
/* so mp3data->bitrate will be 0 until we have decoded the first */
/* frame. Cannot decode first frame here because we are not */
/* yet prepared to handle the output. */
ret = lame_decode1_headersB(buf, len, pcm_l, pcm_r, mp3data,&enc_delay,&enc_padding);
if (-1 == ret)
return -1;
/* repeat until we decode a valid mp3 header. */
while (!mp3data->header_parsed) {
len = fread(buf, 1, sizeof(buf), fd);
if (len != sizeof(buf))
return -1;
ret = lame_decode1_headersB(buf, len, pcm_l, pcm_r, mp3data,&enc_delay,&enc_padding);
if (-1 == ret)
return -1;
}
if (mp3data->bitrate==0 && !freeformat) {
if( silent < 10 ) {
fprintf(stderr, "fail to sync...\n");
}
return lame_decode_initfile(fd, mp3data);
}
if (mp3data->totalframes > 0) {
/* mpglib found a Xing VBR header and computed nsamp & totalframes */
}
else {
/* set as unknown. Later, we will take a guess based on file size
* ant bitrate */
mp3data->nsamp = MAX_U_32_NUM;
}
/*
fprintf(stderr,"ret = %i NEED_MORE=%i \n",ret,MP3_NEED_MORE);
fprintf(stderr,"stereo = %i \n",mp.fr.stereo);
fprintf(stderr,"samp = %i \n",freqs[mp.fr.sampling_frequency]);
fprintf(stderr,"framesize = %i \n",framesize);
fprintf(stderr,"bitrate = %i \n",mp3data->bitrate);
fprintf(stderr,"num frames = %ui \n",num_frames);
fprintf(stderr,"num samp = %ui \n",mp3data->nsamp);
fprintf(stderr,"mode = %i \n",mp.fr.mode);
*/
return 0;
}
/*
For lame_decode_fromfile: return code
-1 error
n number of samples output. either 576 or 1152 depending on MP3 file.
For lame_decode1_headers(): return code
-1 error
0 ok, but need more data before outputing any samples
n number of samples output. either 576 or 1152 depending on MP3 file.
*/
int
lame_decode_fromfile(FILE * fd, short pcm_l[], short pcm_r[],
mp3data_struct * mp3data)
{
int ret = 0, len=0;
unsigned char buf[1024];
/* first see if we still have data buffered in the decoder: */
ret = lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data);
if (ret!=0) return ret;
/* read until we get a valid output frame */
while (1) {
len = fread(buf, 1, 1024, fd);
if (len == 0) {
/* we are done reading the file, but check for buffered data */
ret = lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data);
if (ret<=0) {
lame_decode_exit(); /* release mp3decoder memory */
return -1; /* done with file */
}
break;
}
ret = lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data);
if (ret == -1) {
lame_decode_exit(); /* release mp3decoder memory */
return -1;
}
if (ret >0) break;
}
return ret;
}
#endif /* defined(HAVE_MPGLIB) */
/* end of get_audio.c */