1 /*
2  *   cdda - CD Digital Audio support
3  *
4  *   Copyright (C) 1993-2004  Ti Kan
5  *   E-mail: xmcd@amb.org
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21 #ifndef lint
22 static char *_if_flac_c_ident_ = "@(#)if_flac.c	7.19 03/12/12";
23 #endif
24 
25 #include "common_d/appenv.h"
26 #include "common_d/version.h"
27 #include "common_d/util.h"
28 #include "libdi_d/libdi.h"
29 #include "cdda_d/cdda.h"
30 
31 #if defined(CDDA_SUPPORTED) && defined(HAS_FLAC)
32 
33 #include "cdinfo_d/cdinfo.h"
34 #include "cdda_d/wr_gen.h"
35 #include "cdda_d/if_flac.h"
36 
37 /* Hack: use our own FLAC types instead of using those from <FLAC/ordinals.h>
38  * to be independent of the compiler that was used to build the FLAC library.
39  * This is necessary to resolve a conflict on some platforms where FLAC was
40  * compiled with gcc (which has "long long"), but this file is being compiled
41  * with a compiler that does not have a 64-bit integer type.
42  */
43 #define FLAC__ORDINALS_H	/* Override <FLAC/ordinals.h> */
44 
45 typedef int			FLAC__bool;
46 typedef byte_t			FLAC__uint8;
47 typedef sbyte_t			FLAC__int8;
48 typedef word16_t		FLAC__uint16;
49 typedef sword16_t		FLAC__int16;
50 typedef word32_t		FLAC__uint32;
51 typedef sword32_t		FLAC__int32;
52 typedef word64_t		FLAC__uint64;
53 typedef sword64_t		FLAC__int64;
54 typedef byte_t			FLAC__byte;
55 typedef float			FLAC__real;
56 
57 #include <FLAC/format.h>
58 #include <FLAC/metadata.h>
59 #include <FLAC/stream_encoder.h>
60 
61 
62 extern appdata_t		app_data;
63 extern FILE			*errfp;
64 extern cdda_client_t		*cdda_clinfo;
65 
66 extern char			*tagcomment;	/* Tag comment */
67 
68 
69 /* Convenience macros */
70 #ifdef MIN
71 #undef MIN
72 #endif
73 #define MIN(x,y)		(((x) < (y)) ? (x) : (y))
74 
75 #ifdef MAX
76 #undef MAX
77 #endif
78 #define MAX(x,y)		(((x) > (y)) ? (x) : (y))
79 
80 
81 /* Max number of metadata blocks */
82 #define META_MAXBLOCKS		8
83 
84 
85 /* Container union for encoder instance pointers */
86 typedef union {
87 	FLAC__StreamEncoder		*st;	/* Stream encoder */
88 } flac_desc_t;
89 
90 
91 /* Structure of user-adjustable parameters */
92 typedef struct {
93 	FLAC__bool	mid_side,	/* Enable mid/side stereo */
94 			adap_ms,	/* Enable adaptive mid/side stereo */
95 			exh_srch,	/* Enable exhaustive model search */
96 			vfy_mode,	/* Enable verify mode */
97 			qlp_srch;	/* Enable LP coeff quant search */
98 	unsigned int	lpc_order,	/* LPC order */
99 			block_sz;	/* Block size */
100 	int		min_rpo,	/* Minimum residual partition order */
101 			max_rpo;	/* Maximum residual partition order */
102 } flac_parms_t;
103 
104 
105 /* Pointers to wide samples buffers for each channel */
106 STATIC FLAC__int32		*fenc_buf[2] = { NULL, NULL };
107 STATIC FLAC__StreamMetadata	**flac_mlist = NULL;
108 STATIC int			flac_mblks = 0;
109 
110 
111 /*
112  * if_flac_write_callback
113  *	FLAC stream encoder write callback function
114  *
115  * Args:
116  *	stp - Stream encoder instance descriptor
117  *	buf - Output data buffer
118  *	len - data length
119  *	samples - number of samples
120  *	frame - Current frame
121  *	client_data - Callback data
122  *
123  * Return:
124  *	FLAC__STREAM_ENCODER_WRITE_STATUS_OK - success
125  *	FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR - failure
126  */
127 /*ARGSUSED*/
128 STATIC FLAC__StreamEncoderWriteStatus
if_flac_write_callback(const FLAC__StreamEncoder * stp,const FLAC__byte * buf,unsigned int len,unsigned int samples,unsigned int frame,void * client_data)129 if_flac_write_callback(
130 	const FLAC__StreamEncoder	*stp,
131 	const FLAC__byte		*buf,
132 	unsigned int			len,
133 	unsigned int			samples,
134 	unsigned int			frame,
135 	void				*client_data
136 )
137 {
138 	gen_desc_t	*gdp = (gen_desc_t *) client_data;
139 
140 	if (buf == NULL || len == 0)
141 		/* Nothing to do */
142 		return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
143 
144 	/* Write out the encoded data */
145 	gdp->flags |= GDESC_WRITEOUT;
146 	if (!gen_write_chunk(gdp, (byte_t *) buf, (size_t) len))
147 		return FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR;
148 
149 	return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
150 }
151 
152 
153 /*
154  * if_flac_metadata_callback
155  *	FLAC stream encoder metadata callback function
156  *
157  * Args:
158  *	skp - Encoder instance descriptor
159  *	data - Metadata buffer
160  *	client_data - Callback data
161  *
162  * Return:
163  *	Nothing.
164  */
165 /*ARGSUSED*/
166 STATIC FLAC__StreamEncoderSeekStatus
if_flac_metadata_callback(const FLAC__StreamEncoder * skp,FLAC__uint64 offset,void * client_data)167 if_flac_metadata_callback(
168 	const FLAC__StreamEncoder		*skp,
169 	FLAC__uint64				offset,
170 	void					*client_data
171 )
172 {
173 	gen_desc_t	*gdp = (gen_desc_t *) client_data;
174 	off_t		val;
175 
176 	val = (off_t) ASSIGN32(offset);
177 
178 	if (gen_seek(gdp, val, SEEK_SET))
179 		return FLAC__STREAM_ENCODER_SEEK_STATUS_OK;
180 	else
181 		return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR;
182 }
183 
184 
185 /*
186  * if_flac_addseek_spaced
187  *	Add spaced seek points template to the seektable metadata block.
188  *	A seek point is added to approximately each 10 seconds of audio.
189  *
190  * Args:
191  *	gdp - Pointer to the gen_desc_t structure
192  *	mdp - The metadata descriptor
193  *	cdi - Pointer to the cd_info_t structure
194  *
195  * Return:
196  *	Nothing.
197  */
198 STATIC void
if_flac_addseek_spaced(gen_desc_t * gdp,FLAC__StreamMetadata * mdp,cd_info_t * cdi)199 if_flac_addseek_spaced(
200 	gen_desc_t		*gdp,
201 	FLAC__StreamMetadata	*mdp,
202 	cd_info_t		*cdi
203 )
204 {
205 	FLAC__bool	ret;
206 	FLAC__uint64	val64;
207 	unsigned int	nsectors,
208 			nsamples,
209 			nseekpts;
210 
211 	nsectors = (unsigned int) cdi->end_lba - cdi->start_lba + 1;
212 	nsamples = (unsigned int) (nsectors / FRAME_PER_SEC) * 44100;
213 	nseekpts = nsectors / (FRAME_PER_SEC * 10);
214 
215 	if (nseekpts == 0)
216 		return;
217 
218 	val64 = ASSIGN64(nsamples);
219 
220 	ret = FLAC__metadata_object_seektable_template_append_spaced_points(
221 		mdp, nseekpts, val64
222 	);
223 	if (!ret) {
224 		(void) strcpy(gdp->cdp->i->msgbuf,
225 			    "if_flac_addseek_spaced: "
226 			    "Failed inserting spaced seek point.");
227 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
228 		return;
229 	}
230 
231 	ret = FLAC__metadata_object_seektable_template_sort(mdp, FALSE);
232 	if (!ret) {
233 		(void) strcpy(gdp->cdp->i->msgbuf,
234 			    "if_flac_addseek_spaced: "
235 			    "Failed sorting the seek table.");
236 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
237 	}
238 }
239 
240 
241 /*
242  * if_flac_addseek_tracks
243  *	Add start-of-track seek points template to the seektable metadata
244  *	block.
245  *
246  * Args:
247  *	gdp - Pointer to the gen_desc_t structure
248  *	mdp - The metadata descriptor
249  *	cdi - Pointer to the cd_info_t structure
250  *	s   - Pointer to the curstat_t structure
251  *
252  * Return:
253  *	Nothing.
254  */
255 STATIC void
if_flac_addseek_tracks(gen_desc_t * gdp,FLAC__StreamMetadata * mdp,cd_info_t * cdi,curstat_t * s)256 if_flac_addseek_tracks(
257 	gen_desc_t		*gdp,
258 	FLAC__StreamMetadata	*mdp,
259 	cd_info_t		*cdi,
260 	curstat_t		*s
261 )
262 {
263 	FLAC__bool	ret;
264 	FLAC__uint64	val64;
265 	unsigned int	start,
266 			end,
267 			nsectors,
268 			nsamples,
269 			seekpt;
270 	int		i,
271 			n;
272 
273 	seekpt = 0;
274 	for (i = n = 0; i < (int) s->tot_trks; i++) {
275 		if (cdi->end_lba < s->trkinfo[i].addr ||
276 		    cdi->start_lba > s->trkinfo[i].addr)
277 			continue;
278 
279 		start = (unsigned int) MAX(s->trkinfo[i].addr, cdi->start_lba);
280 		end   = (unsigned int) MIN(s->trkinfo[i+1].addr, cdi->end_lba);
281 		nsectors = end - start + 1;
282 		nsamples = (unsigned int) (nsectors / FRAME_PER_SEC) * 44100;
283 
284 		if (n++ > 0)
285 			seekpt += nsamples;
286 
287 		val64 = ASSIGN64(seekpt);
288 
289 		ret = FLAC__metadata_object_seektable_template_append_point(
290 			mdp, val64
291 		);
292 		if (!ret) {
293 			(void) sprintf(gdp->cdp->i->msgbuf,
294 				    "if_flac_addseek_tracks: "
295 				    "Failed adding seek point for track %d.",
296 				    (int) s->trkinfo[i].trkno);
297 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
298 		}
299 	}
300 
301 	ret = FLAC__metadata_object_seektable_template_sort(mdp, FALSE);
302 	if (!ret) {
303 		(void) strcpy(gdp->cdp->i->msgbuf,
304 			    "if_flac_addseek_tracks: "
305 			    "Failed sorting the seek table.");
306 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
307 	}
308 }
309 
310 
311 /*
312  * if_flac_addtagent
313  *	Add one entry into the vorbis comment metadata block.
314  *
315  * Args:
316  *	gdp - Pointer to the gen_desc_t structure
317  *	mdp - The metadata descriptor
318  *	attr - Attribute name string
319  *	val - Value string name
320  *
321  * Return:
322  *	Nothing.
323  */
324 STATIC void
if_flac_addtagent(gen_desc_t * gdp,FLAC__StreamMetadata * mdp,char * attr,char * val)325 if_flac_addtagent(
326 	gen_desc_t		*gdp,
327 	FLAC__StreamMetadata	*mdp,
328 	char			*attr,
329 	char			*val
330 )
331 {
332 	FLAC__StreamMetadata_VorbisComment_Entry ent;
333 	FLAC__bool	ret;
334 	char		txtstr[STR_BUF_SZ * 2];
335 
336 	/* Vorbis comments should be encoded in UTF-8 so we don't need
337 	 * any conversion here.
338 	 */
339 
340 	(void) sprintf(txtstr, "%.16s=%.100s", attr, val);
341 	ent.entry = (FLAC__byte *) txtstr;
342 	ent.length = (FLAC__uint32) strlen(txtstr);
343 
344 	ret = FLAC__metadata_object_vorbiscomment_insert_comment(
345 		mdp, mdp->data.vorbis_comment.num_comments, ent, TRUE
346 	);
347 	if (!ret) {
348 		(void) sprintf(gdp->cdp->i->msgbuf,
349 			    "if_flac_addtagent: "
350 			    "Failed inserting vorbis comment: attr=[%s]",
351 			    attr);
352 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
353 	}
354 }
355 
356 
357 /*
358  * if_flac_addmeta
359  *	Initialize and set the metadata areas of the FLAC output.
360  *
361  * Args:
362  *	gdp - Pointer to the gen_desc_t structure
363  *	ufdp - Pointer to the FLAC descriptor union
364  *
365  * Return:
366  *	Nothing.
367  */
368 STATIC void
if_flac_addmeta(gen_desc_t * gdp,flac_desc_t * ufdp)369 if_flac_addmeta(gen_desc_t *gdp, flac_desc_t *ufdp)
370 {
371 	FLAC__StreamMetadata	*mdp;
372 	FLAC__bool		ret;
373 	curstat_t		*s = cdda_clinfo->curstat_addr();
374 	cdinfo_incore_t		*cdp = cdinfo_addr();
375 	int			i,
376 				idx = (int) gdp->cdp->i->trk_idx;
377 	size_t			listsz;
378 	char			tmpstr[32];
379 
380 	listsz = sizeof(FLAC__StreamMetadata *) * META_MAXBLOCKS;
381 
382 	flac_mlist = (FLAC__StreamMetadata **) MEM_ALLOC("flac_mlist", listsz);
383 	if (flac_mlist == NULL) {
384 		(void) strcpy(gdp->cdp->i->msgbuf,
385 			    "if_flac_addmeta: Out of memory.");
386 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
387 		return;
388 	}
389 	(void) memset(flac_mlist, 0, listsz);
390 	flac_mblks = 0;
391 
392 	/* Application-specific metadata */
393 	mdp = FLAC__metadata_object_new(FLAC__METADATA_TYPE_APPLICATION);
394 	if (mdp == NULL) {
395 		(void) strcpy(gdp->cdp->i->msgbuf,
396 			"if_flac_addmeta: "
397 			"Failed creating application metadata block.");
398 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
399 	}
400 	else {
401 		char	data[STR_BUF_SZ * 4];
402 
403 		flac_mlist[flac_mblks++] = mdp;
404 
405 		/* Set the application ID - This has been registered
406 		 * with the FLAC developers.
407 		 */
408 		(void) memcpy(mdp->data.application.id, "xmcd", 4);
409 
410 		/* For future expansion: just some app information
411 		 * in here for now.
412 		 */
413 		(void) sprintf(data, "%s.%s.%s\n%s\n%s\n%s\n",
414 			VERSION_MAJ, VERSION_MIN, VERSION_TEENY,
415 			COPYRIGHT, EMAIL, XMCD_URL
416 		);
417 
418 		ret = FLAC__metadata_object_application_set_data(
419 			mdp, (FLAC__byte *) data, (unsigned) strlen(data), TRUE
420 		);
421 		if (!ret) {
422 			(void) strcpy(gdp->cdp->i->msgbuf,
423 				"if_flac_addmeta: "
424 				"Failed setting application metadata.");
425 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
426 		}
427 	}
428 
429 	/* Seek table metadata */
430 	if ((gdp->flags & GDESC_ISPIPE) == 0) {
431 		mdp = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
432 		if (mdp == NULL) {
433 			(void) strcpy(gdp->cdp->i->msgbuf,
434 				"if_flac_addmeta: "
435 				"Failed creating seektable metadata block.");
436 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
437 		}
438 		else {
439 			cd_info_t	*cdi = gdp->cdp->i;
440 
441 			flac_mlist[flac_mblks++] = mdp;
442 
443 			if (app_data.cdda_trkfile) {
444 				/* Insert evenly spaced seek points */
445 				if_flac_addseek_spaced(gdp, mdp, cdi);
446 			}
447 			else {
448 				/* Insert seek points at start of tracks */
449 				if_flac_addseek_tracks(gdp, mdp, cdi, s);
450 			}
451 		}
452 	}
453 
454 	/* Vorbis comment metadata */
455 	if (app_data.add_tag) {
456 		mdp = FLAC__metadata_object_new(
457 			FLAC__METADATA_TYPE_VORBIS_COMMENT
458 		);
459 		if (mdp == NULL) {
460 			(void) strcpy(gdp->cdp->i->msgbuf,
461 				"if_flac_addmeta: "
462 				"Failed creating vorbis metadata block.");
463 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
464 		}
465 		else {
466 			flac_mlist[flac_mblks++] = mdp;
467 
468 			mdp->data.vorbis_comment.num_comments = 0;
469 
470 			if (cdp->disc.title != NULL)
471 				if_flac_addtagent(gdp, mdp, "ALBUM",
472 						  cdp->disc.title);
473 
474 			if (app_data.cdda_trkfile &&
475 			    cdp->track[idx].artist != NULL)
476 				if_flac_addtagent(gdp, mdp, "ARTIST",
477 						  cdp->track[idx].artist);
478 			else
479 				if_flac_addtagent(gdp, mdp, "ARTIST",
480 						  cdp->disc.artist);
481 
482 			if (app_data.cdda_trkfile &&
483 			    cdp->track[idx].title != NULL)
484 				if_flac_addtagent(gdp, mdp, "TITLE",
485 						  cdp->track[idx].title);
486 			else if (cdp->disc.title != NULL)
487 				if_flac_addtagent(gdp, mdp, "TITLE",
488 						  cdp->disc.title);
489 
490 			if (app_data.cdda_trkfile &&
491 			    cdp->track[idx].year != NULL)
492 				if_flac_addtagent(gdp, mdp, "DATE",
493 						  cdp->track[idx].year);
494 			else if (cdp->disc.year != NULL)
495 				if_flac_addtagent(gdp, mdp, "DATE",
496 						  cdp->disc.year);
497 
498 			if (app_data.cdda_trkfile &&
499 			    cdp->track[idx].genre != NULL)
500 				if_flac_addtagent(gdp, mdp, "GENRE",
501 				    cdinfo_genre_name(cdp->track[idx].genre));
502 			else if (cdp->disc.genre != NULL)
503 				if_flac_addtagent(gdp, mdp, "GENRE",
504 				    cdinfo_genre_name(cdp->disc.genre));
505 
506 			if (app_data.cdda_trkfile &&
507 			    cdp->track[idx].label != NULL)
508 				if_flac_addtagent(gdp, mdp, "ORGANIZATION",
509 						  cdp->track[idx].label);
510 			else if (cdp->disc.label != NULL)
511 				if_flac_addtagent(gdp, mdp, "ORGANIZATION",
512 						  cdp->disc.label);
513 
514 			if (app_data.cdda_trkfile) {
515 				(void) sprintf(tmpstr, "%d",
516 						(int) s->trkinfo[idx].trkno);
517 				if_flac_addtagent(gdp, mdp, "TRACKNUMBER",
518 						  tmpstr);
519 
520 				if (cdp->track[idx].bpm != NULL) {
521 				    if_flac_addtagent(gdp, mdp, "BPM",
522 						      cdp->track[idx].bpm);
523 				}
524 
525 				if (cdp->track[idx].isrc != NULL) {
526 				    if_flac_addtagent(gdp, mdp, "ISRC",
527 						      cdp->track[idx].isrc);
528 				}
529 			}
530 			else for (i = 0; i < (int) s->tot_trks; i++) {
531 				cd_info_t	*cdi = gdp->cdp->i;
532 
533 				if (cdi->end_lba < s->trkinfo[i].addr ||
534 				    cdi->start_lba > s->trkinfo[i].addr)
535 					continue;
536 
537 				if (cdp->track[i].artist != NULL) {
538 					(void) sprintf(tmpstr,
539 						"TRACK%02dARTIST",
540 						(int) s->trkinfo[i].trkno
541 					);
542 					if_flac_addtagent(gdp, mdp, tmpstr,
543 						cdp->track[i].artist
544 					);
545 				}
546 				if (cdp->track[i].title != NULL) {
547 					(void) sprintf(tmpstr,
548 						"TRACK%02dTITLE",
549 						(int) s->trkinfo[i].trkno
550 					);
551 					if_flac_addtagent(gdp, mdp, tmpstr,
552 						cdp->track[i].title
553 					);
554 				}
555 			}
556 
557 			if (s->mcn[0] != '\0')
558 				if_flac_addtagent(gdp, mdp, "MCN", s->mcn);
559 
560 			(void) sprintf(tmpstr, "%08x", (int) cdp->discid);
561 			if_flac_addtagent(gdp, mdp, "XMCDDISCID", tmpstr);
562 
563 			if_flac_addtagent(gdp, mdp, "ENCODER", tagcomment);
564 		}
565 	}
566 
567 	if (flac_mblks == 0)
568 		return;	/* No metadata to set */
569 
570 	ret = FLAC__stream_encoder_set_metadata(
571 		ufdp->st, flac_mlist, flac_mblks
572 	);
573 	if (!ret) {
574 		(void) strcpy(gdp->cdp->i->msgbuf,
575 			    "if_flac_addmeta: Failed setting metadata.");
576 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
577 	}
578 }
579 
580 
581 /*
582  * if_flac_encoder_setup
583  *	Create and set up the FLAC stream encoder.
584  *
585  * Args:
586  *	gdp  - Pointer to the gen_desc_t structure
587  *	ufdp - Pointer to the flac_desc_t structure
588  *	pp   - Pointer to the flac_parms_t structure
589  *
590  * Return:
591  *	TRUE  - success
592  *	FALSE - failure
593  */
594 STATIC bool_t
if_flac_encoder_setup(gen_desc_t * gdp,flac_desc_t * ufdp,flac_parms_t * pp)595 if_flac_encoder_setup(
596 	gen_desc_t	*gdp,
597 	flac_desc_t	*ufdp,
598 	flac_parms_t	*pp
599 )
600 {
601 	FLAC__StreamEncoder		*stp;
602 	FLAC__StreamEncoderState	enc_state;
603 	FLAC__uint64			val;
604 	FLAC__bool			ret;
605 
606 	ufdp->st = stp = FLAC__stream_encoder_new();
607 	if (stp == NULL) {
608 		(void) strcpy(gdp->cdp->i->msgbuf,
609 			    "if_flac_encoder_setup: "
610 			    "FLAC encoder instantiation failed.");
611 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
612 		return FALSE;
613 	}
614 
615 	/* Set some basic parameters */
616 
617 	ret = FLAC__stream_encoder_set_channels(stp, 2);
618 	if (!ret) {
619 		(void) strcpy(gdp->cdp->i->msgbuf,
620 			    "if_flac_encoder_setup: "
621 			    "Failed setting channels.");
622 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
623 		return FALSE;
624 	}
625 
626 	ret = FLAC__stream_encoder_set_bits_per_sample(stp, 16);
627 	if (!ret) {
628 		(void) strcpy(gdp->cdp->i->msgbuf,
629 			    "if_flac_encoder_setup: "
630 			    "Failed setting bits per sample.");
631 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
632 		return FALSE;
633 	}
634 
635 	ret = FLAC__stream_encoder_set_sample_rate(stp, 44100);
636 	if (!ret) {
637 		(void) strcpy(gdp->cdp->i->msgbuf,
638 			    "if_flac_encoder_setup: "
639 			    "Failed setting sample rate.");
640 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
641 		return FALSE;
642 	}
643 
644 	val = ASSIGN64(gdp->datalen >> 2);
645 	ret = FLAC__stream_encoder_set_total_samples_estimate(stp, val);
646 	if (!ret) {
647 		(void) strcpy(gdp->cdp->i->msgbuf,
648 			    "if_flac_encoder_setup: "
649 			    "Failed setting samples estimate.");
650 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
651 		return FALSE;
652 	}
653 
654 	ret = FLAC__stream_encoder_set_streamable_subset(stp, TRUE);
655 	if (!ret) {
656 		(void) strcpy(gdp->cdp->i->msgbuf,
657 			    "if_flac_encoder_setup: "
658 			    "Failed setting streamable subset.");
659 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
660 		return FALSE;
661 	}
662 
663 	ret = FLAC__stream_encoder_set_do_qlp_coeff_prec_search(
664 		stp, pp->qlp_srch
665 	);
666 	if (!ret) {
667 		(void) strcpy(gdp->cdp->i->msgbuf,
668 			"if_flac_encoder_setup: "
669 			"Failed setting LP coefficient quantization search."
670 		);
671 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
672 		return FALSE;
673 	}
674 
675 	/* Just use default for now
676 	ret = FLAC__stream_encoder_set_qlp_coeff_precision(stp, 0);
677 	*/
678 
679 	ret = FLAC__stream_encoder_set_verify(stp, pp->vfy_mode);
680 	if (!ret) {
681 		(void) strcpy(gdp->cdp->i->msgbuf,
682 			    "if_flac_encoder_setup: "
683 			    "Failed setting verify mode.");
684 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
685 		return FALSE;
686 	}
687 
688 	ret = FLAC__stream_encoder_set_max_lpc_order(stp, pp->lpc_order);
689 	if (!ret) {
690 		(void) strcpy(gdp->cdp->i->msgbuf,
691 			    "if_flac_encoder_setup: "
692 			    "Failed setting max LPC order.");
693 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
694 		return FALSE;
695 	}
696 
697 	ret = FLAC__stream_encoder_set_blocksize(stp, pp->block_sz);
698 	if (!ret) {
699 		(void) strcpy(gdp->cdp->i->msgbuf,
700 			    "if_flac_encoder_setup: "
701 			    "Failed setting block size.");
702 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
703 		return FALSE;
704 	}
705 
706 	ret = FLAC__stream_encoder_set_do_mid_side_stereo(stp, pp->mid_side);
707 	if (!ret) {
708 		(void) strcpy(gdp->cdp->i->msgbuf,
709 			    "if_flac_encoder_setup: "
710 			    "Failed setting M/S stereo.");
711 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
712 		return FALSE;
713 	}
714 
715 	ret = FLAC__stream_encoder_set_loose_mid_side_stereo(stp, pp->adap_ms);
716 	if (!ret) {
717 		(void) strcpy(gdp->cdp->i->msgbuf,
718 			    "if_flac_encoder_setup: "
719 			    "Failed setting adaptive M/S stereo.");
720 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
721 		return FALSE;
722 	}
723 
724 	if (pp->min_rpo >= 0) {
725 		ret = FLAC__stream_encoder_set_min_residual_partition_order(
726 			stp, (unsigned int) pp->min_rpo
727 		);
728 		if (!ret) {
729 			(void) strcpy(gdp->cdp->i->msgbuf,
730 				    "if_flac_encoder_setup: "
731 				    "Failed setting minimum RPO.");
732 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
733 			return FALSE;
734 		}
735 	}
736 
737 	if (pp->max_rpo >= 0) {
738 		ret = FLAC__stream_encoder_set_max_residual_partition_order(
739 			stp, (unsigned int) pp->max_rpo
740 		);
741 		if (!ret) {
742 			(void) strcpy(gdp->cdp->i->msgbuf,
743 				    "if_flac_encoder_setup: "
744 				    "Failed setting maximum RPO.");
745 			DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
746 			return FALSE;
747 		}
748 	}
749 
750 	ret = FLAC__stream_encoder_set_do_exhaustive_model_search(
751 		stp, pp->exh_srch
752 	);
753 	if (!ret) {
754 		(void) strcpy(gdp->cdp->i->msgbuf,
755 			    "if_flac_encoder_setup: "
756 			    "Failed setting exhaustive model search.");
757 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
758 		return FALSE;
759 	}
760 
761 	/* Initialize and add metadata to FLAC output */
762 	if_flac_addmeta(gdp, ufdp);
763 
764 	/* Initialize FLAC encoder */
765 	enc_state = FLAC__stream_encoder_init_stream(
766 		stp, if_flac_write_callback, NULL, NULL,
767 		if_flac_metadata_callback, gdp
768 	);
769 	if (enc_state != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
770 		(void) sprintf(gdp->cdp->i->msgbuf,
771 			"if_flac_encoder_setup: Encoder init error: %s",
772 			FLAC__stream_encoder_get_resolved_state_string(stp)
773 		);
774 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
775 		return FALSE;
776 	}
777 
778 	/* Allocate wide samples buffers for the two channels */
779 	fenc_buf[0] = (FLAC__int32 *) MEM_ALLOC(
780 		"fenc_buf0",
781 		(size_t) gdp->cdp->cds->chunk_bytes
782 	);
783 	if (fenc_buf[0] == NULL) {
784 		(void) strcpy(gdp->cdp->i->msgbuf,
785 				"if_flac_encoder_setup: Out of memory.");
786 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
787 		return FALSE;
788 	}
789 	fenc_buf[1] = (FLAC__int32 *) MEM_ALLOC(
790 		"fenc_buf1",
791 		(size_t) gdp->cdp->cds->chunk_bytes
792 	);
793 	if (fenc_buf[1] == NULL) {
794 		(void) strcpy(gdp->cdp->i->msgbuf,
795 				"if_flac_encoder_setup: Out of memory.");
796 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
797 		return FALSE;
798 	}
799 
800 	return TRUE;
801 }
802 
803 
804 /*
805  * if_flac_init
806  *	Initialize FLAC encoder and set up encoding parameters
807  *
808  * Args:
809  *	gdp - Pointer to the gen_desc_t structure
810  *
811  * Return:
812  *	FALSE - failure
813  *	TRUE  - success
814  */
815 bool_t
if_flac_init(gen_desc_t * gdp)816 if_flac_init(gen_desc_t *gdp)
817 {
818 	FLAC__bool	ret;
819 	flac_desc_t	*ufdp;
820 	flac_parms_t	parms;
821 
822 	/* Allocate descriptor */
823 	ufdp = (flac_desc_t *) MEM_ALLOC("flac_desc_t", sizeof(flac_desc_t));
824 	if (ufdp == NULL) {
825 		(void) strcpy(gdp->cdp->i->msgbuf,
826 				"if_flac_init: Out of memory.");
827 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
828 		return FALSE;
829 	}
830 
831 	gdp->aux = (void *) ufdp;
832 
833 	/* Set up adjustable parameters */
834 
835 	switch (app_data.comp_mode) {
836 	case COMPMODE_3:
837 		parms.qlp_srch = parms.vfy_mode = TRUE;
838 		break;
839 	case COMPMODE_2:
840 		parms.qlp_srch = FALSE;
841 		parms.vfy_mode = TRUE;
842 		break;
843 	case COMPMODE_1:
844 		parms.qlp_srch = TRUE;
845 		parms.vfy_mode = FALSE;
846 		break;
847 	case COMPMODE_0:
848 	default:
849 		parms.qlp_srch = parms.vfy_mode = FALSE;
850 		break;
851 	}
852 
853 	switch (app_data.comp_algo) {
854 	case 10:
855 	case 9:
856 		parms.lpc_order = 12;
857 		parms.block_sz = 4608;
858 		parms.min_rpo = 6;
859 		parms.max_rpo = -1;
860 		parms.mid_side = TRUE;
861 		parms.adap_ms = FALSE;
862 		parms.exh_srch = TRUE;
863 		break;
864 	case 8:
865 		parms.lpc_order = 8;
866 		parms.block_sz = 4608;
867 		parms.min_rpo = 6;
868 		parms.max_rpo = -1;
869 		parms.mid_side = TRUE;
870 		parms.adap_ms = FALSE;
871 		parms.exh_srch = TRUE;
872 		break;
873 	case 7:
874 		parms.lpc_order = 8;
875 		parms.block_sz = 4608;
876 		parms.min_rpo = 4;
877 		parms.max_rpo = -1;
878 		parms.mid_side = TRUE;
879 		parms.adap_ms = FALSE;
880 		parms.exh_srch = FALSE;
881 		break;
882 	case 6:
883 		parms.lpc_order = 8;
884 		parms.block_sz = 4608;
885 		parms.min_rpo = parms.max_rpo = 3;
886 		parms.mid_side = TRUE;
887 		parms.adap_ms = FALSE;
888 		parms.exh_srch = FALSE;
889 		break;
890 	case 5:
891 		parms.lpc_order = 8;
892 		parms.block_sz = 4608;
893 		parms.min_rpo = parms.max_rpo = 3;
894 		parms.mid_side = parms.adap_ms = TRUE;
895 		parms.exh_srch = FALSE;
896 		break;
897 	case 4:
898 		parms.lpc_order = 6;
899 		parms.block_sz = 4608;
900 		parms.min_rpo = parms.max_rpo = 3;
901 		parms.mid_side = parms.adap_ms = FALSE;
902 		parms.exh_srch = FALSE;
903 		break;
904 	case 3:
905 		parms.lpc_order = 0;
906 		parms.block_sz = 1152;
907 		parms.min_rpo = 3;
908 		parms.max_rpo = -1;
909 		parms.mid_side = TRUE;
910 		parms.adap_ms = FALSE;
911 		parms.exh_srch = FALSE;
912 		break;
913 	case 2:
914 		parms.lpc_order = 0;
915 		parms.block_sz = 1152;
916 		parms.min_rpo = parms.max_rpo = 2;
917 		parms.mid_side = TRUE;
918 		parms.adap_ms = TRUE;
919 		parms.exh_srch = FALSE;
920 		break;
921 	case 1:
922 	default:
923 		parms.lpc_order = 0;
924 		parms.block_sz = 1152;
925 		parms.min_rpo = parms.max_rpo = 2;
926 		parms.mid_side = parms.adap_ms = FALSE;
927 		parms.exh_srch = FALSE;
928 		break;
929 	}
930 
931 	/* Set up encoder */
932 	ret = if_flac_encoder_setup(gdp, ufdp, &parms);
933 
934 	return (ret);
935 }
936 
937 
938 /*
939  * if_flac_encode_chunk
940  *	Encodes the audio data using FLAC and write to the fd.
941  *
942  * Args:
943  *	gdp  - Pointer to the gen_desc_t structure
944  *	data - Pointer to data
945  *	len  - Data length in bytes
946  *
947  * Return:
948  *	FALSE - failure
949  *	TRUE  - success
950  */
951 bool_t
if_flac_encode_chunk(gen_desc_t * gdp,byte_t * data,size_t len)952 if_flac_encode_chunk(gen_desc_t *gdp, byte_t *data, size_t len)
953 {
954 	flac_desc_t	*ufdp;
955 	FLAC__bool	ret;
956 	int		i,
957 			j,
958 			samples;
959 	sword16_t	*p;
960 
961 	if (gdp == NULL || gdp->aux == NULL)
962 		return FALSE;
963 
964 	if (data == NULL || len == 0)
965 		/* Nothing to do */
966 		return TRUE;
967 
968 	ufdp = (flac_desc_t *) gdp->aux;
969 
970 	/* De-interleave data and sign-extend into wide samples buffer */
971 	samples = (len >> 2);
972 	p = (sword16_t *)(void *) data;
973 	for (i = 0, j = 0; i < samples; i++) {
974 		fenc_buf[0][i] = (FLAC__int32) p[j++];
975 		fenc_buf[1][i] = (FLAC__int32) p[j++];
976 	}
977 
978 	DBGPRN(DBG_SND)(errfp, "\nEncoding %d samples\n", samples);
979 
980 	ret = FLAC__stream_encoder_process(
981 		ufdp->st, (void *) fenc_buf, (unsigned int) samples
982 	);
983 	if (!ret) {
984 		(void) strcpy(gdp->cdp->i->msgbuf,
985 			"if_flac_encode_chunk: Process encoding failed.");
986 		DBGPRN(DBG_SND)(errfp, "%s\n", gdp->cdp->i->msgbuf);
987 		return FALSE;
988 	}
989 
990 	return TRUE;
991 }
992 
993 
994 /*
995  * if_flac_halt
996  *	Flush buffers and shut down FLAC encoder
997  *
998  * Args:
999  *	gdp - Pointer to the gen_desc_t structure
1000  *
1001  * Return:
1002  *	Nothing.
1003  */
1004 void
if_flac_halt(gen_desc_t * gdp)1005 if_flac_halt(gen_desc_t *gdp)
1006 {
1007 	flac_desc_t	*ufdp;
1008 	int		i;
1009 
1010 	if (gdp == NULL || gdp->aux == NULL)
1011 		return;
1012 
1013 	ufdp = (flac_desc_t *) gdp->aux;
1014 
1015 	FLAC__stream_encoder_finish(ufdp->st);
1016 	FLAC__stream_encoder_delete(ufdp->st);
1017 
1018 	MEM_FREE(ufdp);
1019 	gdp->aux = NULL;
1020 
1021 	/* Deallocate metadata objects */
1022 	for (i = 0; i < flac_mblks; i++) {
1023 		if (flac_mlist[i] != NULL)
1024 			FLAC__metadata_object_delete(flac_mlist[i]);
1025 	}
1026 	MEM_FREE(flac_mlist);
1027 	flac_mlist = NULL;
1028 	flac_mblks = 0;
1029 
1030 	/* Free wide samples buffers */
1031 	if (fenc_buf[0] != NULL)
1032 		MEM_FREE(fenc_buf[0]);
1033 	if (fenc_buf[1] != NULL)
1034 		MEM_FREE(fenc_buf[1]);
1035 
1036 	fenc_buf[0] = fenc_buf[1] = NULL;
1037 }
1038 
1039 #endif	/* CDDA_SUPPORTED HAS_FLAC */
1040 
1041