/* ** Copyright (C) 2020 Arthur Taylor ** Copyright (C) 2019 Erik de Castro Lopo ** ** 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 /* * 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