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