1 /* this file is a part of amp software, (C) tomislav uzelac 1996,1997
2 */
3
4 /* audio.c main amp source file
5 *
6 * Created by: tomislav uzelac Apr 1996
7 * Karl Anders Oygard added the IRIX code, 10 Mar 1997.
8 * Ilkka Karvinen fixed /dev/dsp initialization, 11 Mar 1997.
9 * Lutz Vieweg added the HP/UX code, 14 Mar 1997.
10 * Dan Nelson added FreeBSD modifications, 23 Mar 1997.
11 * Andrew Richards complete reorganisation, new features, 25 Mar 1997
12 * Edouard Lafargue added sajber jukebox support, 12 May 1997
13 */
14
15
16
17 #include "irc.h"
18 #include "struct.h"
19 #include "ircaux.h"
20 #include "input.h"
21 #include "module.h"
22 #include "hook.h"
23 #define INIT_MODULE
24 #include "modval.h"
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <sys/signal.h>
29 #include <sys/time.h>
30
31 #ifndef __BEOS__
32 #include <sys/uio.h>
33 #endif
34
35 #include <sys/socket.h>
36 #include <errno.h>
37 #include <stdio.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <string.h>
41
42 #include "amp.h"
43 #define AUDIO
44 #include "audio.h"
45 #include "getbits.h"
46 #include "huffman.h"
47 #include "layer2.h"
48 #include "layer3.h"
49 #include "position.h"
50 #include "transform.h"
51 #include "misc2.h"
52
53 int bufferpid = 0;
54 unsigned long filesize = 0;
55 unsigned long framesize = 0;
56
57
file_size(char * filename)58 off_t file_size (char *filename)
59 {
60 struct stat statbuf;
61
62 if (!stat(filename, &statbuf))
63 return (off_t)(statbuf.st_size);
64 else
65 return -1;
66 }
67
68 #if 0
69 void statusDisplay(struct AUDIO_HEADER *header, int frameNo)
70 {
71 return;
72 }
73
74 volatile int intflag = 0;
75
76 void (*catchsignal(int signum, void(*handler)()))()
77 {
78 struct sigaction new_sa;
79 struct sigaction old_sa;
80
81 new_sa.sa_handler = handler;
82 sigemptyset(&new_sa.sa_mask);
83 new_sa.sa_flags = 0;
84 if (sigaction(signum, &new_sa, &old_sa) == -1)
85 return ((void (*)()) -1);
86 return (old_sa.sa_handler);
87 }
88 #endif
89
decodeMPEG(struct AUDIO_HEADER * header)90 int decodeMPEG(struct AUDIO_HEADER *header)
91 {
92 int cnt, g, snd_eof;
93
94 /*
95 * decoder loop **********************************
96 */
97 snd_eof=0;
98 cnt=0;
99
100 while (!snd_eof)
101 {
102 while (!snd_eof && ready_audio())
103 {
104 if ((g=gethdr(header))!=0)
105 {
106 report_header_error(g);
107 snd_eof=1;
108 break;
109 }
110
111 if (header->protection_bit==0)
112 getcrc();
113
114 #if 0
115 statusDisplay(header,cnt);
116 #endif
117 if (header->layer==1)
118 {
119 if (layer3_frame(header,cnt))
120 {
121 yell(" error. blip.");
122 return -1;
123 }
124 }
125 else if (header->layer==2)
126 {
127 if (layer2_frame(header,cnt))
128 {
129 yell(" error. blip.");
130 return -1;
131 }
132 }
133 cnt++;
134 }
135 }
136 return 0;
137 }
138
139
BUILT_IN_DLL(mp3_volume)140 BUILT_IN_DLL(mp3_volume)
141 {
142 char *vol;
143 if ((vol = next_arg(args, &args)))
144 {
145 int volume = 0;
146 volume = my_atol(vol);
147 if (volume > 0 && volume <= 100)
148 {
149 audioSetVolume(volume);
150 bitchsay("Volume is now set to %d", volume);
151 }
152 else
153 bitchsay("Volume is between 0 and 100");
154 }
155 else
156 bitchsay("/mp3vol [1-100]");
157 }
158
BUILT_IN_DLL(mp3_play)159 BUILT_IN_DLL(mp3_play)
160 {
161 if (args && *args)
162 {
163 if (!fork())
164 {
165 play(args);
166 update_input(UPDATE_ALL);
167 _exit(1);
168 }
169 update_input(UPDATE_ALL);
170 }
171 else
172 bitchsay("/mp3 filename");
173 }
174
BUILT_IN_FUNCTION(func_convert_time)175 BUILT_IN_FUNCTION(func_convert_time)
176 {
177 int hours, minutes, seconds;
178 if (!input)
179 return m_strdup(empty_string);
180 seconds = my_atol(input);
181 hours = seconds / ( 60 * 60 );
182 minutes = seconds / 60;
183 seconds = seconds % 60;
184 return m_sprintf("[%02d:%02d:%02d]", hours, minutes, seconds);
185 }
186
Amp_Init(IrcCommandDll ** intp,Function_ptr * global_table)187 int Amp_Init(IrcCommandDll **intp, Function_ptr *global_table)
188 {
189 initialize_module("amp");
190
191 initialise_decoder(); /* initialise decoder */
192 A_QUIET = TRUE;
193 AUDIO_BUFFER_SIZE=300*1024;
194 A_SHOW_CNT=FALSE;
195 A_SET_VOLUME=-1;
196 A_SHOW_TIME=0;
197 A_AUDIO_PLAY=TRUE;
198 A_DOWNMIX=FALSE;
199 add_module_proc(COMMAND_PROC, "Amp", "mp3", NULL, 0, 0, mp3_play, NULL);
200 add_module_proc(COMMAND_PROC, "Amp", "mp3vol", NULL, 0, 0, mp3_volume, NULL);
201 add_module_proc(ALIAS_PROC, "Amp", "TIMEDECODE", NULL, 0, 0, func_convert_time, NULL);
202 bitchsay("Amp Module loaded. /mp3 <filename> /mp3vol <L> <R> $timedecode(seconds)");
203 return 0;
204 }
205
206 /* call this once at the beginning
207 */
initialise_decoder(void)208 void initialise_decoder(void)
209 {
210 premultiply();
211 imdct_init();
212 calculate_t43();
213 }
214
215 /* call this before each file is played
216 */
initialise_globals(void)217 void initialise_globals(void)
218 {
219 append=data=nch=0;
220 f_bdirty=TRUE;
221 bclean_bytes=0;
222
223 memset(s,0,sizeof s);
224 memset(res,0,sizeof res);
225 }
226
report_header_error(int err)227 void report_header_error(int err)
228 {
229 char *s = NULL;
230 switch (err) {
231 case GETHDR_ERR:
232 s = "error reading mpeg bitstream. exiting.";
233 break;
234 case GETHDR_NS :
235 s = "this is a file in MPEG 2.5 format, which is not defined" \
236 "by ISO/MPEG. It is \"a special Fraunhofer format\"." \
237 "amp does not support this format. sorry.";
238 break;
239 case GETHDR_FL1:
240 s = "ISO/MPEG layer 1 is not supported by amp (yet).";
241 break;
242 case GETHDR_FF :
243 s = "free format bitstreams are not supported. sorry.";
244 break;
245 case GETHDR_SYN:
246 s = "oops, we're out of sync.";
247 break;
248 case GETHDR_EOF:
249 default: ; /* some stupid compilers need the semicolon */
250 }
251 if (s)
252 do_hook(MODULE_LIST, "AMP ERROR blip %s", s);
253 }
254
255 /* TODO: there must be a check here to see if the audio device has been opened
256 * successfuly. This is a bitch because it requires all 6 or 7 OS-specific functions
257 * to be changed. Is anyone willing to do this at all???
258 */
setup_audio(struct AUDIO_HEADER * header)259 int setup_audio(struct AUDIO_HEADER *header)
260 {
261 if (A_AUDIO_PLAY)
262 {
263 if (AUDIO_BUFFER_SIZE==0)
264 audioOpen(t_sampling_frequency[header->ID][header->sampling_frequency],
265 (header->mode!=3 && !A_DOWNMIX),A_SET_VOLUME);
266 else
267 bufferpid = audioBufferOpen(t_sampling_frequency[header->ID][header->sampling_frequency],
268 (header->mode!=3 && !A_DOWNMIX),A_SET_VOLUME);
269 }
270 return 0;
271 }
272
close_audio(void)273 void close_audio(void)
274 {
275 if (A_AUDIO_PLAY)
276 {
277 if (AUDIO_BUFFER_SIZE!=0)
278 audioBufferClose();
279 else
280 audioClose();
281 }
282 }
283
ready_audio(void)284 int ready_audio(void)
285 {
286 return 1;
287 }
288
289 /* remove the trailing spaces from a string */
strunpad(char * str)290 static void strunpad(char *str)
291 {
292 int i = strlen(str);
293
294 while ((i > 0) && (str[i-1] == ' '))
295 i--;
296 str[i] = 0;
297 }
298
print_id3_tag(FILE * fp,char * buf)299 static void print_id3_tag(FILE *fp, char *buf)
300 {
301 struct id3tag {
302 char tag[3];
303 char title[30];
304 char artist[30];
305 char album[30];
306 char year[4];
307 char comment[30];
308 unsigned char genre;
309 };
310 struct idxtag {
311 char tag[3];
312 char title[90];
313 char artist[50];
314 char album[50];
315 char comment[50];
316 };
317 struct id3tag *tag = (struct id3tag *) buf;
318 struct idxtag *xtag = (struct idxtag *) buf;
319 char title[121]="\0";
320 char artist[81]="\0";
321 char album[81]="\0";
322 char year[5]="\0";
323 char comment[81]="\0";
324
325 strncpy(title,tag->title,30);
326 strncpy(artist,tag->artist,30);
327 strncpy(album,tag->album,30);
328 strncpy(year,tag->year,4);
329 strncpy(comment,tag->comment,30);
330 strunpad(title);
331 strunpad(artist);
332 strunpad(album);
333 strunpad(comment);
334
335 if ((fseek(fp, 384, SEEK_END) != -1) && (fread(buf, 256, 1, fp) == 1))
336 {
337 if (!strncmp(buf, "TXG", 3))
338 {
339 strncat(title, xtag->title, 90);
340 strncat(artist, xtag->artist, 50);
341 strncat(album, xtag->album, 50);
342 strncat(comment, xtag->comment, 50);
343 strunpad(title);
344 strunpad(artist);
345 strunpad(album);
346 strunpad(comment);
347 }
348 }
349 if (!do_hook(MODULE_LIST, "AMP ID3 \"%s\" \"%s\" \"%s\" %s %d %s", title, artist, album, year, tag->genre, comment))
350 {
351 bitchsay("Title : %.120s Artist: %s",title, artist);
352 bitchsay("Album : %.80s Year: %4s, Genre: %d",album, year, (int)tag->genre);
353 bitchsay("Comment: %.80s",comment);
354 }
355 }
356
357
358 /*
359 * TODO: add some kind of error reporting here
360 */
play(char * inFileStr)361 void play(char *inFileStr)
362 {
363 char *f;
364 long totalframes = 0;
365 long tseconds = 0;
366 struct AUDIO_HEADER header;
367 int bitrate, fs, g, cnt = 0;
368
369 while ((f = new_next_arg(inFileStr, &inFileStr)))
370 {
371 if (!f || !*f)
372 return;
373 if ((in_file=fopen(f,"r"))==NULL)
374 {
375 if (!do_hook(MODULE_LIST, "AMP ERROR open %s", f))
376 put_it("Could not open file: %s\n", f);
377 continue;
378 }
379
380
381
382 filesize = file_size(f);
383 initialise_globals();
384
385 if ((g=gethdr(&header))!=0)
386 {
387 report_header_error(g);
388 continue;
389 }
390
391 if (header.protection_bit==0)
392 getcrc();
393
394 if (setup_audio(&header)!=0)
395 {
396 yell("Cannot set up audio. Exiting");
397 continue;
398 }
399
400 filesize -= sizeof(header);
401
402 switch (header.layer)
403 {
404 case 1:
405 {
406 if (layer3_frame(&header,cnt))
407 {
408 yell(" error. blip.");
409 continue;
410 }
411 break;
412 }
413 case 2:
414 {
415 if (layer2_frame(&header,cnt))
416 {
417 yell(" error. blip.");
418 continue;
419 }
420 break;
421 }
422 default:
423 continue;
424 }
425
426 bitrate=t_bitrate[header.ID][3-header.layer][header.bitrate_index];
427 fs=t_sampling_frequency[header.ID][header.sampling_frequency];
428
429 if (header.ID)
430 framesize=144000*bitrate/fs;
431 else
432 framesize=72000*bitrate/fs;
433
434
435
436 totalframes = (filesize / (framesize + 1)) - 1;
437 tseconds = (totalframes * 1152/
438 t_sampling_frequency[header.ID][header.sampling_frequency]);
439
440 if (A_AUDIO_PLAY)
441 {
442 char *p = strrchr(f, '/');
443 if (!p) p = f; else p++;
444 if (!do_hook(MODULE_LIST, "AMP PLAY %lu %lu %s", tseconds, filesize, p))
445 bitchsay("Playing: %s\n", p);
446 }
447
448 /*
449 *
450 */
451 if (!(fseek(in_file, 0, SEEK_END)))
452 {
453 char id3_tag[256];
454 if (!fseek(in_file, -128, SEEK_END) && (fread(id3_tag,128, 1, in_file) == 1))
455 {
456 if (!strncmp(id3_tag, "TAG", 3))
457 print_id3_tag(in_file, id3_tag);
458 }
459 fseek(in_file,0,SEEK_SET);
460 }
461 decodeMPEG(&header);
462 do_hook(MODULE_LIST, "AMP CLOSE %s", f);
463 close_audio();
464 fclose(in_file);
465 }
466 }
467
468