Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
BitchX
GitHub Repository: BitchX/BitchX1.3
Path: blob/master/dll/amp/audio.c
1074 views
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
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
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
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
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
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
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
*/
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
*/
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
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
*/
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
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
284
int ready_audio(void)
285
{
286
return 1;
287
}
288
289
/* remove the trailing spaces from a string */
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
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
*/
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
469