1998-10-02 13:19:44 -04:00
|
|
|
/* openbsd/audio.c
|
|
|
|
vi:ts=3 sw=3:
|
|
|
|
*/
|
2010-06-30 07:50:51 -04:00
|
|
|
/* sndio(7) interface */
|
1998-10-02 13:19:44 -04:00
|
|
|
|
|
|
|
#include "defs.h"
|
|
|
|
#include <unistd.h>
|
|
|
|
#include "extern.h"
|
|
|
|
#include "prefs.h"
|
|
|
|
#include "autoinit.h"
|
|
|
|
#include "watched_var.h"
|
|
|
|
struct options_set *port_options=0;
|
|
|
|
|
|
|
|
#define DEFAULT_BUFFERS
|
|
|
|
#define UNSIGNED8
|
|
|
|
#define DEFAULT_SET_MIX
|
|
|
|
#define NEW_OUTPUT_SAMPLES_AWARE
|
|
|
|
#define NEW_FUNCS
|
|
|
|
|
|
|
|
/* fine-tune to get the scrolling display in sync with the music */
|
2010-06-30 07:50:51 -04:00
|
|
|
#define ADVANCE_TAGS 20000
|
1998-10-02 13:19:44 -04:00
|
|
|
|
|
|
|
#include "Arch/common.c"
|
|
|
|
|
2010-06-30 07:50:51 -04:00
|
|
|
#include <sndio.h>
|
1998-10-02 13:19:44 -04:00
|
|
|
|
|
|
|
LOCAL unsigned long samples_max;
|
2010-06-30 07:50:51 -04:00
|
|
|
LOCAL long long realpos;
|
|
|
|
LOCAL struct sio_hdl *hdl;
|
1998-10-02 13:19:44 -04:00
|
|
|
LOCAL unsigned long current_freq;
|
|
|
|
|
|
|
|
unsigned long total;
|
|
|
|
|
|
|
|
LOCAL int dsp_samplesize = 0;
|
|
|
|
|
2010-06-30 07:50:51 -04:00
|
|
|
static void
|
|
|
|
movecb(void *arg, int delta)
|
|
|
|
{
|
|
|
|
realpos += delta * dsize * (stereo ? 2 : 1);
|
|
|
|
}
|
|
|
|
|
1998-10-02 13:19:44 -04:00
|
|
|
unsigned long open_audio(unsigned long f, int s)
|
|
|
|
{
|
2010-06-30 07:50:51 -04:00
|
|
|
struct sio_par par;
|
1998-10-02 13:19:44 -04:00
|
|
|
int buf_max;
|
|
|
|
|
2010-06-30 07:50:51 -04:00
|
|
|
hdl = sio_open(NULL, SIO_PLAY, 0);
|
|
|
|
if (hdl == NULL)
|
1998-10-02 13:19:44 -04:00
|
|
|
end_all("Error opening audio device");
|
|
|
|
|
2010-06-30 07:50:51 -04:00
|
|
|
realpos = 0;
|
|
|
|
sio_onmove(hdl, movecb, NULL);
|
1998-10-02 13:19:44 -04:00
|
|
|
|
2010-06-30 07:50:51 -04:00
|
|
|
sio_initpar(&par);
|
|
|
|
par.rate = f ? f : 22050;
|
|
|
|
if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par) || !sio_start(hdl) ||
|
|
|
|
(par.bits != 8 && par.bits != 16))
|
|
|
|
end_all("Sorry, no audio format supported by this binary is available");
|
1998-10-02 13:19:44 -04:00
|
|
|
|
2010-06-30 07:50:51 -04:00
|
|
|
buf_max = par.appbufsz * par.bps * par.pchan;
|
|
|
|
current_freq = par.rate;
|
|
|
|
stereo = par.pchan == 2 ? 1 : 0;
|
1998-10-02 13:19:44 -04:00
|
|
|
|
2010-06-30 07:50:51 -04:00
|
|
|
dsp_samplesize = par.bits;
|
|
|
|
dsize = par.bps;
|
|
|
|
buffer = malloc(buf_max);
|
|
|
|
buffer16 = (short *)buffer;
|
1998-10-02 13:19:44 -04:00
|
|
|
|
2010-06-30 07:50:51 -04:00
|
|
|
idx = 0;
|
|
|
|
samples_max = buf_max / dsize / par.pchan;
|
1998-10-02 13:19:44 -04:00
|
|
|
set_watched_scalar(FREQUENCY, current_freq);
|
|
|
|
total = 0;
|
|
|
|
return current_freq;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* synchronize stuff with audio output */
|
|
|
|
LOCAL struct tagged
|
|
|
|
{
|
2010-06-30 07:50:51 -04:00
|
|
|
struct tagged *next; /* simply linked list */
|
1998-10-02 13:19:44 -04:00
|
|
|
void (*f)(GENERIC p); /* function to call */
|
|
|
|
void (*f2)(GENERIC p); /* function to call for flush */
|
2010-06-30 07:50:51 -04:00
|
|
|
GENERIC p; /* and parameter */
|
|
|
|
unsigned long when; /* number of bytes to let go before calling */
|
1998-10-02 13:19:44 -04:00
|
|
|
}
|
|
|
|
*start, /* what still to output */
|
|
|
|
*end; /* where to add new tags */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* flush_tags: use tags that have gone by recently */
|
|
|
|
LOCAL void flush_tags(void)
|
|
|
|
{
|
|
|
|
if (start)
|
|
|
|
{
|
2010-06-30 07:50:51 -04:00
|
|
|
while (start && start->when <= realpos + ADVANCE_TAGS)
|
1998-10-02 13:19:44 -04:00
|
|
|
{
|
|
|
|
struct tagged *tofree;
|
|
|
|
|
|
|
|
(*start->f)(start->p);
|
|
|
|
tofree = start;
|
|
|
|
start = start->next;
|
|
|
|
free(tofree);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove unused tags at end */
|
|
|
|
LOCAL void remove_pending_tags(void)
|
|
|
|
{
|
|
|
|
while (start)
|
|
|
|
{
|
|
|
|
struct tagged *tofree;
|
|
|
|
|
|
|
|
(*start->f2)(start->p);
|
|
|
|
tofree = start;
|
|
|
|
start = start->next;
|
|
|
|
free(tofree);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void sync_audio(void (*function)(void *p), void (*f2)(void *p), void *parameter)
|
|
|
|
{
|
|
|
|
struct tagged *t;
|
|
|
|
|
2010-06-30 07:50:51 -04:00
|
|
|
if (hdl)
|
1998-10-02 13:19:44 -04:00
|
|
|
{
|
|
|
|
t = malloc(sizeof(struct tagged));
|
|
|
|
if (!t)
|
|
|
|
{
|
|
|
|
(*function)(parameter);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/* build new tag */
|
|
|
|
t->next = 0;
|
|
|
|
t->f = function;
|
|
|
|
t->f2 = f2;
|
|
|
|
t->p = parameter;
|
|
|
|
t->when = total;
|
|
|
|
|
|
|
|
/* add it to list */
|
|
|
|
if (start)
|
|
|
|
end->next = t;
|
|
|
|
else
|
|
|
|
start = t;
|
|
|
|
end = t;
|
|
|
|
|
|
|
|
/* set up for next tag */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
(*function)(parameter);
|
|
|
|
}
|
|
|
|
|
|
|
|
LOCAL void actually_flush_buffer(void)
|
|
|
|
{
|
|
|
|
int l,i;
|
|
|
|
|
|
|
|
if (idx)
|
|
|
|
{
|
|
|
|
total += idx * dsize;
|
2010-06-30 07:50:51 -04:00
|
|
|
sio_write(hdl, buffer, dsize * idx);
|
1998-10-02 13:19:44 -04:00
|
|
|
}
|
|
|
|
idx = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void output_samples(long left, long right, int n)
|
|
|
|
{
|
|
|
|
if (idx >= samples_max - 1)
|
|
|
|
actually_flush_buffer();
|
|
|
|
switch(dsp_samplesize)
|
|
|
|
{
|
|
|
|
case 16: /* Cool! 16 bits samples */
|
|
|
|
add_samples16(left, right, n);
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
add_samples8(left, right, n);
|
|
|
|
break;
|
|
|
|
default: /* should not happen */
|
2010-05-17 14:10:05 -04:00
|
|
|
;
|
1998-10-02 13:19:44 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void flush_buffer(void)
|
|
|
|
{
|
|
|
|
actually_flush_buffer();
|
|
|
|
flush_tags();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Closing the Linux sound device waits for all pending samples to play.
|
|
|
|
*/
|
|
|
|
void close_audio(void)
|
|
|
|
{
|
|
|
|
actually_flush_buffer();
|
2010-06-30 07:50:51 -04:00
|
|
|
sio_close(hdl);
|
1998-10-02 13:19:44 -04:00
|
|
|
free(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long update_frequency(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void discard_buffer(void)
|
|
|
|
{
|
|
|
|
remove_pending_tags();
|
|
|
|
total = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void audio_ui(char c)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|