2013-12-12 02:18:36 +01:00
|
|
|
#include <portaudio.h>
|
2013-12-21 09:20:39 +01:00
|
|
|
#include <semaphore.h>
|
|
|
|
#include <julia/julia.h>
|
2013-12-12 02:18:36 +01:00
|
|
|
#include <math.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2013-12-21 09:20:39 +01:00
|
|
|
// some defines we need to include until PR 4997 is merged
|
|
|
|
STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name)
|
|
|
|
{
|
|
|
|
return (jl_function_t*) jl_get_global(m, jl_symbol(name));
|
|
|
|
}
|
|
|
|
|
|
|
|
DLLEXPORT jl_value_t *jl_call2(jl_function_t *f, jl_value_t *a, jl_value_t *b)
|
|
|
|
{
|
|
|
|
jl_value_t *v;
|
|
|
|
JL_TRY {
|
|
|
|
JL_GC_PUSH3(&f,&a,&b);
|
|
|
|
jl_value_t *args[2] = {a,b};
|
|
|
|
v = jl_apply(f, args, 2);
|
|
|
|
JL_GC_POP();
|
|
|
|
}
|
|
|
|
JL_CATCH {
|
|
|
|
v = NULL;
|
|
|
|
}
|
|
|
|
return v;
|
|
|
|
}
|
2013-12-12 02:18:36 +01:00
|
|
|
|
2013-12-21 09:20:39 +01:00
|
|
|
static int paCallback(const void *inputBuffer, void *outputBuffer,
|
2013-12-12 02:18:36 +01:00
|
|
|
unsigned long framesPerBuffer,
|
|
|
|
const PaStreamCallbackTimeInfo* timeInfo,
|
|
|
|
PaStreamCallbackFlags statusFlags,
|
|
|
|
void *userData);
|
|
|
|
|
2013-12-21 09:20:39 +01:00
|
|
|
static PaStream *AudioStream;
|
|
|
|
static jl_value_t *JuliaRemote;
|
|
|
|
static sem_t CSemaphore;
|
|
|
|
static void *OutData = NULL;
|
|
|
|
static unsigned long OutFrames = 0;
|
|
|
|
static jl_function_t *RemotePutFunc = NULL;
|
|
|
|
static jl_value_t *RemotePutArg = NULL;
|
2013-12-12 02:18:36 +01:00
|
|
|
|
|
|
|
|
2013-12-21 09:20:39 +01:00
|
|
|
void wake_callback_thread(void *outData, unsigned int outFrames)
|
|
|
|
{
|
|
|
|
OutData = outData;
|
|
|
|
OutFrames = outFrames;
|
|
|
|
sem_post(&CSemaphore);
|
|
|
|
}
|
|
|
|
|
|
|
|
PaError open_stream(unsigned int sampleRate, unsigned int bufSize,
|
|
|
|
jl_value_t *jlRemote)
|
2013-12-12 02:18:36 +01:00
|
|
|
{
|
|
|
|
PaError err;
|
|
|
|
|
2013-12-21 09:20:39 +01:00
|
|
|
JuliaRemote = jlRemote;
|
|
|
|
sem_init(&CSemaphore, 0, 0);
|
|
|
|
RemotePutFunc = jl_get_function(jl_base_module, "put");
|
|
|
|
RemotePutArg = jl_box_int32(0);
|
2013-12-12 02:18:36 +01:00
|
|
|
|
2013-12-21 09:20:39 +01:00
|
|
|
err = Pa_OpenDefaultStream(&AudioStream,
|
2013-12-12 02:18:36 +01:00
|
|
|
0, /* no input channels */
|
2013-12-21 09:20:39 +01:00
|
|
|
1, /* mono output */
|
2013-12-12 02:18:36 +01:00
|
|
|
paFloat32, /* 32 bit floating point output */
|
2013-12-21 09:20:39 +01:00
|
|
|
sampleRate,
|
|
|
|
bufSize, /* frames per buffer, i.e. the number of sample frames
|
2013-12-12 02:18:36 +01:00
|
|
|
that PortAudio will request from the callback. Many
|
|
|
|
apps may want to use paFramesPerBufferUnspecified,
|
|
|
|
which tells PortAudio to pick the best, possibly
|
|
|
|
changing, buffer size.*/
|
2013-12-21 09:20:39 +01:00
|
|
|
paCallback, /* this is your callback function */
|
2013-12-12 02:18:36 +01:00
|
|
|
NULL); /*This is a pointer that will be passed to your callback*/
|
|
|
|
if(err != paNoError)
|
|
|
|
{
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2013-12-21 09:20:39 +01:00
|
|
|
err = Pa_StartStream(AudioStream);
|
2013-12-12 02:18:36 +01:00
|
|
|
if(err != paNoError)
|
|
|
|
{
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
return paNoError;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-12-21 09:20:39 +01:00
|
|
|
//PaError stop_sin(void)
|
|
|
|
//{
|
|
|
|
// PaError err;
|
|
|
|
// err = Pa_StopStream(sin_stream);
|
|
|
|
// if(err != paNoError)
|
|
|
|
// {
|
|
|
|
// return err;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// err = Pa_CloseStream(sin_stream);
|
|
|
|
// if( err != paNoError )
|
|
|
|
// {
|
|
|
|
// return err;
|
|
|
|
// }
|
|
|
|
// return paNoError;
|
|
|
|
//}
|
2013-12-12 02:18:36 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This routine will be called by the PortAudio engine when audio is needed.
|
|
|
|
* It may called at interrupt level on some machines so don't do anything that
|
|
|
|
* could mess up the system like calling malloc() or free().
|
|
|
|
*/
|
2013-12-21 09:20:39 +01:00
|
|
|
static int paCallback(const void *inputBuffer, void *outputBuffer,
|
2013-12-12 02:18:36 +01:00
|
|
|
unsigned long framesPerBuffer,
|
|
|
|
const PaStreamCallbackTimeInfo* timeInfo,
|
|
|
|
PaStreamCallbackFlags statusFlags,
|
|
|
|
void *userData)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
2013-12-21 09:20:39 +01:00
|
|
|
sem_wait(&CSemaphore);
|
2013-12-12 02:18:36 +01:00
|
|
|
for(i=0; i<framesPerBuffer; i++)
|
|
|
|
{
|
2013-12-21 09:20:39 +01:00
|
|
|
((float *)outputBuffer)[i] = ((float *)OutData)[i];
|
2013-12-12 02:18:36 +01:00
|
|
|
}
|
2013-12-21 09:20:39 +01:00
|
|
|
// TODO: copy the input data somewhere
|
|
|
|
jl_call2(RemotePutFunc, JuliaRemote, RemotePutArg);
|
2013-12-12 02:18:36 +01:00
|
|
|
return 0;
|
|
|
|
}
|