commit 030b4acd4abbc34e8143f94202c97f2868e94187 Author: Spencer Russell Date: Wed Dec 11 20:18:36 2013 -0500 initial commit with some toy code diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0f797a9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2013 Spencer Russell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..575da38 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ + +default: test diff --git a/README b/README new file mode 100644 index 0000000..6b6f3ee --- /dev/null +++ b/README @@ -0,0 +1,3 @@ +This is a Julia interface to PortAudio. + +More info to come... diff --git a/deps/src/Makefile b/deps/src/Makefile new file mode 100644 index 0000000..a95fe24 --- /dev/null +++ b/deps/src/Makefile @@ -0,0 +1,49 @@ +# Makefile lifted from Clang.jl + +all: default + +ifeq (exists, $(shell [ -e Make.user ] && echo exists )) +include Make.user +endif + +.PHONY: all clean check-env default + +#check-env: +#ifndef JULIA_ROOT +# $(error Environment variable JULIA_ROOT is not set.) +#endif + +INC =-I"$(JULIA_ROOT)/usr/include" +FLAGS =-Wall -Wno-strict-aliasing -fno-omit-frame-pointer -fPIC +CFLAGS =-g +LIBS = + +OBJS = shim.o +# libm can be removed later, it's just for the sin function used in testing +LIBS += -lportaudio -lm + +# Figure out OS and architecture +OS = $(shell uname) +ifeq ($(OS), MINGW32_NT-6.1) + OS=WINNT +endif + +# file extensions +ifeq ($(OS), WINNT) + SHLIB_EXT = dll +else ifeq ($(OS), Darwin) + SHLIB_EXT = dylib +else + SHLIB_EXT = so +endif + +default: portaudio_shim.$(SHLIB_EXT) + +%.o: %.c + $(CC) $< -fPIC -c -o $@ $(INC) $(CFLAGS) $(FLAGS) + +portaudio_shim.$(SHLIB_EXT): $(OBJS) + $(CC) $(OBJS) -rdynamic -shared -o $@ $(LDFLAGS) $(LIBS) + +clean: + rm -f *.o *.$(SHLIB_EXT) diff --git a/deps/src/shim.c b/deps/src/shim.c new file mode 100644 index 0000000..2f14087 --- /dev/null +++ b/deps/src/shim.c @@ -0,0 +1,110 @@ +#include +#include +#include + +#define SAMPLE_RATE 44100 + +static int patestCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData); + +static PaStream *sin_stream; + + +PaError play_sin(void) +{ + PaError err; +// PaDeviceInfo *info; +// int numDevices; + +// printf("Found Devices:\n"); +// numDevices = Pa_GetDeviceCount(); +// for(i = 0; i < numDevices; ++i) +// { +// info = Pa_GetDeviceInfo(i); +// printf("%s\n", info->name); +// } + + err = Pa_OpenDefaultStream(&sin_stream, + 0, /* no input channels */ + 2, /* stereo output */ + paFloat32, /* 32 bit floating point output */ + SAMPLE_RATE, + 1024, /* frames per buffer, i.e. the number of sample frames + 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.*/ + patestCallback, /* this is your callback function */ + NULL); /*This is a pointer that will be passed to your callback*/ + if(err != paNoError) + { + return err; + } + + err = Pa_StartStream(sin_stream); + if(err != paNoError) + { + return err; + } + + return paNoError; +} + +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; +} + + +/* + * 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(). + */ +static int patestCallback(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData) +{ + float freq_l = 100; + float freq_r = 150; + static float phase_l = 0; + static float phase_r = 0; + + float *out = (float*)outputBuffer; + unsigned int i; + + for(i=0; i 2 * M_PI) + { + phase_l -= 2 * M_PI; + } + phase_r += (2 * M_PI * freq_r / SAMPLE_RATE); + if(phase_r > 2 * M_PI) + { + phase_r -= 2 * M_PI; + } + out[2*i] = sin(phase_l); + out[2*i + 1] = sin(phase_r); + } + return 0; +} diff --git a/src/portaudio.jl b/src/portaudio.jl new file mode 100644 index 0000000..cb14bee --- /dev/null +++ b/src/portaudio.jl @@ -0,0 +1,96 @@ +# thanks to Gustavo Goretkin for the start on this + +module PortAudio + +typealias PaTime Cdouble +typealias PaError Cint +typealias PaSampleFormat Culong +typealias PaStream Void + +const PA_NO_ERROR::PaError = 0 + +function handle_status(err::PaError) + if err != PA_NO_ERROR + msg = ccall((:Pa_GetErrorText, "libportaudio"), + Ptr{Cchar}, (PaError,), err) + error(bytestring(msg)) + end +end + +function init() + err = ccall((:Pa_Initialize, "libportaudio"), PaError, ()) + handle_status(err) +end + +function deinit() + err = ccall((:Pa_Terminate, "libportaudio"), PaError, ()) + handle_status(err) +end + +function play_sin() +end + +function stop_sin() +end + +end # module PortAudio + + +type PaStreamCallbackTimeInfo + inputBufferAdcTime::PaTime + currentTime::PaTime + outputBufferDacTime::PaTime +end + +typealias PaStreamCallbackFlags Culong + + +function stream_callback{T}( input_::Ptr{T}, + output_::Ptr{T}, + frame_count::Culong, + time_info::Ptr{PaStreamCallbackTimeInfo}, + status_flags::PaStreamCallbackFlags, + user_data::Ptr{Void}) + + + println("stfl:$status_flags \tframe_count:$frame_count") + + ret = 0 + return convert(Cint,ret)::Cint #continue stream + +end + +T=Float32 +stream_callback_c = cfunction(stream_callback,Cint, +(Ptr{T},Ptr{T},Culong,Ptr{PaStreamCallbackTimeInfo},PaStreamCallbackFlags,Ptr{Void}) +) +stream_obj = Array(Ptr{PaStream},1) + +pa_err = ccall( +(:Pa_Initialize,"libportaudio"), +PaError, +(), +) + +println(get_error_text(pa_err)) + +pa_err = ccall( +(:Pa_OpenDefaultStream,"libportaudio"), +PaError, +(Ptr{Ptr{PaStream}},Cint,Cint,PaSampleFormat,Cdouble,Culong,Ptr{Void},Any), +stream_obj,0,1,0x1,8000.0,4096,stream_callback_c,None +) + +println(get_error_text(pa_err)) + +function start_stream(stream) + pa_err = ccall( + (:Pa_StartStream,"libportaudio"), + PaError, + (Ptr{PaStream},), + stream + ) + println(get_error_text(pa_err)) +end + +end #module