lame/frontend/get_audio.c

2291 lines
68 KiB
C
Raw Normal View History

2022-05-14 00:28:41 +08:00
/*
* Get Audio routines source file
*
* Copyright (c) 1999 Albert L Faber
* 2008-2017 Robert Hegemann
*
* 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.167 2017/09/06 15:07:29 robert 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
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#else
# ifdef HAVE_STDINT_H
# include <stdint.h>
# endif
#endif
#define MAX_U_32_NUM 0xFFFFFFFF
#include <math.h>
#if defined(__riscos__)
# include <kernel.h>
# include <sys/swis.h>
#elif defined(_WIN32)
# include <sys/types.h>
# include <sys/stat.h>
#else
# include <sys/stat.h>
#endif
#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 "lametime.h"
#include "console.h"
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif
#ifndef STR
# define __STR(x) #x
# define STR(x) __STR(x)
#define __LOC__ __FILE__ "("STR(__LINE__)") : "
#endif
#define FLOAT_TO_UNSIGNED(f) ((unsigned long)(((long)((f) - 2147483648.0)) + 2147483647L + 1))
#define UNSIGNED_TO_FLOAT(u) (((double)((long)((u) - 2147483647L - 1))) + 2147483648.0)
static unsigned int uint32_high_low(unsigned char *bytes)
{
uint32_t const hh = bytes[0];
uint32_t const hl = bytes[1];
uint32_t const lh = bytes[2];
uint32_t const ll = bytes[3];
return (hh << 24) | (hl << 16) | (lh << 8) | ll;
}
static double
read_ieee_extended_high_low(FILE * fp)
{
unsigned char bytes[10];
memset(bytes, 0, 10);
fread(bytes, 1, 10, fp);
{
int32_t const s = (bytes[0] & 0x80);
int32_t const e_h = (bytes[0] & 0x7F);
int32_t const e_l = bytes[1];
int32_t e = (e_h << 8) | e_l;
uint32_t const hm = uint32_high_low(bytes + 2);
uint32_t const lm = uint32_high_low(bytes + 6);
double result = 0;
if (e != 0 || hm != 0 || lm != 0) {
if (e == 0x7fff) {
result = HUGE_VAL;
}
else {
double mantissa_h = UNSIGNED_TO_FLOAT(hm);
double mantissa_l = UNSIGNED_TO_FLOAT(lm);
e -= 0x3fff;
e -= 31;
result = ldexp(mantissa_h, e);
e -= 32;
result += ldexp(mantissa_l, e);
}
}
return s ? -result : result;
}
}
static int
read_16_bits_low_high(FILE * fp)
{
unsigned char bytes[2] = { 0, 0 };
fread(bytes, 1, 2, fp);
{
int32_t const low = bytes[0];
int32_t const high = (signed char) (bytes[1]);
return (high << 8) | low;
}
}
static int
read_32_bits_low_high(FILE * fp)
{
unsigned char bytes[4] = { 0, 0, 0, 0 };
fread(bytes, 1, 4, fp);
{
int32_t const low = bytes[0];
int32_t const medl = bytes[1];
int32_t const medh = bytes[2];
int32_t const high = (signed char) (bytes[3]);
return (high << 24) | (medh << 16) | (medl << 8) | low;
}
}
static int
read_16_bits_high_low(FILE * fp)
{
unsigned char bytes[2] = { 0, 0 };
fread(bytes, 1, 2, fp);
{
int32_t const low = bytes[1];
int32_t const high = (signed char) (bytes[0]);
return (high << 8) | low;
}
}
static int
read_32_bits_high_low(FILE * fp)
{
unsigned char bytes[4] = { 0, 0, 0, 0 };
fread(bytes, 1, 4, fp);
{
int32_t const low = bytes[3];
int32_t const medl = bytes[2];
int32_t const medh = bytes[1];
int32_t const high = (signed char) (bytes[0]);
return (high << 24) | (medh << 16) | (medl << 8) | low;
}
}
static void
write_16_bits_low_high(FILE * fp, int val)
{
unsigned char bytes[2];
bytes[0] = (val & 0xff);
bytes[1] = ((val >> 8) & 0xff);
fwrite(bytes, 1, 2, fp);
}
static void
write_32_bits_low_high(FILE * fp, int val)
{
unsigned char bytes[4];
bytes[0] = (val & 0xff);
bytes[1] = ((val >> 8) & 0xff);
bytes[2] = ((val >> 16) & 0xff);
bytes[3] = ((val >> 24) & 0xff);
fwrite(bytes, 1, 4, fp);
}
#ifdef LIBSNDFILE
#include <sndfile.h>
#else
typedef void SNDFILE;
#endif /* ifdef LIBSNDFILE */
typedef struct blockAlign_struct {
unsigned long offset;
unsigned long blockSize;
} blockAlign;
typedef struct IFF_AIFF_struct {
short numChannels;
unsigned long numSampleFrames;
short sampleSize;
double sampleRate;
unsigned long sampleType;
blockAlign blkAlgn;
} IFF_AIFF;
struct PcmBuffer {
void *ch[2]; /* buffer for each channel */
int w; /* sample width */
int n; /* number samples allocated */
int u; /* number samples used */
int skip_start; /* number samples to ignore at the beginning */
int skip_end; /* number samples to ignore at the end */
};
typedef struct PcmBuffer PcmBuffer;
static void
initPcmBuffer(PcmBuffer * b, int w)
{
b->ch[0] = 0;
b->ch[1] = 0;
b->w = w;
b->n = 0;
b->u = 0;
b->skip_start = 0;
b->skip_end = 0;
}
static void
freePcmBuffer(PcmBuffer * b)
{
if (b != 0) {
free(b->ch[0]);
free(b->ch[1]);
b->ch[0] = 0;
b->ch[1] = 0;
b->n = 0;
b->u = 0;
}
}
static int
addPcmBuffer(PcmBuffer * b, void *a0, void *a1, int read)
{
int a_n;
if (b == 0) {
return 0;
}
if (read < 0) {
return b->u - b->skip_end;
}
if (b->skip_start >= read) {
b->skip_start -= read;
return b->u - b->skip_end;
}
a_n = read - b->skip_start;
if (b != 0 && a_n > 0) {
int const a_skip = b->w * b->skip_start;
int const a_want = b->w * a_n;
int const b_used = b->w * b->u;
int const b_have = b->w * b->n;
int const b_need = b->w * (b->u + a_n);
if (b_have < b_need) {
b->n = b->u + a_n;
b->ch[0] = realloc(b->ch[0], b_need);
b->ch[1] = realloc(b->ch[1], b_need);
}
b->u += a_n;
if (b->ch[0] != 0 && a0 != 0) {
char *src = a0;
char *dst = b->ch[0];
memcpy(dst + b_used, src + a_skip, a_want);
}
if (b->ch[1] != 0 && a1 != 0) {
char *src = a1;
char *dst = b->ch[1];
memcpy(dst + b_used, src + a_skip, a_want);
}
}
b->skip_start = 0;
return b->u - b->skip_end;
}
static int
takePcmBuffer(PcmBuffer * b, void *a0, void *a1, int a_n, int mm)
{
if (a_n > mm) {
a_n = mm;
}
if (b != 0 && a_n > 0) {
int const a_take = b->w * a_n;
if (a0 != 0 && b->ch[0] != 0) {
memcpy(a0, b->ch[0], a_take);
}
if (a1 != 0 && b->ch[1] != 0) {
memcpy(a1, b->ch[1], a_take);
}
b->u -= a_n;
if (b->u < 0) {
b->u = 0;
return a_n;
}
if (b->ch[0] != 0) {
memmove(b->ch[0], (char *) b->ch[0] + a_take, b->w * b->u);
}
if (b->ch[1] != 0) {
memmove(b->ch[1], (char *) b->ch[1] + a_take, b->w * b->u);
}
}
return a_n;
}
/* global data for get_audio.c. */
typedef struct get_audio_global_data_struct {
int count_samples_carefully;
int pcmbitwidth;
int pcmswapbytes;
int pcm_is_unsigned_8bit;
int pcm_is_ieee_float;
unsigned int num_samples_read;
FILE *music_in;
SNDFILE *snd_file;
hip_t hip;
PcmBuffer pcm32;
PcmBuffer pcm16;
size_t in_id3v2_size;
unsigned char* in_id3v2_tag;
} get_audio_global_data;
static get_audio_global_data global;
#ifdef AMIGA_MPEGA
int lame_decode_initfile(const char *fullname, mp3data_struct * const mp3data);
#else
int lame_decode_initfile(FILE * fd, mp3data_struct * mp3data, int *enc_delay, int *enc_padding);
#endif
/* read mp3 file until mpglib returns one frame of PCM data */
static 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 samples_to_read);
static int read_samples_mp3(lame_t gfp, FILE * musicin, short int mpg123pcm[2][1152]);
#ifdef LIBSNDFILE
static SNDFILE *open_snd_file(lame_t gfp, char const *inPath);
#endif
static FILE *open_mpeg_file(lame_t gfp, char const *inPath, int *enc_delay, int *enc_padding);
static FILE *open_wave_file(lame_t gfp, char const *inPath, int *enc_delay, int *enc_padding);
static int close_input_file(FILE * musicin);
static size_t
min_size_t(size_t a, size_t b)
{
if (a < b) {
return a;
}
return b;
}
enum ByteOrder machine_byte_order(void);
enum ByteOrder
machine_byte_order(void)
{
long one = 1;
return !(*((char *) (&one))) ? ByteOrderBigEndian : ByteOrderLittleEndian;
}
/* 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
/* S_ISFIFO macro is defined on newer Linuxes */
#ifndef S_ISFIFO
# ifdef _S_IFIFO
/* _S_IFIFO is defined on Win32 and Cygwin */
# define S_ISFIFO(m) (((m)&_S_IFIFO) == _S_IFIFO)
# endif
#endif
#ifdef S_ISFIFO
/* fseek is known to fail on pipes with several C-Library implementations
workaround: 1) test for pipe
2) for pipes, only relatvie seeking is possible
3) and only in forward direction!
else fallback to old code
*/
{
int const fd = fileno(fp);
struct stat file_stat;
if (fstat(fd, &file_stat) == 0) {
if (S_ISFIFO(file_stat.st_mode)) {
if (whence != SEEK_CUR || offset < 0) {
return -1;
}
while (offset > 0) {
size_t const bytes_to_skip = min_size_t(sizeof(buffer), offset);
size_t const read = fread(buffer, 1, bytes_to_skip, fp);
if (read < 1) {
return -1;
}
assert( read <= LONG_MAX );
offset -= (long) read;
}
return 0;
}
}
}
#endif
if (0 == fseek(fp, offset, whence)) {
return 0;
}
if (whence != SEEK_CUR || offset < 0) {
if (global_ui_config.silent < 10) {
error_printf
("fskip problem: Mostly the return status of functions is not evaluate so it is more secure to pollute <stderr>.\n");
2022-05-14 00:28:41 +08:00
}
return -1;
}
while (offset > 0) {
size_t const bytes_to_skip = min_size_t(sizeof(buffer), offset);
size_t const read = fread(buffer, 1, bytes_to_skip, fp);
if (read < 1) {
return -1;
}
assert( read <= LONG_MAX );
offset -= (long) read;
}
return 0;
}
static off_t
lame_get_file_size(FILE * fp)
{
struct stat sb;
int fd = fileno(fp);
if (0 == fstat(fd, &sb))
return sb.st_size;
return (off_t) - 1;
}
FILE *
init_outfile(char const *outPath, int decode)
{
FILE *outf;
/* open the output file */
if (0 == strcmp(outPath, "-")) {
outf = stdout;
lame_set_stream_binary_mode(outf);
}
else {
outf = lame_fopen(outPath, "w+b");
#ifdef __riscos__
/* Assign correct file type */
if (outf != NULL) {
char *p, *out_path = strdup(outPath);
for (p = out_path; *p; p++) { /* ugly, ugly to modify a string */
switch (*p) {
case '.':
*p = '/';
break;
case '/':
*p = '.';
break;
}
}
SetFiletype(out_path, decode ? 0xFB1 /*WAV*/ : 0x1AD /*AMPEG*/);
free(out_path);
}
#else
(void) decode;
#endif
}
return outf;
}
static void
setSkipStartAndEnd(lame_t gfp, int enc_delay, int enc_padding)
{
int skip_start = 0, skip_end = 0;
if (global_decoder.mp3_delay_set)
skip_start = global_decoder.mp3_delay;
switch (global_reader.input_format) {
case sf_mp123:
break;
case sf_mp3:
if (skip_start == 0) {
if (enc_delay > -1 || enc_padding > -1) {
if (enc_delay > -1)
skip_start = enc_delay + 528 + 1;
if (enc_padding > -1)
skip_end = enc_padding - (528 + 1);
}
else
skip_start = lame_get_encoder_delay(gfp) + 528 + 1;
}
else {
/* user specified a value of skip. just add for decoder */
skip_start += 528 + 1; /* mp3 decoder has a 528 sample delay, plus user supplied "skip" */
}
break;
case sf_mp2:
skip_start += 240 + 1;
break;
case sf_mp1:
skip_start += 240 + 1;
break;
case sf_raw:
skip_start += 0; /* other formats have no delay *//* is += 0 not better ??? */
break;
case sf_wave:
skip_start += 0; /* other formats have no delay *//* is += 0 not better ??? */
break;
case sf_aiff:
skip_start += 0; /* other formats have no delay *//* is += 0 not better ??? */
break;
default:
skip_start += 0; /* other formats have no delay *//* is += 0 not better ??? */
break;
}
skip_start = skip_start < 0 ? 0 : skip_start;
skip_end = skip_end < 0 ? 0 : skip_end;
global. pcm16.skip_start = global.pcm32.skip_start = skip_start;
global. pcm16.skip_end = global.pcm32.skip_end = skip_end;
}
int
init_infile(lame_t gfp, char const *inPath)
{
int enc_delay = 0, enc_padding = 0;
/* open the input file */
global. count_samples_carefully = 0;
global. num_samples_read = 0;
global. pcmbitwidth = global_raw_pcm.in_bitwidth;
global. pcmswapbytes = global_reader.swapbytes;
global. pcm_is_unsigned_8bit = global_raw_pcm.in_signed == 1 ? 0 : 1;
global. pcm_is_ieee_float = 0;
global. hip = 0;
global. music_in = 0;
global. snd_file = 0;
global. in_id3v2_size = 0;
global. in_id3v2_tag = 0;
if (is_mpeg_file_format(global_reader.input_format)) {
global. music_in = open_mpeg_file(gfp, inPath, &enc_delay, &enc_padding);
}
else {
#ifdef LIBSNDFILE
if (strcmp(inPath, "-") != 0) { /* not for stdin */
global. snd_file = open_snd_file(gfp, inPath);
}
#endif
if (global.snd_file == 0) {
global. music_in = open_wave_file(gfp, inPath, &enc_delay, &enc_padding);
}
}
initPcmBuffer(&global.pcm32, sizeof(int));
initPcmBuffer(&global.pcm16, sizeof(short));
setSkipStartAndEnd(gfp, enc_delay, enc_padding);
{
unsigned long n = lame_get_num_samples(gfp);
if (n != MAX_U_32_NUM) {
unsigned long const discard = global.pcm32.skip_start + global.pcm32.skip_end;
lame_set_num_samples(gfp, n > discard ? n - discard : 0);
}
}
return (global.snd_file != NULL || global.music_in != NULL) ? 1 : -1;
}
int
samples_to_skip_at_start(void)
{
return global.pcm32.skip_start;
}
int
samples_to_skip_at_end(void)
{
return global.pcm32.skip_end;
}
void
close_infile(void)
{
#if defined(HAVE_MPGLIB)
if (global.hip != 0) {
hip_decode_exit(global.hip); /* release mp3decoder memory */
global. hip = 0;
}
#endif
close_input_file(global.music_in);
#ifdef LIBSNDFILE
if (global.snd_file) {
if (sf_close(global.snd_file) != 0) {
if (global_ui_config.silent < 10) {
error_printf("Could not close sound file \n");
}
}
global. snd_file = 0;
}
#endif
freePcmBuffer(&global.pcm32);
freePcmBuffer(&global.pcm16);
global. music_in = 0;
free(global.in_id3v2_tag);
global.in_id3v2_tag = 0;
global.in_id3v2_size = 0;
}
static int
get_audio_common(lame_t 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_t gfp, int buffer[2][1152])
{
int used = 0, read = 0;
do {
read = get_audio_common(gfp, buffer, NULL);
used = addPcmBuffer(&global.pcm32, buffer[0], buffer[1], read);
} while (used <= 0 && read > 0);
if (read < 0) {
return read;
}
if (global_reader.swap_channel == 0)
return takePcmBuffer(&global.pcm32, buffer[0], buffer[1], used, 1152);
else
return takePcmBuffer(&global.pcm32, buffer[1], buffer[0], used, 1152);
}
/*
get_audio16 - behave as the original get_audio function, with a limited
16 bit per sample output
*/
int
get_audio16(lame_t gfp, short buffer[2][1152])
{
int used = 0, read = 0;
do {
read = get_audio_common(gfp, NULL, buffer);
used = addPcmBuffer(&global.pcm16, buffer[0], buffer[1], read);
} while (used <= 0 && read > 0);
if (read < 0) {
return read;
}
if (global_reader.swap_channel == 0)
return takePcmBuffer(&global.pcm16, buffer[0], buffer[1], used, 1152);
else
return takePcmBuffer(&global.pcm16, buffer[1], buffer[0], used, 1152);
}
/************************************************************************
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_t gfp, int buffer[2][1152], short buffer16[2][1152])
{
const int num_channels = lame_get_num_channels(gfp);
const int framesize = lame_get_framesize(gfp);
int insamp[2 * 1152];
short buf_tmp16[2][1152];
int samples_read;
int samples_to_read;
unsigned int remaining;
int i;
int *p;
/* sanity checks, that's what we expect to be true */
if ((num_channels < 1 || 2 < num_channels)
||(framesize < 1 || 1152 < framesize)) {
if (global_ui_config.silent < 10) {
error_printf("Error: internal problem!\n");
}
return -1;
}
/*
* 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;
/* 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 (global.count_samples_carefully) {
unsigned int tmp_num_samples;
/* get num_samples */
if (is_mpeg_file_format(global_reader.input_format)) {
tmp_num_samples = global_decoder.mp3input_data.nsamp;
}
else {
tmp_num_samples = lame_get_num_samples(gfp);
}
if (global.num_samples_read < tmp_num_samples) {
remaining = tmp_num_samples - global.num_samples_read;
}
else {
remaining = 0;
}
if (remaining < (unsigned int) 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;
}
if (is_mpeg_file_format(global_reader.input_format)) {
if (buffer != NULL)
samples_read = read_samples_mp3(gfp, global.music_in, buf_tmp16);
else
samples_read = read_samples_mp3(gfp, global.music_in, buffer16);
if (samples_read < 0) {
return samples_read;
}
}
else {
if (global.snd_file) {
#ifdef LIBSNDFILE
samples_read = sf_read_int(global.snd_file, insamp, num_channels * samples_to_read);
#else
samples_read = 0;
#endif
}
else {
samples_read =
read_samples_pcm(global.music_in, insamp, num_channels * samples_to_read);
}
if (samples_read < 0) {
return samples_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 (is_mpeg_file_format(global_reader.input_format)) {
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 ... then it is considered infinitely long.
Don't count the samples */
if (global.count_samples_carefully)
global. num_samples_read += samples_read;
return samples_read;
}
static int
read_samples_mp3(lame_t gfp, FILE * musicin, short int mpg123pcm[2][1152])
{
int out;
#if defined(AMIGA_MPEGA) || defined(HAVE_MPGLIB)
int samplerate;
static const char type_name[] = "MP3 file";
out = lame_decode_fromfile(musicin, mpg123pcm[0], mpg123pcm[1], &global_decoder.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) != global_decoder.mp3input_data.stereo) {
if (global_ui_config.silent < 10) {
error_printf("Error: number of channels has changed in %s - not supported\n",
type_name);
}
out = -1;
}
samplerate = global_reader.input_samplerate;
if (samplerate == 0) {
samplerate = global_decoder.mp3input_data.samplerate;
}
if (lame_get_in_samplerate(gfp) != samplerate) {
if (global_ui_config.silent < 10) {
error_printf("Error: sample frequency has changed in %s - not supported\n", type_name);
}
out = -1;
}
#else
out = -1;
#endif
return out;
}
static
int set_input_num_channels(lame_t gfp, int num_channels)
{
if (gfp) {
if (-1 == lame_set_num_channels(gfp, num_channels)) {
if (global_ui_config.silent < 10) {
error_printf("Unsupported number of channels: %d\n", num_channels);
}
return 0;
}
}
return 1;
}
static
int set_input_samplerate(lame_t gfp, int input_samplerate)
{
if (gfp) {
int sr = global_reader.input_samplerate;
if (sr == 0) sr = input_samplerate;
if (-1 == lame_set_in_samplerate(gfp, sr)) {
if (global_ui_config.silent < 10) {
error_printf("Unsupported sample rate: %d\n", sr);
}
return 0;
}
}
return 1;
}
int
WriteWaveHeader(FILE * const fp, int pcmbytes, int freq, int channels, int bits)
{
int bytes = (bits + 7) / 8;
/* quick and dirty, but documented */
fwrite("RIFF", 1, 4, fp); /* label */
write_32_bits_low_high(fp, pcmbytes + 44 - 8); /* length in bytes without header */
fwrite("WAVEfmt ", 2, 4, fp); /* 2 labels */
write_32_bits_low_high(fp, 2 + 2 + 4 + 4 + 2 + 2); /* length of PCM format declaration area */
write_16_bits_low_high(fp, 1); /* is PCM? */
write_16_bits_low_high(fp, channels); /* number of channels */
write_32_bits_low_high(fp, freq); /* sample frequency in [Hz] */
write_32_bits_low_high(fp, freq * channels * bytes); /* bytes per second */
write_16_bits_low_high(fp, channels * bytes); /* bytes per sample time */
write_16_bits_low_high(fp, bits); /* bits per sample */
fwrite("data", 1, 4, fp); /* label */
write_32_bits_low_high(fp, pcmbytes); /* length in bytes of raw PCM data */
return ferror(fp) ? -1 : 0;
}
#if defined(LIBSNDFILE)
extern SNDFILE *sf_wchar_open(wchar_t const *wpath, int mode, SF_INFO * sfinfo);
static SNDFILE *
open_snd_file(lame_t gfp, char const *inPath)
{
char const *lpszFileName = inPath;
SNDFILE *gs_pSndFileIn = NULL;
SF_INFO gs_wfInfo;
{
#if defined( _WIN32 ) && !defined(__MINGW32__)
wchar_t *file_name = utf8ToUnicode(lpszFileName);
#endif
/* Try to open the sound file */
memset(&gs_wfInfo, 0, sizeof(gs_wfInfo));
#if defined( _WIN32 ) && !defined(__MINGW32__)
gs_pSndFileIn = sf_wchar_open(file_name, SFM_READ, &gs_wfInfo);
#else
gs_pSndFileIn = sf_open(lpszFileName, SFM_READ, &gs_wfInfo);
#endif
if (gs_pSndFileIn == NULL) {
if (global_raw_pcm.in_signed == 0 && global_raw_pcm.in_bitwidth != 8) {
error_printf("Unsigned input only supported with bitwidth 8\n");
#if defined( _WIN32 ) && !defined(__MINGW32__)
free(file_name);
#endif
return 0;
}
/* set some defaults incase input is raw PCM */
gs_wfInfo.seekable = (global_reader.input_format != sf_raw); /* if user specified -r, set to not seekable */
gs_wfInfo.samplerate = lame_get_in_samplerate(gfp);
gs_wfInfo.channels = lame_get_num_channels(gfp);
gs_wfInfo.format = SF_FORMAT_RAW;
if ((global_raw_pcm.in_endian == ByteOrderLittleEndian) ^ (global_reader.swapbytes !=
0)) {
gs_wfInfo.format |= SF_ENDIAN_LITTLE;
}
else {
gs_wfInfo.format |= SF_ENDIAN_BIG;
}
switch (global_raw_pcm.in_bitwidth) {
case 8:
gs_wfInfo.format |=
global_raw_pcm.in_signed == 0 ? SF_FORMAT_PCM_U8 : SF_FORMAT_PCM_S8;
break;
case 16:
gs_wfInfo.format |= SF_FORMAT_PCM_16;
break;
case 24:
gs_wfInfo.format |= SF_FORMAT_PCM_24;
break;
case 32:
gs_wfInfo.format |= SF_FORMAT_PCM_32;
break;
default:
break;
}
#if defined( _WIN32 ) && !defined(__MINGW32__)
gs_pSndFileIn = sf_wchar_open(file_name, SFM_READ, &gs_wfInfo);
#else
gs_pSndFileIn = sf_open(lpszFileName, SFM_READ, &gs_wfInfo);
#endif
}
#if defined( _WIN32 ) && !defined(__MINGW32__)
free(file_name);
#endif
/* Check result */
if (gs_pSndFileIn == NULL) {
sf_perror(gs_pSndFileIn);
if (global_ui_config.silent < 10) {
error_printf("Could not open sound file \"%s\".\n", lpszFileName);
}
return 0;
}
sf_command(gs_pSndFileIn, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
if ((gs_wfInfo.format & SF_FORMAT_RAW) == SF_FORMAT_RAW) {
global_reader.input_format = sf_raw;
}
#ifdef _DEBUG_SND_FILE
printf("\n\nSF_INFO structure\n");
printf("samplerate :%d\n", gs_wfInfo.samplerate);
printf("samples :%d\n", gs_wfInfo.frames);
printf("channels :%d\n", gs_wfInfo.channels);
printf("format :");
/* new formats from sbellon@sbellon.de 1/2000 */
switch (gs_wfInfo.format & SF_FORMAT_TYPEMASK) {
case SF_FORMAT_WAV:
printf("Microsoft WAV format (big endian). ");
break;
case SF_FORMAT_AIFF:
printf("Apple/SGI AIFF format (little endian). ");
break;
case SF_FORMAT_AU:
printf("Sun/NeXT AU format (big endian). ");
break;
/*
case SF_FORMAT_AULE:
DEBUGF("DEC AU format (little endian). ");
break;
*/
case SF_FORMAT_RAW:
printf("RAW PCM data. ");
break;
case SF_FORMAT_PAF:
printf("Ensoniq PARIS file format. ");
break;
case SF_FORMAT_SVX:
printf("Amiga IFF / SVX8 / SV16 format. ");
break;
case SF_FORMAT_NIST:
printf("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:
printf("32 bit Intel x86 floats.");
break;
case SF_FORMAT_ULAW:
printf("U-Law encoded.");
break;
case SF_FORMAT_ALAW:
printf("A-Law encoded.");
break;
case SF_FORMAT_IMA_ADPCM:
printf("IMA ADPCM.");
break;
case SF_FORMAT_MS_ADPCM:
printf("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:
printf("Signed 8 bit PCM.");
break;
case SF_FORMAT_PCM_U8:
printf("Unsigned 8 bit PCM.");
break;
case SF_FORMAT_PCM_16:
printf("Signed 16 bit PCM.");
break;
case SF_FORMAT_PCM_24:
printf("Signed 24 bit PCM.");
break;
case SF_FORMAT_PCM_32:
printf("Signed 32 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;
}
printf("\n");
printf("sections :%d\n", gs_wfInfo.sections);
printf("seekable :%d\n", gs_wfInfo.seekable);
#endif
/* Check result */
if (gs_pSndFileIn == NULL) {
sf_perror(gs_pSndFileIn);
if (global_ui_config.silent < 10) {
error_printf("Could not open sound file \"%s\".\n", lpszFileName);
}
return 0;
}
if(gs_wfInfo.frames >= 0 && gs_wfInfo.frames < (sf_count_t)(unsigned)MAX_U_32_NUM)
(void) lame_set_num_samples(gfp, gs_wfInfo.frames);
else
(void) lame_set_num_samples(gfp, MAX_U_32_NUM);
if (!set_input_num_channels(gfp, gs_wfInfo.channels)) {
sf_close(gs_pSndFileIn);
return 0;
}
if (!set_input_samplerate(gfp, gs_wfInfo.samplerate)) {
sf_close(gs_pSndFileIn);
return 0;
}
global. pcmbitwidth = 32;
}
#if 0
if (lame_get_num_samples(gfp) == MAX_U_32_NUM) {
/* try to figure out num_samples */
double const flen = lame_get_file_size(lpszFileName);
if (flen >= 0) {
/* try file size, assume 2 bytes per sample */
lame_set_num_samples(gfp, flen / (2 * lame_get_num_channels(gfp)));
}
}
#endif
return gs_pSndFileIn;
}
#endif /* defined(LIBSNDFILE) */
/************************************************************************
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;
{
size_t samples_read_ = fread(sample_buffer, bytes_per_sample, samples_to_read, pcm_in);
assert( samples_read_ <= INT_MAX );
samples_read = (int) samples_read_;
}
op = sample_buffer + samples_read;
#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;)
if (swap_order == 0) {
GA_URS_IFLOOP(1)
* --op = ip[i] << (b - 8);
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(1)
* --op = (ip[i] ^ 0x80) << (b - 8) | 0x7f << (b - 16); /* convert from unsigned */
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
if (global.pcm_is_ieee_float) {
ieee754_float32_t const m_max = INT_MAX;
ieee754_float32_t const m_min = -(ieee754_float32_t) INT_MIN;
ieee754_float32_t *x = (ieee754_float32_t *) sample_buffer;
assert(sizeof(ieee754_float32_t) == sizeof(int));
for (i = 0; i < samples_to_read; ++i) {
ieee754_float32_t const u = x[i];
int v;
if (u >= 1) {
v = INT_MAX;
}
else if (u <= -1) {
v = INT_MIN;
}
else if (u >= 0) {
v = (int) (u * m_max + 0.5f);
}
else {
v = (int) (u * m_min - 0.5f);
}
sample_buffer[i] = v;
}
}
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.
*
************************************************************************/
static int
read_samples_pcm(FILE * musicin, int sample_buffer[2304], int samples_to_read)
{
int samples_read;
int bytes_per_sample = global.pcmbitwidth / 8;
int swap_byte_order; /* byte order of input stream */
switch (global.pcmbitwidth) {
case 32:
case 24:
case 16:
if (global_raw_pcm.in_signed == 0) {
if (global_ui_config.silent < 10) {
error_printf("Unsigned input only supported with bitwidth 8\n");
}
return -1;
}
swap_byte_order = (global_raw_pcm.in_endian != ByteOrderLittleEndian) ? 1 : 0;
if (global.pcmswapbytes) {
swap_byte_order = !swap_byte_order;
}
break;
case 8:
swap_byte_order = global.pcm_is_unsigned_8bit;
break;
default:
if (global_ui_config.silent < 10) {
error_printf("Only 8, 16, 24 and 32 bit input files supported \n");
}
return -1;
}
if (samples_to_read < 0 || samples_to_read > 2304) {
if (global_ui_config.silent < 10) {
error_printf("Error: unexpected number of samples to read: %d\n", samples_to_read);
}
return -1;
}
samples_read = unpack_read_samples(samples_to_read, bytes_per_sample, swap_byte_order,
sample_buffer, musicin);
if (ferror(musicin)) {
if (global_ui_config.silent < 10) {
error_printf("Error reading input file\n");
}
return -1;
}
return samples_read;
}
/* AIFF Definitions */
static int const IFF_ID_FORM = 0x464f524d; /* "FORM" */
static int const IFF_ID_AIFF = 0x41494646; /* "AIFF" */
static int const IFF_ID_AIFC = 0x41494643; /* "AIFC" */
static int const IFF_ID_COMM = 0x434f4d4d; /* "COMM" */
static int const IFF_ID_SSND = 0x53534e44; /* "SSND" */
static int const IFF_ID_MPEG = 0x4d504547; /* "MPEG" */
static int const IFF_ID_NONE = 0x4e4f4e45; /* "NONE" *//* AIFF-C data format */
static int const IFF_ID_2CBE = 0x74776f73; /* "twos" *//* AIFF-C data format */
static int const IFF_ID_2CLE = 0x736f7774; /* "sowt" *//* AIFF-C data format */
static int const WAV_ID_RIFF = 0x52494646; /* "RIFF" */
static int const WAV_ID_WAVE = 0x57415645; /* "WAVE" */
static int const WAV_ID_FMT = 0x666d7420; /* "fmt " */
static int const WAV_ID_DATA = 0x64617461; /* "data" */
#ifndef WAVE_FORMAT_PCM
static short const WAVE_FORMAT_PCM = 0x0001;
#endif
#ifndef WAVE_FORMAT_IEEE_FLOAT
static short const WAVE_FORMAT_IEEE_FLOAT = 0x0003;
#endif
#ifndef WAVE_FORMAT_EXTENSIBLE
static short const WAVE_FORMAT_EXTENSIBLE = 0xFFFE;
#endif
static long
make_even_number_of_bytes_in_length(long x)
{
if ((x & 0x01) != 0) {
return x + 1;
}
return x;
}
/*****************************************************************************
*
* 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 bits_per_sample = 0;
int samples_per_sec = 0;
int is_wav = 0;
unsigned long data_length = 0, subSize = 0;
int loop_sanity = 0;
(void) read_32_bits_high_low(sf); /* file_length */
if (read_32_bits_high_low(sf) != WAV_ID_WAVE)
return -1;
for (loop_sanity = 0; loop_sanity < 20; ++loop_sanity) {
int type = read_32_bits_high_low(sf);
if (type == WAV_ID_FMT) {
subSize = read_32_bits_low_high(sf);
subSize = make_even_number_of_bytes_in_length(subSize);
if (subSize < 16) {
/*DEBUGF(
"'fmt' chunk too short (only %ld bytes)!", subSize); */
return -1;
}
format_tag = read_16_bits_low_high(sf);
subSize -= 2;
channels = read_16_bits_low_high(sf);
subSize -= 2;
samples_per_sec = read_32_bits_low_high(sf);
subSize -= 4;
(void) read_32_bits_low_high(sf); /* avg_bytes_per_sec */
subSize -= 4;
(void) read_16_bits_low_high(sf); /* block_align */
subSize -= 2;
bits_per_sample = read_16_bits_low_high(sf);
subSize -= 2;
/* WAVE_FORMAT_EXTENSIBLE support */
if ((subSize > 9) && (format_tag == WAVE_FORMAT_EXTENSIBLE)) {
read_16_bits_low_high(sf); /* cbSize */
read_16_bits_low_high(sf); /* ValidBitsPerSample */
read_32_bits_low_high(sf); /* ChannelMask */
/* SubType coincident with format_tag for PCM int or float */
format_tag = read_16_bits_low_high(sf);
subSize -= 10;
}
/* DEBUGF(" skipping %d bytes\n", subSize); */
if (subSize > 0) {
if (fskip(sf, (long) subSize, SEEK_CUR) != 0)
return -1;
};
}
else if (type == WAV_ID_DATA) {
subSize = read_32_bits_low_high(sf);
data_length = subSize;
is_wav = 1;
/* We've found the audio data. Read no further! */
break;
}
else {
subSize = read_32_bits_low_high(sf);
subSize = make_even_number_of_bytes_in_length(subSize);
if (fskip(sf, (long) subSize, SEEK_CUR) != 0) {
return -1;
}
}
}
if (is_wav) {
if (format_tag == 0x0050 || format_tag == 0x0055) {
return sf_mp123;
}
if (format_tag != WAVE_FORMAT_PCM && format_tag != WAVE_FORMAT_IEEE_FLOAT) {
if (global_ui_config.silent < 10) {
error_printf("Unsupported data format: 0x%04X\n", format_tag);
}
return 0; /* oh no! non-supported format */
}
/* make sure the header is sane */
if (!set_input_num_channels(gfp, channels))
return 0;
if (!set_input_samplerate(gfp, samples_per_sec))
return 0;
/* avoid division by zero */
if (bits_per_sample < 1) {
if (global_ui_config.silent < 10)
error_printf("Unsupported bits per sample: %d\n", bits_per_sample);
return -1;
}
global. pcmbitwidth = bits_per_sample;
global. pcm_is_unsigned_8bit = 1;
global. pcm_is_ieee_float = (format_tag == WAVE_FORMAT_IEEE_FLOAT ? 1 : 0);
if (data_length == MAX_U_32_NUM)
(void) lame_set_num_samples(gfp, MAX_U_32_NUM);
else
(void) lame_set_num_samples(gfp, data_length / (channels * ((bits_per_sample + 7) / 8)));
return 1;
}
return -1;
}
/************************************************************************
* aiff_check2
*
* PURPOSE: Checks AIFF header information to make sure it is valid.
* returns 0 on success, 1 on errors
************************************************************************/
static int
aiff_check2(IFF_AIFF * const pcm_aiff_data)
{
if (pcm_aiff_data->sampleType != (unsigned long) IFF_ID_SSND) {
if (global_ui_config.silent < 10) {
error_printf("ERROR: input sound data is not PCM\n");
}
return 1;
}
switch (pcm_aiff_data->sampleSize) {
case 32:
case 24:
case 16:
case 8:
break;
default:
if (global_ui_config.silent < 10) {
error_printf("ERROR: input sound data is not 8, 16, 24 or 32 bits\n");
}
return 1;
}
if (pcm_aiff_data->numChannels != 1 && pcm_aiff_data->numChannels != 2) {
if (global_ui_config.silent < 10) {
error_printf("ERROR: input sound data is not mono or stereo\n");
}
return 1;
}
if (pcm_aiff_data->blkAlgn.blockSize != 0) {
if (global_ui_config.silent < 10) {
error_printf("ERROR: block size of input sound data is not 0 bytes\n");
}
return 1;
}
/* A bug, since we correctly skip the offset earlier in the code.
if (pcm_aiff_data->blkAlgn.offset != 0) {
error_printf("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)
{
long chunkSize = 0, subSize = 0, typeID = 0, dataType = IFF_ID_NONE;
IFF_AIFF aiff_info;
int seen_comm_chunk = 0, seen_ssnd_chunk = 0;
long pcm_data_pos = -1;
memset(&aiff_info, 0, sizeof(aiff_info));
chunkSize = read_32_bits_high_low(sf);
typeID = read_32_bits_high_low(sf);
if ((typeID != IFF_ID_AIFF) && (typeID != IFF_ID_AIFC))
return -1;
while (chunkSize > 0) {
long ckSize;
int type = read_32_bits_high_low(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) {
seen_comm_chunk = seen_ssnd_chunk + 1;
subSize = read_32_bits_high_low(sf);
ckSize = make_even_number_of_bytes_in_length(subSize);
chunkSize -= ckSize;
aiff_info.numChannels = (short) read_16_bits_high_low(sf);
ckSize -= 2;
aiff_info.numSampleFrames = read_32_bits_high_low(sf);
ckSize -= 4;
aiff_info.sampleSize = (short) read_16_bits_high_low(sf);
ckSize -= 2;
aiff_info.sampleRate = read_ieee_extended_high_low(sf);
ckSize -= 10;
if (typeID == IFF_ID_AIFC) {
dataType = read_32_bits_high_low(sf);
ckSize -= 4;
}
if (fskip(sf, ckSize, SEEK_CUR) != 0)
return -1;
}
else if (type == IFF_ID_SSND) {
seen_ssnd_chunk = 1;
subSize = read_32_bits_high_low(sf);
ckSize = make_even_number_of_bytes_in_length(subSize);
chunkSize -= ckSize;
aiff_info.blkAlgn.offset = read_32_bits_high_low(sf);
ckSize -= 4;
aiff_info.blkAlgn.blockSize = read_32_bits_high_low(sf);
ckSize -= 4;
aiff_info.sampleType = IFF_ID_SSND;
if (seen_comm_chunk > 0) {
if (fskip(sf, (long) aiff_info.blkAlgn.offset, SEEK_CUR) != 0)
return -1;
/* We've found the audio data. Read no further! */
break;
}
pcm_data_pos = ftell(sf);
if (pcm_data_pos >= 0) {
pcm_data_pos += aiff_info.blkAlgn.offset;
}
if (fskip(sf, ckSize, SEEK_CUR) != 0)
return -1;
}
else {
subSize = read_32_bits_high_low(sf);
ckSize = make_even_number_of_bytes_in_length(subSize);
chunkSize -= ckSize;
if (fskip(sf, ckSize, SEEK_CUR) != 0)
return -1;
}
}
if (dataType == IFF_ID_2CLE) {
global. pcmswapbytes = global_reader.swapbytes;
}
else if (dataType == IFF_ID_2CBE) {
global. pcmswapbytes = !global_reader.swapbytes;
}
else if (dataType == IFF_ID_NONE) {
global. pcmswapbytes = !global_reader.swapbytes;
}
else {
return -1;
}
/* DEBUGF("Parsed AIFF %d\n", is_aiff); */
if (seen_comm_chunk && (seen_ssnd_chunk > 0 || aiff_info.numSampleFrames == 0)) {
/* make sure the header is sane */
if (0 != aiff_check2(&aiff_info))
return 0;
if (!set_input_num_channels(gfp, aiff_info.numChannels))
return 0;
if (!set_input_samplerate(gfp, (int) aiff_info.sampleRate))
return 0;
(void) lame_set_num_samples(gfp, aiff_info.numSampleFrames);
global. pcmbitwidth = aiff_info.sampleSize;
global. pcm_is_unsigned_8bit = 0;
global. pcm_is_ieee_float = 0; /* FIXME: possible ??? */
if (pcm_data_pos >= 0) {
if (fseek(sf, pcm_data_pos, SEEK_SET) != 0) {
if (global_ui_config.silent < 10) {
error_printf("Can't rewind stream to audio data position\n");
}
return 0;
}
}
return 1;
}
return -1;
}
/************************************************************************
*
* 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.
*
************************************************************************/
static int
parse_file_header(lame_global_flags * gfp, FILE * sf)
{
int type = read_32_bits_high_low(sf);
/*
DEBUGF(
"First word of input stream: %08x '%4.4s'\n", type, (char*) &type);
*/
global. count_samples_carefully = 0;
global. pcm_is_unsigned_8bit = global_raw_pcm.in_signed == 1 ? 0 : 1;
/*global_reader.input_format = sf_raw; commented out, because it is better to fail
here as to encode some hundreds of input files not supported by LAME
If you know you have RAW PCM data, use the -r switch
*/
if (type == WAV_ID_RIFF) {
/* It's probably a WAV file */
int const ret = parse_wave_header(gfp, sf);
if (ret == sf_mp123) {
global. count_samples_carefully = 1;
return sf_mp123;
}
if (ret > 0) {
if (lame_get_num_samples(gfp) == MAX_U_32_NUM || global_reader.ignorewavlength == 1)
{
global. count_samples_carefully = 0;
lame_set_num_samples(gfp, MAX_U_32_NUM);
}
else
global. count_samples_carefully = 1;
return sf_wave;
}
if (ret < 0) {
if (global_ui_config.silent < 10) {
error_printf("Warning: corrupt or unsupported WAVE format\n");
}
}
}
else if (type == IFF_ID_FORM) {
/* It's probably an AIFF file */
int const ret = parse_aiff_header(gfp, sf);
if (ret > 0) {
global. count_samples_carefully = 1;
return sf_aiff;
}
if (ret < 0) {
if (global_ui_config.silent < 10) {
error_printf("Warning: corrupt or unsupported AIFF format\n");
}
}
}
else {
if (global_ui_config.silent < 10) {
error_printf("Warning: unsupported audio format\n");
}
}
return sf_unknown;
}
static int
open_mpeg_file_part2(lame_t gfp, FILE* musicin, char const *inPath, int *enc_delay, int *enc_padding)
{
#ifdef HAVE_MPGLIB
if (-1 == lame_decode_initfile(musicin, &global_decoder.mp3input_data, enc_delay, enc_padding)) {
if (global_ui_config.silent < 10) {
error_printf("Error reading headers in mp3 input file %s.\n", inPath);
}
return 0;
}
#endif
if (!set_input_num_channels(gfp, global_decoder.mp3input_data.stereo)) {
return 0;
}
if (!set_input_samplerate(gfp, global_decoder.mp3input_data.samplerate)) {
return 0;
}
(void) lame_set_num_samples(gfp, global_decoder.mp3input_data.nsamp);
return 1;
}
static FILE *
open_wave_file(lame_t gfp, char const *inPath, int *enc_delay, int *enc_padding)
{
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 = lame_fopen(inPath, "rb")) == NULL) {
if (global_ui_config.silent < 10) {
error_printf("Could not find \"%s\".\n", inPath);
}
return 0;
}
}
if (global_reader.input_format == sf_ogg) {
if (global_ui_config.silent < 10) {
error_printf("sorry, vorbis support in LAME is deprecated.\n");
}
close_input_file(musicin);
return 0;
}
else if (global_reader.input_format == sf_raw) {
/* assume raw PCM */
if (global_ui_config.silent < 9) {
console_printf("Assuming raw pcm input file");
if (global_reader.swapbytes)
console_printf(" : Forcing byte-swapping\n");
else
console_printf("\n");
}
global. pcmswapbytes = global_reader.swapbytes;
}
else {
global_reader.input_format = parse_file_header(gfp, musicin);
}
if (global_reader.input_format == sf_mp123) {
if (open_mpeg_file_part2(gfp, musicin, inPath, enc_delay, enc_padding))
return musicin;
close_input_file(musicin);
return 0;
}
if (global_reader.input_format == sf_unknown) {
close_input_file(musicin);
return 0;
}
if (lame_get_num_samples(gfp) == MAX_U_32_NUM && musicin != stdin) {
int const tmp_num_channels = lame_get_num_channels(gfp);
double const flen = lame_get_file_size(musicin); /* try to figure out num_samples */
if (flen >= 0 && tmp_num_channels > 0 ) {
/* try file size, assume 2 bytes per sample */
unsigned long fsize = (unsigned long) (flen / (2 * tmp_num_channels));
(void) lame_set_num_samples(gfp, fsize);
global. count_samples_carefully = 0;
}
}
return musicin;
}
static FILE *
open_mpeg_file(lame_t gfp, char const *inPath, int *enc_delay, int *enc_padding)
{
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, "-") == 0) {
musicin = stdin;
lame_set_stream_binary_mode(musicin); /* Read from standard input. */
}
else {
musicin = lame_fopen(inPath, "rb");
if (musicin == NULL) {
if (global_ui_config.silent < 10) {
error_printf("Could not find \"%s\".\n", inPath);
}
return 0;
}
}
#ifdef AMIGA_MPEGA
if (-1 == lame_decode_initfile(inPath, &global_decoder.mp3input_data)) {
if (global_ui_config.silent < 10) {
error_printf("Error reading headers in mp3 input file %s.\n", inPath);
}
close_input_file(musicin);
return 0;
}
#endif
if ( 0 == open_mpeg_file_part2(gfp, musicin, inPath, enc_delay, enc_padding) ) {
close_input_file(musicin);
return 0;
}
if (lame_get_num_samples(gfp) == MAX_U_32_NUM && musicin != stdin) {
double flen = lame_get_file_size(musicin); /* try to figure out num_samples */
if (flen >= 0) {
/* try file size, assume 2 bytes per sample */
if (global_decoder.mp3input_data.bitrate > 0) {
double totalseconds =
(flen * 8.0 / (1000.0 * global_decoder.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);
global_decoder.mp3input_data.nsamp = tmp_num_samples;
global. count_samples_carefully = 0;
}
}
}
return musicin;
}
static int
close_input_file(FILE * musicin)
{
int ret = 0;
if (musicin != stdin && musicin != 0) {
ret = fclose(musicin);
}
if (ret != 0) {
if (global_ui_config.silent < 10) {
error_printf("Could not close audio input file\n");
}
}
return ret;
}
#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 */
switch (p[1] & 0x06) {
default:
case 0x00: /* illegal Layer */
return 0;
case 0x02: /* Layer3 */
if (global_reader.input_format != sf_mp3 && global_reader.input_format != sf_mp123) {
return 0;
}
global_reader.input_format = sf_mp3;
break;
case 0x04: /* Layer2 */
if (global_reader.input_format != sf_mp2 && global_reader.input_format != sf_mp123) {
return 0;
}
global_reader.input_format = sf_mp2;
break;
case 0x06: /* Layer1 */
if (global_reader.input_format != sf_mp1 && global_reader.input_format != sf_mp123) {
return 0;
}
global_reader.input_format = sf_mp1;
break;
}
if ((p[1] & 0x06) == 0x00)
return 0; /* no Layer I, II and III */
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;
}
static size_t
lenOfId3v2Tag(unsigned char const* buf)
{
unsigned int b0 = buf[0] & 127;
unsigned int b1 = buf[1] & 127;
unsigned int b2 = buf[2] & 127;
unsigned int b3 = buf[3] & 127;
return (((((b0 << 7) + b1) << 7) + b2) << 7) + b3;
}
int
lame_decode_initfile(FILE * fd, mp3data_struct * mp3data, int *enc_delay, int *enc_padding)
{
/* VBRTAGDATA pTagData; */
/* int xing_header,len2,num_frames; */
unsigned char buf[100];
int ret;
size_t len;
int aid_header;
short int pcm_l[1152], pcm_r[1152];
int freeformat = 0;
memset(mp3data, 0, sizeof(mp3data_struct));
if (global.hip) {
hip_decode_exit(global.hip);
}
global. hip = hip_decode_init();
hip_set_msgf(global.hip, global_ui_config.silent < 10 ? &frontend_msgf : 0);
hip_set_errorf(global.hip, global_ui_config.silent < 10 ? &frontend_errorf : 0);
hip_set_debugf(global.hip, &frontend_debugf);
len = 4;
if (fread(buf, 1, len, fd) != len)
return -1; /* failed */
while (buf[0] == 'I' && buf[1] == 'D' && buf[2] == '3') {
len = 6;
if (fread(&buf[4], 1, len, fd) != len)
return -1; /* failed */
len = lenOfId3v2Tag(&buf[6]);
if (global.in_id3v2_size < 1) {
global.in_id3v2_size = 10 + len;
global.in_id3v2_tag = malloc(global.in_id3v2_size);
if (global.in_id3v2_tag) {
memcpy(global.in_id3v2_tag, buf, 10);
if (fread(&global.in_id3v2_tag[10], 1, len, fd) != len)
return -1; /* failed */
len = 0; /* copied, nothing to skip */
}
else {
global.in_id3v2_size = 0;
}
}
assert( len <= LONG_MAX );
fskip(fd, (long) 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 (global_ui_config.silent < 9) {
console_printf("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)) {
unsigned 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 (global_ui_config.silent < 9) {
console_printf("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 = hip_decode1_headersB(global.hip, 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 =
hip_decode1_headersB(global.hip, buf, len, pcm_l, pcm_r, mp3data, enc_delay,
enc_padding);
if (-1 == ret)
return -1;
}
if (mp3data->bitrate == 0 && !freeformat) {
if (global_ui_config.silent < 10) {
error_printf("fail to sync...\n");
}
return lame_decode_initfile(fd, mp3data, enc_delay, enc_padding);
}
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;
}
/*
report_printf("ret = %i NEED_MORE=%i \n",ret,MP3_NEED_MORE);
report_printf("stereo = %i \n",mp.fr.stereo);
report_printf("samp = %i \n",freqs[mp.fr.sampling_frequency]);
report_printf("framesize = %i \n",framesize);
report_printf("bitrate = %i \n",mp3data->bitrate);
report_printf("num frames = %ui \n",num_frames);
report_printf("num samp = %ui \n",mp3data->nsamp);
report_printf("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.
*/
static int
lame_decode_fromfile(FILE * fd, short pcm_l[], short pcm_r[], mp3data_struct * mp3data)
{
int ret = 0;
size_t len = 0;
unsigned char buf[1024];
/* first see if we still have data buffered in the decoder: */
ret = hip_decode1_headers(global.hip, buf, len, pcm_l, pcm_r, mp3data);
if (ret != 0)
return ret;
/* read until we get a valid output frame */
for (;;) {
len = fread(buf, 1, 1024, fd);
if (len == 0) {
/* we are done reading the file, but check for buffered data */
ret = hip_decode1_headers(global.hip, buf, len, pcm_l, pcm_r, mp3data);
if (ret <= 0) {
return -1; /* done with file */
}
break;
}
ret = hip_decode1_headers(global.hip, buf, len, pcm_l, pcm_r, mp3data);
if (ret == -1) {
return -1;
}
if (ret > 0)
break;
}
return ret;
}
#endif /* defined(HAVE_MPGLIB) */
int
is_mpeg_file_format(int input_file_format)
{
switch (input_file_format) {
case sf_mp1:
return 1;
case sf_mp2:
return 2;
case sf_mp3:
return 3;
case sf_mp123:
return -1;
default:
break;
}
return 0;
}
#define LOW__BYTE(x) (x & 0x00ff)
#define HIGH_BYTE(x) ((x >> 8) & 0x00ff)
void
put_audio16(FILE * outf, short Buffer[2][1152], int iread, int nch)
{
char data[2 * 1152 * 2];
int i, m = 0;
if (global_decoder.disable_wav_header && global_reader.swapbytes) {
if (nch == 1) {
for (i = 0; i < iread; i++) {
short x = Buffer[0][i];
/* write 16 Bits High Low */
data[m++] = HIGH_BYTE(x);
data[m++] = LOW__BYTE(x);
}
}
else {
for (i = 0; i < iread; i++) {
short x = Buffer[0][i], y = Buffer[1][i];
/* write 16 Bits High Low */
data[m++] = HIGH_BYTE(x);
data[m++] = LOW__BYTE(x);
/* write 16 Bits High Low */
data[m++] = HIGH_BYTE(y);
data[m++] = LOW__BYTE(y);
}
}
}
else {
if (nch == 1) {
for (i = 0; i < iread; i++) {
short x = Buffer[0][i];
/* write 16 Bits Low High */
data[m++] = LOW__BYTE(x);
data[m++] = HIGH_BYTE(x);
}
}
else {
for (i = 0; i < iread; i++) {
short x = Buffer[0][i], y = Buffer[1][i];
/* write 16 Bits Low High */
data[m++] = LOW__BYTE(x);
data[m++] = HIGH_BYTE(x);
/* write 16 Bits Low High */
data[m++] = LOW__BYTE(y);
data[m++] = HIGH_BYTE(y);
}
}
}
if (m > 0) {
fwrite(data, 1, m, outf);
}
if (global_writer.flush_write == 1) {
fflush(outf);
}
}
hip_t
get_hip(void)
{
return global.hip;
}
size_t
sizeOfOldTag(lame_t gf)
{
(void) gf;
return global.in_id3v2_size;
}
unsigned char*
getOldTag(lame_t gf)
{
(void) gf;
return global.in_id3v2_tag;
}
/* end of get_audio.c */