1b815c7f3Sopenharmony_ci/*
2b815c7f3Sopenharmony_ci** Copyright (C) 2020 Arthur Taylor <art@ified.ca>
3b815c7f3Sopenharmony_ci** Copyright (C) 2019 Erik de Castro Lopo <erikd@mega-nerd.com>
4b815c7f3Sopenharmony_ci**
5b815c7f3Sopenharmony_ci** This program is free software ; you can redistribute it and/or modify
6b815c7f3Sopenharmony_ci** it under the terms of the GNU Lesser General Public License as published by
7b815c7f3Sopenharmony_ci** the Free Software Foundation ; either version 2.1 of the License, or
8b815c7f3Sopenharmony_ci** (at your option) any later version.
9b815c7f3Sopenharmony_ci**
10b815c7f3Sopenharmony_ci** This program is distributed in the hope that it will be useful,
11b815c7f3Sopenharmony_ci** but WITHOUT ANY WARRANTY ; without even the implied warranty of
12b815c7f3Sopenharmony_ci** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13b815c7f3Sopenharmony_ci** GNU Lesser General Public License for more details.
14b815c7f3Sopenharmony_ci**
15b815c7f3Sopenharmony_ci** You should have received a copy of the GNU Lesser General Public License
16b815c7f3Sopenharmony_ci** along with this program ; if not, write to the Free Software
17b815c7f3Sopenharmony_ci** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18b815c7f3Sopenharmony_ci*/
19b815c7f3Sopenharmony_ci
20b815c7f3Sopenharmony_ci#include	"sfconfig.h"
21b815c7f3Sopenharmony_ci#include	"sndfile.h"
22b815c7f3Sopenharmony_ci#include	"common.h"
23b815c7f3Sopenharmony_ci#include	"mpeg.h"
24b815c7f3Sopenharmony_ci
25b815c7f3Sopenharmony_ci
26b815c7f3Sopenharmony_ci#if HAVE_MPEG
27b815c7f3Sopenharmony_ci
28b815c7f3Sopenharmony_ci#include <lame/lame.h>
29b815c7f3Sopenharmony_ci
30b815c7f3Sopenharmony_ci/*
31b815c7f3Sopenharmony_ci * RANT RANT RANT
32b815c7f3Sopenharmony_ci *
33b815c7f3Sopenharmony_ci * Lame has 11 functions for inputing sample data of various types and
34b815c7f3Sopenharmony_ci * configurations, but due to bad definitions, or missing combinations, they
35b815c7f3Sopenharmony_ci * aren't really of much help to us.
36b815c7f3Sopenharmony_ci *
37b815c7f3Sopenharmony_ci */
38b815c7f3Sopenharmony_ci
39b815c7f3Sopenharmony_citypedef struct
40b815c7f3Sopenharmony_ci{	lame_t lamef ;
41b815c7f3Sopenharmony_ci	unsigned char *block ;
42b815c7f3Sopenharmony_ci	size_t block_len ;
43b815c7f3Sopenharmony_ci	int frame_samples ;
44b815c7f3Sopenharmony_ci	double compression ;
45b815c7f3Sopenharmony_ci	int initialized ;
46b815c7f3Sopenharmony_ci} MPEG_L3_ENC_PRIVATE ;
47b815c7f3Sopenharmony_ci
48b815c7f3Sopenharmony_ci
49b815c7f3Sopenharmony_ci/*-----------------------------------------------------------------------------------------------
50b815c7f3Sopenharmony_ci** Private function prototypes.
51b815c7f3Sopenharmony_ci*/
52b815c7f3Sopenharmony_ci
53b815c7f3Sopenharmony_cistatic int mpeg_l3_encoder_close (SF_PRIVATE *psf) ;
54b815c7f3Sopenharmony_cistatic int mpeg_l3_encoder_construct (SF_PRIVATE *psf) ;
55b815c7f3Sopenharmony_cistatic int mpeg_l3_encoder_byterate (SF_PRIVATE *psf) ;
56b815c7f3Sopenharmony_ci
57b815c7f3Sopenharmony_cistatic sf_count_t mpeg_l3_encode_write_short_stereo (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
58b815c7f3Sopenharmony_cistatic sf_count_t mpeg_l3_encode_write_int_stereo (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
59b815c7f3Sopenharmony_cistatic sf_count_t mpeg_l3_encode_write_float_stereo (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
60b815c7f3Sopenharmony_cistatic sf_count_t mpeg_l3_encode_write_double_stereo (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
61b815c7f3Sopenharmony_cistatic sf_count_t mpeg_l3_encode_write_short_mono (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
62b815c7f3Sopenharmony_cistatic sf_count_t mpeg_l3_encode_write_int_mono (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
63b815c7f3Sopenharmony_cistatic sf_count_t mpeg_l3_encode_write_float_mono (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
64b815c7f3Sopenharmony_cistatic sf_count_t mpeg_l3_encode_write_double_mono (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
65b815c7f3Sopenharmony_ci
66b815c7f3Sopenharmony_ci/*-----------------------------------------------------------------------------------------------
67b815c7f3Sopenharmony_ci** Exported functions.
68b815c7f3Sopenharmony_ci*/
69b815c7f3Sopenharmony_ci
70b815c7f3Sopenharmony_ciint
71b815c7f3Sopenharmony_cimpeg_l3_encoder_init (SF_PRIVATE *psf, int info_tag)
72b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE* pmpeg = NULL ;
73b815c7f3Sopenharmony_ci
74b815c7f3Sopenharmony_ci	if (psf->file.mode == SFM_RDWR)
75b815c7f3Sopenharmony_ci		return SFE_BAD_MODE_RW ;
76b815c7f3Sopenharmony_ci
77b815c7f3Sopenharmony_ci	if (psf->file.mode != SFM_WRITE)
78b815c7f3Sopenharmony_ci		return SFE_INTERNAL ;
79b815c7f3Sopenharmony_ci
80b815c7f3Sopenharmony_ci	psf->codec_data = pmpeg = calloc (1, sizeof (MPEG_L3_ENC_PRIVATE)) ;
81b815c7f3Sopenharmony_ci	if (!pmpeg)
82b815c7f3Sopenharmony_ci		return SFE_MALLOC_FAILED ;
83b815c7f3Sopenharmony_ci
84b815c7f3Sopenharmony_ci	if (psf->sf.channels < 1 || psf->sf.channels > 2)
85b815c7f3Sopenharmony_ci		return SFE_BAD_OPEN_FORMAT ;
86b815c7f3Sopenharmony_ci
87b815c7f3Sopenharmony_ci	if (! (pmpeg->lamef = lame_init ()))
88b815c7f3Sopenharmony_ci		return SFE_MALLOC_FAILED ;
89b815c7f3Sopenharmony_ci
90b815c7f3Sopenharmony_ci	pmpeg->compression = -1.0 ; /* Unset */
91b815c7f3Sopenharmony_ci
92b815c7f3Sopenharmony_ci	lame_set_in_samplerate (pmpeg->lamef, psf->sf.samplerate) ;
93b815c7f3Sopenharmony_ci	lame_set_num_channels (pmpeg->lamef, psf->sf.channels) ;
94b815c7f3Sopenharmony_ci	if (lame_set_out_samplerate (pmpeg->lamef, psf->sf.samplerate) < 0)
95b815c7f3Sopenharmony_ci		return SFE_MPEG_BAD_SAMPLERATE ;
96b815c7f3Sopenharmony_ci
97b815c7f3Sopenharmony_ci	lame_set_write_id3tag_automatic (pmpeg->lamef, 0) ;
98b815c7f3Sopenharmony_ci
99b815c7f3Sopenharmony_ci	if (!info_tag || psf->is_pipe)
100b815c7f3Sopenharmony_ci	{	/* Can't seek back, so force disable Xing/Lame/Info header. */
101b815c7f3Sopenharmony_ci		lame_set_bWriteVbrTag (pmpeg->lamef, 0) ;
102b815c7f3Sopenharmony_ci		} ;
103b815c7f3Sopenharmony_ci
104b815c7f3Sopenharmony_ci	if (psf->sf.channels == 2)
105b815c7f3Sopenharmony_ci	{	psf->write_short	= mpeg_l3_encode_write_short_stereo ;
106b815c7f3Sopenharmony_ci		psf->write_int		= mpeg_l3_encode_write_int_stereo ;
107b815c7f3Sopenharmony_ci		psf->write_float	= mpeg_l3_encode_write_float_stereo ;
108b815c7f3Sopenharmony_ci		psf->write_double	= mpeg_l3_encode_write_double_stereo ;
109b815c7f3Sopenharmony_ci		}
110b815c7f3Sopenharmony_ci	else
111b815c7f3Sopenharmony_ci	{	psf->write_short	= mpeg_l3_encode_write_short_mono ;
112b815c7f3Sopenharmony_ci		psf->write_int		= mpeg_l3_encode_write_int_mono ;
113b815c7f3Sopenharmony_ci		psf->write_float	= mpeg_l3_encode_write_float_mono ;
114b815c7f3Sopenharmony_ci		psf->write_double	= mpeg_l3_encode_write_double_mono ;
115b815c7f3Sopenharmony_ci		}
116b815c7f3Sopenharmony_ci
117b815c7f3Sopenharmony_ci	psf->sf.seekable	= 0 ;
118b815c7f3Sopenharmony_ci	psf->codec_close	= mpeg_l3_encoder_close ;
119b815c7f3Sopenharmony_ci	psf->byterate		= mpeg_l3_encoder_byterate ;
120b815c7f3Sopenharmony_ci	psf->datalength		= 0 ;
121b815c7f3Sopenharmony_ci
122b815c7f3Sopenharmony_ci	return 0 ;
123b815c7f3Sopenharmony_ci} /* mpeg_l3_encoder_init */
124b815c7f3Sopenharmony_ci
125b815c7f3Sopenharmony_ciint
126b815c7f3Sopenharmony_cimpeg_l3_encoder_write_id3tag (SF_PRIVATE *psf)
127b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
128b815c7f3Sopenharmony_ci	unsigned char *id3v2_buffer ;
129b815c7f3Sopenharmony_ci	int i, id3v2_size ;
130b815c7f3Sopenharmony_ci
131b815c7f3Sopenharmony_ci	if (psf->have_written)
132b815c7f3Sopenharmony_ci		return 0 ;
133b815c7f3Sopenharmony_ci
134b815c7f3Sopenharmony_ci	if ((i = mpeg_l3_encoder_construct (psf)))
135b815c7f3Sopenharmony_ci		return i ;
136b815c7f3Sopenharmony_ci
137b815c7f3Sopenharmony_ci	if (psf_fseek (psf, 0, SEEK_SET) != 0)
138b815c7f3Sopenharmony_ci		return SFE_NOT_SEEKABLE ;
139b815c7f3Sopenharmony_ci
140b815c7f3Sopenharmony_ci	/* Safe to call multiple times. */
141b815c7f3Sopenharmony_ci	id3tag_init (pmpeg->lamef) ;
142b815c7f3Sopenharmony_ci
143b815c7f3Sopenharmony_ci	for (i = 0 ; i < SF_MAX_STRINGS ; i++)
144b815c7f3Sopenharmony_ci	{	switch (psf->strings.data [i].type)
145b815c7f3Sopenharmony_ci		{	case SF_STR_TITLE :
146b815c7f3Sopenharmony_ci				id3tag_set_title (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
147b815c7f3Sopenharmony_ci				break ;
148b815c7f3Sopenharmony_ci
149b815c7f3Sopenharmony_ci			case SF_STR_ARTIST :
150b815c7f3Sopenharmony_ci				id3tag_set_artist (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
151b815c7f3Sopenharmony_ci				break ;
152b815c7f3Sopenharmony_ci
153b815c7f3Sopenharmony_ci			case SF_STR_ALBUM :
154b815c7f3Sopenharmony_ci				id3tag_set_album (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
155b815c7f3Sopenharmony_ci				break ;
156b815c7f3Sopenharmony_ci
157b815c7f3Sopenharmony_ci			case SF_STR_DATE :
158b815c7f3Sopenharmony_ci				id3tag_set_year (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
159b815c7f3Sopenharmony_ci				break ;
160b815c7f3Sopenharmony_ci
161b815c7f3Sopenharmony_ci			case SF_STR_COMMENT :
162b815c7f3Sopenharmony_ci				id3tag_set_comment (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
163b815c7f3Sopenharmony_ci				break ;
164b815c7f3Sopenharmony_ci
165b815c7f3Sopenharmony_ci			case SF_STR_GENRE :
166b815c7f3Sopenharmony_ci				id3tag_set_genre (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
167b815c7f3Sopenharmony_ci				break ;
168b815c7f3Sopenharmony_ci
169b815c7f3Sopenharmony_ci			case SF_STR_TRACKNUMBER :
170b815c7f3Sopenharmony_ci				id3tag_set_track (pmpeg->lamef, psf->strings.storage + psf->strings.data [i].offset) ;
171b815c7f3Sopenharmony_ci				break ;
172b815c7f3Sopenharmony_ci
173b815c7f3Sopenharmony_ci			default:
174b815c7f3Sopenharmony_ci				break ;
175b815c7f3Sopenharmony_ci			} ;
176b815c7f3Sopenharmony_ci		} ;
177b815c7f3Sopenharmony_ci
178b815c7f3Sopenharmony_ci	/* The header in this case is the ID3v2 tag header. */
179b815c7f3Sopenharmony_ci	id3v2_size = lame_get_id3v2_tag (pmpeg->lamef, 0, 0) ;
180b815c7f3Sopenharmony_ci	if (id3v2_size > 0)
181b815c7f3Sopenharmony_ci	{	psf_log_printf (psf, "Writing ID3v2 header.\n") ;
182b815c7f3Sopenharmony_ci		if (! (id3v2_buffer = malloc (id3v2_size)))
183b815c7f3Sopenharmony_ci			return SFE_MALLOC_FAILED ;
184b815c7f3Sopenharmony_ci		lame_get_id3v2_tag (pmpeg->lamef, id3v2_buffer, id3v2_size) ;
185b815c7f3Sopenharmony_ci		psf_fwrite (id3v2_buffer, 1, id3v2_size, psf) ;
186b815c7f3Sopenharmony_ci		psf->dataoffset = id3v2_size ;
187b815c7f3Sopenharmony_ci		free (id3v2_buffer) ;
188b815c7f3Sopenharmony_ci		} ;
189b815c7f3Sopenharmony_ci
190b815c7f3Sopenharmony_ci	return 0 ;
191b815c7f3Sopenharmony_ci}
192b815c7f3Sopenharmony_ci
193b815c7f3Sopenharmony_ciint
194b815c7f3Sopenharmony_cimpeg_l3_encoder_set_quality (SF_PRIVATE *psf, double compression)
195b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
196b815c7f3Sopenharmony_ci	int bitrate_mode ;
197b815c7f3Sopenharmony_ci	int bitrate ;
198b815c7f3Sopenharmony_ci	int ret ;
199b815c7f3Sopenharmony_ci
200b815c7f3Sopenharmony_ci	if (compression < 0.0 || compression > 1.0)
201b815c7f3Sopenharmony_ci		return SF_FALSE ;
202b815c7f3Sopenharmony_ci
203b815c7f3Sopenharmony_ci	/*
204b815c7f3Sopenharmony_ci	** Save the compression setting, as we may have to re-interpret it if
205b815c7f3Sopenharmony_ci	** the bitrate mode changes.
206b815c7f3Sopenharmony_ci	*/
207b815c7f3Sopenharmony_ci	pmpeg->compression = compression ;
208b815c7f3Sopenharmony_ci
209b815c7f3Sopenharmony_ci	bitrate_mode = mpeg_l3_encoder_get_bitrate_mode (psf) ;
210b815c7f3Sopenharmony_ci	if (bitrate_mode == SF_BITRATE_MODE_VARIABLE)
211b815c7f3Sopenharmony_ci	{	ret = lame_set_VBR_quality (pmpeg->lamef, compression * 10.0) ;
212b815c7f3Sopenharmony_ci		}
213b815c7f3Sopenharmony_ci	else
214b815c7f3Sopenharmony_ci	{	/* Choose a bitrate. */
215b815c7f3Sopenharmony_ci		if (psf->sf.samplerate >= 32000)
216b815c7f3Sopenharmony_ci		{	/* MPEG-1.0, bitrates are [32,320] kbps */
217b815c7f3Sopenharmony_ci			bitrate = (320.0 - (compression * (320.0 - 32.0))) ;
218b815c7f3Sopenharmony_ci			}
219b815c7f3Sopenharmony_ci		else if (psf->sf.samplerate >= 16000)
220b815c7f3Sopenharmony_ci		{	/* MPEG-2.0, bitrates are [8,160] */
221b815c7f3Sopenharmony_ci			bitrate = (160.0 - (compression * (160.0 - 8.0))) ;
222b815c7f3Sopenharmony_ci			}
223b815c7f3Sopenharmony_ci		else
224b815c7f3Sopenharmony_ci		{	/* MPEG-2.5, bitrates are [8,64] */
225b815c7f3Sopenharmony_ci			bitrate = (64.0 - (compression * (64.0 - 8.0))) ;
226b815c7f3Sopenharmony_ci			}
227b815c7f3Sopenharmony_ci
228b815c7f3Sopenharmony_ci		if (bitrate_mode == SF_BITRATE_MODE_AVERAGE)
229b815c7f3Sopenharmony_ci			ret = lame_set_VBR_mean_bitrate_kbps (pmpeg->lamef, bitrate) ;
230b815c7f3Sopenharmony_ci		else
231b815c7f3Sopenharmony_ci			ret = lame_set_brate (pmpeg->lamef, bitrate) ;
232b815c7f3Sopenharmony_ci		} ;
233b815c7f3Sopenharmony_ci
234b815c7f3Sopenharmony_ci	if (ret == LAME_OKAY)
235b815c7f3Sopenharmony_ci		return SF_TRUE ;
236b815c7f3Sopenharmony_ci
237b815c7f3Sopenharmony_ci	psf_log_printf (psf, "Failed to set lame encoder quality.\n") ;
238b815c7f3Sopenharmony_ci	return SF_FALSE ;
239b815c7f3Sopenharmony_ci} /* mpeg_l3_encoder_set_quality */
240b815c7f3Sopenharmony_ci
241b815c7f3Sopenharmony_ciint
242b815c7f3Sopenharmony_cimpeg_l3_encoder_set_bitrate_mode (SF_PRIVATE *psf, int mode)
243b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
244b815c7f3Sopenharmony_ci	enum vbr_mode_e vbr_mode ;
245b815c7f3Sopenharmony_ci
246b815c7f3Sopenharmony_ci	if (pmpeg->initialized)
247b815c7f3Sopenharmony_ci	{	psf->error = SFE_CMD_HAS_DATA ;
248b815c7f3Sopenharmony_ci		return SF_FALSE ;
249b815c7f3Sopenharmony_ci		} ;
250b815c7f3Sopenharmony_ci
251b815c7f3Sopenharmony_ci	switch (mode)
252b815c7f3Sopenharmony_ci	{	case SF_BITRATE_MODE_CONSTANT :	vbr_mode = vbr_off ; break ;
253b815c7f3Sopenharmony_ci		case SF_BITRATE_MODE_AVERAGE : vbr_mode = vbr_abr ; break ;
254b815c7f3Sopenharmony_ci		case SF_BITRATE_MODE_VARIABLE : vbr_mode = vbr_default ; break ;
255b815c7f3Sopenharmony_ci		default :
256b815c7f3Sopenharmony_ci			psf->error = SFE_BAD_COMMAND_PARAM ;
257b815c7f3Sopenharmony_ci			return SF_FALSE ;
258b815c7f3Sopenharmony_ci		} ;
259b815c7f3Sopenharmony_ci
260b815c7f3Sopenharmony_ci	if (lame_set_VBR (pmpeg->lamef, vbr_mode) == LAME_OKAY)
261b815c7f3Sopenharmony_ci	{	/* Re-evaluate the compression setting. */
262b815c7f3Sopenharmony_ci		return mpeg_l3_encoder_set_quality (psf, pmpeg->compression) ;
263b815c7f3Sopenharmony_ci		} ;
264b815c7f3Sopenharmony_ci
265b815c7f3Sopenharmony_ci	psf_log_printf (psf, "Failed to set LAME vbr mode to %d.\n", vbr_mode) ;
266b815c7f3Sopenharmony_ci	return SF_FALSE ;
267b815c7f3Sopenharmony_ci} /* mpeg_l3_encoder_set_bitrate_mode */
268b815c7f3Sopenharmony_ci
269b815c7f3Sopenharmony_ciint
270b815c7f3Sopenharmony_cimpeg_l3_encoder_get_bitrate_mode (SF_PRIVATE *psf)
271b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
272b815c7f3Sopenharmony_ci	enum vbr_mode_e vbr_mode ;
273b815c7f3Sopenharmony_ci
274b815c7f3Sopenharmony_ci	vbr_mode = lame_get_VBR (pmpeg->lamef) ;
275b815c7f3Sopenharmony_ci
276b815c7f3Sopenharmony_ci	if (vbr_mode == vbr_off)
277b815c7f3Sopenharmony_ci		return SF_BITRATE_MODE_CONSTANT ;
278b815c7f3Sopenharmony_ci	if (vbr_mode == vbr_abr)
279b815c7f3Sopenharmony_ci		return SF_BITRATE_MODE_AVERAGE ;
280b815c7f3Sopenharmony_ci	if (vbr_mode == vbr_default || vbr_mode < vbr_max_indicator)
281b815c7f3Sopenharmony_ci		return SF_BITRATE_MODE_VARIABLE ;
282b815c7f3Sopenharmony_ci
283b815c7f3Sopenharmony_ci	/* Something is wrong. */
284b815c7f3Sopenharmony_ci	psf->error = SFE_INTERNAL ;
285b815c7f3Sopenharmony_ci	return -1 ;
286b815c7f3Sopenharmony_ci} /* mpeg_l3_encoder_get_bitrate_mode */
287b815c7f3Sopenharmony_ci
288b815c7f3Sopenharmony_ci
289b815c7f3Sopenharmony_ci/*-----------------------------------------------------------------------------------------------
290b815c7f3Sopenharmony_ci** Private functions.
291b815c7f3Sopenharmony_ci*/
292b815c7f3Sopenharmony_ci
293b815c7f3Sopenharmony_cistatic int
294b815c7f3Sopenharmony_cimpeg_l3_encoder_close (SF_PRIVATE *psf)
295b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE* pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
296b815c7f3Sopenharmony_ci	int ret, len ;
297b815c7f3Sopenharmony_ci	sf_count_t pos ;
298b815c7f3Sopenharmony_ci	unsigned char *buffer ;
299b815c7f3Sopenharmony_ci
300b815c7f3Sopenharmony_ci	/* Magic number 7200 comes from a comment in lame.h */
301b815c7f3Sopenharmony_ci	len = 7200 ;
302b815c7f3Sopenharmony_ci	if (! (buffer = malloc (len)))
303b815c7f3Sopenharmony_ci		return SFE_MALLOC_FAILED ;
304b815c7f3Sopenharmony_ci	ret = lame_encode_flush (pmpeg->lamef, buffer, len) ;
305b815c7f3Sopenharmony_ci	if (ret > 0)
306b815c7f3Sopenharmony_ci		psf_fwrite (buffer, 1, ret, psf) ;
307b815c7f3Sopenharmony_ci
308b815c7f3Sopenharmony_ci	/*
309b815c7f3Sopenharmony_ci	** Write an IDv1 trailer. The whole tag structure is always 128 bytes, so is
310b815c7f3Sopenharmony_ci	** guaranteed to fit in the buffer allocated above.
311b815c7f3Sopenharmony_ci	*/
312b815c7f3Sopenharmony_ci	ret = lame_get_id3v1_tag (pmpeg->lamef, buffer, len) ;
313b815c7f3Sopenharmony_ci	if (ret > 0)
314b815c7f3Sopenharmony_ci	{	psf_log_printf (psf, "  Writing ID3v1 trailer.\n") ;
315b815c7f3Sopenharmony_ci		psf_fwrite (buffer, 1, ret, psf) ;
316b815c7f3Sopenharmony_ci		} ;
317b815c7f3Sopenharmony_ci
318b815c7f3Sopenharmony_ci	/*
319b815c7f3Sopenharmony_ci	** If possible, seek back and write the LAME/XING/Info headers. This
320b815c7f3Sopenharmony_ci	** contains information about the whole file and a seek table, and can
321b815c7f3Sopenharmony_ci	** only be written after encoding.
322b815c7f3Sopenharmony_ci	**
323b815c7f3Sopenharmony_ci	** If enabled, Lame wrote an empty header at the beginning of the data
324b815c7f3Sopenharmony_ci	** that we now fill in.
325b815c7f3Sopenharmony_ci	*/
326b815c7f3Sopenharmony_ci	ret = lame_get_lametag_frame (pmpeg->lamef, 0, 0) ;
327b815c7f3Sopenharmony_ci	if (ret > 0)
328b815c7f3Sopenharmony_ci	{	if (ret > len)
329b815c7f3Sopenharmony_ci		{	len = ret ;
330b815c7f3Sopenharmony_ci			free (buffer) ;
331b815c7f3Sopenharmony_ci			if (! (buffer = malloc (len)))
332b815c7f3Sopenharmony_ci				return SFE_MALLOC_FAILED ;
333b815c7f3Sopenharmony_ci			} ;
334b815c7f3Sopenharmony_ci		psf_log_printf (psf, "  Writing LAME info header at offset %d, %d bytes.\n",
335b815c7f3Sopenharmony_ci			psf->dataoffset, len) ;
336b815c7f3Sopenharmony_ci		lame_get_lametag_frame (pmpeg->lamef, buffer, len) ;
337b815c7f3Sopenharmony_ci		pos = psf_ftell (psf) ;
338b815c7f3Sopenharmony_ci		if (psf_fseek (psf, psf->dataoffset, SEEK_SET) == psf->dataoffset)
339b815c7f3Sopenharmony_ci		{	psf_fwrite (buffer, 1, ret, psf) ;
340b815c7f3Sopenharmony_ci			psf_fseek (psf, pos, SEEK_SET) ;
341b815c7f3Sopenharmony_ci			} ;
342b815c7f3Sopenharmony_ci		} ;
343b815c7f3Sopenharmony_ci	free (buffer) ;
344b815c7f3Sopenharmony_ci
345b815c7f3Sopenharmony_ci	free (pmpeg->block) ;
346b815c7f3Sopenharmony_ci	pmpeg->block = NULL ;
347b815c7f3Sopenharmony_ci
348b815c7f3Sopenharmony_ci	if (pmpeg->lamef)
349b815c7f3Sopenharmony_ci	{	lame_close (pmpeg->lamef) ;
350b815c7f3Sopenharmony_ci		pmpeg->lamef = NULL ;
351b815c7f3Sopenharmony_ci		} ;
352b815c7f3Sopenharmony_ci
353b815c7f3Sopenharmony_ci	return 0 ;
354b815c7f3Sopenharmony_ci} /* mpeg_l3_encoder_close */
355b815c7f3Sopenharmony_ci
356b815c7f3Sopenharmony_cistatic void
357b815c7f3Sopenharmony_cimpeg_l3_encoder_log_config (SF_PRIVATE *psf, lame_t lamef)
358b815c7f3Sopenharmony_ci{	const char *version ;
359b815c7f3Sopenharmony_ci	const char *chn_mode ;
360b815c7f3Sopenharmony_ci
361b815c7f3Sopenharmony_ci	switch (lame_get_version (lamef))
362b815c7f3Sopenharmony_ci	{	case 0 : version = "2" ; break ;
363b815c7f3Sopenharmony_ci		case 1 : version = "1" ; break ;
364b815c7f3Sopenharmony_ci		case 2 : version = "2.5" ; break ;
365b815c7f3Sopenharmony_ci		default : version = "unknown!?" ; break ;
366b815c7f3Sopenharmony_ci		} ;
367b815c7f3Sopenharmony_ci	switch (lame_get_mode (lamef))
368b815c7f3Sopenharmony_ci	{	case STEREO : chn_mode = "stereo" ; break ;
369b815c7f3Sopenharmony_ci		case JOINT_STEREO : chn_mode = "joint-stereo" ; break ;
370b815c7f3Sopenharmony_ci		case MONO : chn_mode = "mono" ; break ;
371b815c7f3Sopenharmony_ci		default : chn_mode = "unknown!?" ; break ;
372b815c7f3Sopenharmony_ci		} ;
373b815c7f3Sopenharmony_ci	psf_log_printf (psf, "  MPEG Version      : %s\n", version) ;
374b815c7f3Sopenharmony_ci	psf_log_printf (psf, "  Block samples     : %d\n", lame_get_framesize (lamef)) ;
375b815c7f3Sopenharmony_ci	psf_log_printf (psf, "  Channel mode      : %s\n", chn_mode) ;
376b815c7f3Sopenharmony_ci	psf_log_printf (psf, "  Samplerate        : %d\n", lame_get_out_samplerate (lamef)) ;
377b815c7f3Sopenharmony_ci	psf_log_printf (psf, "  Encoder mode      : ") ;
378b815c7f3Sopenharmony_ci	switch (lame_get_VBR (lamef))
379b815c7f3Sopenharmony_ci	{	case vbr_off :
380b815c7f3Sopenharmony_ci			psf_log_printf (psf, "CBR\n") ;
381b815c7f3Sopenharmony_ci			psf_log_printf (psf, "  Bitrate           : %d kbps\n", lame_get_brate (lamef)) ;
382b815c7f3Sopenharmony_ci			break ;
383b815c7f3Sopenharmony_ci		case vbr_abr :
384b815c7f3Sopenharmony_ci			psf_log_printf (psf, "ABR\n") ;
385b815c7f3Sopenharmony_ci			psf_log_printf (psf, "  Mean Bitrate      : %d kbps\n", lame_get_VBR_mean_bitrate_kbps (lamef)) ;
386b815c7f3Sopenharmony_ci			break ;
387b815c7f3Sopenharmony_ci
388b815c7f3Sopenharmony_ci		case vbr_mt :
389b815c7f3Sopenharmony_ci		case vbr_default :
390b815c7f3Sopenharmony_ci			psf_log_printf (psf, "VBR\n") ;
391b815c7f3Sopenharmony_ci			psf_log_printf (psf, "  Quality           : %d\n", lame_get_VBR_q (lamef)) ;
392b815c7f3Sopenharmony_ci			break ;
393b815c7f3Sopenharmony_ci
394b815c7f3Sopenharmony_ci		default:
395b815c7f3Sopenharmony_ci			psf_log_printf (psf, "Unknown!? (%d)\n", lame_get_VBR (lamef)) ;
396b815c7f3Sopenharmony_ci			break ;
397b815c7f3Sopenharmony_ci		} ;
398b815c7f3Sopenharmony_ci
399b815c7f3Sopenharmony_ci	psf_log_printf (psf, "  Encoder delay     : %d\n", lame_get_encoder_delay (lamef)) ;
400b815c7f3Sopenharmony_ci	psf_log_printf (psf, "  Write INFO header : %d\n", lame_get_bWriteVbrTag (lamef)) ;
401b815c7f3Sopenharmony_ci} /* mpeg_l3_encoder_log_config */
402b815c7f3Sopenharmony_ci
403b815c7f3Sopenharmony_cistatic int
404b815c7f3Sopenharmony_cimpeg_l3_encoder_construct (SF_PRIVATE *psf)
405b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
406b815c7f3Sopenharmony_ci	int frame_samples_per_channel ;
407b815c7f3Sopenharmony_ci
408b815c7f3Sopenharmony_ci	if (pmpeg->initialized == SF_FALSE)
409b815c7f3Sopenharmony_ci	{	if (lame_init_params (pmpeg->lamef) < 0)
410b815c7f3Sopenharmony_ci		{	psf_log_printf (psf, "Failed to initialize lame encoder!\n") ;
411b815c7f3Sopenharmony_ci			return SFE_INTERNAL ;
412b815c7f3Sopenharmony_ci			} ;
413b815c7f3Sopenharmony_ci
414b815c7f3Sopenharmony_ci		psf_log_printf (psf, "Initialized LAME encoder.\n") ;
415b815c7f3Sopenharmony_ci		mpeg_l3_encoder_log_config (psf, pmpeg->lamef) ;
416b815c7f3Sopenharmony_ci
417b815c7f3Sopenharmony_ci		frame_samples_per_channel = lame_get_framesize (pmpeg->lamef) ;
418b815c7f3Sopenharmony_ci
419b815c7f3Sopenharmony_ci		/*
420b815c7f3Sopenharmony_ci		 * Suggested output buffer size in bytes from lame.h comment is
421b815c7f3Sopenharmony_ci		 * 1.25 * samples + 7200
422b815c7f3Sopenharmony_ci		 */
423b815c7f3Sopenharmony_ci		pmpeg->block_len = (frame_samples_per_channel * 4) / 3 + 7200 ;
424b815c7f3Sopenharmony_ci		pmpeg->frame_samples = frame_samples_per_channel * psf->sf.channels ;
425b815c7f3Sopenharmony_ci
426b815c7f3Sopenharmony_ci		pmpeg->block = malloc (pmpeg->block_len) ;
427b815c7f3Sopenharmony_ci		if (!pmpeg->block)
428b815c7f3Sopenharmony_ci			return SFE_MALLOC_FAILED ;
429b815c7f3Sopenharmony_ci
430b815c7f3Sopenharmony_ci		pmpeg->initialized = SF_TRUE ;
431b815c7f3Sopenharmony_ci		} ;
432b815c7f3Sopenharmony_ci
433b815c7f3Sopenharmony_ci	return 0 ;
434b815c7f3Sopenharmony_ci} /* mpeg_l3_encoder_construct */
435b815c7f3Sopenharmony_ci
436b815c7f3Sopenharmony_cistatic int
437b815c7f3Sopenharmony_cimpeg_l3_encoder_byterate (SF_PRIVATE *psf)
438b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE *) psf->codec_data ;
439b815c7f3Sopenharmony_ci	int bitrate_mode ;
440b815c7f3Sopenharmony_ci	int byterate ;
441b815c7f3Sopenharmony_ci	float calculated_byterate ;
442b815c7f3Sopenharmony_ci
443b815c7f3Sopenharmony_ci	bitrate_mode = mpeg_l3_encoder_get_bitrate_mode (psf) ;
444b815c7f3Sopenharmony_ci	byterate = (lame_get_brate (pmpeg->lamef) + 7) / 8 ;
445b815c7f3Sopenharmony_ci
446b815c7f3Sopenharmony_ci	if (bitrate_mode == SF_BITRATE_MODE_VARIABLE)
447b815c7f3Sopenharmony_ci	{	/*
448b815c7f3Sopenharmony_ci		** For VBR, lame_get_brate returns the minimum bitrate, so calculate the
449b815c7f3Sopenharmony_ci		** average byterate so far.
450b815c7f3Sopenharmony_ci		*/
451b815c7f3Sopenharmony_ci		calculated_byterate = psf_ftell (psf) - psf->dataoffset ;
452b815c7f3Sopenharmony_ci		calculated_byterate /= (float) psf->write_current ;
453b815c7f3Sopenharmony_ci		calculated_byterate *= (float) psf->sf.samplerate ;
454b815c7f3Sopenharmony_ci
455b815c7f3Sopenharmony_ci		return SF_MIN (byterate, (int) calculated_byterate) ;
456b815c7f3Sopenharmony_ci	}
457b815c7f3Sopenharmony_ci
458b815c7f3Sopenharmony_ci	return byterate ;
459b815c7f3Sopenharmony_ci} /* mpeg_l3_encoder_byterate */
460b815c7f3Sopenharmony_ci
461b815c7f3Sopenharmony_cistatic sf_count_t
462b815c7f3Sopenharmony_cimpeg_l3_encode_write_short_mono (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
463b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
464b815c7f3Sopenharmony_ci	sf_count_t total = 0 ;
465b815c7f3Sopenharmony_ci	int nbytes, writecount, writen ;
466b815c7f3Sopenharmony_ci
467b815c7f3Sopenharmony_ci	if ((psf->error = mpeg_l3_encoder_construct (psf)))
468b815c7f3Sopenharmony_ci		return 0 ;
469b815c7f3Sopenharmony_ci
470b815c7f3Sopenharmony_ci	while (len)
471b815c7f3Sopenharmony_ci	{	writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ;
472b815c7f3Sopenharmony_ci
473b815c7f3Sopenharmony_ci		nbytes = lame_encode_buffer (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
474b815c7f3Sopenharmony_ci		if (nbytes < 0)
475b815c7f3Sopenharmony_ci		{	psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
476b815c7f3Sopenharmony_ci			break ;
477b815c7f3Sopenharmony_ci			} ;
478b815c7f3Sopenharmony_ci
479b815c7f3Sopenharmony_ci		if (nbytes)
480b815c7f3Sopenharmony_ci		{	writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
481b815c7f3Sopenharmony_ci			if (writen != nbytes)
482b815c7f3Sopenharmony_ci			{	psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
483b815c7f3Sopenharmony_ci				} ;
484b815c7f3Sopenharmony_ci			} ;
485b815c7f3Sopenharmony_ci
486b815c7f3Sopenharmony_ci		total += writecount ;
487b815c7f3Sopenharmony_ci		len -= writecount ;
488b815c7f3Sopenharmony_ci		} ;
489b815c7f3Sopenharmony_ci
490b815c7f3Sopenharmony_ci	return total ;
491b815c7f3Sopenharmony_ci}
492b815c7f3Sopenharmony_ci
493b815c7f3Sopenharmony_ci
494b815c7f3Sopenharmony_cistatic sf_count_t
495b815c7f3Sopenharmony_cimpeg_l3_encode_write_short_stereo (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
496b815c7f3Sopenharmony_ci{	BUF_UNION ubuf ;
497b815c7f3Sopenharmony_ci	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
498b815c7f3Sopenharmony_ci	sf_count_t total = 0 ;
499b815c7f3Sopenharmony_ci	int nbytes, writecount, writen ;
500b815c7f3Sopenharmony_ci
501b815c7f3Sopenharmony_ci	if ((psf->error = mpeg_l3_encoder_construct (psf)))
502b815c7f3Sopenharmony_ci		return 0 ;
503b815c7f3Sopenharmony_ci
504b815c7f3Sopenharmony_ci	const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.sbuf), pmpeg->frame_samples) ;
505b815c7f3Sopenharmony_ci	while (len)
506b815c7f3Sopenharmony_ci	{	writecount = SF_MIN (len, max_samples) ;
507b815c7f3Sopenharmony_ci		/*
508b815c7f3Sopenharmony_ci		 * An oversight, but lame_encode_buffer_interleaved() lacks a const.
509b815c7f3Sopenharmony_ci		 * As such, need another memcpy to not cause a warning.
510b815c7f3Sopenharmony_ci		 */
511b815c7f3Sopenharmony_ci		memcpy (ubuf.sbuf, ptr + total, writecount) ;
512b815c7f3Sopenharmony_ci		nbytes = lame_encode_buffer_interleaved (pmpeg->lamef, ubuf.sbuf, writecount / 2, pmpeg->block, pmpeg->block_len) ;
513b815c7f3Sopenharmony_ci		if (nbytes < 0)
514b815c7f3Sopenharmony_ci		{	psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
515b815c7f3Sopenharmony_ci			break ;
516b815c7f3Sopenharmony_ci			} ;
517b815c7f3Sopenharmony_ci
518b815c7f3Sopenharmony_ci		if (nbytes)
519b815c7f3Sopenharmony_ci		{	writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
520b815c7f3Sopenharmony_ci			if (writen != nbytes)
521b815c7f3Sopenharmony_ci			{	psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
522b815c7f3Sopenharmony_ci				} ;
523b815c7f3Sopenharmony_ci			} ;
524b815c7f3Sopenharmony_ci
525b815c7f3Sopenharmony_ci		total += writecount ;
526b815c7f3Sopenharmony_ci		len -= writecount ;
527b815c7f3Sopenharmony_ci		} ;
528b815c7f3Sopenharmony_ci
529b815c7f3Sopenharmony_ci	return total ;
530b815c7f3Sopenharmony_ci}
531b815c7f3Sopenharmony_ci
532b815c7f3Sopenharmony_ci
533b815c7f3Sopenharmony_cistatic sf_count_t
534b815c7f3Sopenharmony_cimpeg_l3_encode_write_int_mono (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
535b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
536b815c7f3Sopenharmony_ci	sf_count_t total = 0 ;
537b815c7f3Sopenharmony_ci	int nbytes, writecount, writen ;
538b815c7f3Sopenharmony_ci
539b815c7f3Sopenharmony_ci	if ((psf->error = mpeg_l3_encoder_construct (psf)))
540b815c7f3Sopenharmony_ci		return 0 ;
541b815c7f3Sopenharmony_ci
542b815c7f3Sopenharmony_ci	while (len)
543b815c7f3Sopenharmony_ci	{	writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ;
544b815c7f3Sopenharmony_ci
545b815c7f3Sopenharmony_ci		nbytes = lame_encode_buffer_int (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
546b815c7f3Sopenharmony_ci		if (nbytes < 0)
547b815c7f3Sopenharmony_ci		{	psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
548b815c7f3Sopenharmony_ci			break ;
549b815c7f3Sopenharmony_ci			} ;
550b815c7f3Sopenharmony_ci
551b815c7f3Sopenharmony_ci		if (nbytes)
552b815c7f3Sopenharmony_ci		{	writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
553b815c7f3Sopenharmony_ci			if (writen != nbytes)
554b815c7f3Sopenharmony_ci			{	psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
555b815c7f3Sopenharmony_ci				} ;
556b815c7f3Sopenharmony_ci			} ;
557b815c7f3Sopenharmony_ci
558b815c7f3Sopenharmony_ci		total += writecount ;
559b815c7f3Sopenharmony_ci		len -= writecount ;
560b815c7f3Sopenharmony_ci		} ;
561b815c7f3Sopenharmony_ci
562b815c7f3Sopenharmony_ci	return total ;
563b815c7f3Sopenharmony_ci}
564b815c7f3Sopenharmony_ci
565b815c7f3Sopenharmony_ci
566b815c7f3Sopenharmony_cistatic sf_count_t
567b815c7f3Sopenharmony_cimpeg_l3_encode_write_int_stereo (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
568b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
569b815c7f3Sopenharmony_ci	sf_count_t total = 0 ;
570b815c7f3Sopenharmony_ci	int nbytes, writecount, writen ;
571b815c7f3Sopenharmony_ci
572b815c7f3Sopenharmony_ci	if ((psf->error = mpeg_l3_encoder_construct (psf)))
573b815c7f3Sopenharmony_ci		return 0 ;
574b815c7f3Sopenharmony_ci
575b815c7f3Sopenharmony_ci	while (len)
576b815c7f3Sopenharmony_ci	{	writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ;
577b815c7f3Sopenharmony_ci
578b815c7f3Sopenharmony_ci		nbytes = lame_encode_buffer_interleaved_int (pmpeg->lamef, ptr + total, writecount / 2, pmpeg->block, pmpeg->block_len) ;
579b815c7f3Sopenharmony_ci		if (nbytes < 0)
580b815c7f3Sopenharmony_ci		{	psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
581b815c7f3Sopenharmony_ci			break ;
582b815c7f3Sopenharmony_ci			} ;
583b815c7f3Sopenharmony_ci
584b815c7f3Sopenharmony_ci		if (nbytes)
585b815c7f3Sopenharmony_ci		{	writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
586b815c7f3Sopenharmony_ci			if (writen != nbytes)
587b815c7f3Sopenharmony_ci			{	psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
588b815c7f3Sopenharmony_ci				} ;
589b815c7f3Sopenharmony_ci			} ;
590b815c7f3Sopenharmony_ci
591b815c7f3Sopenharmony_ci		total += writecount ;
592b815c7f3Sopenharmony_ci		len -= writecount ;
593b815c7f3Sopenharmony_ci		} ;
594b815c7f3Sopenharmony_ci
595b815c7f3Sopenharmony_ci	return total ;
596b815c7f3Sopenharmony_ci}
597b815c7f3Sopenharmony_ci
598b815c7f3Sopenharmony_ci
599b815c7f3Sopenharmony_cistatic sf_count_t
600b815c7f3Sopenharmony_cimpeg_l3_encode_write_float_mono (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
601b815c7f3Sopenharmony_ci{	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
602b815c7f3Sopenharmony_ci	sf_count_t total = 0 ;
603b815c7f3Sopenharmony_ci	int nbytes, writecount, writen ;
604b815c7f3Sopenharmony_ci
605b815c7f3Sopenharmony_ci	if ((psf->error = mpeg_l3_encoder_construct (psf)))
606b815c7f3Sopenharmony_ci		return 0 ;
607b815c7f3Sopenharmony_ci
608b815c7f3Sopenharmony_ci	while (len)
609b815c7f3Sopenharmony_ci	{	writecount = SF_MIN (len, (sf_count_t) pmpeg->frame_samples) ;
610b815c7f3Sopenharmony_ci
611b815c7f3Sopenharmony_ci		if (psf->norm_float)
612b815c7f3Sopenharmony_ci			nbytes = lame_encode_buffer_ieee_float (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
613b815c7f3Sopenharmony_ci		else
614b815c7f3Sopenharmony_ci			nbytes = lame_encode_buffer_float (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
615b815c7f3Sopenharmony_ci		if (nbytes < 0)
616b815c7f3Sopenharmony_ci		{	psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
617b815c7f3Sopenharmony_ci			break ;
618b815c7f3Sopenharmony_ci			} ;
619b815c7f3Sopenharmony_ci
620b815c7f3Sopenharmony_ci		if (nbytes)
621b815c7f3Sopenharmony_ci		{	writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
622b815c7f3Sopenharmony_ci			if (writen != nbytes)
623b815c7f3Sopenharmony_ci			{	psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
624b815c7f3Sopenharmony_ci				} ;
625b815c7f3Sopenharmony_ci			} ;
626b815c7f3Sopenharmony_ci
627b815c7f3Sopenharmony_ci		total += writecount ;
628b815c7f3Sopenharmony_ci		len -= writecount ;
629b815c7f3Sopenharmony_ci		} ;
630b815c7f3Sopenharmony_ci
631b815c7f3Sopenharmony_ci	return total ;
632b815c7f3Sopenharmony_ci}
633b815c7f3Sopenharmony_ci
634b815c7f3Sopenharmony_ci
635b815c7f3Sopenharmony_cistatic inline void
636b815c7f3Sopenharmony_cinormalize_float (float *dest, const float *src, sf_count_t count, float norm_fact)
637b815c7f3Sopenharmony_ci{	while (--count >= 0)
638b815c7f3Sopenharmony_ci	{	dest [count] = src [count] * norm_fact ;
639b815c7f3Sopenharmony_ci		} ;
640b815c7f3Sopenharmony_ci}
641b815c7f3Sopenharmony_ci
642b815c7f3Sopenharmony_ci
643b815c7f3Sopenharmony_cistatic sf_count_t
644b815c7f3Sopenharmony_cimpeg_l3_encode_write_float_stereo (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
645b815c7f3Sopenharmony_ci{	BUF_UNION ubuf ;
646b815c7f3Sopenharmony_ci	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
647b815c7f3Sopenharmony_ci	sf_count_t total = 0 ;
648b815c7f3Sopenharmony_ci	int nbytes, writecount, writen ;
649b815c7f3Sopenharmony_ci
650b815c7f3Sopenharmony_ci	if ((psf->error = mpeg_l3_encoder_construct (psf)))
651b815c7f3Sopenharmony_ci		return 0 ;
652b815c7f3Sopenharmony_ci
653b815c7f3Sopenharmony_ci	const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.fbuf), pmpeg->frame_samples) ;
654b815c7f3Sopenharmony_ci	while (len)
655b815c7f3Sopenharmony_ci	{	writecount = SF_MIN (len, max_samples) ;
656b815c7f3Sopenharmony_ci
657b815c7f3Sopenharmony_ci		if (psf->norm_float)
658b815c7f3Sopenharmony_ci			nbytes = lame_encode_buffer_interleaved_ieee_float (pmpeg->lamef, ptr + total, writecount / 2, pmpeg->block, pmpeg->block_len) ;
659b815c7f3Sopenharmony_ci		else
660b815c7f3Sopenharmony_ci		{	/* Lame lacks a non-normalized interleaved float write. Bummer. */
661b815c7f3Sopenharmony_ci			normalize_float (ubuf.fbuf, ptr + total, writecount, 1.0 / (float) 0x8000) ;
662b815c7f3Sopenharmony_ci			nbytes = lame_encode_buffer_interleaved_ieee_float (pmpeg->lamef, ubuf.fbuf, writecount / 2, pmpeg->block, pmpeg->block_len) ;
663b815c7f3Sopenharmony_ci			}
664b815c7f3Sopenharmony_ci
665b815c7f3Sopenharmony_ci		if (nbytes < 0)
666b815c7f3Sopenharmony_ci		{	psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
667b815c7f3Sopenharmony_ci			break ;
668b815c7f3Sopenharmony_ci			} ;
669b815c7f3Sopenharmony_ci
670b815c7f3Sopenharmony_ci		if (nbytes)
671b815c7f3Sopenharmony_ci		{	writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
672b815c7f3Sopenharmony_ci			if (writen != nbytes)
673b815c7f3Sopenharmony_ci			{	psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
674b815c7f3Sopenharmony_ci				} ;
675b815c7f3Sopenharmony_ci			} ;
676b815c7f3Sopenharmony_ci
677b815c7f3Sopenharmony_ci		total += writecount ;
678b815c7f3Sopenharmony_ci		len -= writecount ;
679b815c7f3Sopenharmony_ci		} ;
680b815c7f3Sopenharmony_ci
681b815c7f3Sopenharmony_ci	return total ;
682b815c7f3Sopenharmony_ci}
683b815c7f3Sopenharmony_ci
684b815c7f3Sopenharmony_ci
685b815c7f3Sopenharmony_cistatic inline void
686b815c7f3Sopenharmony_cinormalize_double (double *dest, const double *src, sf_count_t count, double norm_fact)
687b815c7f3Sopenharmony_ci{	while (--count >= 0)
688b815c7f3Sopenharmony_ci	{	dest [count] = src [count] * norm_fact ;
689b815c7f3Sopenharmony_ci		} ;
690b815c7f3Sopenharmony_ci}
691b815c7f3Sopenharmony_ci
692b815c7f3Sopenharmony_ci
693b815c7f3Sopenharmony_cistatic sf_count_t
694b815c7f3Sopenharmony_cimpeg_l3_encode_write_double_mono (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
695b815c7f3Sopenharmony_ci{	BUF_UNION ubuf ;
696b815c7f3Sopenharmony_ci	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
697b815c7f3Sopenharmony_ci	sf_count_t total = 0 ;
698b815c7f3Sopenharmony_ci	int nbytes, writecount, writen ;
699b815c7f3Sopenharmony_ci
700b815c7f3Sopenharmony_ci	if ((psf->error = mpeg_l3_encoder_construct (psf)))
701b815c7f3Sopenharmony_ci		return 0 ;
702b815c7f3Sopenharmony_ci
703b815c7f3Sopenharmony_ci	const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.dbuf), pmpeg->frame_samples) ;
704b815c7f3Sopenharmony_ci	while (len)
705b815c7f3Sopenharmony_ci	{	writecount = SF_MIN (len, max_samples) ;
706b815c7f3Sopenharmony_ci
707b815c7f3Sopenharmony_ci		if (psf->norm_double)
708b815c7f3Sopenharmony_ci			nbytes = lame_encode_buffer_ieee_double (pmpeg->lamef, ptr + total, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
709b815c7f3Sopenharmony_ci		else
710b815c7f3Sopenharmony_ci		{	/* Lame lacks non-normalized double writing */
711b815c7f3Sopenharmony_ci			normalize_double (ubuf.dbuf, ptr + total, writecount, 1.0 / (double) 0x8000) ;
712b815c7f3Sopenharmony_ci			nbytes = lame_encode_buffer_ieee_double (pmpeg->lamef, ubuf.dbuf, NULL, writecount, pmpeg->block, pmpeg->block_len) ;
713b815c7f3Sopenharmony_ci			}
714b815c7f3Sopenharmony_ci
715b815c7f3Sopenharmony_ci		if (nbytes < 0)
716b815c7f3Sopenharmony_ci		{	psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
717b815c7f3Sopenharmony_ci			break ;
718b815c7f3Sopenharmony_ci			} ;
719b815c7f3Sopenharmony_ci
720b815c7f3Sopenharmony_ci		if (nbytes)
721b815c7f3Sopenharmony_ci		{	writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
722b815c7f3Sopenharmony_ci			if (writen != nbytes)
723b815c7f3Sopenharmony_ci			{	psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
724b815c7f3Sopenharmony_ci				} ;
725b815c7f3Sopenharmony_ci			} ;
726b815c7f3Sopenharmony_ci
727b815c7f3Sopenharmony_ci		total += writecount ;
728b815c7f3Sopenharmony_ci		len -= writecount ;
729b815c7f3Sopenharmony_ci		} ;
730b815c7f3Sopenharmony_ci
731b815c7f3Sopenharmony_ci	return total ;
732b815c7f3Sopenharmony_ci}
733b815c7f3Sopenharmony_ci
734b815c7f3Sopenharmony_ci
735b815c7f3Sopenharmony_cistatic sf_count_t
736b815c7f3Sopenharmony_cimpeg_l3_encode_write_double_stereo (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
737b815c7f3Sopenharmony_ci{	BUF_UNION ubuf ;
738b815c7f3Sopenharmony_ci	MPEG_L3_ENC_PRIVATE *pmpeg = (MPEG_L3_ENC_PRIVATE*) psf->codec_data ;
739b815c7f3Sopenharmony_ci	sf_count_t total = 0 ;
740b815c7f3Sopenharmony_ci	int nbytes, writecount, writen ;
741b815c7f3Sopenharmony_ci
742b815c7f3Sopenharmony_ci	if ((psf->error = mpeg_l3_encoder_construct (psf)))
743b815c7f3Sopenharmony_ci		return 0 ;
744b815c7f3Sopenharmony_ci
745b815c7f3Sopenharmony_ci	const sf_count_t max_samples = SF_MIN (ARRAY_LEN (ubuf.dbuf), pmpeg->frame_samples) ;
746b815c7f3Sopenharmony_ci	while (len)
747b815c7f3Sopenharmony_ci	{	writecount = SF_MIN (len, max_samples) ;
748b815c7f3Sopenharmony_ci
749b815c7f3Sopenharmony_ci		if (psf->norm_double)
750b815c7f3Sopenharmony_ci			nbytes = lame_encode_buffer_interleaved_ieee_double (pmpeg->lamef, ptr + total, writecount / 2, pmpeg->block, pmpeg->block_len) ;
751b815c7f3Sopenharmony_ci		else
752b815c7f3Sopenharmony_ci		{	/* Lame lacks interleaved non-normalized double writing */
753b815c7f3Sopenharmony_ci			normalize_double (ubuf.dbuf, ptr + total, writecount, 1.0 / (double) 0x8000) ;
754b815c7f3Sopenharmony_ci			nbytes = lame_encode_buffer_interleaved_ieee_double (pmpeg->lamef, ubuf.dbuf, writecount / 2, pmpeg->block, pmpeg->block_len) ;
755b815c7f3Sopenharmony_ci			}
756b815c7f3Sopenharmony_ci
757b815c7f3Sopenharmony_ci		if (nbytes < 0)
758b815c7f3Sopenharmony_ci		{	psf_log_printf (psf, "lame_encode_buffer returned %d\n", nbytes) ;
759b815c7f3Sopenharmony_ci			break ;
760b815c7f3Sopenharmony_ci			} ;
761b815c7f3Sopenharmony_ci
762b815c7f3Sopenharmony_ci		if (nbytes)
763b815c7f3Sopenharmony_ci		{	writen = psf_fwrite (pmpeg->block, 1, nbytes, psf) ;
764b815c7f3Sopenharmony_ci			if (writen != nbytes)
765b815c7f3Sopenharmony_ci			{	psf_log_printf (psf, "*** Warning : short write (%d != %d).\n", writen, nbytes) ;
766b815c7f3Sopenharmony_ci				} ;
767b815c7f3Sopenharmony_ci			} ;
768b815c7f3Sopenharmony_ci
769b815c7f3Sopenharmony_ci		total += writecount ;
770b815c7f3Sopenharmony_ci		len -= writecount ;
771b815c7f3Sopenharmony_ci		} ;
772b815c7f3Sopenharmony_ci
773b815c7f3Sopenharmony_ci	return total ;
774b815c7f3Sopenharmony_ci}
775b815c7f3Sopenharmony_ci
776b815c7f3Sopenharmony_ci#else /* HAVE_MPEG */
777b815c7f3Sopenharmony_ci
778b815c7f3Sopenharmony_ciint
779b815c7f3Sopenharmony_cimpeg_l3_encoder_init (SF_PRIVATE *psf, int UNUSED (vbr))
780b815c7f3Sopenharmony_ci{	psf_log_printf (psf, "This version of libsndfile was compiled without MPEG Layer 3 encoding support.\n") ;
781b815c7f3Sopenharmony_ci	return SFE_UNIMPLEMENTED ;
782b815c7f3Sopenharmony_ci} /* mpeg_l3_encoder_init */
783b815c7f3Sopenharmony_ci
784b815c7f3Sopenharmony_ci#endif
785