furnace/extern/libsndfile-modified/src/mpeg_l3_encode.c
tildearrow 061991fe60 desubmodulize libsndfile - PLEASE READ
it appears a one-character typo in the cmake_minimum_required line prevents it from compiling under CMake 4.0.
in order to fix that, I had to take this thing out of submodules...

it is recommended to do this after you pull;

git submodule deinit extern/libsndfile
2025-04-02 15:09:53 -05:00

785 lines
23 KiB
C

/*
** Copyright (C) 2020 Arthur Taylor <art@ified.ca>
** Copyright (C) 2019 Erik de Castro Lopo <erikd@mega-nerd.com>
**
** This program is free software ; you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation ; either version 2.1 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY ; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with this program ; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "sfconfig.h"
#include "sndfile.h"
#include "common.h"
#include "mpeg.h"
#if HAVE_MPEG
#include <lame/lame.h>
/*
* RANT RANT RANT
*
* Lame has 11 functions for inputing sample data of various types and
* configurations, but due to bad definitions, or missing combinations, they
* aren't really of much help to us.
*
*/
typedef struct
{ lame_t lamef ;
unsigned char *block ;
size_t block_len ;
int frame_samples ;
double compression ;
int initialized ;
} MPEG_L3_ENC_PRIVATE ;
/*-----------------------------------------------------------------------------------------------
** Private function prototypes.
*/
static int mpeg_l3_encoder_close (SF_PRIVATE *psf) ;
static int mpeg_l3_encoder_construct (SF_PRIVATE *psf) ;
static int mpeg_l3_encoder_byterate (SF_PRIVATE *psf) ;
static sf_count_t mpeg_l3_encode_write_short_stereo (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t mpeg_l3_encode_write_int_stereo (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t mpeg_l3_encode_write_float_stereo (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t mpeg_l3_encode_write_double_stereo (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
static sf_count_t mpeg_l3_encode_write_short_mono (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
static sf_count_t mpeg_l3_encode_write_int_mono (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
static sf_count_t mpeg_l3_encode_write_float_mono (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
static sf_count_t mpeg_l3_encode_write_double_mono (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
/*-----------------------------------------------------------------------------------------------
** Exported functions.
*/
int
mpeg_l3_encoder_init (SF_PRIVATE *psf, int info_tag)
{ MPEG_L3_ENC_PRIVATE* pmpeg = NULL ;
if (psf->file.mode == SFM_RDWR)
return SFE_BAD_MODE_RW ;
if (psf->file.mode != SFM_WRITE)
return SFE_INTERNAL ;
psf->codec_data = pmpeg = calloc (1, sizeof (MPEG_L3_ENC_PRIVATE)) ;
if (!pmpeg)
return SFE_MALLOC_FAILED ;
if (psf->sf.channels < 1 || psf->sf.channels > 2)
return SFE_BAD_OPEN_FORMAT ;
if (! (pmpeg->lamef = lame_init ()))
return SFE_MALLOC_FAILED ;
pmpeg->compression = -1.0 ; /* Unset */
lame_set_in_samplerate (pmpeg->lamef, psf->sf.samplerate) ;
lame_set_num_channels (pmpeg->lamef, psf->sf.channels) ;
if (lame_set_out_samplerate (pmpeg->lamef, psf->sf.samplerate) < 0)
return SFE_MPEG_BAD_SAMPLERATE ;
lame_set_write_id3tag_automatic (pmpeg->lamef, 0) ;
if (!info_tag || psf->is_pipe)
{ /* Can't seek back, so force disable Xing/Lame/Info header. */
lame_set_bWriteVbrTag (pmpeg->lamef, 0) ;
} ;
if (psf->sf.channels == 2)
{ psf->write_short = mpeg_l3_encode_write_short_stereo ;
psf->write_int = mpeg_l3_encode_write_int_stereo ;
psf->write_float = mpeg_l3_encode_write_float_stereo ;
psf->write_double = mpeg_l3_encode_write_double_stereo ;
}
else
{ psf->write_short = mpeg_l3_encode_write_short_mono ;
psf->write_int = mpeg_l3_encode_write_int_mono ;
psf->write_float = mpeg_l3_encode_write_float_mono ;
psf->write_double = mpeg_l3_encode_write_double_mono ;
}
psf->sf.seekable = 0 ;
psf->codec_close = mpeg_l3_encoder_close ;
psf->byterate = mpeg_l3_encoder_byterate ;
psf->datalength = 0 ;
return 0 ;
} /* mpeg_l3_encoder_init */
int
mpeg_l3_encoder_write_id3tag (SF_PRIVATE *psf)
{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
unsigned char *id3v2_buffer ;
int i, id3v2_size ;
if (psf->have_written)
return 0 ;
if ((i = mpeg_l3_encoder_construct (psf)))
return i ;
if (psf_fseek (psf, 0, SEEK_SET) != 0)
return SFE_NOT_SEEKABLE ;
/* Safe to call multiple times. */
id3tag_init (pmpeg->lamef) ;
for (i = 0 ; i < SF_MAX_STRINGS ; i++)
{ switch (psf->strings.data [i].type)
{ case SF_STR_TITLE :
id3tag_set_title (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
break ;
case SF_STR_ARTIST :
id3tag_set_artist (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
break ;
case SF_STR_ALBUM :
id3tag_set_album (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
break ;
case SF_STR_DATE :
id3tag_set_year (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
break ;
case SF_STR_COMMENT :
id3tag_set_comment (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
break ;
case SF_STR_GENRE :
id3tag_set_genre (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
break ;
case SF_STR_TRACKNUMBER :
id3tag_set_track (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
break ;
default:
break ;
} ;
} ;
/* The header in this case is the ID3v2 tag header. */
id3v2_size = lame_get_id3v2_tag (pmpeg->lamef, 0, 0) ;
if (id3v2_size > 0)
{ psf_log_printf (psf, "Writing ID3v2 header.\n") ;
if (! (id3v2_buffer = malloc (id3v2_size)))
return SFE_MALLOC_FAILED ;
lame_get_id3v2_tag (pmpeg->lamef, id3v2_buffer, id3v2_size) ;
psf_fwrite (id3v2_buffer, 1, id3v2_size, psf) ;
psf->dataoffset = id3v2_size ;
free (id3v2_buffer) ;
} ;
return 0 ;
}
int
mpeg_l3_encoder_set_quality (SF_PRIVATE *psf, double compression)
{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
int bitrate_mode ;
int bitrate ;
int ret ;
if (compression < 0.0 || compression > 1.0)
return SF_FALSE ;
/*
** Save the compression setting, as we may have to re-interpret it if
** the bitrate mode changes.
*/
pmpeg->compression = compression ;
bitrate_mode = mpeg_l3_encoder_get_bitrate_mode (psf) ;
if (bitrate_mode == SF_BITRATE_MODE_VARIABLE)
{ ret = lame_set_VBR_quality (pmpeg->lamef, compression * 10.0) ;
}
else
{ /* Choose a bitrate. */
if (psf->sf.samplerate >= 32000)
{ /* MPEG-1.0, bitrates are [32,320] kbps */
bitrate = (320.0 - (compression * (320.0 - 32.0))) ;
}
else if (psf->sf.samplerate >= 16000)
{ /* MPEG-2.0, bitrates are [8,160] */
bitrate = (160.0 - (compression * (160.0 - 8.0))) ;
}
else
{ /* MPEG-2.5, bitrates are [8,64] */
bitrate = (64.0 - (compression * (64.0 - 8.0))) ;
}
if (bitrate_mode == SF_BITRATE_MODE_AVERAGE)
ret = lame_set_VBR_mean_bitrate_kbps (pmpeg->lamef, bitrate) ;
else
ret = lame_set_brate (pmpeg->lamef, bitrate) ;
} ;
if (ret == LAME_OKAY)
return SF_TRUE ;
psf_log_printf (psf, "Failed to set lame encoder quality.\n") ;
return SF_FALSE ;
} /* mpeg_l3_encoder_set_quality */
int
mpeg_l3_encoder_set_bitrate_mode (SF_PRIVATE *psf, int mode)
{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
enum vbr_mode_e vbr_mode ;
if (pmpeg->initialized)
{ psf->error = SFE_CMD_HAS_DATA ;
return SF_FALSE ;
} ;
switch (mode)
{ case SF_BITRATE_MODE_CONSTANT : vbr_mode = vbr_off ; break ;
case SF_BITRATE_MODE_AVERAGE : vbr_mode = vbr_abr ; break ;
case SF_BITRATE_MODE_VARIABLE : vbr_mode = vbr_default ; break ;
default :
psf->error = SFE_BAD_COMMAND_PARAM ;
return SF_FALSE ;
} ;
if (lame_set_VBR (pmpeg->lamef, vbr_mode) == LAME_OKAY)
{ /* Re-evaluate the compression setting. */
return mpeg_l3_encoder_set_quality (psf, pmpeg->compression) ;
} ;
psf_log_printf (psf, "Failed to set LAME vbr mode to %d.\n", vbr_mode) ;
return SF_FALSE ;
} /* mpeg_l3_encoder_set_bitrate_mode */
int
mpeg_l3_encoder_get_bitrate_mode (SF_PRIVATE *psf)
{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
enum vbr_mode_e vbr_mode ;
vbr_mode = lame_get_VBR (pmpeg->lamef) ;
if (vbr_mode == vbr_off)
return SF_BITRATE_MODE_CONSTANT ;
if (vbr_mode == vbr_abr)
return SF_BITRATE_MODE_AVERAGE ;
if (vbr_mode == vbr_default || vbr_mode < vbr_max_indicator)
return SF_BITRATE_MODE_VARIABLE ;
/* Something is wrong. */
psf->error = SFE_INTERNAL ;
return -1 ;
} /* mpeg_l3_encoder_get_bitrate_mode */
/*-----------------------------------------------------------------------------------------------
** Private functions.
*/
static int
mpeg_l3_encoder_close (SF_PRIVATE *psf)
{ MPEG_L3_ENC_PRIVATE* pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
int ret, len ;
sf_count_t pos ;
unsigned char *buffer ;
/* Magic number 7200 comes from a comment in lame.h */
len = 7200 ;
if (! (buffer = malloc (len)))
return SFE_MALLOC_FAILED ;
ret = lame_encode_flush (pmpeg->lamef, buffer, len) ;
if (ret > 0)
psf_fwrite (buffer, 1, ret, psf) ;
/*
** Write an IDv1 trailer. The whole tag structure is always 128 bytes, so is
** guaranteed to fit in the buffer allocated above.
*/
ret = lame_get_id3v1_tag (pmpeg->lamef, buffer, len) ;
if (ret > 0)
{ psf_log_printf (psf, " Writing ID3v1 trailer.\n") ;
psf_fwrite (buffer, 1, ret, psf) ;
} ;
/*
** If possible, seek back and write the LAME/XING/Info headers. This
** contains information about the whole file and a seek table, and can
** only be written after encoding.
**
** If enabled, Lame wrote an empty header at the beginning of the data
** that we now fill in.
*/
ret = lame_get_lametag_frame (pmpeg->lamef, 0, 0) ;
if (ret > 0)
{ if (ret > len)
{ len = ret ;
free (buffer) ;
if (! (buffer = malloc (len)))
return SFE_MALLOC_FAILED ;
} ;
psf_log_printf (psf, " Writing LAME info header at offset %d, %d bytes.\n",
psf->dataoffset, len) ;
lame_get_lametag_frame (pmpeg->lamef, buffer, len) ;
pos = psf_ftell (psf) ;
if (psf_fseek (psf, psf->dataoffset, SEEK_SET) == psf->dataoffset)
{ psf_fwrite (buffer, 1, ret, psf) ;
psf_fseek (psf, pos, SEEK_SET) ;
} ;
} ;
free (buffer) ;
free (pmpeg->block) ;
pmpeg->block = NULL ;
if (pmpeg->lamef)
{ lame_close (pmpeg->lamef) ;
pmpeg->lamef = NULL ;
} ;
return 0 ;
} /* mpeg_l3_encoder_close */
static void
mpeg_l3_encoder_log_config (SF_PRIVATE *psf, lame_t lamef)
{ const char *version ;
const char *chn_mode ;
switch (lame_get_version (lamef))
{ case 0 : version = "2" ; break ;
case 1 : version = "1" ; break ;
case 2 : version = "2.5" ; break ;
default : version = "unknown!?" ; break ;
} ;
switch (lame_get_mode (lamef))
{ case STEREO : chn_mode = "stereo" ; break ;
case JOINT_STEREO : chn_mode = "joint-stereo" ; break ;
case MONO : chn_mode = "mono" ; break ;
default : chn_mode = "unknown!?" ; break ;
} ;
psf_log_printf (psf, " MPEG Version : %s\n", version) ;
psf_log_printf (psf, " Block samples : %d\n", lame_get_framesize (lamef)) ;
psf_log_printf (psf, " Channel mode : %s\n", chn_mode) ;
psf_log_printf (psf, " Samplerate : %d\n", lame_get_out_samplerate (lamef)) ;
psf_log_printf (psf, " Encoder mode : ") ;
switch (lame_get_VBR (lamef))
{ case vbr_off :
psf_log_printf (psf, "CBR\n") ;
psf_log_printf (psf, " Bitrate : %d kbps\n", lame_get_brate (lamef)) ;
break ;
case vbr_abr :
psf_log_printf (psf, "ABR\n") ;
psf_log_printf (psf, " Mean Bitrate : %d kbps\n", lame_get_VBR_mean_bitrate_kbps (lamef)) ;
break ;
case vbr_mt :
case vbr_default :
psf_log_printf (psf, "VBR\n") ;
psf_log_printf (psf, " Quality : %d\n", lame_get_VBR_q (lamef)) ;
break ;
default:
psf_log_printf (psf, "Unknown!? (%d)\n", lame_get_VBR (lamef)) ;
break ;
} ;
psf_log_printf (psf, " Encoder delay : %d\n", lame_get_encoder_delay (lamef)) ;
psf_log_printf (psf, " Write INFO header : %d\n", lame_get_bWriteVbrTag (lamef)) ;
} /* mpeg_l3_encoder_log_config */
static int
mpeg_l3_encoder_construct (SF_PRIVATE *psf)
{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
int frame_samples_per_channel ;
if (pmpeg->initialized == SF_FALSE)
{ if (lame_init_params (pmpeg->lamef) < 0)
{ psf_log_printf (psf, "Failed to initialize lame encoder!\n") ;
return SFE_INTERNAL ;
} ;
psf_log_printf (psf, "Initialized LAME encoder.\n") ;
mpeg_l3_encoder_log_config (psf, pmpeg->lamef) ;
frame_samples_per_channel = lame_get_framesize (pmpeg->lamef) ;
/*
* Suggested output buffer size in bytes from lame.h comment is
* 1.25 * samples + 7200
*/
pmpeg->block_len = (frame_samples_per_channel * 4) / 3 + 7200 ;
pmpeg->frame_samples = frame_samples_per_channel * psf->sf.channels ;
pmpeg->block = malloc (pmpeg->block_len) ;
if (!pmpeg->block)
return SFE_MALLOC_FAILED ;
pmpeg->initialized = SF_TRUE ;
} ;
return 0 ;
} /* mpeg_l3_encoder_construct */
static int
mpeg_l3_encoder_byterate (SF_PRIVATE *psf)
{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
int bitrate_mode ;
int byterate ;
float calculated_byterate ;
bitrate_mode = mpeg_l3_encoder_get_bitrate_mode (psf) ;
byterate = (lame_get_brate (pmpeg->lamef) + 7) / 8 ;
if (bitrate_mode == SF_BITRATE_MODE_VARIABLE)
{ /*
** For VBR, lame_get_brate returns the minimum bitrate, so calculate the
** average byterate so far.
*/
calculated_byterate = psf_ftell (psf) - psf->dataoffset ;
calculated_byterate /= (float) psf->write_current ;
calculated_byterate *= (float) psf->sf.samplerate ;
return SF_MIN (byterate, (int) calculated_byterate) ;
}
return byterate ;
} /* mpeg_l3_encoder_byterate */
static sf_count_t
mpeg_l3_encode_write_short_mono (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
sf_count_t total = 0 ;
int nbytes, writecount, writen ;
if ((psf->error = mpeg_l3_encoder_construct (psf)))
return 0 ;
while (len)
{ writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ;
nbytes = lame_encode_buffer (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
if (nbytes < 0)
{ psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
break ;
} ;
if (nbytes)
{ writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
if (writen != nbytes)
{ psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
} ;
} ;
total += writecount ;
len -= writecount ;
} ;
return total ;
}
static sf_count_t
mpeg_l3_encode_write_short_stereo (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
{ BUF_UNION ubuf ;
MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
sf_count_t total = 0 ;
int nbytes, writecount, writen ;
if ((psf->error = mpeg_l3_encoder_construct (psf)))
return 0 ;
const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.sbuf), pmpeg->frame_samples) ;
while (len)
{ writecount = SF_MIN (len, max_samples) ;
/*
* An oversight, but lame_encode_buffer_interleaved() lacks a const.
* As such, need another memcpy to not cause a warning.
*/
memcpy (ubuf.sbuf, ptr + total, writecount) ;
nbytes = lame_encode_buffer_interleaved (pmpeg->lamef, ubuf.sbuf, writecount / 2, pmpeg->block, pmpeg->block_len) ;
if (nbytes < 0)
{ psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
break ;
} ;
if (nbytes)
{ writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
if (writen != nbytes)
{ psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
} ;
} ;
total += writecount ;
len -= writecount ;
} ;
return total ;
}
static sf_count_t
mpeg_l3_encode_write_int_mono (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
sf_count_t total = 0 ;
int nbytes, writecount, writen ;
if ((psf->error = mpeg_l3_encoder_construct (psf)))
return 0 ;
while (len)
{ writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ;
nbytes = lame_encode_buffer_int (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
if (nbytes < 0)
{ psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
break ;
} ;
if (nbytes)
{ writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
if (writen != nbytes)
{ psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
} ;
} ;
total += writecount ;
len -= writecount ;
} ;
return total ;
}
static sf_count_t
mpeg_l3_encode_write_int_stereo (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
sf_count_t total = 0 ;
int nbytes, writecount, writen ;
if ((psf->error = mpeg_l3_encoder_construct (psf)))
return 0 ;
while (len)
{ writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ;
nbytes = lame_encode_buffer_interleaved_int (pmpeg->lamef, ptr + total, writecount / 2, pmpeg->block, pmpeg->block_len) ;
if (nbytes < 0)
{ psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
break ;
} ;
if (nbytes)
{ writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
if (writen != nbytes)
{ psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
} ;
} ;
total += writecount ;
len -= writecount ;
} ;
return total ;
}
static sf_count_t
mpeg_l3_encode_write_float_mono (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
sf_count_t total = 0 ;
int nbytes, writecount, writen ;
if ((psf->error = mpeg_l3_encoder_construct (psf)))
return 0 ;
while (len)
{ writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ;
if (psf->norm_float)
nbytes = lame_encode_buffer_ieee_float (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
else
nbytes = lame_encode_buffer_float (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
if (nbytes < 0)
{ psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
break ;
} ;
if (nbytes)
{ writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
if (writen != nbytes)
{ psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
} ;
} ;
total += writecount ;
len -= writecount ;
} ;
return total ;
}
static inline void
normalize_float (float *dest, const float *src, sf_count_t count, float norm_fact)
{ while (--count >= 0)
{ dest [count] = src [count] * norm_fact ;
} ;
}
static sf_count_t
mpeg_l3_encode_write_float_stereo (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
{ BUF_UNION ubuf ;
MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
sf_count_t total = 0 ;
int nbytes, writecount, writen ;
if ((psf->error = mpeg_l3_encoder_construct (psf)))
return 0 ;
const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.fbuf), pmpeg->frame_samples) ;
while (len)
{ writecount = SF_MIN (len, max_samples) ;
if (psf->norm_float)
nbytes = lame_encode_buffer_interleaved_ieee_float (pmpeg->lamef, ptr + total, writecount / 2, pmpeg->block, pmpeg->block_len) ;
else
{ /* Lame lacks a non-normalized interleaved float write. Bummer. */
normalize_float (ubuf.fbuf, ptr + total, writecount, 1.0 / (float) 0x8000) ;
nbytes = lame_encode_buffer_interleaved_ieee_float (pmpeg->lamef, ubuf.fbuf, writecount / 2, pmpeg->block, pmpeg->block_len) ;
}
if (nbytes < 0)
{ psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
break ;
} ;
if (nbytes)
{ writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
if (writen != nbytes)
{ psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
} ;
} ;
total += writecount ;
len -= writecount ;
} ;
return total ;
}
static inline void
normalize_double (double *dest, const double *src, sf_count_t count, double norm_fact)
{ while (--count >= 0)
{ dest [count] = src [count] * norm_fact ;
} ;
}
static sf_count_t
mpeg_l3_encode_write_double_mono (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ BUF_UNION ubuf ;
MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
sf_count_t total = 0 ;
int nbytes, writecount, writen ;
if ((psf->error = mpeg_l3_encoder_construct (psf)))
return 0 ;
const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.dbuf), pmpeg->frame_samples) ;
while (len)
{ writecount = SF_MIN (len, max_samples) ;
if (psf->norm_double)
nbytes = lame_encode_buffer_ieee_double (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
else
{ /* Lame lacks non-normalized double writing */
normalize_double (ubuf.dbuf, ptr + total, writecount, 1.0 / (double) 0x8000) ;
nbytes = lame_encode_buffer_ieee_double (pmpeg->lamef, ubuf.dbuf, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
}
if (nbytes < 0)
{ psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
break ;
} ;
if (nbytes)
{ writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
if (writen != nbytes)
{ psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
} ;
} ;
total += writecount ;
len -= writecount ;
} ;
return total ;
}
static sf_count_t
mpeg_l3_encode_write_double_stereo (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
{ BUF_UNION ubuf ;
MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
sf_count_t total = 0 ;
int nbytes, writecount, writen ;
if ((psf->error = mpeg_l3_encoder_construct (psf)))
return 0 ;
const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.dbuf), pmpeg->frame_samples) ;
while (len)
{ writecount = SF_MIN (len, max_samples) ;
if (psf->norm_double)
nbytes = lame_encode_buffer_interleaved_ieee_double (pmpeg->lamef, ptr + total, writecount / 2, pmpeg->block, pmpeg->block_len) ;
else
{ /* Lame lacks interleaved non-normalized double writing */
normalize_double (ubuf.dbuf, ptr + total, writecount, 1.0 / (double) 0x8000) ;
nbytes = lame_encode_buffer_interleaved_ieee_double (pmpeg->lamef, ubuf.dbuf, writecount / 2, pmpeg->block, pmpeg->block_len) ;
}
if (nbytes < 0)
{ psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
break ;
} ;
if (nbytes)
{ writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
if (writen != nbytes)
{ psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
} ;
} ;
total += writecount ;
len -= writecount ;
} ;
return total ;
}
#else /* HAVE_MPEG */
int
mpeg_l3_encoder_init (SF_PRIVATE *psf, int UNUSED (vbr))
{ psf_log_printf (psf, "This version of libsndfile was compiled without MPEG Layer 3 encoding support.\n") ;
return SFE_UNIMPLEMENTED ;
} /* mpeg_l3_encoder_init */
#endif