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