Commit c8470102 authored by Miller Puckette's avatar Miller Puckette
Browse files

first cut at callback scheduler

parent 85a56dd9
......@@ -15,7 +15,8 @@
#define THREAD_LOCKING
#include "pthread.h"
#define SYS_QUIT_QUIT 1
#define SYS_QUIT_RESTART 2
static int sys_quit;
double sys_time;
static double sys_time_per_msec = TIMEUNITPERSEC / 1000.;
......@@ -326,14 +327,14 @@ void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
void dsp_tick(void);
static int sched_usedacs = 1;
static int sched_useaudio = SCHED_AUDIO_POLL;
static double sched_referencerealtime, sched_referencelogicaltime;
double sys_time_per_dsp_tick;
void sched_set_using_dacs(int flag)
void sched_set_using_audio(int flag)
{
sched_usedacs = flag;
if (!flag)
sched_useaudio = flag;
if (flag == SCHED_AUDIO_NONE)
{
sched_referencerealtime = sys_getrealtime();
sched_referencelogicaltime = clock_getlogicaltime();
......@@ -385,7 +386,7 @@ nonzero if you actually used the time; otherwise we're really really idle and
will now sleep. */
int (*sys_idlehook)(void);
int m_scheduler( void)
static void m_pollingscheduler( void)
{
int idlecount = 0;
sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
......@@ -410,7 +411,7 @@ int m_scheduler( void)
sys_addhist(0);
waitfortick:
if (sched_usedacs)
if (sched_useaudio != SCHED_AUDIO_NONE)
{
#ifdef THREAD_LOCKING
/* T.Grill - send_dacs may sleep ->
......@@ -441,7 +442,7 @@ int m_scheduler( void)
{
post("audio I/O stuck... closing audio\n");
sys_close_audio();
sched_set_using_dacs(0);
sched_set_using_audio(SCHED_AUDIO_NONE);
goto waitfortick;
}
}
......@@ -475,7 +476,6 @@ int m_scheduler( void)
{
sched_pollformeters();
sys_reportidle();
#ifdef THREAD_LOCKING
sys_unlock(); /* unlock while we idle */
#endif
......@@ -489,20 +489,52 @@ int m_scheduler( void)
#ifdef THREAD_LOCKING
sys_lock();
#endif
sys_addhist(5);
sched_didnothing++;
}
}
#ifdef THREAD_LOCKING
sys_unlock();
#endif
}
return (0);
void sched_audio_callbackfn(void)
{
sys_setmiditimediff(0, 1e-6 * sys_schedadvance);
sys_addhist(1);
sched_tick(sys_time + sys_time_per_dsp_tick);
sys_addhist(2);
sys_pollmidiqueue();
sys_addhist(3);
sys_pollgui();
sys_addhist(5);
sched_pollformeters();
sys_addhist(0);
}
static void m_callbackscheduler(void)
{
sys_initmidiqueue();
while (1)
{
sleep(1);
if (sys_idlehook)
sys_idlehook();
}
}
int m_mainloop(void)
{
while (sys_quit != SYS_QUIT_QUIT)
{
post("sched %d", sched_useaudio);
if (sched_useaudio == SCHED_AUDIO_CALLBACK)
m_callbackscheduler();
else m_pollingscheduler();
}
return (0);
}
/* ------------ thread locking ------------------- */
......@@ -534,5 +566,5 @@ int sys_trylock(void) {}
void sys_exit(void)
{
sys_quit = 1;
sys_quit = SYS_QUIT_QUIT;
}
......@@ -67,7 +67,7 @@ static int audio_rate;
static int audio_advance;
static int audio_callback;
void sched_set_callback(int flag);
void sched_audio_callbackfn(void);
static int audio_isopen(void)
{
......@@ -170,14 +170,14 @@ void sys_setchsr(int chin, int chout, int sr)
/* ----------------------- public routines ----------------------- */
/* open audio devices (after cleaning up the specified device and channel
vectors). The audio devices are "zero based" (i.e. "0" means the first
one.) We also save the cleaned-up device specification so that we
can later re-open audio and/or show the settings on a dialog window. */
/* set audio device settings (after cleaning up the specified device and
channel vectors). The audio devices are "zero based" (i.e. "0" means the
first one.) We can later re-open audio and/or show the settings on a\
dialog window. */
void sys_open_audio(int naudioindev, int *audioindev, int nchindev,
void sys_set_audio_settings(int naudioindev, int *audioindev, int nchindev,
int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
int *choutdev, int rate, int advance, int callback, int enable)
int *choutdev, int rate, int advance, int callback)
{
int i, *ip;
int defaultchannels = SYS_DEFAULTCH;
......@@ -189,7 +189,6 @@ void sys_open_audio(int naudioindev, int *audioindev, int nchindev,
int indevs = 0, outdevs = 0, canmulti = 0, cancallback = 0;
audio_getdevs(indevlist, &indevs, outdevlist, &outdevs, &canmulti,
&cancallback, MAXNDEV, DEVDESCSIZE);
if (sys_externalschedlib)
{
return;
......@@ -324,62 +323,11 @@ void sys_open_audio(int naudioindev, int *audioindev, int nchindev,
outchans += choutdev[i];
nrealoutdev++;
}
/* if no input or output devices seem to have been specified,
this really means just disable audio, which we now do. */
if (!inchans && !outchans)
enable = 0;
sys_schedadvance = advance * 1000;
sys_setchsr(inchans, outchans, rate);
sys_log_error(ERR_NOTHING);
if (enable)
{
#ifdef USEAPI_PORTAUDIO
if (sys_audioapi == API_PORTAUDIO)
{
int blksize = (sys_blocksize ? sys_blocksize : 64);
pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout,
blksize, sys_advance_samples/blksize, callback,
(naudiooutdev > 0 ? audioindev[0] : 0),
(naudiooutdev > 0 ? audiooutdev[0] : 0));
}
else
#endif
#ifdef USEAPI_JACK
if (sys_audioapi == API_JACK)
jack_open_audio((nrealindev > 0 ? realinchans[0] : 0),
(nrealoutdev > 0 ? realoutchans[0] : 0), rate);
else
#endif
#ifdef USEAPI_OSS
if (sys_audioapi == API_OSS)
oss_open_audio(nrealindev, realindev, nrealindev, realinchans,
nrealoutdev, realoutdev, nrealoutdev, realoutchans, rate);
else
#endif
#ifdef USEAPI_ALSA
/* for alsa, only one device is supported; it may
be open for both input and output. */
if (sys_audioapi == API_ALSA)
alsa_open_audio(nrealindev, audioindev, nrealindev, realinchans,
nrealoutdev, audiooutdev, nrealoutdev, realoutchans, rate);
else
#endif
#ifdef USEAPI_MMIO
if (sys_audioapi == API_MMIO)
mmio_open_audio(nrealindev, audioindev, nrealindev, realinchans,
nrealoutdev, audiooutdev, nrealoutdev, realoutchans, rate);
else
#endif
post("unknown audio API specified");
}
sys_save_audio_params(naudioindev, audioindev, chindev,
naudiooutdev, audiooutdev, choutdev, sys_dacsr, advance, callback);
if (sys_inchannels == 0 && sys_outchannels == 0)
enable = 0;
audio_state = enable;
sys_vgui("set pd_whichapi %d\n", (audio_isopen() ? sys_audioapi : 0));
sched_set_using_dacs(enable);
sys_save_audio_params(nrealindev, realindev, realinchans,
nrealoutdev, realoutdev, realoutchans, sys_dacsr, advance, callback);
}
void sys_close_audio(void)
......@@ -417,6 +365,7 @@ void sys_close_audio(void)
#endif
post("sys_close_audio: unknown API %d", sys_audioapi);
sys_inchannels = sys_outchannels = 0;
sched_set_using_audio(SCHED_AUDIO_NONE);
}
/* open audio using whatever parameters were last used */
......@@ -424,12 +373,67 @@ void sys_reopen_audio( void)
{
int naudioindev, audioindev[MAXAUDIOINDEV], chindev[MAXAUDIOINDEV];
int naudiooutdev, audiooutdev[MAXAUDIOOUTDEV], choutdev[MAXAUDIOOUTDEV];
int rate, advance, callback;
int rate, advance, callback, outcome = 0;
sys_get_audio_params(&naudioindev, audioindev, chindev,
&naudiooutdev, audiooutdev, choutdev, &rate, &advance, &callback);
sys_open_audio(naudioindev, audioindev, naudioindev, chindev,
naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance,
callback, 1);
if (!naudioindev && !naudiooutdev)
{
sched_set_using_audio(SCHED_AUDIO_NONE);
return;
}
#ifdef USEAPI_PORTAUDIO
if (sys_audioapi == API_PORTAUDIO)
{
int blksize = (sys_blocksize ? sys_blocksize : 64);
outcome = pa_open_audio((naudioindev > 0 ? chindev[0] : 0),
(naudiooutdev > 0 ? choutdev[0] : 0), rate, sys_soundin,
sys_soundout, blksize, sys_advance_samples/blksize,
(naudioindev > 0 ? audioindev[0] : 0),
(naudiooutdev > 0 ? audiooutdev[0] : 0),
(callback ? sched_audio_callbackfn : 0));
}
else
#endif
#ifdef USEAPI_JACK
if (sys_audioapi == API_JACK)
outcome = jack_open_audio((naudioindev > 0 ? chindev[0] : 0),
(naudioindev > 0 ? choutdev[0] : 0), rate);
else
#endif
#ifdef USEAPI_OSS
if (sys_audioapi == API_OSS)
outcome = oss_open_audio(naudioindev, audioindev, naudioindev,
chindev, naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate);
else
#endif
#ifdef USEAPI_ALSA
/* for alsa, only one device is supported; it may
be open for both input and output. */
if (sys_audioapi == API_ALSA)
outcome = alsa_open_audio(naudioindev, audioindev, naudioindev,
chindev, naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate);
else
#endif
#ifdef USEAPI_MMIO
if (sys_audioapi == API_MMIO)
outcome = mmio_open_audio(naudioindev, audioindev, naudioindev,
chindev, naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate);
else
#endif
post("unknown audio API specified");
if (outcome) /* failed */
{
audio_state = 0;
sched_set_using_audio(SCHED_AUDIO_NONE);
}
else
{
audio_state = 1;
sched_set_using_audio(
(callback ? SCHED_AUDIO_CALLBACK : SCHED_AUDIO_POLL));
}
sys_vgui("set pd_whichapi %d\n", (outcome == 0 ? sys_audioapi : 0));
}
int sys_send_dacs(void)
......@@ -727,9 +731,10 @@ void glob_audio_dialog(t_pd *dummy, t_symbol *s, int argc, t_atom *argv)
}
sys_close_audio();
sys_open_audio(nindev, newaudioindev, nindev, newaudioinchan,
sys_set_audio_settings(nindev, newaudioindev, nindev, newaudioinchan,
noutdev, newaudiooutdev, noutdev, newaudiooutchan,
newrate, newadvance, newcallback, 1);
newrate, newadvance, newcallback);
sys_reopen_audio();
}
void sys_listdevs(void )
......@@ -807,7 +812,6 @@ void glob_audio_setapi(void *dummy, t_floatarg f)
{
sys_close_audio();
audio_state = 0;
sched_set_using_dacs(0);
}
}
......@@ -822,10 +826,7 @@ void sys_set_audio_state(int onoff)
else
{
if (audio_isopen())
{
sys_close_audio();
sched_set_using_dacs(0);
}
}
audio_state = onoff;
}
......
......@@ -23,19 +23,133 @@
static PABLIO_Stream *pa_stream;
static int pa_inchans, pa_outchans;
static float *pa_soundin, *pa_soundout;
static t_audiocallback pa_callback;
#define MAX_PA_CHANS 32
#define MAX_SAMPLES_PER_FRAME MAX_PA_CHANS * DEFDACBLKSIZE
static int pa_lowlevel_callback(const void *inputBuffer,
void *outputBuffer, unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo *outTime, PaStreamCallbackFlags myflags,
void *userData)
{
int i;
unsigned int j;
float *fbuf, *fp2, *fp3, *soundiop;
if (inputBuffer != NULL)
{
fbuf = (float *)inputBuffer;
soundiop = pa_soundin;
for (i = 0, fp2 = fbuf; i < pa_inchans; i++, fp2++)
for (j = 0, fp3 = fp2; j < framesPerBuffer; j++, fp3 += pa_inchans)
*soundiop++ = *fp3;
}
else memset((void *)pa_soundin, 0,
framesPerBuffer * pa_inchans * sizeof(float));
(*pa_callback)();
if (outputBuffer != NULL)
{
fbuf = (float *)outputBuffer;
soundiop = pa_soundout;
for (i = 0, fp2 = fbuf; i < pa_inchans; i++, fp2++)
for (j = 0, fp3 = fp2; j < framesPerBuffer; j++, fp3 += pa_inchans)
*fp3 = *soundiop;
}
return 0;
}
PaError pa_open_callback(double sampleRate, int inchannels, int outchannels,
int framesperbuf, int nbuffers, int indeviceno, int outdeviceno)
{
long bytesPerSample;
PaError err;
PABLIO_Stream *pastream;
long numFrames;
PaStreamParameters instreamparams, outstreamparams;
if (indeviceno < 0)
{
indeviceno = Pa_GetDefaultInputDevice();
fprintf(stderr, "using default input device number: %d\n", indeviceno);
}
if (outdeviceno < 0)
{
outdeviceno = Pa_GetDefaultOutputDevice();
fprintf(stderr, "using default output device number: %d\n", outdeviceno);
}
/* fprintf(stderr, "nchan %d, flags %d, bufs %d, framesperbuf %d\n",
nchannels, flags, nbuffers, framesperbuf); */
/* Allocate PABLIO_Stream structure for caller. */
pastream = (PABLIO_Stream *)malloc( sizeof(PABLIO_Stream));
if (pastream == NULL)
return (1);
memset(pastream, 0, sizeof(PABLIO_Stream));
/* Determine size of a sample. */
bytesPerSample = Pa_GetSampleSize(paFloat32);
if (bytesPerSample < 0)
{
err = (PaError) bytesPerSample;
goto error;
}
pastream->insamplesPerFrame = inchannels;
pastream->inbytesPerFrame = bytesPerSample * pastream->insamplesPerFrame;
pastream->outsamplesPerFrame = outchannels;
pastream->outbytesPerFrame = bytesPerSample * pastream->outsamplesPerFrame;
numFrames = nbuffers * framesperbuf;
instreamparams.device = indeviceno;
instreamparams.channelCount = inchannels;
instreamparams.sampleFormat = paFloat32;
instreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
instreamparams.hostApiSpecificStreamInfo = 0;
outstreamparams.device = outdeviceno;
outstreamparams.channelCount = outchannels;
outstreamparams.sampleFormat = paFloat32;
outstreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
outstreamparams.hostApiSpecificStreamInfo = 0;
err = Pa_OpenStream(
&pastream->stream,
(inchannels ? &instreamparams : 0),
(outchannels ? &outstreamparams : 0),
sampleRate,
framesperbuf,
paNoFlag, /* portaudio will clip for us */
pa_lowlevel_callback,
pastream);
if (err != paNoError)
goto error;
err = Pa_StartStream(pastream->stream);
if (err != paNoError)
{
fprintf(stderr, "Pa_StartStream failed; closing audio stream...\n");
CloseAudioStream( pastream );
goto error;
}
pa_stream = pastream;
return paNoError;
error:
pa_stream = NULL;
return err;
}
int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
t_sample *soundout, int framesperbuf, int nbuffers, int callback,
int indeviceno, int outdeviceno)
t_sample *soundout, int framesperbuf, int nbuffers,
int indeviceno, int outdeviceno, t_audiocallback callbackfn)
{
PaError err;
static int initialized;
int j, devno, pa_indev = 0, pa_outdev = 0;
if (callback)
pa_callback = callbackfn;
if (callbackfn)
fprintf(stderr, "callback enabled\n");
if (!initialized)
{
......@@ -103,26 +217,34 @@ int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
post("output device %d, channels %d", pa_outdev, outchans);
post("framesperbuf %d, nbufs %d", framesperbuf, nbuffers);
}
if (inchans || outchans)
pa_inchans = inchans;
pa_outchans = outchans;
pa_soundin = soundin;
pa_soundout = soundout;
if (! inchans && !outchans)
return(0);
if (callbackfn)
{
pa_callback = callbackfn;
err = pa_open_callback(rate, inchans, outchans,
framesperbuf, nbuffers, pa_indev, pa_outdev);
}
else
{
err = OpenAudioStream( &pa_stream, rate, paFloat32,
inchans, outchans, framesperbuf, nbuffers,
pa_indev, pa_outdev);
else err = 0;
}
if ( err != paNoError )
{
fprintf( stderr, "Error number %d occured opening portaudio stream\n",
fprintf(stderr, "Error number %d opening portaudio stream\n",
err);
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
Pa_Terminate();
sys_inchannels = sys_outchannels = 0;
return (1);
}
else if (sys_verbose)
post("... opened OK.");
pa_inchans = inchans;
pa_outchans = outchans;
pa_soundin = soundin;
pa_soundout = soundout;
return (0);
}
......
......@@ -339,9 +339,9 @@ void sys_loadpreferences( void)
sscanf(prefbuf, "%d", &advance);
if (sys_getpreference("callback", prefbuf, MAXPDSTRING))
sscanf(prefbuf, "%d", &callback);
sys_open_audio(naudioindev, audioindev, naudioindev, chindev,
sys_set_audio_settings(naudioindev, audioindev, naudioindev, chindev,
naudiooutdev, audiooutdev, naudiooutdev, choutdev, rate, advance,
callback, 0);
callback);
/* load MIDI preferences */
/* JMZ/MB: brackets for initializing */
......
......@@ -31,7 +31,7 @@ int sys_argparse(int argc, char **argv);
void sys_findprogdir(char *progname);
int sys_startgui(const char *guipath);
int sys_rcfile(void);
int m_scheduler(void);
int m_mainloop(void);
void sys_addhelppath(char *p);
#ifdef USEAPI_ALSA
void alsa_adddev(char *name);
......@@ -71,7 +71,7 @@ char sys_extraflagsstring[MAXPDSTRING];
/* here the "-1" counts signify that the corresponding vector hasn't been
specified in command line arguments; sys_open_audio will detect this
specified in command line arguments; sys_set_audio_settings will detect it
and fill things in. */
static int sys_nsoundin = -1;
static int sys_nsoundout = -1;
......@@ -314,7 +314,7 @@ int sys_main(int argc, char **argv)
sys_reopen_midi();
sys_reopen_audio();
/* run scheduler until it quits */
return (m_scheduler());
return (m_mainloop());
}
}
......@@ -989,9 +989,9 @@ static void sys_afterargparse(void)
rate = sys_main_srate;
if (sys_main_callback)
callback = sys_main_callback;
sys_open_audio(naudioindev, audioindev, nchindev, chindev,
sys_set_audio_settings(naudioindev, audioindev, nchindev, chindev,
naudiooutdev, audiooutdev, nchoutdev, choutdev, rate, advance,
callback, 0);
callback);
sys_open_midi(nmidiindev, midiindev, nmidioutdev, midioutdev, 0);
}
......
......@@ -71,10 +71,10 @@ extern int sys_blocksize; /* audio I/O block size in sample frames */
extern float sys_dacsr;
extern int sys_schedadvance;
extern int sys_sleepgrain;
void sys_open_audio(int naudioindev, int *audioindev,
void sys_set_audio_settings(int naudioindev, int *audioindev,
int nchindev, int *chindev,
int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
int srate, int advance, int callback, int enable);
int srate, int advance, int callback);
void sys_reopen_audio( void);
void sys_close_audio(void);
......@@ -139,7 +139,11 @@ EXTERN void sys_log_error(int type);
#define ERR_DACSLEPT 2
#define ERR_RESYNC 3
#define ERR_DATALATE 4
void sched_set_using_dacs(int flag);
#define SCHED_AUDIO_NONE 0
#define SCHED_AUDIO_POLL 1
#define SCHED_AUDIO_CALLBACK 2
void sched_set_using_audio(int flag);
/* s_inter.c */
......@@ -205,9 +209,11 @@ void sys_setvirtualalarm( void);
#define DEFAULTADVANCE 50
#endif
typedef void (*t_audiocallback)(vid);
int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
t_sample *soundout, int framesperbuf, int nbuffers, int callback,
int indeviceno, int outdeviceno);
t_sample *soundout, int framesperbuf, int nbuffers,
int indeviceno, int outdeviceno, t_audiocallback callback);
void pa_close_audio(void);
int pa_send_dacs(void);
void sys_reportidle(void);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment