Initial import of the ircii-pana-1.1-final source tree.
git-svn-id: svn://svn.code.sf.net/p/bitchx/code/tags/ircii-pana-1.1-final@1 13b04d17-f746-0410-82c6-800466cd88b0
This commit is contained in:
467
dll/amp/audio.c
Normal file
467
dll/amp/audio.c
Normal file
@@ -0,0 +1,467 @@
|
||||
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
||||
*/
|
||||
|
||||
/* audio.c main amp source file
|
||||
*
|
||||
* Created by: tomislav uzelac Apr 1996
|
||||
* Karl Anders Oygard added the IRIX code, 10 Mar 1997.
|
||||
* Ilkka Karvinen fixed /dev/dsp initialization, 11 Mar 1997.
|
||||
* Lutz Vieweg added the HP/UX code, 14 Mar 1997.
|
||||
* Dan Nelson added FreeBSD modifications, 23 Mar 1997.
|
||||
* Andrew Richards complete reorganisation, new features, 25 Mar 1997
|
||||
* Edouard Lafargue added sajber jukebox support, 12 May 1997
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "irc.h"
|
||||
#include "struct.h"
|
||||
#include "ircaux.h"
|
||||
#include "input.h"
|
||||
#include "module.h"
|
||||
#include "hook.h"
|
||||
#define INIT_MODULE
|
||||
#include "modval.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifndef __BEOS__
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "amp.h"
|
||||
#define AUDIO
|
||||
#include "audio.h"
|
||||
#include "getbits.h"
|
||||
#include "huffman.h"
|
||||
#include "layer2.h"
|
||||
#include "layer3.h"
|
||||
#include "position.h"
|
||||
#include "transform.h"
|
||||
#include "misc2.h"
|
||||
|
||||
int bufferpid = 0;
|
||||
unsigned long filesize = 0;
|
||||
unsigned long framesize = 0;
|
||||
|
||||
|
||||
off_t file_size (char *filename)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (!stat(filename, &statbuf))
|
||||
return (off_t)(statbuf.st_size);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void statusDisplay(struct AUDIO_HEADER *header, int frameNo)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
volatile int intflag = 0;
|
||||
|
||||
void (*catchsignal(int signum, void(*handler)()))()
|
||||
{
|
||||
struct sigaction new_sa;
|
||||
struct sigaction old_sa;
|
||||
|
||||
new_sa.sa_handler = handler;
|
||||
sigemptyset(&new_sa.sa_mask);
|
||||
new_sa.sa_flags = 0;
|
||||
if (sigaction(signum, &new_sa, &old_sa) == -1)
|
||||
return ((void (*)()) -1);
|
||||
return (old_sa.sa_handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
int decodeMPEG(struct AUDIO_HEADER *header)
|
||||
{
|
||||
int cnt, g, snd_eof;
|
||||
|
||||
/*
|
||||
* decoder loop **********************************
|
||||
*/
|
||||
snd_eof=0;
|
||||
cnt=0;
|
||||
|
||||
while (!snd_eof)
|
||||
{
|
||||
while (!snd_eof && ready_audio())
|
||||
{
|
||||
if ((g=gethdr(header))!=0)
|
||||
{
|
||||
report_header_error(g);
|
||||
snd_eof=1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (header->protection_bit==0)
|
||||
getcrc();
|
||||
|
||||
#if 0
|
||||
statusDisplay(header,cnt);
|
||||
#endif
|
||||
if (header->layer==1)
|
||||
{
|
||||
if (layer3_frame(header,cnt))
|
||||
{
|
||||
yell(" error. blip.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (header->layer==2)
|
||||
{
|
||||
if (layer2_frame(header,cnt))
|
||||
{
|
||||
yell(" error. blip.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
BUILT_IN_DLL(mp3_volume)
|
||||
{
|
||||
char *vol;
|
||||
if ((vol = next_arg(args, &args)))
|
||||
{
|
||||
int volume = 0;
|
||||
volume = my_atol(vol);
|
||||
if (volume > 0 && volume <= 100)
|
||||
{
|
||||
audioSetVolume(volume);
|
||||
bitchsay("Volume is now set to %d", volume);
|
||||
}
|
||||
else
|
||||
bitchsay("Volume is between 0 and 100");
|
||||
}
|
||||
else
|
||||
bitchsay("/mp3vol [1-100]");
|
||||
}
|
||||
|
||||
BUILT_IN_DLL(mp3_play)
|
||||
{
|
||||
if (args && *args)
|
||||
{
|
||||
if (!fork())
|
||||
{
|
||||
play(args);
|
||||
update_input(UPDATE_ALL);
|
||||
_exit(1);
|
||||
}
|
||||
update_input(UPDATE_ALL);
|
||||
}
|
||||
else
|
||||
bitchsay("/mp3 filename");
|
||||
}
|
||||
|
||||
BUILT_IN_FUNCTION(func_convert_time)
|
||||
{
|
||||
int hours, minutes, seconds;
|
||||
if (!input)
|
||||
return m_strdup(empty_string);
|
||||
seconds = my_atol(input);
|
||||
hours = seconds / ( 60 * 60 );
|
||||
minutes = seconds / 60;
|
||||
seconds = seconds % 60;
|
||||
return m_sprintf("[%02d:%02d:%02d]", hours, minutes, seconds);
|
||||
}
|
||||
|
||||
int Amp_Init(IrcCommandDll **intp, Function_ptr *global_table)
|
||||
{
|
||||
initialize_module("amp");
|
||||
|
||||
initialise_decoder(); /* initialise decoder */
|
||||
A_QUIET = TRUE;
|
||||
AUDIO_BUFFER_SIZE=300*1024;
|
||||
A_SHOW_CNT=FALSE;
|
||||
A_SET_VOLUME=-1;
|
||||
A_SHOW_TIME=0;
|
||||
A_AUDIO_PLAY=TRUE;
|
||||
A_DOWNMIX=FALSE;
|
||||
add_module_proc(COMMAND_PROC, "Amp", "mp3", NULL, 0, 0, mp3_play, NULL);
|
||||
add_module_proc(COMMAND_PROC, "Amp", "mp3vol", NULL, 0, 0, mp3_volume, NULL);
|
||||
add_module_proc(ALIAS_PROC, "Amp", "TIMEDECODE", NULL, 0, 0, func_convert_time, NULL);
|
||||
bitchsay("Amp Module loaded. /mp3 <filename> /mp3vol <L> <R> $timedecode(seconds)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* call this once at the beginning
|
||||
*/
|
||||
void initialise_decoder(void)
|
||||
{
|
||||
premultiply();
|
||||
imdct_init();
|
||||
calculate_t43();
|
||||
}
|
||||
|
||||
/* call this before each file is played
|
||||
*/
|
||||
void initialise_globals(void)
|
||||
{
|
||||
append=data=nch=0;
|
||||
f_bdirty=TRUE;
|
||||
bclean_bytes=0;
|
||||
|
||||
memset(s,0,sizeof s);
|
||||
memset(res,0,sizeof res);
|
||||
}
|
||||
|
||||
void report_header_error(int err)
|
||||
{
|
||||
char *s = NULL;
|
||||
switch (err) {
|
||||
case GETHDR_ERR:
|
||||
s = "error reading mpeg bitstream. exiting.";
|
||||
break;
|
||||
case GETHDR_NS :
|
||||
s = "this is a file in MPEG 2.5 format, which is not defined" \
|
||||
"by ISO/MPEG. It is \"a special Fraunhofer format\"." \
|
||||
"amp does not support this format. sorry.";
|
||||
break;
|
||||
case GETHDR_FL1:
|
||||
s = "ISO/MPEG layer 1 is not supported by amp (yet).";
|
||||
break;
|
||||
case GETHDR_FF :
|
||||
s = "free format bitstreams are not supported. sorry.";
|
||||
break;
|
||||
case GETHDR_SYN:
|
||||
s = "oops, we're out of sync.";
|
||||
break;
|
||||
case GETHDR_EOF:
|
||||
default: ; /* some stupid compilers need the semicolon */
|
||||
}
|
||||
if (s)
|
||||
do_hook(MODULE_LIST, "AMP ERROR blip %s", s);
|
||||
}
|
||||
|
||||
/* TODO: there must be a check here to see if the audio device has been opened
|
||||
* successfuly. This is a bitch because it requires all 6 or 7 OS-specific functions
|
||||
* to be changed. Is anyone willing to do this at all???
|
||||
*/
|
||||
int setup_audio(struct AUDIO_HEADER *header)
|
||||
{
|
||||
if (A_AUDIO_PLAY)
|
||||
{
|
||||
if (AUDIO_BUFFER_SIZE==0)
|
||||
audioOpen(t_sampling_frequency[header->ID][header->sampling_frequency],
|
||||
(header->mode!=3 && !A_DOWNMIX),A_SET_VOLUME);
|
||||
else
|
||||
bufferpid = audioBufferOpen(t_sampling_frequency[header->ID][header->sampling_frequency],
|
||||
(header->mode!=3 && !A_DOWNMIX),A_SET_VOLUME);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void close_audio(void)
|
||||
{
|
||||
if (A_AUDIO_PLAY)
|
||||
{
|
||||
if (AUDIO_BUFFER_SIZE!=0)
|
||||
audioBufferClose();
|
||||
else
|
||||
audioClose();
|
||||
}
|
||||
}
|
||||
|
||||
int ready_audio(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* remove the trailing spaces from a string */
|
||||
static void strunpad(char *str)
|
||||
{
|
||||
int i = strlen(str);
|
||||
|
||||
while ((i > 0) && (str[i-1] == ' '))
|
||||
i--;
|
||||
str[i] = 0;
|
||||
}
|
||||
|
||||
static void print_id3_tag(FILE *fp, char *buf)
|
||||
{
|
||||
struct id3tag {
|
||||
char tag[3];
|
||||
char title[30];
|
||||
char artist[30];
|
||||
char album[30];
|
||||
char year[4];
|
||||
char comment[30];
|
||||
unsigned char genre;
|
||||
};
|
||||
struct idxtag {
|
||||
char tag[3];
|
||||
char title[90];
|
||||
char artist[50];
|
||||
char album[50];
|
||||
char comment[50];
|
||||
};
|
||||
struct id3tag *tag = (struct id3tag *) buf;
|
||||
struct idxtag *xtag = (struct idxtag *) buf;
|
||||
char title[121]="\0";
|
||||
char artist[81]="\0";
|
||||
char album[81]="\0";
|
||||
char year[5]="\0";
|
||||
char comment[81]="\0";
|
||||
|
||||
strncpy(title,tag->title,30);
|
||||
strncpy(artist,tag->artist,30);
|
||||
strncpy(album,tag->album,30);
|
||||
strncpy(year,tag->year,4);
|
||||
strncpy(comment,tag->comment,30);
|
||||
strunpad(title);
|
||||
strunpad(artist);
|
||||
strunpad(album);
|
||||
strunpad(comment);
|
||||
|
||||
if ((fseek(fp, 384, SEEK_END) != -1) && (fread(buf, 256, 1, fp) == 1))
|
||||
{
|
||||
if (!strncmp(buf, "TXG", 3))
|
||||
{
|
||||
strncat(title, xtag->title, 90);
|
||||
strncat(artist, xtag->artist, 50);
|
||||
strncat(album, xtag->album, 50);
|
||||
strncat(comment, xtag->comment, 50);
|
||||
strunpad(title);
|
||||
strunpad(artist);
|
||||
strunpad(album);
|
||||
strunpad(comment);
|
||||
}
|
||||
}
|
||||
if (!do_hook(MODULE_LIST, "AMP ID3 \"%s\" \"%s\" \"%s\" %s %d %s", title, artist, album, year, tag->genre, comment))
|
||||
{
|
||||
bitchsay("Title : %.120s Artist: %s",title, artist);
|
||||
bitchsay("Album : %.80s Year: %4s, Genre: %d",album, year, (int)tag->genre);
|
||||
bitchsay("Comment: %.80s",comment);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* TODO: add some kind of error reporting here
|
||||
*/
|
||||
void play(char *inFileStr)
|
||||
{
|
||||
char *f;
|
||||
long totalframes = 0;
|
||||
long tseconds = 0;
|
||||
struct AUDIO_HEADER header;
|
||||
int bitrate, fs, g, cnt = 0;
|
||||
|
||||
while ((f = new_next_arg(inFileStr, &inFileStr)))
|
||||
{
|
||||
if (!f || !*f)
|
||||
return;
|
||||
if ((in_file=fopen(f,"r"))==NULL)
|
||||
{
|
||||
if (!do_hook(MODULE_LIST, "AMP ERROR open %s", f))
|
||||
put_it("Could not open file: %s\n", f);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
filesize = file_size(f);
|
||||
initialise_globals();
|
||||
|
||||
if ((g=gethdr(&header))!=0)
|
||||
{
|
||||
report_header_error(g);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (header.protection_bit==0)
|
||||
getcrc();
|
||||
|
||||
if (setup_audio(&header)!=0)
|
||||
{
|
||||
yell("Cannot set up audio. Exiting");
|
||||
continue;
|
||||
}
|
||||
|
||||
filesize -= sizeof(header);
|
||||
|
||||
switch (header.layer)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if (layer3_frame(&header,cnt))
|
||||
{
|
||||
yell(" error. blip.");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if (layer2_frame(&header,cnt))
|
||||
{
|
||||
yell(" error. blip.");
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
bitrate=t_bitrate[header.ID][3-header.layer][header.bitrate_index];
|
||||
fs=t_sampling_frequency[header.ID][header.sampling_frequency];
|
||||
|
||||
if (header.ID)
|
||||
framesize=144000*bitrate/fs;
|
||||
else
|
||||
framesize=72000*bitrate/fs;
|
||||
|
||||
|
||||
|
||||
totalframes = (filesize / (framesize + 1)) - 1;
|
||||
tseconds = (totalframes * 1152/
|
||||
t_sampling_frequency[header.ID][header.sampling_frequency]);
|
||||
|
||||
if (A_AUDIO_PLAY)
|
||||
{
|
||||
char *p = strrchr(f, '/');
|
||||
if (!p) p = f; else p++;
|
||||
if (!do_hook(MODULE_LIST, "AMP PLAY %lu %lu %s", tseconds, filesize, p))
|
||||
bitchsay("Playing: %s\n", p);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
if (!(fseek(in_file, 0, SEEK_END)))
|
||||
{
|
||||
char id3_tag[256];
|
||||
if (!fseek(in_file, -128, SEEK_END) && (fread(id3_tag,128, 1, in_file) == 1))
|
||||
{
|
||||
if (!strncmp(id3_tag, "TAG", 3))
|
||||
print_id3_tag(in_file, id3_tag);
|
||||
}
|
||||
fseek(in_file,0,SEEK_SET);
|
||||
}
|
||||
decodeMPEG(&header);
|
||||
do_hook(MODULE_LIST, "AMP CLOSE %s", f);
|
||||
close_audio();
|
||||
fclose(in_file);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user