1 
2 /*
3  *  Diverse SLab audio routines.
4  *  Copyright (c) by Nick Copeland <nickycopeland@hotmail.com> 1996,2012
5  *
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 3 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, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 
23 /*
24  * This will contain 3 called routines, from the audio daemon, one to open the
25  * mastering file, one to write the header, and one to close the file.
26  *
27  * openMaster()
28  *	The calling rouine will pass the file type. Expects an answer of:
29  *		-1: failure - forget mastering.
30  *		Anything else - do mastering with output to that FD number.
31  *
32  * writeMaster()
33  *	Calling routine passes type of file, and a buffer of data. Called party
34  *	must format data as necessary.
35  *
36  * closeMaster()
37  *	The calling rouine will pass the file type, and the number of bytes written.
38  */
39 #include <slabrevisions.h>
40 #include <slabaudiodev.h>
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <sys/types.h>
45 
46 #ifdef MASTER_WAV
47 /***** I stole this from Topy Shepard                         *****/
48 /***** He stole the rest of this file from 'vplay'.           *****/
49 /***** Thanks to: Michael Beck - beck@informatik.hu-berlin.de *****/
50 
51 /* Definitions for Microsoft WAVE format */
52 
53 #define BUFFSIZE	0x10000
54 #define RIFF		0x46464952
55 #define WAVE		0x45564157
56 #define FMT			0x20746d66
57 #define DATA		0x61746164
58 #define PCM_CODE	1
59 #define WAVE_MONO	1
60 #define WAVE_STEREO	2
61 
62 /* it's in chunks like .voc and AMIGA iff, but my source say there
63    are in only in this combination, so I combined them in one header;
64    it works on all WAVE-file I have
65 */
66 
67 typedef struct {
68 	u_long	main_chunk;	/* 'RIFF' */
69 	u_long	length;		/* filelen */
70 	u_long	chunk_type;	/* 'WAVE' */
71 
72 	u_long	sub_chunk;	/* 'fmt ' */
73 	u_long	sc_len;		/* length of sub_chunk, =16 */
74 	u_short	format;		/* should be 1 for PCM-code */
75 	u_short	modus;		/* 1 Mono, 2 Stereo */
76 	u_long	sample_fq;	/* frequence of sample */
77 	u_long	byte_p_sec;
78 	u_short	byte_p_spl;	/* samplesize; 1 or 2 bytes */
79 	u_short	bit_p_spl;	/* 8, 12 or 16 bit */
80 
81 	u_long	data_chunk;	/* 'data' */
82 	u_long	data_length;/* samplecount */
83 } WaveHeader;
84 
85 WaveHeader header;
86 #endif
87 
88 #ifdef MASTER_MP3ONLINE
89 int pipeFD[2];
90 int pid = -1;
91 int status;
92 #endif
93 
94 static int d;
95 
96 #ifdef MASTERING
97 #include <sys/types.h>
98 #include <sys/wait.h>
99 #include <sys/stat.h>
100 #include <fcntl.h>
101 #include <signal.h>
102 #include <unistd.h>
103 
104 static void writeWaveHdr(duplexDev *, int, int);
105 static void cdrFormat();
106 static void cdrPad();
107 
108 /*
109  * Note that the count parameter is the current songlength. This is only needed
110  * for MP3ONLINE, since we need to put some value in the waveHeader before we
111  * start piping the output.
112  */
113 int
openMaster(duplexDev * audioDev,int type,char * fileName,int count)114 openMaster(duplexDev *audioDev, int type, char *fileName, int count)
115 {
116 	int fd;
117 
118 	if (audioDev->cflags & SLAB_AUDIODBG)
119 		printf("openMaster(%i, %s, %i)\n", type, fileName, count);
120 
121 #ifdef MASTER_WAV
122 #ifdef MASTER_MP3ONLINE
123 	if (pid != -1)
124 	{
125 		/* kill(pid, SIGINT); */
126 		waitpid(pid, &status, WNOHANG);
127 		pid = -1;
128 	}
129 	/*
130 	 * BASICALLY THIS DOES NOT WORK, NOT SURE WHY. FOR FUTURE STUDY.....
131 	 *
132 	 * Online MP3 will open a pipe to bladeenc and work dynamically. This is
133 	 * a bit of a CPU hog, so the normal MP3 encoding will use output to a WAV
134 	 * file, and then bladeenc is called separately by the GUI once the output
135 	 * file is closed.
136 	 */
137 	if (type & MASTER_MP3ONLINE)
138 	{
139 		/*
140 		 * A bit ugly, but we are going to open a pipe, and fork/exec bladeenc.
141 		 * This is going into a separate library when it finally works.
142 		 *
143 		 * The library may use socketpair(2) instead.
144 		 */
145 		if (socketpair(PF_UNIX, SOCK_STREAM, PF_UNSPEC, pipeFD) < 0)
146 		{
147 			printf("mp3 online: socketpair() error\n");
148 			return(-1);
149 		} else {
150 			if ((pid = vfork()) == 0)
151 			{
152 				close(pipeFD[1]);
153 				dup2(pipeFD[0], 0);
154 				execlp("bladeenc", "bladeenc", /* "-quiet", */ "stdin",
155 					fileName, (char *) NULL);
156 				printf("Could not find bladeenc\n");
157 				_exit(0);
158 			} else {
159 				close(pipeFD[0]);
160 				fd = pipeFD[1];
161 			}
162 		}
163 	} else
164 #endif
165 #endif
166 		fd = open(fileName, O_CREAT|O_WRONLY|O_TRUNC, 0644);
167 
168 	switch(type & MASTERING_MASK)
169 	{
170 #ifdef MASTER_WAV
171 #ifdef MASTER_MP3ONLINE
172 		case MASTER_MP3ONLINE:
173 			writeWaveHdr(audioDev, fd, count);
174 			break;
175 #endif
176 #ifdef MASTER_MP3
177 		case MASTER_MP3:
178 #endif
179 		case MASTER_WAV:
180 			/*
181 			 * We write a zero length now, and when we close the file we put
182 			 * the actual length in there.
183 			 */
184 			writeWaveHdr(audioDev, fd, 0);
185 			break;
186 #endif
187 #ifdef MASTER_CDR
188 		case MASTER_CDR:
189 #endif
190 		default:
191 			/*
192 			 * No header.
193 			 */
194 			break;
195 	}
196 	return(fd);
197 }
198 
199 int
writeMaster(duplexDev * audioDev,int type,int fd,void * buffer,int size)200 writeMaster(duplexDev *audioDev, int type, int fd, void *buffer, int size)
201 {
202 	int d;
203 
204 	if (audioDev->cflags & SLAB_AUDIODBG)
205 		printf("writeMaster(%i, %i, %p, %i)\n", type, fd, buffer, size);
206 
207 	switch(type & MASTERING_MASK)
208 	{
209 #ifdef MASTER_CDR
210 		case MASTER_CDR:
211 			/*
212 			 * We need to byteswap first. Oops, this should cater for differnt
213 			 * output data types.
214 			 */
215 			cdrFormat(buffer, size >> 2);
216 
217 			d = write(fd, buffer, size);
218 			break;
219 #endif
220 #ifdef MASTER_WAV
221 #ifdef MASTER_MP3
222 #ifdef MASTER_MP3ONLINE
223 		case MASTER_MP3ONLINE:
224 /*			printf("MP3 Online write to fd %i\n", fd); */
225 #endif
226 		case MASTER_MP3:
227 #endif
228 		case MASTER_WAV:
229 #endif
230 		default:
231 			/*
232 			 * We don't need to byteswap first.
233 			 */
234 			d = write(fd, buffer, size);
235 			break;
236 	}
237 	return(0);
238 }
239 
240 void
closeMaster(duplexDev * audioDev,int fd,int type,int count)241 closeMaster(duplexDev *audioDev, int fd, int type, int count)
242 {
243 	if (audioDev->cflags & SLAB_AUDIODBG)
244 		printf("closeMaster(%i, %i, %i)\n", type, fd, count);
245 
246 	switch(type & MASTERING_MASK)
247 	{
248 #ifdef MASTER_CDR
249 		case MASTER_CDR:
250 			/*
251 			 * We need to pad the file to frag boundry.
252 			 */
253 			cdrPad(fd, count);
254 			break;
255 #endif
256 #ifdef MASTER_WAV
257 #ifdef MASTER_MP3ONLINE
258 		case MASTER_MP3ONLINE:
259 			/*
260 			 * We cannot kick the child yet, since it may not be finnished.
261 			 */
262 			break;
263 #endif
264 #ifdef MASTER_MP3
265 		case MASTER_MP3:
266 #endif
267 		case MASTER_WAV:
268 			/*
269 			 * We don't need to byteswap first.
270 			 */
271 			writeWaveHdr(audioDev, fd, count);
272 			break;
273 #endif
274 		default:
275 			/*
276 			 * We don't need to byteswap first.
277 			 */
278 			break;
279 	}
280 	close(fd);
281 }
282 
283 #ifdef MASTERING
284 void
cdrFormat(buffer,count)285 static cdrFormat(buffer, count)
286 register int count;
287 register char *buffer;
288 {
289 #if defined(__i386) || defined(__i486) || defined(__i586) || defined(__i686) \
290 	|| defined(__pentium) || defined(__pentiumpro)
291 
292 	register short tmp;
293 
294 #ifdef DEBUG
295 	printf("cdrFormat(%x, %i)\n", buffer, count);
296 #endif
297 
298 	/*
299 	 * This needs to convert the Linux based short into CD-DA format.
300 	 * Not going to bother with porting issues just yet, but we should add
301 	 * "ENDIAN" flags for compilation.
302 	 *
303 	 * cdrecord expects MSBLeft, LSBLeft, MSBRight, LSBRight.
304 	 *
305 	 * Swap each byte pair.
306 	 */
307 	for (;count > 0; count--)
308 	{
309 		tmp = *(buffer + 1);
310 		*(buffer + 1) = *buffer;
311 		*buffer = tmp;
312 		buffer += 2;
313 
314 		tmp = *(buffer + 1);
315 		*(buffer + 1) = *buffer;
316 		*buffer = tmp;
317 		buffer += 2;
318 	}
319 #endif /* cpu type */
320 }
321 
322 /*
323  * Check the number of samples written to the output file, and pad this out
324  * to match the CD-R sector size.
325  */
326 static void
cdrPad(int fd,int size)327 cdrPad(int fd, int size)
328 {
329 	int outCount;
330 	short extend[2];
331 
332 #ifdef DEBUG
333 	printf("cdrPad(%i, %i)\n", fd, size);
334 #endif
335 
336 #ifdef CD_R_OUTPUT
337 	/*
338 	 * This is the number of bytes, converted into samples, modulo sectorsize.
339 	 */
340 	if ((outCount = CD_R_OUTPUT - (size % CD_R_OUTPUT)) == CD_R_OUTPUT)
341 		return;
342 #endif
343 	extend[0] = 0;
344 
345 #ifdef DEBUG
346 	printf("cdrPadding with %i bytes\n", outCount);
347 #endif
348 
349 	while (outCount > 0) {
350 		d = write(fd, extend, 1);
351 		outCount-=1;
352 	}
353 }
354 #endif
355 
356 #ifdef MASTERING_WAV
357 /*
358  * This was taken from SLabIO, with many thanks to Toby Shepard. He in turn
359  * took it from Michael Beck - beck@informatik.hu-berlin.de - thanks Michael.
360  * Minor changes for audioDev support. Funny how code goes around.....
361  */
362 static void
writeWaveHdr(duplexDev * audioDev,int fd,int count)363 writeWaveHdr(duplexDev *audioDev, int fd, int count)
364 {
365 	if (audioDev->cflags & SLAB_AUDIODBG)
366 		printf("writeWavHdr(%i, %i, %i): %i, %i\n", audioDev->devID, fd, count,
367 			audioDev->channels, audioDev->writeSampleRate);
368 
369 	if (audioDev->channels == 0)
370 		audioDev->channels = 2;
371 
372 	lseek(fd, (long) 0, SEEK_SET);
373 
374 	header.main_chunk	= RIFF;
375 	header.length		= 36 + count + 8; /* HUH? header is 36 + data + chunk */
376 	header.chunk_type	= WAVE;
377 
378 	header.sub_chunk	= FMT;
379 	header.sc_len		= 16;
380 	header.format		= PCM_CODE;
381 	header.modus		= audioDev->channels;
382 	header.sample_fq	= audioDev->writeSampleRate;
383 	header.byte_p_sec	= header.modus * header.sample_fq;
384 	header.byte_p_spl	= 2;
385 	header.bit_p_spl	= 16;
386 
387 	header.data_chunk	= DATA;
388 	header.data_length	= count / header.modus / header.byte_p_spl;
389 
390 	d = write(fd, &header, 44);
391 }
392 #endif
393 
394 #endif /* MASTERING over whole file */
395 
396