aboutsummaryrefslogtreecommitdiff
path: root/pd/portaudio
diff options
context:
space:
mode:
authorGuenter Geiger <ggeiger@users.sourceforge.net>2003-05-09 16:04:00 +0000
committerGuenter Geiger <ggeiger@users.sourceforge.net>2003-05-09 16:04:00 +0000
commit9c0e19a3be2288db79e2502e5fa450c3e20a668d (patch)
treeca97ce615e037a533304fc4660dcf372ca3b9cd6 /pd/portaudio
parentef50dd62804d54af7da18d8bd8413c0dccd729b8 (diff)
This commit was generated by cvs2svn to compensate for changes in r610,
which included commits to RCS files with non-trunk default branches. svn path=/trunk/; revision=611
Diffstat (limited to 'pd/portaudio')
-rw-r--r--pd/portaudio/MSP-README.txt7
-rw-r--r--pd/portaudio/Makefile.in132
-rw-r--r--pd/portaudio/Makefile.linux59
-rw-r--r--pd/portaudio/Makefile.mingw57
-rw-r--r--pd/portaudio/README.txt2
-rw-r--r--pd/portaudio/V19-devel-readme.txt230
-rw-r--r--pd/portaudio/aclocal.m457
-rw-r--r--pd/portaudio/config.doxy185
-rwxr-xr-xpd/portaudio/config.guess1308
-rwxr-xr-xpd/portaudio/configure2903
-rw-r--r--pd/portaudio/configure.in123
-rw-r--r--pd/portaudio/docs/index.html60
-rw-r--r--pd/portaudio/docs/latency.html192
-rw-r--r--pd/portaudio/docs/pa_impl_guide.html197
-rw-r--r--pd/portaudio/docs/pa_impl_startstop.html190
-rw-r--r--pd/portaudio/docs/pa_tut_asio.html55
-rw-r--r--pd/portaudio/docs/pa_tut_callback.html91
-rw-r--r--pd/portaudio/docs/pa_tut_devs.html65
-rw-r--r--pd/portaudio/docs/pa_tut_explore.html42
-rw-r--r--pd/portaudio/docs/pa_tut_init.html43
-rw-r--r--pd/portaudio/docs/pa_tut_mac.html41
-rw-r--r--pd/portaudio/docs/pa_tut_mac_osx.html46
-rw-r--r--pd/portaudio/docs/pa_tut_open.html52
-rw-r--r--pd/portaudio/docs/pa_tut_oss.html46
-rw-r--r--pd/portaudio/docs/pa_tut_over.html92
-rw-r--r--pd/portaudio/docs/pa_tut_pc.html78
-rw-r--r--pd/portaudio/docs/pa_tut_run.html56
-rw-r--r--pd/portaudio/docs/pa_tut_rw.html79
-rw-r--r--pd/portaudio/docs/pa_tut_term.html47
-rw-r--r--pd/portaudio/docs/pa_tut_util.html55
-rw-r--r--pd/portaudio/docs/pa_tutorial.html46
-rw-r--r--pd/portaudio/docs/portaudio_h.txt425
-rw-r--r--pd/portaudio/docs/portaudio_icmc2001.pdfbin0 -> 50968 bytes
-rw-r--r--pd/portaudio/docs/proposals.html36
-rw-r--r--pd/portaudio/docs/releases.html339
-rwxr-xr-xpd/portaudio/fixdir.bat19
-rwxr-xr-xpd/portaudio/fixfile.bat7
-rw-r--r--pd/portaudio/index.html89
-rwxr-xr-xpd/portaudio/install-sh251
-rw-r--r--pd/portaudio/pa_asio/Callback_adaptation_.pdfbin0 -> 50527 bytes
-rw-r--r--pd/portaudio/pa_asio/Pa_ASIO.pdfbin0 -> 50778 bytes
-rw-r--r--pd/portaudio/pa_asio/borland_asio_readme.txt6
-rw-r--r--pd/portaudio/pa_asio/pa_asio.cpp4403
-rw-r--r--pd/portaudio/pa_asio/pa_asio.h68
-rwxr-xr-xpd/portaudio/pa_asio/readme_asio_sdk_patch.txt25
-rw-r--r--pd/portaudio/pa_beos/PlaybackNode.cc538
-rw-r--r--pd/portaudio/pa_beos/PlaybackNode.h108
-rw-r--r--pd/portaudio/pa_beos/pa_beos_mk.cc441
-rw-r--r--pd/portaudio/pa_common/pa_allocation.c217
-rw-r--r--pd/portaudio/pa_common/pa_allocation.h92
-rw-r--r--pd/portaudio/pa_common/pa_allocation.obin0 -> 1744 bytes
-rw-r--r--pd/portaudio/pa_common/pa_converters.c1653
-rw-r--r--pd/portaudio/pa_common/pa_converters.h197
-rw-r--r--pd/portaudio/pa_common/pa_converters.obin0 -> 20384 bytes
-rw-r--r--pd/portaudio/pa_common/pa_cpuload.c79
-rw-r--r--pd/portaudio/pa_common/pa_cpuload.h56
-rw-r--r--pd/portaudio/pa_common/pa_cpuload.obin0 -> 1452 bytes
-rw-r--r--pd/portaudio/pa_common/pa_dither.c91
-rw-r--r--pd/portaudio/pa_common/pa_dither.h189
-rw-r--r--pd/portaudio/pa_common/pa_dither.obin0 -> 1136 bytes
-rw-r--r--pd/portaudio/pa_common/pa_endianness.h108
-rw-r--r--pd/portaudio/pa_common/pa_front.c1884
-rw-r--r--pd/portaudio/pa_common/pa_front.obin0 -> 12576 bytes
-rw-r--r--pd/portaudio/pa_common/pa_hostapi.h238
-rw-r--r--pd/portaudio/pa_common/pa_process.c1355
-rw-r--r--pd/portaudio/pa_common/pa_process.h203
-rw-r--r--pd/portaudio/pa_common/pa_process.obin0 -> 10192 bytes
-rw-r--r--pd/portaudio/pa_common/pa_skeleton.c724
-rw-r--r--pd/portaudio/pa_common/pa_skeleton.obin0 -> 3468 bytes
-rw-r--r--pd/portaudio/pa_common/pa_stream.c114
-rw-r--r--pd/portaudio/pa_common/pa_stream.h128
-rw-r--r--pd/portaudio/pa_common/pa_stream.obin0 -> 1059 bytes
-rw-r--r--pd/portaudio/pa_common/pa_trace.c22
-rw-r--r--pd/portaudio/pa_common/pa_trace.h31
-rw-r--r--pd/portaudio/pa_common/pa_trace.obin0 -> 584 bytes
-rw-r--r--pd/portaudio/pa_common/pa_util.h143
-rw-r--r--pd/portaudio/pa_common/portaudio.h1189
-rw-r--r--pd/portaudio/pa_dll_switch/PaDllEntry.h184
-rw-r--r--pd/portaudio/pa_dll_switch/letter_from_tim_010817.txtbin0 -> 1176 bytes
-rw-r--r--pd/portaudio/pa_dll_switch/loadPA_DLL.cpp203
-rw-r--r--pd/portaudio/pa_dll_switch/pa_lib.c827
-rw-r--r--pd/portaudio/pa_dll_switch/portaudio.h439
-rw-r--r--pd/portaudio/pa_jack/pa_jack.c864
-rw-r--r--pd/portaudio/pa_linux_alsa/blocking_calls.c61
-rw-r--r--pd/portaudio/pa_linux_alsa/blocking_calls.obin0 -> 1180 bytes
-rw-r--r--pd/portaudio/pa_linux_alsa/callback_thread.c374
-rw-r--r--pd/portaudio/pa_linux_alsa/callback_thread.obin0 -> 4180 bytes
-rw-r--r--pd/portaudio/pa_linux_alsa/pa_linux_alsa.c989
-rw-r--r--pd/portaudio/pa_linux_alsa/pa_linux_alsa.h45
-rw-r--r--pd/portaudio/pa_linux_alsa/pa_linux_alsa.obin0 -> 10728 bytes
-rw-r--r--pd/portaudio/pa_mac_core/notes.txt14
-rw-r--r--pd/portaudio/pa_mac_core/pa_mac_core.c1512
-rw-r--r--pd/portaudio/pa_mac_sm/pa_mac_sm.c1656
-rw-r--r--pd/portaudio/pa_sgi/Makefile51
-rw-r--r--pd/portaudio/pa_sgi/pa_sgi.c999
-rw-r--r--pd/portaudio/pa_sgi/pthread-Makefile52
-rw-r--r--pd/portaudio/pa_sgi/pthread-pa_sgi.c908
-rw-r--r--pd/portaudio/pa_tests/debug_convert.c131
-rw-r--r--pd/portaudio/pa_tests/debug_dither_calc.c55
-rw-r--r--pd/portaudio/pa_tests/debug_dual.c183
-rw-r--r--pd/portaudio/pa_tests/debug_multi_in.c179
-rw-r--r--pd/portaudio/pa_tests/debug_multi_out.c144
-rw-r--r--pd/portaudio/pa_tests/debug_record.c339
-rw-r--r--pd/portaudio/pa_tests/debug_record_reuse.c351
-rw-r--r--pd/portaudio/pa_tests/debug_sine.c192
-rw-r--r--pd/portaudio/pa_tests/debug_sine_amp.c157
-rw-r--r--pd/portaudio/pa_tests/debug_sine_formats.c202
-rw-r--r--pd/portaudio/pa_tests/debug_srate.c265
-rw-r--r--pd/portaudio/pa_tests/debug_test1.c114
-rw-r--r--pd/portaudio/pa_tests/pa_devs.c199
-rw-r--r--pd/portaudio/pa_tests/pa_fuzz.c168
-rw-r--r--pd/portaudio/pa_tests/pa_minlat.c176
-rw-r--r--pd/portaudio/pa_tests/paqa_devs.c317
-rw-r--r--pd/portaudio/pa_tests/paqa_errs.c330
-rw-r--r--pd/portaudio/pa_tests/patest1.c119
-rw-r--r--pd/portaudio/pa_tests/patest_buffer.c181
-rw-r--r--pd/portaudio/pa_tests/patest_clip.c156
-rw-r--r--pd/portaudio/pa_tests/patest_dither.c152
-rw-r--r--pd/portaudio/pa_tests/patest_hang.c151
-rw-r--r--pd/portaudio/pa_tests/patest_latency.c176
-rw-r--r--pd/portaudio/pa_tests/patest_leftright.c168
-rw-r--r--pd/portaudio/pa_tests/patest_longsine.c137
-rw-r--r--pd/portaudio/pa_tests/patest_many.c194
-rw-r--r--pd/portaudio/pa_tests/patest_maxsines.c197
-rw-r--r--pd/portaudio/pa_tests/patest_multi_sine.c175
-rw-r--r--pd/portaudio/pa_tests/patest_pink.c245
-rw-r--r--pd/portaudio/pa_tests/patest_record.c327
-rw-r--r--pd/portaudio/pa_tests/patest_ringmix.c41
-rw-r--r--pd/portaudio/pa_tests/patest_saw.c118
-rw-r--r--pd/portaudio/pa_tests/patest_sine.c152
-rw-r--r--pd/portaudio/pa_tests/patest_sine8.c184
-rw-r--r--pd/portaudio/pa_tests/patest_sine_formats.c196
-rw-r--r--pd/portaudio/pa_tests/patest_sine_time.c194
-rw-r--r--pd/portaudio/pa_tests/patest_start_stop.c160
-rw-r--r--pd/portaudio/pa_tests/patest_stop.c288
-rw-r--r--pd/portaudio/pa_tests/patest_sync.c257
-rw-r--r--pd/portaudio/pa_tests/patest_toomanysines.c172
-rw-r--r--pd/portaudio/pa_tests/patest_underflow.c151
-rw-r--r--pd/portaudio/pa_tests/patest_wire.c277
-rw-r--r--pd/portaudio/pa_unix/pa_unix_hostapis.c60
-rw-r--r--pd/portaudio/pa_unix/pa_unix_hostapis.obin0 -> 768 bytes
-rw-r--r--pd/portaudio/pa_unix/pa_unix_util.c102
-rw-r--r--pd/portaudio/pa_unix/pa_unix_util.obin0 -> 1096 bytes
-rw-r--r--pd/portaudio/pa_unix_oss/Makefile43
-rw-r--r--pd/portaudio/pa_unix_oss/Makefile_freebsd36
-rw-r--r--pd/portaudio/pa_unix_oss/low_latency_tip.txtbin0 -> 3111 bytes
-rw-r--r--pd/portaudio/pa_unix_oss/pa_unix_oss.c1187
-rw-r--r--pd/portaudio/pa_unix_oss/pa_unix_oss.obin0 -> 8548 bytes
-rw-r--r--pd/portaudio/pa_unix_oss/recplay.c114
-rw-r--r--pd/portaudio/pa_win/pa_win_hostapis.c63
-rw-r--r--pd/portaudio/pa_win/pa_win_util.c128
-rw-r--r--pd/portaudio/pa_win/pa_x86_plain_converters.c1167
-rw-r--r--pd/portaudio/pa_win/pa_x86_plain_converters.h19
-rw-r--r--pd/portaudio/pa_win_ds/dsound_wrapper.c604
-rw-r--r--pd/portaudio/pa_win_ds/dsound_wrapper.h129
-rw-r--r--pd/portaudio/pa_win_ds/pa_dsound.c1021
-rw-r--r--pd/portaudio/pa_win_ds/pa_win_ds.c1441
-rw-r--r--pd/portaudio/pa_win_ds/portaudio.def28
-rw-r--r--pd/portaudio/pa_win_wmme/Makefile.cygwin34
-rw-r--r--pd/portaudio/pa_win_wmme/pa_win_wmme.c2672
-rw-r--r--pd/portaudio/pa_win_wmme/pa_win_wmme.h105
-rw-r--r--pd/portaudio/pablio/pablio.h5
-rw-r--r--pd/portaudio/pablio/pablio_pd.c51
-rw-r--r--pd/portaudio/pablio/pablio_pd.h4
-rw-r--r--pd/portaudio/pablio/pablio_pd.obin0 -> 3500 bytes
-rw-r--r--pd/portaudio/pablio/ringbuffer_pd.obin0 -> 1824 bytes
-rw-r--r--pd/portaudio/testcvs/changeme.txt8
167 files changed, 44398 insertions, 3975 deletions
diff --git a/pd/portaudio/MSP-README.txt b/pd/portaudio/MSP-README.txt
index e29de09f..bd75626b 100644
--- a/pd/portaudio/MSP-README.txt
+++ b/pd/portaudio/MSP-README.txt
@@ -1,3 +1,6 @@
-This is not the full distribution, just what's needed to get Pd running
-on Mac OSX and ASIO (Windows.) I changed some code in pablio.c as marked.
+These files are from the V19 branch, a CVS snapshot, around 2003.03.21.
+
+I had to hack up "pablio" a fair bit... my copies are named "pablio_pd.c"
+and so on.
+
-MSP
diff --git a/pd/portaudio/Makefile.in b/pd/portaudio/Makefile.in
new file mode 100644
index 00000000..18c2707f
--- /dev/null
+++ b/pd/portaudio/Makefile.in
@@ -0,0 +1,132 @@
+#
+# PortAudio V19 Makefile.in
+#
+# Dominic Mazzoni
+#
+
+PREFIX = @prefix@
+CC = @CC@
+CFLAGS = @CFLAGS@ -Ipa_common @DEFS@
+LIBS = @LIBS@
+AR = @AR@
+RANLIB = @RANLIB@
+INSTALL = @INSTALL@
+SHARED_FLAGS = @SHARED_FLAGS@
+DLL_LIBS = @DLL_LIBS@
+
+OTHER_OBJS = @OTHER_OBJS@
+
+PALIB = libportaudio.a
+PADLL = @PADLL@
+PADLLV = $(PADLL).0.0.19
+PAINC = pa_common/portaudio.h
+
+COMMON_OBJS = \
+ pa_common/pa_allocation.o \
+ pa_common/pa_converters.o \
+ pa_common/pa_cpuload.o \
+ pa_common/pa_dither.o \
+ pa_common/pa_front.o \
+ pa_common/pa_process.o \
+ pa_common/pa_skeleton.o \
+ pa_common/pa_stream.o \
+ pa_common/pa_trace.o
+
+TESTS = \
+ bin/pa_devs \
+ bin/pa_fuzz \
+ bin/patest_sine \
+ bin/patest1
+
+# Most of these don't compile yet. Put them in TESTS, above, if
+# you want to try to compile them...
+ALL_TESTS = \
+ bin/debug_convert \
+ bin/debug_dither_calc \
+ bin/debug_dual \
+ bin/debug_multi_in \
+ bin/debug_multi_out \
+ bin/debug_record \
+ bin/debug_record_reuse \
+ bin/debug_sine_amp \
+ bin/debug_sine \
+ bin/debug_sine_formats \
+ bin/debug_srate \
+ bin/debug_test1 \
+ bin/pa_devs \
+ bin/pa_fuzz \
+ bin/pa_minlat \
+ bin/paqa_devs \
+ bin/paqa_errs \
+ bin/patest1 \
+ bin/patest_buffer \
+ bin/patest_clip \
+ bin/patest_dither \
+ bin/patest_hang \
+ bin/patest_latency \
+ bin/patest_leftright \
+ bin/patest_longsine \
+ bin/patest_many \
+ bin/patest_maxsines \
+ bin/patest_multi_sine \
+ bin/patest_pink \
+ bin/patest_record \
+ bin/patest_ringmix \
+ bin/patest_saw \
+ bin/patest_sine8 \
+ bin/patest_sine \
+ bin/patest_sine_formats \
+ bin/patest_sine_time \
+ bin/patest_start_stop \
+ bin/patest_stop \
+ bin/patest_sync \
+ bin/patest_toomanysines \
+ bin/patest_underflow \
+ bin/patest_wire
+
+OBJS = $(COMMON_OBJS) $(OTHER_OBJS)
+
+all: lib/$(PALIB) lib/$(PADLLV) tests
+
+tests: bin/ $(TESTS)
+
+lib/$(PALIB): lib/ $(OBJS) Makefile $(PAINC)
+ $(AR) ruv lib/$(PALIB) $(OBJS)
+ $(RANLIB) lib/$(PALIB)
+
+lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC)
+ $(CC) $(SHARED_FLAGS) -o lib/$(PADLLV) $(OBJS) $(DLL_LIBS)
+
+$(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c
+ $(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS)
+
+install: lib/$(PALIB) lib/$(PADLLV)
+ $(INSTALL) -m 644 lib/$(PADLLV) $(PREFIX)/lib/$(PADLLV)
+ $(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB)
+ cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL)
+ $(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h
+ @echo ""
+ @echo "------------------------------------------------------------"
+ @echo "PortAudio was successfully installed."
+ @echo ""
+ @echo "On some systems (e.g. Linux) you should run 'ldconfig' now"
+ @echo "to make the shared object available. You may also need to"
+ @echo "modify your LD_LIBRARY_PATH environment variable to include"
+ @echo "the directory $(PREFIX)/lib"
+ @echo "------------------------------------------------------------"
+ @echo ""
+
+clean:
+ rm -f $(OBJS) $(TESTS) lib/$(PALIB)
+
+%.o: %.c Makefile $(PAINC)
+ $(CC) -c $(CFLAGS) $< -o $@
+
+bin:
+ mkdir bin
+
+lib:
+ mkdir lib
+
+
+
diff --git a/pd/portaudio/Makefile.linux b/pd/portaudio/Makefile.linux
new file mode 100644
index 00000000..4deee60a
--- /dev/null
+++ b/pd/portaudio/Makefile.linux
@@ -0,0 +1,59 @@
+# Make PortAudio for Linux
+# Updated 2001/08/25 Bill Eldridge bill@rfa.org
+# Updated 2001/10/16, philburk@softsynth.com, s/unix_oss/unix_oss/
+# Updated 2002/04/30 Bill Eldridge bill@rfa.org
+# Made the libinstall and tests compile a bit cleaner
+
+# A pretty bare makefile, that figures out all the test files
+# and compiles them against the library in the pa_unix_oss directory.
+
+# Do "make all" and then when happy, "make libinstall"
+# (if not happy, "make clean")
+
+# The ldconfig stuff in libinstall is the wrong way to do it -
+# someone tell me the right way, please
+
+
+LIBS = -lm -lpthread
+
+CDEFINES = -I../pa_common
+CFLAGS = -g
+LIBINST = /usr/local/lib
+
+TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c)
+TESTO:= $(wildcard pa_tests/pa*.o pa_tests/debug*.o)
+
+LIBFILES:= ./pa_common/pa_lib.c ./pa_unix_oss/pa_unix_oss.c
+
+#all: sharedlib libinstall tests
+all: sharedlib libinstall testo testq
+
+.c.o:
+ -gcc -c -I./pa_common $< -o $*.o
+
+.o:
+ -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio
+
+#.c.o:
+# -gcc -c -I./pa_common $< -o $*.o
+# -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio
+
+
+sharedlib: $(LIBFILES:.c=.o)
+ gcc -shared -o ./pa_unix_oss/libportaudio.so ./pa_common/pa_lib.o ./pa_unix_oss/pa_unix_oss.o
+
+libinstall: ./pa_unix_oss/libportaudio.so
+ @cp -f ./pa_unix_oss/libportaudio.so $(LIBINST)
+ @/sbin/ldconfig
+
+testo: $(TESTS:.c=.o)
+
+testq: $(TESTO:.o=)
+
+clean:
+ -@rm -f $(TESTS:.c=.o)
+ -@rm -f $(TESTS:.c=)
+ -@rm -f $(LIBFILES:.c=.o)
+ -@rm -f ./pa_unix_oss/libportaudio.so
+
+
diff --git a/pd/portaudio/Makefile.mingw b/pd/portaudio/Makefile.mingw
new file mode 100644
index 00000000..2043a161
--- /dev/null
+++ b/pd/portaudio/Makefile.mingw
@@ -0,0 +1,57 @@
+
+# Makefile for PortAudio on mingw (http://mingw.sourceforge.net)
+
+# Contributed by Bill Eldridge, bill@rfa.org, Radio Free Asia
+# Copyright 2002/02/20, GPL
+
+# Uses a common mingw32 cross-compiler that defaults
+# to everything in /usr/local/cross-tools
+
+# First edit your path with
+# export PATH=/usr/local/cross-tools/bin:$PATH
+
+# Usage: make -f Makefile.mingw all
+# or make -f Makefile.mingw sharedlib
+# make -f Makefile.mingw tests
+#
+# Then copy executables & portaudio.dll to your Windows machine
+#
+# To make work with pa_win_ds, you'll have to substitue
+# all the pa_win_wmme files with pa_win_ds files, no biggie.
+
+CC= i586-mingw32msvc-gcc
+DLLTOOL= i586-mingw32msvc-dlltool
+DLLWRAP= i586-mingw32msvc-dllwrap
+
+ARCH= pa_win_wmme
+
+TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c)
+
+.c.o:
+ -$(CC) -c -I./pa_common $< -o $*.o
+ -$(CC) $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm
+
+all: sharedlib tests
+
+sharedlib: ./pa_common/pa_lib.c
+ $(CC) -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o
+ $(CC) -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o
+ $(CC) -shared -mthreads -o portaudio.dll pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm
+ $(DLLWRAP) --export-all --output-def=libportaudio.def --output-lib=libportaudio.a --dllname=portaudio.dll --drivername=i586-mingw32msvc-gcc pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm
+ $(CC) -shared -Wl,--enable-auto-image-base -o portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm
+
+
+tests: $(TESTS:.c=.o)
+
+sine:
+ $(CC) -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o
+ $(CC) pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm
+
+clean:
+ -rm ./pa_tests/*.exe
+ -rm ./pa_tests/*.o
+
+nothing:
+ $(CC) pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm
+
+
diff --git a/pd/portaudio/README.txt b/pd/portaudio/README.txt
index d1e5d7d6..4cfc6166 100644
--- a/pd/portaudio/README.txt
+++ b/pd/portaudio/README.txt
@@ -58,7 +58,7 @@ Important Files and Folders:
Platform Implementations
pa_asio = ASIO for Windows and Macintosh
pa_beos = BeOS
- pa_mac = Macintosh Sound Manager for OS 8,9 and Carbon
+ pa_mac_sm = Macintosh Sound Manager for OS 8,9 and Carbon
pa_mac_core = Macintosh Core Audio for OS X
pa_sgi = Silicon Graphics AL
pa_unix_oss = OSS implementation for various Unixes
diff --git a/pd/portaudio/V19-devel-readme.txt b/pd/portaudio/V19-devel-readme.txt
new file mode 100644
index 00000000..a6bca780
--- /dev/null
+++ b/pd/portaudio/V19-devel-readme.txt
@@ -0,0 +1,230 @@
+STATUS:
+
+MME, DirectSound and ASIO versions are more-or-less working. See FIXMEs @todos
+and the proposals matrix at portaudio.com for further status.
+
+ The following tests might run if you're lucky:
+ tests/pa_devs.c
+ tests/patest_sine.c
+ tests/pa_fuzz.c
+
+ tests/patest1.c
+
+The PaUtil support code is finished enough for other implementations to be
+ported. No changes are expected to be made to the definition of the PaUtil
+functions.
+
+Note that it's not yet 100% clear how the current support functions
+will interact with blocking read/write streams.
+
+BUILD INSTRUCTIONS
+
+to build tests/patest_sine.c you will need to compile and link the following
+files (MME)
+pa_common\pa_process.c
+pa_common\pa_skeleton.c
+pa_common\pa_stream.c
+pa_common\pa_trace.c
+pa_common\pa_byteswappers.c
+pa_common\pa_converters.c
+pa_common\pa_cpuload.c
+pa_common\pa_dither.c
+pa_common\pa_front.c
+pa_common\pa_allocation.h
+pa_win\pa_win_util.c
+pa_win\pa_win_hostapis.c
+pa_win_wmme\pa_win_wmme.c
+
+see below for a description of these files.
+
+
+FILES:
+
+portaudio.h
+ public api header file
+
+pa_front.c
+ implements the interface defined in portaudio.h. manages multiple host apis.
+ validates function parameters before calling through to host apis. tracks
+ open streams and closes them at Pa_Terminate().
+
+pa_util.h
+ declares utility functions for use my implementations. including utility
+ functions which must be implemented separately for each platform.
+
+pa_hostapi.h
+ hostapi representation structure used to interface between pa_front.c
+ and implementations
+
+pa_stream.c/h
+ stream interface and representation structures and helper functions
+ used to interface between pa_front.c and implementations
+
+pa_cpuload.c/h
+ source and header for cpu load calculation facility
+
+pa_trace.c/h
+ source and header for debug trace log facility
+
+pa_byteswappers.c/h
+ byte swapping facility
+
+pa_converters.c/h
+ sample buffer conversion facility
+
+pa_dither.c/h
+ dither noise generator
+
+pa_process.c/h
+ callback buffer processing facility including interleave and block adaption
+
+pa_allocation.c/h
+ allocation context for tracking groups of allocations
+
+pa_skeleton.c
+ an skeleton implementation showing how the common code can be used.
+
+pa_win_util.c
+ Win32 implementation of platform specific PaUtil functions (memory allocation,
+ usec clock, Pa_Sleep().) The file will be used with all Win32 host APIs.
+
+pa_win_hostapis.c
+ contains the paHostApiInitializers array and an implementation of
+ Pa_GetDefaultHostApi() for win32 builds.
+
+pa_win_wmme.c
+ Win32 host api implementation for the windows multimedia extensions audio API.
+
+pa_win_wmme.h
+ public header file containing interfaces to mme-specific functions and the
+ deviceInfo data structure.
+
+
+CODING GUIDELINES:
+
+naming conventions:
+ #defines begin with PA_
+ #defines local to a file end with _
+ global utility variables begin with paUtil
+ global utility types begin with PaUtil (including function types)
+ global utility functions begin with PaUtil_
+ static variables end with _
+ static constants begin with const and end with _
+ static funtions have no special prefix/suffix
+
+In general, implementations should declare all of their members static,
+except for their initializer which should be exported. All exported names
+should be preceeded by Pa<MN>_ where MN is the module name, for example
+the windows mme initializer should be named PaWinWmme_Initialize().
+
+Every host api should define an initializer which returns an error code
+and a PaHostApiInterface*. The initializer should only return an error other
+than paNoError if it encounters an unexpected and fatal error (memory allocation
+error for example). In general, there may be conditions under which it returns
+a NULL interface pointer and also returns paNoError. For example, if the ASIO
+implementation detects that ASIO is not installed, it should return a
+NULL interface, and paNoError.
+
+Platform-specific shared functions should begin with Pa<PN>_ where PN is the
+platform name. eg. PaWin_ for windows, PaUnix_ for unix.
+
+The above two conventions should also be followed whenever it is necessary to
+share functions accross multiple source files.
+
+Two utilities for debug messages are provided. The PA_DEBUG macro defined in
+pa_implementation.h provides a simple way to print debug messages to stderr.
+Due to real-time performance issues, PA_DEBUG may not be suitable for use
+within the portaudio processing callback, or in other threads. In such cases
+the event tracing facility provided in pa_trace.h may be more appropriate.
+
+If PA_LOG_API_CALLS is defined, all calls to the public PortAudio API
+will be logged to stderr along with parameter and return values.
+
+
+TODO:
+ (this list is totally out of date)
+
+ finish coding converter functions in pa_converters.c (anyone?)
+
+ implement block adaption in pa_process.c (phil?)
+
+ fix all current tests to work with new code. this should mostly involve
+ changing PortAudioStream to PaStream, and GetDefaultDeviceID to GetDefaultDevice etc.
+
+ write some new tests to exercise the multi-api functions
+
+ write (doxygen) documentation for pa_trace (phil?)
+
+ remove unused typeids from PaHostAPITypeID
+
+ create a global configuration file which documents which PA_ defines can be
+ used for configuration
+
+ need a coding standard for comment formatting
+
+ migrate directx (phil)
+
+ migrate asio (ross?, stephane?)
+
+ see top of pa_win_wmme.c for MME todo items (ross)
+
+ write style guide document (ross)
+
+
+DESIGN ISSUES:
+ (this list is totally out of date)
+
+ consider removing Pa_ConvertHostApiDeviceIndexToGlobalDeviceIndex() from the API
+
+ switch to new latency parameter mechanism now (?)
+
+ question: if input or outputDriverInfo structures are passed for a different
+ hostApi from the one being called, do we return an error or just ignore
+ them? (i think return error)
+
+ consider renaming PortAudioCallback to PaStreamCallback
+
+ consider renaming PaError, PaResult
+
+
+ASSORTED DISORGANISED NOTES:
+
+ NOTE:
+ pa_lib.c performs the following validations for Pa_OpenStream() which we do not currently do:
+ - checks the device info to make sure that the device supports the requested sample rate,
+ it may also change the sample rate to the "closest available" sample rate if it
+ is within a particular error margin
+
+ rationale for breaking up internalPortAudioStream:
+ each implementation has its own requirements and behavior, and should be
+ able to choose the best way to operate without being limited by the
+ constraints imposed by a common infrastructure. in other words the
+ implementations should be able to pick and choose services from the
+ common infrastructure. currently identified services include:
+
+ - cpu load tracking
+ - buffering and conversion service (same code works for input and output)
+ - should support buffer multiplexing (non-integer length input and output buffers)
+ - in-place conversion where possible (only for callback, read/write always copies)
+ - should manage allocation of temporary buffers if necessary
+ - instrumentation (should be able to be disabled): callback count, framesProcessed
+ - common data: magic, streamInterface, callback, userdata
+
+
+- conversion functions:
+ - should handle temp buffer allocation
+ - dithering (random number state per-stream)
+ - buffer size mismatches
+ - with new buffer slip rules, temp buffers may always be needed
+ - we should aim for in-place conversion wherever possible
+ - does phil's code support in-place conversion? (yes)
+
+- dicuss relationship between user and host buffer sizes
+ - completely independent.. individual implementations may constrain
+ host buffer sizes if necessary
+
+
+- discuss device capabilities:
+ - i'd like to be able to request certain information:
+ - channel count for example
+
diff --git a/pd/portaudio/aclocal.m4 b/pd/portaudio/aclocal.m4
new file mode 100644
index 00000000..c80e0acf
--- /dev/null
+++ b/pd/portaudio/aclocal.m4
@@ -0,0 +1,57 @@
+
+dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not)
+dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page
+dnl also defines GSTUFF_PKG_ERRORS on error
+AC_DEFUN(PKG_CHECK_MODULES, [
+ succeeded=no
+
+ if test -z "$PKG_CONFIG"; then
+ AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+ fi
+
+ if test "$PKG_CONFIG" = "no" ; then
+ echo "*** The pkg-config script could not be found. Make sure it is"
+ echo "*** in your path, or set the PKG_CONFIG environment variable"
+ echo "*** to the full path to pkg-config."
+ echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+ else
+ PKG_CONFIG_MIN_VERSION=0.9.0
+ if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+ AC_MSG_CHECKING(for $2)
+
+ if $PKG_CONFIG --exists "$2" ; then
+ AC_MSG_RESULT(yes)
+ succeeded=yes
+
+ AC_MSG_CHECKING($1_CFLAGS)
+ $1_CFLAGS=`$PKG_CONFIG --cflags "$2"`
+ AC_MSG_RESULT($$1_CFLAGS)
+
+ AC_MSG_CHECKING($1_LIBS)
+ $1_LIBS=`$PKG_CONFIG --libs "$2"`
+ AC_MSG_RESULT($$1_LIBS)
+ else
+ $1_CFLAGS=""
+ $1_LIBS=""
+ ## If we have a custom action on failure, don't print errors, but
+ ## do set a variable so people can do so.
+ $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+ ifelse([$4], ,echo $$1_PKG_ERRORS,)
+ fi
+
+ AC_SUBST($1_CFLAGS)
+ AC_SUBST($1_LIBS)
+ else
+ echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+ echo "*** See http://www.freedesktop.org/software/pkgconfig"
+ fi
+ fi
+
+ if test $succeeded = yes; then
+ ifelse([$3], , :, [$3])
+ else
+ ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4])
+ fi
+])
+
+
diff --git a/pd/portaudio/config.doxy b/pd/portaudio/config.doxy
new file mode 100644
index 00000000..98342765
--- /dev/null
+++ b/pd/portaudio/config.doxy
@@ -0,0 +1,185 @@
+# Doxyfile 1.2.13-20020210
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = PortAudio
+PROJECT_NUMBER = 2.0
+OUTPUT_DIRECTORY = "./docs/"
+OUTPUT_LANGUAGE = English
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+INTERNAL_DOCS = NO
+STRIP_CODE_COMMENTS = YES
+CASE_SENSE_NAMES = YES
+SHORT_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+VERBATIM_HEADERS = YES
+SHOW_INCLUDE_FILES = YES
+JAVADOC_AUTOBRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+ALIASES =
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SHOW_USED_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = ./pa_common ./pa_win_wmme ./pa_asio ./pa_win_ds
+FILE_PATTERNS = *.h *.c *.cpp
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = doxygen_html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = NO
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
+CGI_NAME = search.cgi
+CGI_URL =
+DOC_URL =
+DOC_ABSPATH =
+BIN_ABSPATH = /usr/local/bin/
+EXT_DOC_PATHS =
diff --git a/pd/portaudio/config.guess b/pd/portaudio/config.guess
new file mode 100755
index 00000000..297e5c30
--- /dev/null
+++ b/pd/portaudio/config.guess
@@ -0,0 +1,1308 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+
+timestamp='2001-10-05'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script.
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int dummy(){}" > $dummy.c ;
+ for c in cc gcc c89 ; do
+ ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ;
+ if test $? = 0 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ rm -f $dummy.c $dummy.o $dummy.rel ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ # Determine the machine/vendor (is the vendor relevant).
+ case "${UNAME_MACHINE}" in
+ amiga) machine=m68k-unknown ;;
+ arm32) machine=arm-unknown ;;
+ atari*) machine=m68k-atari ;;
+ sun3*) machine=m68k-sun ;;
+ mac68k) machine=m68k-apple ;;
+ macppc) machine=powerpc-apple ;;
+ hp3[0-9][05]) machine=m68k-hp ;;
+ ibmrt|romp-ibm) machine=romp-ibm ;;
+ sparc*) machine=`uname -p`-unknown ;;
+ *) machine=${UNAME_MACHINE}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE}" in
+ i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvmeppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mipseb-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <<EOF >$dummy.s
+ .data
+\$Lformat:
+ .byte 37,100,45,37,120,10,0 # "%d-%x\n"
+
+ .text
+ .globl main
+ .align 4
+ .ent main
+main:
+ .frame \$30,16,\$26,0
+ ldgp \$29,0(\$27)
+ .prologue 1
+ .long 0x47e03d80 # implver \$0
+ lda \$2,-1
+ .long 0x47e20c21 # amask \$2,\$1
+ lda \$16,\$Lformat
+ mov \$0,\$17
+ not \$1,\$18
+ jsr \$26,printf
+ ldgp \$29,0(\$26)
+ mov 0,\$16
+ jsr \$26,exit
+ .end main
+EOF
+ eval $set_cc_for_build
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ case `./$dummy` in
+ 0-0)
+ UNAME_MACHINE="alpha"
+ ;;
+ 1-0)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 1-1)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 1-101)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 2-303)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ 2-307)
+ UNAME_MACHINE="alphaev67"
+ ;;
+ 2-1307)
+ UNAME_MACHINE="alphaev68"
+ ;;
+ esac
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit 0;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy \
+ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`./$dummy`
+ if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+ rm -f $dummy.c $dummy
+ fi ;;
+ esac
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3D:*:*:*)
+ echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i386-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux
+ exit 0 ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ mips:Linux:*:*)
+ case `sed -n '/^byte/s/^.*: \(.*\) endian/\1/p' < /proc/cpuinfo` in
+ big) echo mips-unknown-linux-gnu && exit 0 ;;
+ little) echo mipsel-unknown-linux-gnu && exit 0 ;;
+ esac
+ ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit 0 ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit 0 ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit 0 ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit 0 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit 0 ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit 0 ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit 0 ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ ld_supported_targets=`cd /; ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit 0 ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit 0 ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit 0 ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+# if __GLIBC__ >= 2
+ printf ("%s-pc-linux-gnu\n", argv[1]);
+# else
+ printf ("%s-pc-linux-gnulibc1\n", argv[1]);
+# endif
+# else
+ printf ("%s-pc-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+ printf ("%s-pc-linux-gnuaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i*86:*:5:[78]*)
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Darwin:*:*)
+ echo `uname -p`-apple-darwin${UNAME_RELEASE}
+ exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ if test "${UNAME_MACHINE}" = "x86pc"; then
+ UNAME_MACHINE=pc
+ fi
+ echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit 0 ;;
+ NSR-[KW]:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit 0 ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit 0 ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit 0 ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit 0 ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit 0 ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit 0 ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit 0 ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit 0 ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit 0 ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/pd/portaudio/configure b/pd/portaudio/configure
new file mode 100755
index 00000000..1dfe83fc
--- /dev/null
+++ b/pd/portaudio/configure
@@ -0,0 +1,2903 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by Autoconf 2.52.
+#
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Name of the executable.
+as_me=`echo "$0" |sed 's,.*[\\/],,'`
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+as_executable_p="test -f"
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+# NLS nuisances.
+$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; }
+$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; }
+$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; }
+$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; }
+$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; }
+$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; }
+$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; }
+$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; }
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; }
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+cross_compiling=no
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+ac_unique_file="pa_common/portaudio.h"
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: should be removed in autoconf 3.0.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo "$ac_prog" | sed 's%[\\/][^\\/][^\\/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<EOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+EOF
+
+ cat <<EOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+EOF
+
+ cat <<\EOF
+EOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\EOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-alsa (default=auto)
+ --with-jack (default=auto)
+ --with-oss (default=yes)
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+EOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_subdir in : $ac_subdirs_all; do test "x$ac_subdir" = x: && continue
+ cd $ac_subdir
+ # A "../" for each directory in /$ac_subdir.
+ ac_dots=`echo $ac_subdir |
+ sed 's,^\./,,;s,[^/]$,&/,;s,[^/]*/,../,g'`
+
+ case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_sub_srcdir=$srcdir ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_sub_srcdir=$srcdir/$ac_subdir ;;
+ *) # Relative path.
+ ac_sub_srcdir=$ac_dots$srcdir/$ac_subdir ;;
+ esac
+
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_sub_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_sub_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_sub_srcdir/configure; then
+ echo
+ $SHELL $ac_sub_srcdir/configure --help=recursive
+ elif test -f $ac_sub_srcdir/configure.ac ||
+ test -f $ac_sub_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_subdir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\EOF
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+EOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<EOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.52. Invocation command line was
+
+ $ $0 $@
+
+EOF
+{
+cat <<_ASUNAME
+## ---------- ##
+## Platform. ##
+## ---------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+PATH = $PATH
+
+_ASUNAME
+} >&5
+
+cat >&5 <<EOF
+## ------------ ##
+## Core tests. ##
+## ------------ ##
+
+EOF
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell meta-characters.
+ac_configure_args=
+ac_sep=
+for ac_arg
+do
+ case $ac_arg in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"`
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ ac_sep=" " ;;
+ *) ac_configure_args="$ac_configure_args$ac_sep$ac_arg"
+ ac_sep=" " ;;
+ esac
+ # Get rid of the leading space.
+done
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ echo >&5
+ echo "## ----------------- ##" >&5
+ echo "## Cache variables. ##" >&5
+ echo "## ----------------- ##" >&5
+ echo >&5
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} >&5
+ sed "/^$/d" confdefs.h >conftest.log
+ if test -s conftest.log; then
+ echo >&5
+ echo "## ------------ ##" >&5
+ echo "## confdefs.h. ##" >&5
+ echo "## ------------ ##" >&5
+ echo >&5
+ cat conftest.log >&5
+ fi
+ (echo; echo) >&5
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal" >&5
+ echo "$as_me: exit $exit_status" >&5
+ rm -rf conftest* confdefs* core core.* *.core conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:821: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ cat "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:832: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:840: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:856: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:860: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:866: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:868: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:870: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status. It doesn't matter if
+ # we pass some twice (in addition to the command line arguments).
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"`
+ ac_configure_args="$ac_configure_args '$ac_arg'"
+ ;;
+ *) ac_configure_args="$ac_configure_args $ac_var=$ac_new_val"
+ ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:889: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:891: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+echo "#! $SHELL" >conftest.sh
+echo "exit 0" >>conftest.sh
+chmod +x conftest.sh
+if { (echo "$as_me:911: PATH=\".;.\"; conftest.sh") >&5
+ (PATH=".;."; conftest.sh) 2>&5
+ ac_status=$?
+ echo "$as_me:914: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ ac_path_separator=';'
+else
+ ac_path_separator=:
+fi
+PATH_SEPARATOR="$ac_path_separator"
+rm -f conftest.sh
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:931: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CC="${ac_tool_prefix}gcc"
+echo "$as_me:946: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:954: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:957: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:966: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_CC="gcc"
+echo "$as_me:981: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:989: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:992: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:1005: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CC="${ac_tool_prefix}cc"
+echo "$as_me:1020: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:1028: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:1031: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:1040: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_CC="cc"
+echo "$as_me:1055: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:1063: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:1066: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:1079: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+fi
+ac_cv_prog_CC="cc"
+echo "$as_me:1099: found $ac_dir/$ac_word" >&5
+break
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" ${1+"$@"}
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:1121: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:1124: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:1135: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+echo "$as_me:1150: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:1158: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:1161: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:1174: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_CC="$ac_prog"
+echo "$as_me:1189: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:1197: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:1200: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+test -z "$CC" && { { echo "$as_me:1212: error: no acceptable cc found in \$PATH" >&5
+echo "$as_me: error: no acceptable cc found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:1217:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:1220: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:1223: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:1225: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:1228: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:1230: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:1233: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+#line 1237 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:1253: checking for C compiler default output" >&5
+echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:1256: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:1259: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+for ac_file in `ls a.exe conftest.exe 2>/dev/null;
+ ls a.out conftest 2>/dev/null;
+ ls a.* conftest.* 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;;
+ a.out ) # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool --akim.
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:1282: error: C compiler cannot create executables" >&5
+echo "$as_me: error: C compiler cannot create executables" >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:1288: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:1293: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:1299: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1302: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:1309: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:1317: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:1324: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:1326: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:1329: checking for executable suffix" >&5
+echo $ECHO_N "checking for executable suffix... $ECHO_C" >&6
+if { (eval echo "$as_me:1331: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:1334: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:1350: error: cannot compute EXEEXT: cannot compile and link" >&5
+echo "$as_me: error: cannot compute EXEEXT: cannot compile and link" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:1356: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:1362: checking for object suffix" >&5
+echo $ECHO_N "checking for object suffix... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1368 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:1380: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1383: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:1395: error: cannot compute OBJEXT: cannot compile" >&5
+echo "$as_me: error: cannot compute OBJEXT: cannot compile" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:1402: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:1406: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1412 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1427: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1430: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1433: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1436: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_compiler_gnu=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:1448: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:1454: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1460 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1472: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1475: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1478: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1481: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:1491: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1518: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1521: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1524: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1527: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ ''\
+ '#include <stdlib.h>' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1539 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1552: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1555: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1558: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1561: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+continue
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1571 "configure"
+#include "confdefs.h"
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1583: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1586: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1589: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1592: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:1622: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+echo "$as_me:1637: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:1645: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:1648: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:1657: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_RANLIB="ranlib"
+echo "$as_me:1672: found $ac_dir/$ac_word" >&5
+break
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:1681: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:1684: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:1710: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:1730: checking for a BSD compatible install" >&5
+echo $ECHO_N "checking for a BSD compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ for ac_dir in $PATH; do
+ IFS=$ac_save_IFS
+ # Account for people who put trailing slashes in PATH elements.
+ case $ac_dir/ in
+ / | ./ | .// | /cC/* \
+ | /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* \
+ | /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if $as_executable_p "$ac_dir/$ac_prog"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$ac_dir/$ac_prog" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$ac_dir/$ac_prog" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:1779: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:1792: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $AR in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_AR="$AR" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_AR="$ac_dir/$ac_word"
+ echo "$as_me:1809: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ test -z "$ac_cv_path_AR" && ac_cv_path_AR="no"
+ ;;
+esac
+fi
+AR=$ac_cv_path_AR
+
+if test -n "$AR"; then
+ echo "$as_me:1821: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+ echo "$as_me:1824: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if [ $AR = "no" ] ; then
+ { { echo "$as_me:1829: error: \"Could not find ar - needed to create a library\"" >&5
+echo "$as_me: error: \"Could not find ar - needed to create a library\"" >&2;}
+ { (exit 1); exit 1; }; };
+fi
+
+echo "$as_me:1834: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6
+if test "${ac_cv_c_bigendian+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+#line 1842 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1859: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1862: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1865: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1868: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+#line 1872 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1889: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1892: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1895: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1898: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_c_bigendian=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+ { { echo "$as_me:1914: error: cannot run test program while cross compiling" >&5
+echo "$as_me: error: cannot run test program while cross compiling" >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1919 "configure"
+#include "confdefs.h"
+int
+main ()
+{
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:1935: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:1938: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:1940: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1943: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_c_bigendian=yes
+fi
+rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:1956: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6
+if test $ac_cv_c_bigendian = yes; then
+
+cat >>confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+fi
+
+echo "$as_me:1966: checking for snd_pcm_open in -lasound" >&5
+echo $ECHO_N "checking for snd_pcm_open in -lasound... $ECHO_C" >&6
+if test "${ac_cv_lib_asound_snd_pcm_open+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lasound $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line 1974 "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char snd_pcm_open ();
+int
+main ()
+{
+snd_pcm_open ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:1993: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:1996: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:1999: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:2002: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_asound_snd_pcm_open=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_asound_snd_pcm_open=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:2013: result: $ac_cv_lib_asound_snd_pcm_open" >&5
+echo "${ECHO_T}$ac_cv_lib_asound_snd_pcm_open" >&6
+if test $ac_cv_lib_asound_snd_pcm_open = yes; then
+ have_alsa=yes
+else
+ have_alsa=no
+fi
+
+ succeeded=no
+
+ if test -z "$PKG_CONFIG"; then
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+echo "$as_me:2026: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_PKG_CONFIG="$ac_dir/$ac_word"
+ echo "$as_me:2043: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no"
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+
+if test -n "$PKG_CONFIG"; then
+ echo "$as_me:2055: result: $PKG_CONFIG" >&5
+echo "${ECHO_T}$PKG_CONFIG" >&6
+else
+ echo "$as_me:2058: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ fi
+
+ if test "$PKG_CONFIG" = "no" ; then
+ echo "*** The pkg-config script could not be found. Make sure it is"
+ echo "*** in your path, or set the PKG_CONFIG environment variable"
+ echo "*** to the full path to pkg-config."
+ echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+ else
+ PKG_CONFIG_MIN_VERSION=0.9.0
+ if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+ echo "$as_me:2072: checking for jack" >&5
+echo $ECHO_N "checking for jack... $ECHO_C" >&6
+
+ if $PKG_CONFIG --exists "jack" ; then
+ echo "$as_me:2076: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ succeeded=yes
+
+ echo "$as_me:2080: checking JACK_CFLAGS" >&5
+echo $ECHO_N "checking JACK_CFLAGS... $ECHO_C" >&6
+ JACK_CFLAGS=`$PKG_CONFIG --cflags "jack"`
+ echo "$as_me:2083: result: $JACK_CFLAGS" >&5
+echo "${ECHO_T}$JACK_CFLAGS" >&6
+
+ echo "$as_me:2086: checking JACK_LIBS" >&5
+echo $ECHO_N "checking JACK_LIBS... $ECHO_C" >&6
+ JACK_LIBS=`$PKG_CONFIG --libs "jack"`
+ echo "$as_me:2089: result: $JACK_LIBS" >&5
+echo "${ECHO_T}$JACK_LIBS" >&6
+ else
+ JACK_CFLAGS=""
+ JACK_LIBS=""
+ ## If we have a custom action on failure, don't print errors, but
+ ## do set a variable so people can do so.
+ JACK_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "jack"`
+
+ fi
+
+ else
+ echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+ echo "*** See http://www.freedesktop.org/software/pkgconfig"
+ fi
+ fi
+
+ if test $succeeded = yes; then
+ have_jack=yes
+ else
+ have_jack=no
+ fi
+
+# Check whether --with-alsa or --without-alsa was given.
+if test "${with_alsa+set}" = set; then
+ withval="$with_alsa"
+ with_alsa=$withval
+else
+ with_alsa="yes"
+fi;
+
+# Check whether --with-jack or --without-jack was given.
+if test "${with_jack+set}" = set; then
+ withval="$with_jack"
+ with_jack=$withval
+else
+ with_jack="yes"
+fi;
+
+# Check whether --with-oss or --without-oss was given.
+if test "${with_oss+set}" = set; then
+ withval="$with_oss"
+ with_oss=$withval
+else
+ with_oss="yes"
+fi;
+
+CFLAGS="-g -O2 -Wall"
+
+if [ $ac_cv_c_bigendian = "yes" ] ; then
+ CFLAGS="$CFLAGS -DPA_BIG_ENDIAN"
+else
+ CFLAGS="$CFLAGS -DPA_LITTLE_ENDIAN"
+fi
+
+case "${host_os}" in
+ darwin* )
+
+ OTHER_OBJS="pa_mac_core/pa_mac_core.o";
+ LIBS="-framework AudioUnit -framework AudioToolbox -framework CoreAudio";
+ PADLL="libportaudio.dylib";
+ SHARED_FLAGS="-framework AudioUnit -framework AudioToolbox";
+ SHARED_FLAGS="$SHARED_FLAGS -framework CoreAudio -dynamiclib";
+ ;;
+
+ mingw* )
+
+ OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
+ LIBS="-lwinmm -lm";
+ PADLL="portaudio.dll";
+ SHARED_FLAGS="-shared -mthreads";
+ DLL_LIBS="-lwinmm";
+ ;;
+
+ cygwin* )
+
+ OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
+ LIBS="-lwinmm -lm";
+ PADLL="portaudio.dll";
+ SHARED_FLAGS="-shared -mthreads";
+ DLL_LIBS="-lwinmm";
+ ;;
+
+ *)
+
+echo "$as_me:2174: checking for pthread_create in -lpthread" >&5
+echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line 2182 "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:2201: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:2204: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:2207: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:2210: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:2221: result: $ac_cv_lib_pthread_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6
+if test $ac_cv_lib_pthread_pthread_create = yes; then
+ cat >>confdefs.h <<EOF
+#define HAVE_LIBPTHREAD 1
+EOF
+
+ LIBS="-lpthread $LIBS"
+
+else
+ { { echo "$as_me:2231: error: libpthread not found!" >&5
+echo "$as_me: error: libpthread not found!" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ if [ $have_alsa = "yes" ] && [ $with_alsa != "no" ] ; then
+ LIBS="$LIBS -lasound"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/pa_linux_alsa.o"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/callback_thread.o"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/blocking_calls.o"
+ cat >>confdefs.h <<\EOF
+#define PA_USE_ALSA 1
+EOF
+
+ fi
+
+ if [ $have_jack = "yes" ] && [ $with_jack != "no" ] ; then
+ LIBS="$LIBS $JACK_LIBS"
+ CFLAGS="$CFLAGS $JACK_CFLAGS"
+ OTHER_OBJS="$OTHER_OBJS pa_jack/pa_jack.o"
+ cat >>confdefs.h <<\EOF
+#define PA_USE_JACK 1
+EOF
+
+ fi
+
+ if [ $with_oss != "no" ] ; then
+ OTHER_OBJS="$OTHER_OBJS pa_unix_oss/pa_unix_oss.o"
+ cat >>confdefs.h <<\EOF
+#define PA_USE_OSS 1
+EOF
+
+ fi
+ LIBS="$LIBS -lm -lpthread";
+ PADLL="libportaudio.so";
+ SHARED_FLAGS="-shared";
+
+ OTHER_OBJS="$OTHER_OBJS pa_unix/pa_unix_hostapis.o pa_unix/pa_unix_util.o"
+esac
+
+ac_config_files="$ac_config_files Makefile"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overriden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if cmp -s $cache_file confcache; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then we branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+cat >confdef2opt.sed <<\EOF
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g
+t quote
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g
+t quote
+d
+: quote
+s,[ `~#$^&*(){}\\|;'"<>?],\\&,g
+s,\[,\\&,g
+s,\],\\&,g
+s,\$,$$,g
+p
+EOF
+# We use echo to avoid assuming a particular line-breaking character.
+# The extra dot is to prevent the shell from consuming trailing
+# line-breaks from the sub-command output. A line-break within
+# single-quotes doesn't work because, if this script is created in a
+# platform that uses two characters for line-breaks (e.g., DOS), tr
+# would break.
+ac_LF_and_DOT=`echo; echo .`
+DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
+rm -f confdef2opt.sed
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:2381: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+ac_cs_invocation="\$0 \$@"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Name of the executable.
+as_me=`echo "$0" |sed 's,.*[\\/],,'`
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+as_executable_p="test -f"
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+# NLS nuisances.
+$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; }
+$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; }
+$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; }
+$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; }
+$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; }
+$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; }
+$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; }
+$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; }
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; }
+
+exec 6>&1
+
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\EOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <bug-autoconf@gnu.org>."
+EOF
+
+cat >>$CONFIG_STATUS <<EOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.52,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ shift
+ set dummy "$ac_option" "$ac_optarg" ${1+"$@"}
+ shift
+ ;;
+ -*);;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_need_defaults=false;;
+ esac
+
+ case $1 in
+ # Handling of the options.
+EOF
+cat >>$CONFIG_STATUS <<EOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion"
+ exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;;
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:2549: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ shift
+ CONFIG_FILES="$CONFIG_FILES $1"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $1"
+ ac_need_defaults=false;;
+
+ # This is an error.
+ -*) { { echo "$as_me:2568: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+exec 5>>config.log
+cat >&5 << _ACEOF
+
+## ----------------------- ##
+## Running config.status. ##
+## ----------------------- ##
+
+This file was extended by $as_me 2.52, executed with
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ > $ac_cs_invocation
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+
+_ACEOF
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ *) { { echo "$as_me:2604: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+: ${TMPDIR=/tmp}
+{
+ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=$TMPDIR/cs$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in $TMPDIR" >&2
+ { (exit 1); exit 1; }
+}
+
+EOF
+
+cat >>$CONFIG_STATUS <<EOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@DEFS@,$DEFS,;t t
+s,@LIBS@,$LIBS,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@AR@,$AR,;t t
+s,@OTHER_OBJS@,$OTHER_OBJS,;t t
+s,@PADLL@,$PADLL,;t t
+s,@SHARED_FLAGS@,$SHARED_FLAGS,;t t
+s,@DLL_LIBS@,$DLL_LIBS,;t t
+s,@PKG_CONFIG@,$PKG_CONFIG,;t t
+s,@JACK_CFLAGS@,$JACK_CFLAGS,;t t
+s,@JACK_LIBS@,$JACK_LIBS,;t t
+CEOF
+
+EOF
+
+ cat >>$CONFIG_STATUS <<\EOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ { case "$ac_dir" in
+ [\\/]* | ?:[\\/]* ) as_incr_dir=;;
+ *) as_incr_dir=.;;
+esac
+as_dummy="$ac_dir"
+for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
+ case $as_mkdir_dir in
+ # Skip DOS drivespec
+ ?:) as_incr_dir=$as_mkdir_dir ;;
+ *)
+ as_incr_dir=$as_incr_dir/$as_mkdir_dir
+ test -d "$as_incr_dir" || mkdir "$as_incr_dir"
+ ;;
+ esac
+done; }
+
+ ac_dir_suffix="/`echo $ac_dir|sed 's,^\./,,'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo "$ac_dir_suffix" | sed 's,/[^/]*,../,g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case $srcdir in
+ .) ac_srcdir=.
+ if test -z "$ac_dots"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_dots | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* )
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_dots$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_dots$srcdir ;;
+ esac
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_dots$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:2818: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated automatically by config.status. */
+ configure_input="Generated automatically from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:2836: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:2849: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+EOF
+cat >>$CONFIG_STATUS <<EOF
+ sed "$ac_vpsub
+$extrasub
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+
+{ (exit 0); exit 0; }
+EOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/pd/portaudio/configure.in b/pd/portaudio/configure.in
new file mode 100644
index 00000000..edb0fe11
--- /dev/null
+++ b/pd/portaudio/configure.in
@@ -0,0 +1,123 @@
+dnl
+dnl portaudio V19 configure.in script
+dnl
+dnl Dominic Mazzoni
+dnl
+
+dnl Require autoconf >= 2.13
+AC_PREREQ(2.13)
+
+dnl Init autoconf and make sure configure is being called
+dnl from the right directory
+AC_INIT([pa_common/portaudio.h])
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+AC_PATH_PROG(AR, ar, no)
+if [[ $AR = "no" ]] ; then
+ AC_MSG_ERROR("Could not find ar - needed to create a library");
+fi
+
+dnl This must be one of the first tests we do or it will fail...
+AC_C_BIGENDIAN
+
+dnl extra variables
+AC_SUBST(OTHER_OBJS)
+AC_SUBST(PADLL)
+AC_SUBST(SHARED_FLAGS)
+AC_SUBST(DLL_LIBS)
+
+dnl checks for various host APIs and arguments to configure that
+dnl turn them on or off
+
+AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no)
+
+PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no)
+
+AC_ARG_WITH(alsa,
+ [ --with-alsa (default=auto)],
+ with_alsa=$withval, with_alsa="yes")
+
+AC_ARG_WITH(jack,
+ [ --with-jack (default=auto)],
+ with_jack=$withval, with_jack="yes")
+
+AC_ARG_WITH(oss,
+ [ --with-oss (default=yes)],
+ with_oss=$withval, with_oss="yes")
+
+CFLAGS="-g -O2 -Wall"
+
+if [[ $ac_cv_c_bigendian = "yes" ]] ; then
+ CFLAGS="$CFLAGS -DPA_BIG_ENDIAN"
+else
+ CFLAGS="$CFLAGS -DPA_LITTLE_ENDIAN"
+fi
+
+case "${host_os}" in
+ darwin* )
+ dnl Mac OS X configuration
+
+ OTHER_OBJS="pa_mac_core/pa_mac_core.o";
+ LIBS="-framework AudioUnit -framework AudioToolbox -framework CoreAudio";
+ PADLL="libportaudio.dylib";
+ SHARED_FLAGS="-framework AudioUnit -framework AudioToolbox";
+ SHARED_FLAGS="$SHARED_FLAGS -framework CoreAudio -dynamiclib";
+ ;;
+
+ mingw* )
+ dnl MingW configuration
+
+ OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
+ LIBS="-lwinmm -lm";
+ PADLL="portaudio.dll";
+ SHARED_FLAGS="-shared -mthreads";
+ DLL_LIBS="-lwinmm";
+ ;;
+
+ cygwin* )
+ dnl Cygwin configuration
+
+ OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
+ LIBS="-lwinmm -lm";
+ PADLL="portaudio.dll";
+ SHARED_FLAGS="-shared -mthreads";
+ DLL_LIBS="-lwinmm";
+ ;;
+
+ *)
+ dnl Unix OSS configuration
+
+ AC_CHECK_LIB(pthread, pthread_create,
+ ,
+ AC_MSG_ERROR([libpthread not found!]))
+
+ if [[ $have_alsa = "yes" ] && [ $with_alsa != "no" ]] ; then
+ LIBS="$LIBS -lasound"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/pa_linux_alsa.o"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/callback_thread.o"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/blocking_calls.o"
+ AC_DEFINE(PA_USE_ALSA)
+ fi
+
+ if [[ $have_jack = "yes" ] && [ $with_jack != "no" ]] ; then
+ LIBS="$LIBS $JACK_LIBS"
+ CFLAGS="$CFLAGS $JACK_CFLAGS"
+ OTHER_OBJS="$OTHER_OBJS pa_jack/pa_jack.o"
+ AC_DEFINE(PA_USE_JACK)
+ fi
+
+ if [[ $with_oss != "no" ]] ; then
+ OTHER_OBJS="$OTHER_OBJS pa_unix_oss/pa_unix_oss.o"
+ AC_DEFINE(PA_USE_OSS)
+ fi
+ LIBS="$LIBS -lm -lpthread";
+ PADLL="libportaudio.so";
+ SHARED_FLAGS="-shared";
+
+ OTHER_OBJS="$OTHER_OBJS pa_unix/pa_unix_hostapis.o pa_unix/pa_unix_util.o"
+esac
+
+AC_OUTPUT([Makefile])
diff --git a/pd/portaudio/docs/index.html b/pd/portaudio/docs/index.html
new file mode 100644
index 00000000..7d9b248d
--- /dev/null
+++ b/pd/portaudio/docs/index.html
@@ -0,0 +1,60 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="PortAudio Docs, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Docs</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Documentation</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>Copyright 2000 Phil Burk and Ross Bencina
+<br>&nbsp;
+<h3>
+<a href="portaudio_h.txt">API Reference</a></h3>
+
+<blockquote>The Application Programmer Interface is documented in "portaudio.h".</blockquote>
+
+<h3>
+<a href="pa_tutorial.html">Tutorial</a></h3>
+
+<blockquote>Describes how to write audio programs using the PortAudio API.</blockquote>
+
+<h3>
+<a href="pa_impl_guide.html">Implementation Guide</a></h3>
+
+<blockquote>Describes how to write an implementation of PortAudio for a
+new computer platform.</blockquote>
+
+<h3>
+<a href="portaudio_icmc2001.pdf">Paper Presented at ICMC2001</a> (PDF)</h3>
+
+<blockquote>Describes the PortAudio API and discusses implementation issues.
+Written July 2001.</blockquote>
+
+<h3>
+<a href="latency.html">Improving Latency</a></h3>
+
+<blockquote>How to tune your computer to achieve the lowest possible audio
+delay.</blockquote>
+
+<h3>
+<a href="proposals.html">Proposed Changes</a></h3>
+
+<blockquote>Describes API changes being considered by the developer community.
+Feedback welcome.</blockquote>
+<a href="http://www.portaudio.com/">Return to PortAudio Home Page</a>
+</body>
+</html>
diff --git a/pd/portaudio/docs/latency.html b/pd/portaudio/docs/latency.html
new file mode 100644
index 00000000..87f1d122
--- /dev/null
+++ b/pd/portaudio/docs/latency.html
@@ -0,0 +1,192 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Internal docs. How a stream is started or stopped.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Implementation - Start/Stop</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+<a href="http://www.portaudio.com">PortAudio</a> Latency</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>This page discusses the issues of audio latency for <a href="http://www.portaudio.com">PortAudio</a>
+. It offers suggestions on how to lower latency to improve the responsiveness
+of applications.
+<blockquote><b><a href="#what">What is Latency?</a></b>
+<br><b><a href="#portaudio">PortAudio and Latency</a></b>
+<br><b><a href="#macintosh">Macintosh</a></b>
+<br><b><a href="#unix">Unix</a></b>
+<br><b><a href="#windows">WIndows</a></b></blockquote>
+By Phil Burk, Copyright 2002 Phil Burk and Ross Bencina
+<h2>
+<a NAME="what"></a>What is Latency?</h2>
+Latency is basically longest time that you have to wait before you obtain
+a desired result. For digital audio output it is the time between making
+a sound in software and finally hearing it.
+<p>Consider the example of pressing a key on the ASCII keyboard to play
+a note. There are several stages in this process which each contribute
+their own latency. First the operating system must respond to the keypress.
+Then the audio signal generated must work its way through the PortAudio
+buffers. Then it must work its way through the audio card hardware. Then
+it must go through the audio amplifier which is very quick and then travel
+through the air. Sound travels at abous one foot per millisecond through
+air so placing speakers across the room can add 5-20 msec of delay.
+<p>The reverse process occurs when recording or responding to audio input.
+If you are processing audio, for example if you implement a software guitar
+fuzz box, then you have both the audio input and audio output latencies
+added together.
+<p>The audio buffers are used to prevent glitches in the audio stream.
+The user software writes audio into the output buffers. That audio is read
+by the low level audio driver or by DMA and sent to the DAC. If the computer
+gets busy doing something like reading the disk or redrawing the screen,
+then it may not have time to fill the audio buffer. The audio hardware
+then runs out of audio data, which causes a glitch. By using a large enough
+buffer we can ensure that there is always enough audio data for the audio
+hardware to play. But if the buffer is too large then the latency is high
+and the system feels sluggish. If you play notes on the keyboard then the
+"instrument" will feel unresponsive. So you want the buffers to be as small
+as possible without glitching.
+<h2>
+<a NAME="portaudio"></a>PortAudio and Latency</h2>
+The only delay that PortAudio can control is the total length of its buffers.
+The Pa_OpenStream() call takes two parameters: numBuffers and framesPerBuffer.
+The latency is also affected by the sample rate which we will call framesPerSecond.
+A frame is a set of samples that occur simultaneously. For a stereo stream,
+a frame is two samples.
+<p>The latency in milliseconds due to this buffering&nbsp; is:
+<blockquote><tt>latency_msec = 1000 * numBuffers * framesPerBuffer / framesPerSecond</tt></blockquote>
+This is not the total latency, as we have seen, but it is the part we can
+control.
+<p>If you call Pa_OpenStream() with numBuffers equal to zero, then PortAudio
+will select a conservative number that will prevent audio glitches. If
+you still get glitches, then you can pass a larger value for numBuffers
+until the glitching stops. if you try to pass a numBuffers value that is
+too small, then PortAudio will use its own idea of the minimum value.
+<p>PortAudio decides on the minimum number of buffers in a conservative
+way based on the frameRate, operating system and other variables. You can
+query the value that PortAudio will use by calling:
+<blockquote><tt>int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate
+);</tt></blockquote>
+On some systems you can override the PortAudio minimum if you know your
+system can handle a lower value. You do this by setting an environment
+variable called PA_MIN_LATENCY_MSEC which is read by PortAudio when it
+starts up. This is supported on the PortAudio implementations for Windows
+MME, Windows DirectSound, and Unix OSS.
+<h2>
+<a NAME="macintosh"></a>Macintosh</h2>
+The best thing you can do to improve latency on Mac OS 8 and 9 is to turn
+off Virtual Memory. PortAudio V18 will detect that Virtual Memory is turned
+off and use a very low latency.
+<p>For Mac OS X the latency is very low because Apple Core Audio is so
+well written. You can set the PA_MIN_LATENCY_MSEC variable using:
+<blockquote><tt>setenv PA_MIN_LATENCY_MSEC 4</tt></blockquote>
+
+<h2>
+<a NAME="unix"></a>Unix</h2>
+PortAudio under Unix currently uses a backgroud thread that reads and writes
+to OSS. This gives you decent but not great latency. But if you raise the
+priority of the background thread to a very priority then you can get under
+10 milliseconds latency. In order to raise your priority you must run the
+PortAudio program as root! You must also set PA_MIN_LATENCY_MSEC using
+the appropriate command for your shell.
+<h2>
+<a NAME="windows"></a>Windows</h2>
+Latency under Windows is a complex issue because of all the alternative
+operating system versions and device drivers. I have seen latency range
+from 8 milliseconds to 400 milliseconds. The worst case is when using Windows
+NT. Windows 98 is a little better, and Windows XP can be quite good if
+properly tuned.
+<p>The underlying audio API also makes a lot of difference. If the audio
+device has its own DirectSound driver then DirectSound can often provide
+better latency than WMME. But if a real DirectSound driver is not available
+for your device then it is emulated using WMME and the latency can be very
+high. That's where I saw the 400 millisecond latency. The ASIO implementation
+is generally very good and will give the lowest latency if available.
+<p>You can set the PA_MIN_LATENCY_MSEC variable to 50, for example, by
+entering in MS-DOS:
+<blockquote><tt>set PA_MIN_LATENCY_MSEC=50</tt></blockquote>
+If you enter this in a DOS window then you must run the PortAudio program
+from that same window for the variable to have an effect. You can add that
+line to your C:\AUTOEXEC.BAT file and reboot if you want it to affect any
+PortAudio based program.
+<p>For Windows XP, you can set environment variables as follows:
+<ol>
+<li>
+Select "Control Panel" from the "Start Menu".</li>
+
+<li>
+Launch the "System" Control Panel</li>
+
+<li>
+Click on the "Advanced" tab.</li>
+
+<li>
+Click on the "Environment Variables" button.</li>
+
+<li>
+Click "New" button under&nbsp; User Variables.</li>
+
+<li>
+Enter PA_MIN_LATENCY_MSEC for the name and some optimistic number for the
+value.</li>
+
+<li>
+Click OK, OK, OK.</li>
+</ol>
+
+<h3>
+Improving Latency on Windows</h3>
+There are several steps you can take to improve latency under windows.
+<ol>
+<li>
+Avoid reading or writng to disk when doing audio.</li>
+
+<li>
+Turn off all automated background tasks such as email clients, virus scanners,
+backup programs, FTP servers, web servers, etc. when doing audio.</li>
+
+<li>
+Disconnect from the network to prevent network traffic from interrupting
+your CPU.</li>
+</ol>
+<b>Important: </b>Windows XP users can also tune the OS to favor background
+tasks, such as audio, over foreground tasks, such as word processing. I
+lowered my latency from 40 to 10 milliseconds using this simple technique.
+<ol>
+<li>
+Select "Control Panel" from the "Start Menu".</li>
+
+<li>
+Launch the "System" Control Panel</li>
+
+<li>
+Click on the "Advanced" tab.</li>
+
+<li>
+Click on the "Settings" button in the Performance area.</li>
+
+<li>
+Click on the "Advanced" tab.</li>
+
+<li>
+Select "Background services" in the Processor Scheduling area.</li>
+
+<li>
+Click OK, OK.</li>
+</ol>
+Please let us know if you have others sugestions for lowering latency.
+<br>&nbsp;
+<br>&nbsp;
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_impl_guide.html b/pd/portaudio/docs/pa_impl_guide.html
new file mode 100644
index 00000000..50abc304
--- /dev/null
+++ b/pd/portaudio/docs/pa_impl_guide.html
@@ -0,0 +1,197 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Internal docs. How a stream is started or stopped.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Implementation - Start/Stop</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+<a href="http://www.portaudio.com">PortAudio</a> Implementation Guide</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>This document describes how to implement the PortAudio API on a new
+computer platform. Implementing PortAudio on a new platform, makes it possible
+to port many existing audio applications to that platform.
+<p>By Phil Burk
+<br>Copyright 2000 Phil Burk and Ross Bencina
+<p>Note that the license says: <b>"Any person wishing to distribute modifications
+to the Software is requested to send the modifications to the original
+developer so that they can be incorporated into the canonical version."</b>.
+So when you have finished a new implementation, please send it back to
+us at&nbsp; "<a href="http://www.portaudio.com">http://www.portaudio.com</a>"
+so that we can make it available for other users. Thank you!
+<h2>
+Download the Latest PortAudio Implementation</h2>
+Always start with the latest implementation available at "<a href="http://www.portaudio.com">http://www.portaudio.com</a>".
+Look for the nightly snapshot under the CVS section.
+<h2>
+Select an Existing Implementation as a Basis</h2>
+The fastest way to get started is to take an existing implementation and
+translate it for your new platform. Choose an implementation whose architecture
+is as close as possible to your target.
+<ul>
+<li>
+DirectSound Implementation - pa_win_ds - Uses a timer callback for the
+background "thread". Polls a circular buffer and writes blocks of data
+to keep it full.</li>
+
+<li>
+Windows MME - pa_win_wmme - Spawns an actual Win32 thread. Writes blocks
+of data to the HW device and waits for events that signal buffer completion.</li>
+
+<li>
+Linux OSS - pa_linux - Spawns a real thread that writes to the "/dev/dsp"
+stream using blocking I/O calls.</li>
+</ul>
+When you write a new implementation, you will be using some code that is
+in common with all implementations. This code is in the folder "pa_common".
+It provides various functions such as parameter checking, error code to
+text conversion, sample format conversion, clipping and dithering, etc.
+<p>The code that you write will go into a separate folder called "pa_{os}_{api}".
+For example, code specific to the DirectSound interface for Windows goes
+in "pa_win_ds".
+<h2>
+Read Docs and Code</h2>
+Famialiarize yourself with the system by reading the documentation provided.
+here is a suggested order:
+<ol>
+<li>
+User Programming <a href="pa_tutorial.html">Tutorial</a></li>
+
+<li>
+Header file "pa_common/portaudio.h" which defines API.</li>
+
+<li>
+Header file "pa_common/pa_host.h" for host dependant code. This definces
+the routine you will need to provide.</li>
+
+<li>
+Shared code in "pa_common/pa_lib.c".</li>
+
+<li>
+Docs on Implementation of <a href="pa_impl_startstop.html">Start/Stop</a>
+code.</li>
+</ol>
+
+<h2>
+Implement&nbsp; Output to Default Device</h2>
+Now we are ready to crank some code. For instant gratification, let's try
+to play a sine wave.
+<ol>
+<li>
+Link the test program "pa_tests/patest_sine.c" with the file "pa_lib.c"
+and the implementation specific file you are creating.</li>
+
+<li>
+For now, just stub out the device query code and the audio input code.</li>
+
+<li>
+Modify PaHost_OpenStream() to open your default target device and get everything
+setup.</li>
+
+<li>
+Modify PaHost_StartOutput() to start playing audio.</li>
+
+<li>
+Modify PaHost_StopOutput() to stop audio.</li>
+
+<li>
+Modify PaHost_CloseStream() to clean up. Free all memory that you allocated
+in PaHost_OpenStream().</li>
+
+<li>
+Keep cranking until you can play a sine wave using "patest_sine.c".</li>
+
+<li>
+Once that works, try "patest_pink.c", "patest_clip.c", "patest_sine8.c".</li>
+
+<li>
+To test your Open and Close code, try "patest_many.c".</li>
+
+<li>
+Now test to make sure that the three modes of stopping are properly supported
+by running "patest_stop.c".</li>
+
+<li>
+Test your implementation of time stamping with "patest_sync.c".</li>
+</ol>
+
+<h2>
+Implement Device Queries</h2>
+Now that output is working, lets implement the code for querying what devices
+are available to the user. Run "pa_tests/pa_devs.c". It should print all
+of the devices available and their characteristics.
+<h2>
+Implement Input</h2>
+Implement audio input and test it with:
+<ol>
+<li>
+patest_record.c - record in half duplex, play back as recorded.</li>
+
+<li>
+patest_wire.c - full duplex, copies input to output. Note that some HW
+may not support full duplex.</li>
+
+<li>
+patest_fuzz.c - plug in your guitar and get a feel for why latency is an
+important issue in computer music.</li>
+
+<li>
+paqa_devs.c - try to open every device and use it with every possible format</li>
+</ol>
+
+<h2>
+Debugging Tools</h2>
+You generally cannot use printf() calls to debug real-time processes because
+they disturb the timing. Also calling printf() from your background thread
+or interrupt could crash the machine. So PA includes a tool for capturing
+events and storing the information while it is running. It then prints
+the events when Pa_Terminate() is called.
+<ol>
+<li>
+To enable trace mode, change TRACE_REALTIME_EVENTS in "pa_common/pa_trace.h"
+from a (0) to a (1).</li>
+
+<li>
+Link with "pa_common/pa_trace.c".</li>
+
+<li>
+Add trace messages to your code by calling:</li>
+
+<br><tt>&nbsp;&nbsp; void AddTraceMessage( char *msg, int data );</tt>
+<br><tt>for example</tt>
+<br><tt>&nbsp;&nbsp; AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ",
+past->past_NumCallbacks );</tt>
+<li>
+Run your program. You will get a dump of events at the end.</li>
+
+<li>
+You can leave the trace messages in your code. They will turn to NOOPs
+when you change TRACE_REALTIME_EVENTS back to (0).</li>
+</ol>
+
+<h2>
+Delivery</h2>
+Please send your new code along with notes on the implementation back to
+us at "<a href="http://www.portaudio.com">http://www.portaudio.com</a>".
+We will review the implementation and post it with your name. If you had
+to make any modifications to the code in "pa_common" or "pa_tests" <b>please</b>
+send us those modifications and your notes. We will try to merge your changes
+so that the "pa_common" code works with <b>all</b> implementations.
+<p>If you have suggestions for how to make future implementations easier,
+please let us know.
+<br>THANKS!
+<br>&nbsp;
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_impl_startstop.html b/pd/portaudio/docs/pa_impl_startstop.html
new file mode 100644
index 00000000..0f2d0ce5
--- /dev/null
+++ b/pd/portaudio/docs/pa_impl_startstop.html
@@ -0,0 +1,190 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.75 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Internal docs. How a stream is started or stopped.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Implementation - Start/Stop</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Implementation</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Starting and Stopping Streams</h2>
+PortAudio is generally executed in two "threads". The foreground thread
+is the application thread. The background "thread" may be implemented as
+an actual thread, an interrupt handler, or a callback from a timer thread.
+<p>There are three ways that PortAudio can stop a stream. In each case
+we look at the sequence of events and the messages sent between the two
+threads. The following variables are contained in the internalPortAudioStream.
+<blockquote><tt>int&nbsp;&nbsp; past_IsActive;&nbsp;&nbsp;&nbsp;&nbsp;
+/* Background is still playing. */</tt>
+<br><tt>int&nbsp;&nbsp; past_StopSoon;&nbsp;&nbsp;&nbsp;&nbsp; /* Stop
+when last buffer done. */</tt>
+<br><tt>int&nbsp;&nbsp; past_StopNow;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*
+Stop IMMEDIATELY. */</tt></blockquote>
+
+<h3>
+Pa_AbortStream()</h3>
+This function causes the background thread to terminate as soon as possible
+and audio I/O to stop abruptly.
+<br>&nbsp;
+<table BORDER COLS=2 WIDTH="60%" >
+<tr>
+<td><b>Foreground Thread</b></td>
+
+<td><b>Background Thread</b></td>
+</tr>
+
+<tr>
+<td>sets <tt>StopNow</tt></td>
+
+<td></td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>sees <tt>StopNow</tt>,&nbsp;</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>clears IsActive, stops thread</td>
+</tr>
+
+<tr>
+<td>waits for thread to exit</td>
+
+<td></td>
+</tr>
+
+<tr>
+<td>turns off audio I/O</td>
+
+<td></td>
+</tr>
+</table>
+
+<h3>
+Pa_StopStream()</h3>
+This function stops the user callback function from being called and then
+waits for all audio data written to the output buffer to be played. In
+a system with very low latency, you may not hear any difference between
+<br>&nbsp;
+<table BORDER COLS=2 WIDTH="60%" >
+<tr>
+<td><b>Foreground Thread</b></td>
+
+<td><b>Background Thread</b></td>
+</tr>
+
+<tr>
+<td>sets StopSoon</td>
+
+<td></td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>stops calling user callback</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>continues until output buffer empty</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>clears IsActive, stops thread</td>
+</tr>
+
+<tr>
+<td>waits for thread to exit</td>
+
+<td></td>
+</tr>
+
+<tr>
+<td>turns off audio I/O</td>
+
+<td></td>
+</tr>
+</table>
+
+<h3>
+User callback returns one.</h3>
+If the user callback returns one then the user callback function will no
+longer be called. Audio output will continue until all audio data written
+to the output buffer has been played. Then the audio I/O is stopped, the
+background thread terminates, and the stream becomes inactive.
+<br>&nbsp;
+<table BORDER COLS=2 WIDTH="60%" >
+<tr>
+<td><b>Foreground Thread</b></td>
+
+<td><b>Background Thread</b></td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>callback returns 1</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>sets StopSoon</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>stops calling user callback</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>continues until output buffer empty</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>clears IsActive, stops thread</td>
+</tr>
+
+<tr>
+<td>waits for thread to exit</td>
+
+<td></td>
+</tr>
+
+<tr>
+<td>turns off audio I/O</td>
+
+<td></td>
+</tr>
+</table>
+
+<br>&nbsp;
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_asio.html b/pd/portaudio/docs/pa_tut_asio.html
new file mode 100644
index 00000000..1c3e5bfa
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_asio.html
@@ -0,0 +1,55 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Compiling for ASIO (Windows or Macintosh)</h2>
+
+<blockquote>ASIO is a low latency audio API from Steinberg. To compile
+an ASIO application, you must first <a href="http://www.steinberg.net/developers/ASIO2SDKAbout.phtml">download
+the ASIO SDK</a> from Steinberg. You also need to obtain ASIO drivers for
+your audio device.
+<p>Note: I am using '/' as a file separator below. On Macintosh replace
+'/' with ':'. On Windows, replace '/' with '\'.
+<p>&nbsp;To use ASIO with the PortAudio library add the following source
+files to your project:
+<blockquote>
+<pre>pa_asio/pa_asio.cpp</pre>
+</blockquote>
+and also these files from the ASIO SDK:
+<blockquote>
+<pre>common/asio.cpp
+host/asiodrivers.cpp
+host/asiolist.cpp</pre>
+</blockquote>
+and add these directories to the path for include files
+<blockquote>
+<pre>asiosdk2/host/pc&nbsp;&nbsp; (for Windows)
+asiosdk2/common
+asiosdk2/host</pre>
+</blockquote>
+You may try compiling the "pa_tests/patest_saw.c" file first because it
+is the simplest.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_over.html">previous</a> |&nbsp; <a href="pa_tut_callback.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_callback.html b/pd/portaudio/docs/pa_tut_callback.html
new file mode 100644
index 00000000..f5ccaf0f
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_callback.html
@@ -0,0 +1,91 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Writing a Callback Function</h2>
+
+<blockquote>To write a program using PortAudio, you must include the "portaudio.h"
+include file. You may wish to read "<a href="portaudio_h.txt">portaudio.h</a>"
+because it contains a complete description of the PortAudio functions and
+constants.
+<blockquote>
+<pre>#include "portaudio.h"</pre>
+</blockquote>
+The next task is to write your custom callback function. It is a function
+that is called by the PortAudio engine whenever it has captured audio data,
+or when it needs more audio data for output.
+<p>Your callback function is often called by an interrupt, or low level
+process so you should not do any complex system activities like allocating
+memory, or reading or writing files, or printf(). Just crunch numbers and
+generate audio signals. What is safe or not safe will vary from platform
+to platform. On the Macintosh, for example, you can only call "interrupt
+safe" routines. Also do not call any PortAudio functions in the callback
+except for Pa_StreamTime() and Pa_GetCPULoad().
+<p>Your callback function must return an int and accept the exact parameters
+specified in this typedef:
+<blockquote>
+<pre>typedef int (PortAudioCallback)(
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *inputBuffer, void *outputBuffer,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long framesPerBuffer,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PaTimestamp outTime, void *userData );</pre>
+</blockquote>
+Here is an example callback function from the test file "patests/patest_saw.c".
+It calculates a simple left and right sawtooth signal and writes it to
+the output buffer. Notice that in this example, the signals are of <tt>float</tt>
+data type. The signals must be between -1.0 and +1.0. You can also use
+16 bit integers or other formats which are specified during setup. You
+can pass a pointer to your data structure through PortAudio which will
+appear as <tt>userData</tt>.
+<blockquote>
+<pre>int patestCallback(&nbsp; void *inputBuffer, void *outputBuffer,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long framesPerBuffer,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PaTimestamp outTime, void *userData )
+{
+&nbsp;&nbsp;&nbsp; unsigned int i;
+/* Cast data passed through stream to our structure type. */
+&nbsp;&nbsp;&nbsp; paTestData *data = (paTestData*)userData;
+&nbsp;&nbsp;&nbsp; float *out = (float*)outputBuffer;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; for( i=0; i&lt;framesPerBuffer; i++ )
+&nbsp;&nbsp;&nbsp; {
+&nbsp;&nbsp;&nbsp; /* Stereo channels are interleaved. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *out++ = data->left_phase;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* left */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *out++ = data->right_phase;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* right */
+
+&nbsp;&nbsp;&nbsp; /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data->left_phase += 0.01f;
+&nbsp;&nbsp;&nbsp; /* When signal reaches top, drop back down. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
+
+&nbsp;&nbsp;&nbsp; /* higher pitch so we can distinguish left and right. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data->right_phase += 0.03f;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
+&nbsp;&nbsp;&nbsp; }
+&nbsp;&nbsp;&nbsp; return 0;
+}</pre>
+</blockquote>
+</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_over.html">previous</a> |&nbsp; <a href="pa_tut_init.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_devs.html b/pd/portaudio/docs/pa_tut_devs.html
new file mode 100644
index 00000000..1756992c
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_devs.html
@@ -0,0 +1,65 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.75 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Querying for Available Devices</h2>
+
+<blockquote>There are often several different audio devices available in
+a computer with different capabilities. They can differ in the sample rates
+supported, bit widths, etc. PortAudio provides a simple way to query for
+the available devices, and then pass the selected device to Pa_OpenStream().
+For an example, see the file "pa_tests/pa_devs.c".
+<p>To determine the number of devices:
+<blockquote>
+<pre>numDevices = Pa_CountDevices();</pre>
+</blockquote>
+You can then query each device in turn by calling Pa_GetDeviceInfo() with
+an index.
+<blockquote>
+<pre>for( i=0; i&lt;numDevices; i++ ) {
+&nbsp;&nbsp;&nbsp;&nbsp; pdi = Pa_GetDeviceInfo( i );</pre>
+</blockquote>
+It will return a pointer to a <tt>PaDeviceInfo</tt> structure which is
+defined as:
+<blockquote>
+<pre>typedef struct{
+&nbsp;&nbsp;&nbsp; int structVersion;&nbsp;
+&nbsp;&nbsp;&nbsp; const char *name;
+&nbsp;&nbsp;&nbsp; int maxInputChannels;
+&nbsp;&nbsp;&nbsp; int maxOutputChannels;
+/* Number of discrete rates, or -1 if range supported. */
+&nbsp;&nbsp;&nbsp; int numSampleRates;
+/* Array of supported sample rates, or {min,max} if range supported. */
+&nbsp;&nbsp;&nbsp; const double *sampleRates;
+&nbsp;&nbsp;&nbsp; PaSampleFormat nativeSampleFormat;
+}PaDeviceInfo;</pre>
+</blockquote>
+If the device supports a continuous range of sample rates, then numSampleRates
+will equal -1, and the sampleRates array will have two values, the minimum&nbsp;
+and maximum rate.
+<p>The device information is allocated by Pa_Initialize() and freed by
+Pa_Terminate() so you do not have to free() the structure returned by Pa_GetDeviceInfo().</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_util.html">previous</a> |&nbsp; <a href="pa_tut_rw.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_explore.html b/pd/portaudio/docs/pa_tut_explore.html
new file mode 100644
index 00000000..91c08a5b
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_explore.html
@@ -0,0 +1,42 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Exploring PortAudio</h2>
+
+<blockquote>Now that you have a good idea of how PortAudio works, you can
+try out the test programs.
+<ul>
+<li>
+For an example of playing a sine wave, see "pa_tests/patest_sine.c".</li>
+
+<li>
+For an example of recording and playing back a sound, see&nbsp; "pa_tests/patest_record.c".</li>
+</ul>
+I also encourage you to examine the source for the PortAudio libraries.
+If you have suggestions on ways to improve them, please let us know. if
+you want to implement PortAudio on a new platform, please let us know as
+well so we can coordinate people's efforts.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_rw.html">previous</a> |&nbsp; next</font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_init.html b/pd/portaudio/docs/pa_tut_init.html
new file mode 100644
index 00000000..91bfa8d9
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_init.html
@@ -0,0 +1,43 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Initializing PortAudio</h2>
+
+<blockquote>Before making any other calls to PortAudio, you must call <tt>Pa_Initialize</tt>().
+This will trigger a scan of available devices which can be queried later.
+Like most PA functions, it will return a result of type <tt>paError</tt>.
+If the result is not <tt>paNoError</tt>, then an error has occurred.
+<blockquote>
+<pre>err = Pa_Initialize();
+if( err != paNoError ) goto error;</pre>
+</blockquote>
+You can get a text message that explains the error message by passing it
+to
+<blockquote>
+<pre>printf(&nbsp; "PortAudio error: %s\n", Pa_GetErrorText( err ) );</pre>
+</blockquote>
+</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_callback.html">previous</a> |&nbsp; <a href="pa_tut_open.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_mac.html b/pd/portaudio/docs/pa_tut_mac.html
new file mode 100644
index 00000000..bf3dafd1
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_mac.html
@@ -0,0 +1,41 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Compiling for Macintosh</h2>
+
+<blockquote>To compile a Macintosh application with the PortAudio library,
+add the following source files to your project:
+<blockquote>
+<pre>pa_mac:pa_mac.c
+pa_common:pa_lib.c
+pa_common:portaudio.h
+pa_common:pa_host.h</pre>
+</blockquote>
+Also add the Apple <b>SoundLib</b> to your project.
+<p>You may try compiling the "pa_tests:patest_saw.c" file first because
+it is the simplest.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_over.html">previous</a> |&nbsp; <a href="pa_tut_callback.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_mac_osx.html b/pd/portaudio/docs/pa_tut_mac_osx.html
new file mode 100644
index 00000000..3af8c140
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_mac_osx.html
@@ -0,0 +1,46 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Compiling for Macintosh OS X</h2>
+
+<blockquote>To compile a Macintosh OS X CoreAudio application with the
+PortAudio library:
+<p>Create a new ProjectBuilder project. You can use a "Tool" project to
+run the PortAudio examples.
+<p>Add the following source files to your Project:
+<blockquote>
+<pre>pa_mac_core/pa_mac_core.c
+pa_common/pa_lib.c
+pa_common/portaudio.h
+pa_common/pa_host.h
+pa_common/pa_convert.c</pre>
+</blockquote>
+Add the Apple CoreAudio.framework to your project by selecting "Add FrameWorks..."
+from the Project menu.
+<p>Compile and run the "pa_tests:patest_saw.c" file first because it is
+the simplest.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_over.html">previous</a> |&nbsp; <a href="pa_tut_callback.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_open.html b/pd/portaudio/docs/pa_tut_open.html
new file mode 100644
index 00000000..1621ef30
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_open.html
@@ -0,0 +1,52 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Opening a Stream using Defaults</h2>
+
+<blockquote>The next step is to open a stream which is similar to opening
+a file. You can specify whether you want audio input and/or output, how
+many channels, the data format, sample rate, etc. There are two calls for
+opening streams, <tt>Pa_OpenStream</tt>() and <tt>Pa_OpenDefaultStream</tt>().
+<p><tt>Pa_OpenStream()</tt> takes extra&nbsp; parameters which give you
+more control. You can normally just use <tt>Pa_OpenDefaultStream</tt>()
+which just calls <tt>Pa_OpenStream()</tt> <tt>with</tt> some reasonable
+default values.&nbsp; Let's open a stream for stereo output, using floating
+point data, at 44100 Hz.
+<blockquote>
+<pre>err = Pa_OpenDefaultStream(
+&nbsp;&nbsp;&nbsp; &amp;stream,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* passes back stream pointer */
+&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* no input channels */
+&nbsp;&nbsp;&nbsp; 2,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* stereo output */
+&nbsp;&nbsp;&nbsp; paFloat32,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 32 bit floating point output */
+&nbsp;&nbsp;&nbsp; 44100,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* sample rate */
+&nbsp;&nbsp;&nbsp; 256,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* frames per buffer */
+&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* number of buffers, if zero then use default minimum */
+&nbsp;&nbsp;&nbsp; patestCallback, /* specify our custom callback */
+&nbsp;&nbsp;&nbsp; &amp;data );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* pass our data through to callback */</pre>
+</blockquote>
+If you want to use 16 bit integer data, pass <tt>paInt16</tt> instead of
+<tt>paFloat32</tt>.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_init.html">previous</a> |&nbsp; <a href="pa_tut_run.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_oss.html b/pd/portaudio/docs/pa_tut_oss.html
new file mode 100644
index 00000000..1bb76f25
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_oss.html
@@ -0,0 +1,46 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Compiling for Unix OSS</h2>
+
+<blockquote>[Skip this page if you are not using Unix and OSS]
+<p>We currently support the <a href="http://www.opensound.com/">OSS</a>
+audio drivers for Linux, Solaris, and FreeBSD. We hope to someday support
+the newer ALSA drivers.
+<ol>
+<li>
+cd to pa_unix_oss directory</li>
+
+<li>
+Edit the Makefile and uncomment one of the tests. You may try compiling
+the "patest_sine.c" file first because it is very simple.</li>
+
+<li>
+gmake run</li>
+</ol>
+</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_pc.html">previous</a> |&nbsp; <a href="pa_tut_callback.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_over.html b/pd/portaudio/docs/pa_tut_over.html
new file mode 100644
index 00000000..baa99205
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_over.html
@@ -0,0 +1,92 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Overview of PortAudio</h2>
+
+<blockquote>PortAudio is a library that provides streaming audio input
+and output. It is a cross-platform API (Application Programming Interface)
+that works on Windows, Macintosh, Unix running OSS, SGI, BeOS, and perhaps
+other platforms by the time you read this. This means that you can write
+a simple 'C' program to process or generate an audio signal, and that program
+can run on several different types of computer just by recompiling the
+source code.
+<p>Here are the steps to writing a PortAudio application:
+<ol>
+<li>
+Write a callback function that will be called by PortAudio when audio processing
+is needed.</li>
+
+<li>
+Initialize the PA library and open a stream for audio I/O.</li>
+
+<li>
+Start the stream. Your callback function will be now be called repeatedly
+by PA in the background.</li>
+
+<li>
+In your callback you can read audio data from the inputBuffer and/or write
+data to the outputBuffer.</li>
+
+<li>
+Stop the stream by returning 1 from your callback, or by calling a stop
+function.</li>
+
+<li>
+Close the stream and terminate the library.</li>
+</ol>
+</blockquote>
+
+<blockquote>There is also <a href="pa_tut_rw.html">another interface</a>
+provided that allows you to generate audio in the foreground. You then
+simply write data to the stream and the tool will not return until it is
+ready to accept more data. This interface is simpler to use but is usually
+not preferred for large applications because it requires that you launch
+a thread to perform the synthesis. Launching a thread may be difficult
+on non-multi-tasking systems such as the Macintosh prior to MacOS X.
+<p>Let's continue by building a simple application that will play a sawtooth
+wave.
+<p>Please select the page for the specific implementation you would like
+to use:
+<ul>
+<li>
+<a href="pa_tut_pc.html">Windows (WMME or DirectSound)</a></li>
+
+<li>
+<a href="pa_tut_mac.html">Macintosh SoundManager for OS 7,8,9</a></li>
+
+<li>
+<a href="pa_tut_mac_osx.html">Macintosh CoreAudio for OS X</a></li>
+
+<li>
+<a href="pa_tut_asio.html">ASIO on Windows or Macintosh</a></li>
+
+<li>
+<a href="pa_tut_oss.html">Unix OSS</a></li>
+</ul>
+or continue with the <a href="pa_tut_callback.html">next page of the programming
+tutorial</a>.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tutorial.html">previous</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_pc.html b/pd/portaudio/docs/pa_tut_pc.html
new file mode 100644
index 00000000..87e5f9a0
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_pc.html
@@ -0,0 +1,78 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Compiling for Windows (WMME or DirectSound)</h2>
+
+<blockquote>To compile PortAudio for Windows, you can choose between two
+options. One implementation uses the DirectSound API. The other uses the
+Windows MultiMedia Extensions API (aka WMME or WAVE).
+<p>Some advantages of using DirectSound are that DirectSound may have lower
+latency than WMME, and supports effects processing plugins. But one disadvantage
+is that DirectSound is not installed on all PCs, and is not well supported
+under Windows NT. So WMME is the best choice for most projects.
+<p>For either implementation add the following source files to your project:
+<blockquote>
+<pre><b>pa_common\pa_lib.c
+pa_common\portaudio.h
+pa_common\pa_host.h</b></pre>
+</blockquote>
+Link with the system library "<b>winmm.lib</b>". For Visual C++:
+<ol>
+<li>
+select "Settings..." from the "Project" menu,</li>
+
+<li>
+select the project name in the tree on the left,</li>
+
+<li>
+choose "All Configurations" in the popup menu above the tree,</li>
+
+<li>
+select the "Link" tab,</li>
+
+<li>
+enter "winmm.lib", without quotes, as the first item in the "Object/library
+modules:" field.</li>
+</ol>
+<b>WMME</b> - To use the WMME implementation, add the following source
+files to your project:
+<blockquote><b><tt>pa_win_wmme/pa_win_wmme.c</tt></b></blockquote>
+<b>DirectSound</b> - If you want to use the DirectSound implementation
+of PortAudio then you must have a recent copy of the free
+<a href="http://www.microsoft.com/directx/download.asp">DirectX</a>
+SDK for Developers from Microsoft installed on your computer. To compile
+an application add the following source files to your project:
+<blockquote>
+<pre><b>pa_win_ds\dsound_wrapper.c
+pa_win_ds\pa_dsound.c</b></pre>
+</blockquote>
+Link with the system library "<b>dsound.lib</b>" using the procedure described
+above for "winmm.lib".</blockquote>
+
+<blockquote>You might try compiling the "pa_tests\patest_saw.c" file first
+because it is the simplest.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_over.html">previous</a> |&nbsp; <a href="pa_tut_callback.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_run.html b/pd/portaudio/docs/pa_tut_run.html
new file mode 100644
index 00000000..5c70d089
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_run.html
@@ -0,0 +1,56 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Starting and Stopping a Stream</h2>
+
+<blockquote>The stream will not start running until you call Pa_StartStream().
+Then it will start calling your callback function to perform the audio
+processing.
+<blockquote>
+<pre>err = Pa_StartStream( stream );
+if( err != paNoError ) goto error;</pre>
+</blockquote>
+At this point, audio is being generated. You can communicate to your callback
+routine through the data structure you passed in on the open call, or through
+global variables, or using other interprocess communication techniques.
+Please be aware that your callback function may be called at interrupt
+time when your foreground process is least expecting it. So avoid sharing
+complex data structures that are easily corrupted like double linked lists.
+<p>In many of the tests we simply sleep for a few seconds so we can hear
+the sound. This is easy to do with Pa_Sleep() which will sleep for some
+number of milliseconds. Do not rely on this function for accurate scheduling.
+it is mostly for writing examples.
+<blockquote>
+<pre>/* Sleep for several seconds. */
+Pa_Sleep(NUM_SECONDS*1000);</pre>
+</blockquote>
+When you are through, you can stop the stream from the foreground.
+<blockquote>
+<pre>err = Pa_StopStream( stream );
+if( err != paNoError ) goto error;</pre>
+</blockquote>
+You can also stop the stream by returning 1 from your custom callback function.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_open.html">previous</a> |&nbsp; <a href="pa_tut_term.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_rw.html b/pd/portaudio/docs/pa_tut_rw.html
new file mode 100644
index 00000000..93c7b8bb
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_rw.html
@@ -0,0 +1,79 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Blocking Read/Write Functions</h2>
+
+<blockquote>[Note: These functions are not part of the official PortAudio
+API. They are simply built on top of PortAudio as an extra utility. Also
+note that they are under evaluation and their definition may change.]
+<p>There are two fundamentally different ways to design an audio API. One
+is to use callback functions the way we have already shown. The callback
+function operates under an interrupt or background thread This leaves the
+foreground application free to do other things while the audio just runs
+in the background. But this can sometimes be awkward.
+<p>So we have provided an alternative technique that lets a program generate
+audio in the foreground and then just write it to the audio stream as if
+it was a file. If there is not enough room in the audio buffer for more
+data, then the write function will just block until more room is available.
+This can make it very easy to write an audio example. To use this tool,
+you must add the files "pablio/pablio.c" and "pablio/ringbuffer.c" to your
+project. You must also:
+<blockquote>
+<pre>#include "pablio.h"</pre>
+</blockquote>
+Here is a short excerpt of a program that opens a stream for input and
+output. It then reads a block of samples from input, and writes them to
+output, in a loop.&nbsp; The complete example can be found in "pablio/test_rw.c".
+<blockquote>
+<pre>&nbsp;&nbsp;&nbsp; #define SAMPLES_PER_FRAME&nbsp;&nbsp;&nbsp;&nbsp; (2)
+&nbsp;&nbsp;&nbsp; #define FRAMES_PER_BLOCK&nbsp;&nbsp;&nbsp; (1024)
+&nbsp;&nbsp;&nbsp; SAMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK];
+&nbsp;&nbsp;&nbsp; PaError&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err;
+&nbsp;&nbsp;&nbsp; PABLIO_Stream&nbsp; *aStream;
+
+/* Open simplified blocking I/O layer on top of PortAudio. */
+&nbsp;&nbsp;&nbsp; err = OpenAudioStream( &amp;rwbl, SAMPLE_RATE, paFloat32,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (PABLIO_READ_WRITE | PABLIO_STEREO) );
+&nbsp;&nbsp;&nbsp; if( err != paNoError ) goto error;
+
+/* Process samples in the foreground. */
+&nbsp;&nbsp;&nbsp; for( i=0; i&lt;(NUM_SECONDS * SAMPLE_RATE); i++ )
+&nbsp;&nbsp;&nbsp; {
+&nbsp;&nbsp;&nbsp; /* Read one block of data into sample array from audio input. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK );
+&nbsp;&nbsp;&nbsp; /*
+&nbsp;&nbsp;&nbsp; ** At this point you could process the data in samples array,
+&nbsp;&nbsp;&nbsp; ** and write the result back to the same samples array.
+&nbsp;&nbsp;&nbsp; */
+&nbsp;&nbsp;&nbsp; /* Write that same frame of data to output. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK );
+&nbsp;&nbsp;&nbsp; }
+
+&nbsp;&nbsp;&nbsp; CloseAudioStream( aStream );</pre>
+</blockquote>
+</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_devs.html">previous</a> |&nbsp; <a href="pa_tut_explore.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_term.html b/pd/portaudio/docs/pa_tut_term.html
new file mode 100644
index 00000000..1c72209f
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_term.html
@@ -0,0 +1,47 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Terminating PortAudio</h2>
+
+<blockquote>You can start and stop a stream as many times as you like.
+But when you are done using it, you should close it by calling:</blockquote>
+
+<blockquote>
+<blockquote>
+<pre>err = Pa_CloseStream( stream );
+if( err != paNoError ) goto error;</pre>
+</blockquote>
+Then when you are done using PortAudio, you should terminate the whole
+system by calling:
+<blockquote>
+<pre>Pa_Terminate();</pre>
+</blockquote>
+That's basically it. You can now write an audio program in 'C' that will
+run on multiple platforms, for example PCs and Macintosh.
+<p>In the rest of the tutorial we will look at some additional utility
+functions, and a different way of using PortAudio that does not require
+the use of a callback function.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_run.html">previous</a> |&nbsp; <a href="pa_tut_util.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_util.html b/pd/portaudio/docs/pa_tut_util.html
new file mode 100644
index 00000000..f4b54750
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_util.html
@@ -0,0 +1,55 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.75 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Utility Functions</h2>
+
+<blockquote>Here are several more functions that are not critical, but
+may be handy when using PortAudio.
+<p>Pa_StreamActive() returns one when the stream in playing audio, zero
+when not playing, or a negative error number if the stream is invalid.
+The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
+but may also become inactive if the callback returns a non-zero value.
+In the latter case, the stream is considered inactive after the last buffer
+has finished playing.
+<blockquote>
+<pre>PaError Pa_StreamActive( PortAudioStream *stream );</pre>
+</blockquote>
+Pa_StreamTime() returns the number of samples that have been generated.
+PaTimeStamp is a double precision number which is a convenient way to pass
+big numbers around even though we only need integers.
+<blockquote>
+<pre>PaTimestamp Pa_StreamTime( PortAudioStream *stream );</pre>
+</blockquote>
+The "CPU Load" is a fraction of total CPU time consumed by the stream's
+audio processing. A value of 0.5 would imply that PortAudio and the sound
+generating callback was consuming roughly 50% of the available CPU time.
+This function may be called from the callback function or the application.
+<blockquote>
+<pre>double Pa_GetCPULoad( PortAudioStream* stream );</pre>
+</blockquote>
+</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a> | <a href="pa_tut_term.html">previous</a>
+|&nbsp; <a href="pa_tut_devs.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tutorial.html b/pd/portaudio/docs/pa_tutorial.html
new file mode 100644
index 00000000..1371c44f
--- /dev/null
+++ b/pd/portaudio/docs/pa_tutorial.html
@@ -0,0 +1,46 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>Copyright 2000 Phil Burk and Ross Bencina
+<h2>
+Table of Contents</h2>
+
+<blockquote><a href="pa_tut_over.html">Overview of PortAudio</a>
+<br><a href="pa_tut_mac.html">Compiling for Macintosh OS 7,8,9</a>
+<br><a href="pa_tut_mac_osx.html">Compiling for Macintosh OS X</a>
+<br><a href="pa_tut_pc.html">Compiling for Windows (DirectSound and WMME)</a>
+<br><a href="pa_tut_asio.html">Compiling for ASIO on Windows or Mac OS
+8,9</a>
+<br><a href="pa_tut_oss.html">Compiling for Unix OSS</a>
+<br><a href="pa_tut_callback.html">Writing a Callback Function</a>
+<br><a href="pa_tut_init.html">Initializing PortAudio</a>
+<br><a href="pa_tut_open.html">Opening a Stream using Defaults</a>
+<br><a href="pa_tut_run.html">Starting and Stopping a Stream</a>
+<br><a href="pa_tut_term.html">Cleaning Up</a>
+<br><a href="pa_tut_util.html">Utilities</a>
+<br><a href="pa_tut_devs.html">Querying for Devices</a>
+<br><a href="pa_tut_rw.html">Blocking Read/Write Functions</a>
+<br><a href="pa_tut_explore.html">Exploring the PortAudio Package</a></blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | contents |
+previous |&nbsp; <a href="pa_tut_over.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/portaudio_h.txt b/pd/portaudio/docs/portaudio_h.txt
new file mode 100644
index 00000000..6d60086f
--- /dev/null
+++ b/pd/portaudio/docs/portaudio_h.txt
@@ -0,0 +1,425 @@
+#ifndef PORT_AUDIO_H
+#define PORT_AUDIO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio API Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+typedef int PaError;
+typedef enum {
+ paNoError = 0,
+
+ paHostError = -10000,
+ paInvalidChannelCount,
+ paInvalidSampleRate,
+ paInvalidDeviceId,
+ paInvalidFlag,
+ paSampleFormatNotSupported,
+ paBadIODeviceCombination,
+ paInsufficientMemory,
+ paBufferTooBig,
+ paBufferTooSmall,
+ paNullCallback,
+ paBadStreamPtr,
+ paTimedOut,
+ paInternalError
+} PaErrorNum;
+
+/*
+ Pa_Initialize() is the library initialisation function - call this before
+ using the library.
+*/
+
+PaError Pa_Initialize( void );
+
+/*
+ Pa_Terminate() is the library termination function - call this after
+ using the library.
+*/
+
+PaError Pa_Terminate( void );
+
+/*
+ Return host specific error.
+ This can be called after receiving a paHostError.
+*/
+long Pa_GetHostError( void );
+
+/*
+ Translate the error number into a human readable message.
+*/
+const char *Pa_GetErrorText( PaError errnum );
+
+/*
+ Sample formats
+
+ These are formats used to pass sound data between the callback and the
+ stream. Each device has a "native" format which may be used when optimum
+ efficiency or control over conversion is required.
+
+ Formats marked "always available" are supported (emulated) by all devices.
+
+ The floating point representation uses +1.0 and -1.0 as the respective
+ maximum and minimum.
+
+*/
+
+typedef unsigned long PaSampleFormat;
+#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
+#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
+#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
+#define paInt24 ((PaSampleFormat) (1<<3))
+#define paPackedInt24 ((PaSampleFormat) (1<<4))
+#define paInt8 ((PaSampleFormat) (1<<5))
+#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */
+#define paCustomFormat ((PaSampleFormat) (1<<16))
+
+/*
+ Device enumeration mechanism.
+
+ Device ids range from 0 to Pa_CountDevices()-1.
+
+ Devices may support input, output or both. Device 0 is always the "default"
+ device and should support at least stereo in and out if that is available
+ on the taget platform _even_ if this involves kludging an input/output
+ device on platforms that usually separate input from output. Other platform
+ specific devices are specified by positive device ids.
+*/
+
+typedef int PaDeviceID;
+#define paNoDevice -1
+
+typedef struct{
+ int structVersion;
+ const char *name;
+ int maxInputChannels;
+ int maxOutputChannels;
+/* Number of discrete rates, or -1 if range supported. */
+ int numSampleRates;
+/* Array of supported sample rates, or {min,max} if range supported. */
+ const double *sampleRates;
+ PaSampleFormat nativeSampleFormats;
+} PaDeviceInfo;
+
+
+int Pa_CountDevices();
+/*
+ Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID()
+
+ Return the default device ID or paNoDevice if there is no devices.
+ The result can be passed to Pa_OpenStream().
+
+ On the PC, the user can specify a default device by
+ setting an environment variable. For example, to use device #1.
+
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ID by using
+ the supplied application "pa_devs".
+*/
+PaDeviceID Pa_GetDefaultInputDeviceID( void );
+PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+
+/*
+ PaTimestamp is used to represent a continuous sample clock with arbitrary
+ start time useful for syncronisation. The type is used in the outTime
+ argument to the callback function and the result of Pa_StreamTime()
+*/
+
+typedef double PaTimestamp;
+
+/*
+ Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
+ referring to the device specified by id.
+ If id is out of range the function returns NULL.
+
+ The returned structure is owned by the PortAudio implementation and must
+ not be manipulated or freed. The pointer is guaranteed to be valid until
+ between calls to Pa_Initialize() and Pa_Terminate().
+*/
+
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID );
+
+/*
+ PortAudioCallback is implemented by clients of the portable audio api.
+
+ inputBuffer and outputBuffer are arrays of interleaved samples,
+ the format, packing and number of channels used by the buffers are
+ determined by parameters to Pa_OpenStream() (see below).
+
+ framesPerBuffer is the number of sample frames to be processed by the callback.
+
+ outTime is the time in samples when the buffer(s) processed by
+ this callback will begin being played at the audio output.
+ See also Pa_StreamTime()
+
+ userData is the value of a user supplied pointer passed to Pa_OpenStream()
+ intended for storing synthesis data etc.
+
+ return value:
+ The callback can return a nonzero value to stop the stream. This may be
+ useful in applications such as soundfile players where a specific duration
+ of output is required. However, it is not necessary to utilise this mechanism
+ as StopStream() will also terminate the stream. A callback returning a
+ nonzero value must fill the entire outputBuffer.
+
+ NOTE: None of the other stream functions may be called from within the
+ callback function except for Pa_GetCPULoad().
+
+*/
+
+typedef int (PortAudioCallback)(
+ void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+
+/*
+ Stream flags
+
+ These flags may be supplied (ored together) in the streamFlags argument to
+ the Pa_OpenStream() function.
+
+ [ suggestions? ]
+*/
+
+#define paNoFlag (0)
+#define paClipOff (1<<0) /* disable defult clipping of out of range samples */
+#define paDitherOff (1<<1) /* disable default dithering */
+#define paPlatformSpecificFlags (0x00010000)
+typedef unsigned long PaStreamFlags;
+
+/*
+ A single PortAudioStream provides multiple channels of real-time
+ input and output audio streaming to a client application.
+ Pointers to PortAudioStream objects are passed between PortAudio functions.
+*/
+
+typedef void PortAudioStream;
+#define PaStream PortAudioStream
+
+/*
+ Pa_OpenStream() opens a stream for either input, output or both.
+
+ stream is the address of a PortAudioStream pointer which will receive
+ a pointer to the newly opened stream.
+
+ inputDevice is the id of the device used for input (see PaDeviceID above.)
+ inputDevice may be paNoDevice to indicate that an input device is not required.
+
+ numInputChannels is the number of channels of sound to be delivered to the
+ callback. It can range from 1 to the value of maxInputChannels in the
+ device input record for the device specified in the inputDevice parameter.
+ If inputDevice is paNoDevice numInputChannels is ignored.
+
+ inputSampleFormat is the format of inputBuffer provided to the callback
+ function. inputSampleFormat may be any of the formats described by the
+ PaSampleFormat enumeration (see above). PortAudio guarantees support for
+ the sound devices native formats (nativeSampleFormats in the device info
+ record) and additionally 16 and 32 bit integer and 32 bit floating point
+ formats. Support for other formats is implementation defined.
+
+ inputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ inputDriverInfo is never required for correct operation. If not used
+ inputDriverInfo should be NULL.
+
+ outputDevice is the id of the device used for output (see PaDeviceID above.)
+ outputDevice may be paNoDevice to indicate that an output device is not required.
+
+ numOutputChannels is the number of channels of sound to be supplied by the
+ callback. See the definition of numInputChannels above for more details.
+
+ outputSampleFormat is the sample format of the outputBuffer filled by the
+ callback function. See the definition of inputSampleFormat above for more
+ details.
+
+ outputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ outputDriverInfo is never required for correct operation. If not used
+ outputDriverInfo should be NULL.
+
+ sampleRate is the desired sampleRate for input and output
+
+ framesPerBuffer is the length in sample frames of all internal sample buffers
+ used for communication with platform specific audio routines. Wherever
+ possible this corresponds to the framesPerBuffer parameter passed to the
+ callback function.
+
+ numberOfBuffers is the number of buffers used for multibuffered
+ communication with the platform specific audio routines. This parameter is
+ provided only as a guide - and does not imply that an implementation must
+ use multibuffered i/o when reliable double buffering is available (such as
+ SndPlayDoubleBuffer() on the Macintosh.)
+
+ streamFlags may contain a combination of flags ORed together.
+ These flags modify the behavior of the
+ streaming process. Some flags may only be relevant to certain buffer formats.
+
+ callback is a pointer to a client supplied function that is responsible
+ for processing and filling input and output buffers (see above for details.)
+
+ userData is a client supplied pointer which is passed to the callback
+ function. It could for example, contain a pointer to instance data necessary
+ for processing the audio buffers.
+
+ return value:
+ Apon success Pa_OpenStream() returns PaNoError and places a pointer to a
+ valid PortAudioStream in the stream argument. The stream is inactive (stopped).
+ If a call to Pa_OpenStream() fails a nonzero error code is returned (see
+ PAError above) and the value of stream is invalid.
+
+*/
+
+PaError Pa_OpenStream( PortAudioStream** stream,
+ PaDeviceID inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+/*
+ Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that
+ opens the default input and/or ouput devices. Most parameters have
+ identical meaning to their Pa_OpenStream() counterparts, with the following
+ exceptions:
+
+ If either numInputChannels or numOutputChannels is 0 the respective device
+ is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() )
+
+ sampleFormat applies to both the input and output buffers.
+*/
+
+PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+/*
+ Pa_CloseStream() closes an audio stream, flushing any pending buffers.
+*/
+
+PaError Pa_CloseStream( PortAudioStream* );
+
+/*
+ Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
+ Pa_StopStream() waits until all pending audio buffers have been played.
+ Pa_AbortStream() stops playing immediately without waiting for pending
+ buffers to complete.
+*/
+
+PaError Pa_StartStream( PortAudioStream *stream );
+
+PaError Pa_StopStream( PortAudioStream *stream );
+
+PaError Pa_AbortStream( PortAudioStream *stream );
+
+/*
+ Pa_StreamActive() returns one when the stream is playing audio,
+ zero when not playing, or a negative error number if the
+ stream is invalid.
+ The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
+ but may also become inactive if the callback returns a non-zero value.
+ In the latter case, the stream is considered inactive after the last
+ buffer has finished playing.
+*/
+
+PaError Pa_StreamActive( PortAudioStream *stream );
+
+/*
+ Pa_StreamTime() returns the current output time for the stream in samples.
+ This time may be used as a time reference (for example syncronising audio to
+ MIDI).
+*/
+
+PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+
+/*
+ The "CPU Load" is a fraction of total CPU time consumed by the
+ stream's audio processing.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ This function may be called from the callback function or the application.
+*/
+double Pa_GetCPULoad( PortAudioStream* stream );
+
+/*
+ Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for
+ the current host based on minimum latency.
+ On the PC, for the DirectSound implementation, latency can be optionally set
+ by user by setting an environment variable.
+ For example, to set latency to 200 msec, put:
+
+ set PA_MIN_LATENCY_MSEC=200
+
+ in the AUTOEXEC.BAT file and reboot.
+ If the environment variable is not set, then the latency will be determined
+ based on the OS. Windows NT has higher latency than Win95.
+*/
+
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
+
+/*
+ Sleep for at least 'msec' milliseconds.
+ You may sleep longer than the requested time so don't rely
+ on this for accurate musical timing.
+*/
+void Pa_Sleep( long msec );
+
+/*
+ Return size in bytes of a single sample in a given PaSampleFormat
+ or paSampleFormatNotSupported.
+*/
+PaError Pa_GetSampleSize( PaSampleFormat format );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PORT_AUDIO_H */
diff --git a/pd/portaudio/docs/portaudio_icmc2001.pdf b/pd/portaudio/docs/portaudio_icmc2001.pdf
new file mode 100644
index 00000000..dd074b7d
--- /dev/null
+++ b/pd/portaudio/docs/portaudio_icmc2001.pdf
Binary files differ
diff --git a/pd/portaudio/docs/proposals.html b/pd/portaudio/docs/proposals.html
new file mode 100644
index 00000000..0f9b8cb6
--- /dev/null
+++ b/pd/portaudio/docs/proposals.html
@@ -0,0 +1,36 @@
+<HTML>
+<HEAD>
+<TITLE>Proposed Changes to PortAudio API</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META content="Phil Burk, Ross Bencina" name=Author>
+<META content="Changes being discussed by the community of PortAudio deveopers."
+name=Description>
+<META
+content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,"
+name=KeyWords>
+</HEAD>
+<BODY LINK="#0000ff" VLINK="#800080">&nbsp;
+<CENTER>
+<TABLE bgColor=#fada7a cols=1 width="100%">
+ <TBODY>
+ <TR>
+ <TD>
+ <CENTER>
+ <H1>Proposed Changes to PortAudio API</H1>
+ </CENTER>
+</TD></TR></TBODY></TABLE></CENTER>
+<P><A href="http://www.portaudio.com/">PortAudio Home Page</A></P>
+
+<P>Updated: July 27, 2002 </P>
+<H2>The Proposals Have Moved</H2>
+
+<p>
+All PortAudio Enhancement Proposal documentation has moved. On the web site, it is now located at:
+<A HREF="http://www.portaudio.com/docs/proposals">http://www.portaudio.com/docs/proposals</A>
+
+On the CVS server it is now located in a module named "pa_proposals".
+</p>
+
+
+</BODY>
+</HTML>
diff --git a/pd/portaudio/docs/releases.html b/pd/portaudio/docs/releases.html
new file mode 100644
index 00000000..aec80a1c
--- /dev/null
+++ b/pd/portaudio/docs/releases.html
@@ -0,0 +1,339 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="PortAudio is a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Release Notes</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio - Release Notes</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>Link to <a href="http://www.portaudio.com">PortAudio Home Page</a>
+<h2>
+<b>V18 - 5/6/02</b></h2>
+
+<blockquote>All source code and documentation now under <a href="http://www.portaudio.com/usingcvs.html">CVS</a>.
+<p>Ran most of the code through <a href="http://astyle.sourceforge.net/">AStyle</a>
+to cleanup ragged indentation caused by using different editors. Used this
+command:
+<br><tt>&nbsp;&nbsp; astyle --style=ansi -c -o --convert-tabs --indent-preprocessor
+*.c</tt></blockquote>
+
+<blockquote>Added "pa_common/pa_convert.c" for Mac OS X. Start of new conversion
+utilities.
+<p><b>ASIO</b>
+<ul>
+<li>
+New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables,</li>
+
+<li>
+Cleanup of Pa_ASIO_Callback_Input</li>
+
+<li>
+Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo</li>
+
+<li>
+Deallocate all resources in PaHost_Term for cases where Pa_CloseStream
+is not called properly</li>
+
+<li>
+New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows.
+Allows use by multiple threads.</li>
+
+<li>
+Correct error code management in PaHost_Term, removed various compiler
+warning</li>
+
+<li>
+Add Mac includes for &lt;Devices.h> and &lt;Timer.h></li>
+
+<li>
+Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better
+error handling</li>
+</ul>
+<b>Mac OS X</b>
+<ul>
+<li>
+Major cleanup and improvements.</li>
+
+<li>
+Fixed device queries for numChannels and sampleRates,</li>
+
+<li>
+Audio input works if using same CoreAudio device (some HW devices make
+separate CoreAudio devices).</li>
+
+<li>
+Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file.</li>
+
+<li>
+Return error if opened in mono mode cuz not supported.</li>
+
+<li>
+Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally.</li>
+
+<li>
+Use getrusage() instead of gettimeofday() for CPU Load calculation.</li>
+</ul>
+<b>Windows MME</b>
+<ul>
+<li>
+Fixed bug that caused TIMEOUT in Pa_StopStream(). Added check for past_StopSoon()
+in Pa_TimeSlice(). Thanks Julien Maillard.</li>
+
+<li>
+Detect Win XP versus NT, use lower latency.</li>
+
+<li>
+Fix DBUG typo;</li>
+
+<li>
+removed init of CurrentCount which was not compiling on Borland</li>
+
+<li>
+general cleanup, factored streamData alloc and cpu usage initialization</li>
+
+<li>
+stopped counting WAVE_MAPPER when there were no audio cards plugged in</li>
+</ul>
+<b>Windows DirectSound</b>
+<ul>
+<li>
+Detect Win XP and Win 2K properly when determining latency.</li>
+</ul>
+<b>Unix OSS</b>
+<ul>
+<li>
+Use high real-time priority if app is running with root priveledges. Lowers
+latency.</li>
+
+<li>
+Added watch dog thread that prevents real-time thread from hogging CPU
+and hanging the computer.</li>
+
+<li>
+Check error return from read() and write().</li>
+
+<li>
+Check CPU endianness instead of assuming Little Endian.</li>
+</ul>
+</blockquote>
+
+<h2>
+<b>V17 - 10/15/01</b></h2>
+
+<blockquote><b>Unix OSS</b>
+<ul>
+<li>
+Set num channels back to two after device query for ALSA. This fixed a
+bug in V16 that sometimes caused a failure when querying for the sample
+rates. Thanks Stweart Greenhill.</li>
+</ul>
+</blockquote>
+
+<blockquote>
+<h4>
+<b>Macintosh Sound Manager</b></h4>
+
+<ul>
+<li>
+Use NewSndCallBackUPP() for CARBON compatibility.</li>
+</ul>
+</blockquote>
+
+<h2>
+<b>V16 - 9/27/01</b></h2>
+
+<blockquote><b>Added Alpha implementations for ASIO, SGI, and BeOS!</b>
+<br>&nbsp;
+<li>
+CPULoad is now calculated based on the time spent to generate a known number
+of frames. This is more accurate than a simple percentage of real-time.
+Implemented in pa_unix_oss, pa_win_wmme and pa_win_ds.</li>
+
+<li>
+Fix dither and shift for recording PaUInt8 format data.</li>
+
+<li>
+Added "patest_maxsines.c" which tests <tt>Pa_GetCPULoad().</tt></li>
+</blockquote>
+
+<blockquote>
+<h4>
+Windows WMME</h4>
+
+<ul>
+<li>
+sDevicePtrs now allocated using <tt>GlobalAlloc()</tt>. This prevents a
+crash in Pa_Terminate() on Win2000. Thanks Mike Berry for finding this.
+Thanks Mike Berry.</li>
+
+<li>
+Pass process instead of thread to <tt>SetPriorityClass</tt>(). This fixes
+a bug that caused the priority to not be increased. Thanks to Alberto di
+Bene for spotting this.</li>
+</ul>
+
+<h4>
+Windows DirectSound</h4>
+
+<ul>
+<li>
+Casts for compiling with __MWERKS__ CodeWarrior.</li>
+</ul>
+
+<h4>
+UNIX OSS</h4>
+
+<ul>
+<li>
+Derived from Linux OSS implementation.</li>
+
+<li>
+Numerous patches from Heiko Purnhagen, Stephen Brandon, etc.</li>
+
+<li>
+Improved query mechanism which often bailed out unnecessarily.</li>
+
+<li>
+Removed sNumDevices and potential related bugs,</li>
+
+<li>
+Use <tt>getenv("PA_MIN_LATENCY_MSEC")</tt> in code to set desired latency.
+User can set by entering:</li>
+
+<br>&nbsp;&nbsp;&nbsp; <tt>export PA_MIN_LATENCY_MSEC=40</tt></ul>
+
+<h4>
+Macintosh Sound Manager</h4>
+
+<ul>
+<li>
+Pass unused event to WaitNextEvent instead of NULL to prevent Mac OSX crash.
+Thanks Dominic Mazzoni.</li>
+
+<li>
+Use requested number of input channels.</li>
+
+<br>&nbsp;</ul>
+</blockquote>
+
+<h2>
+<b>V15 - 5/29/01</b></h2>
+
+<blockquote>
+<ul>
+<li>
+<b>New Linux OSS Beta</b></li>
+</ul>
+
+<h4>
+Windows WMME</h4>
+
+<ul>
+<li>
+&nbsp;sDevicePtrs now allocated based on sizeof(pointer). Was allocating
+too much space.</li>
+
+<li>
+&nbsp;Check for excessive numbers of channels. Some drivers reported bogus
+numbers.</li>
+
+<li>
+Apply Mike Berry's changes for CodeWarrior on PC including condition including
+of memory.h, and explicit typecasting on memory allocation.</li>
+</ul>
+
+<h4>
+Macintosh Sound Manager</h4>
+
+<ul>
+<li>
+ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID.</li>
+
+<li>
+Device Scan was crashing for anything other than siBadSoundInDevice, but
+some Macs may return other errors! Caused failure to init on some G4s under
+OS9.</li>
+
+<li>
+Fix TIMEOUT in record mode.</li>
+
+<li>
+Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON</li>
+</ul>
+</blockquote>
+
+<h2>
+<b>V14 - 2/6/01</b></h2>
+
+<blockquote>
+<ul>
+<li>
+Added implementation for Windows MultiMedia Extensions (WMME) by Ross and
+Phil</li>
+
+<li>
+Changed Pa_StopStream() so that it waits for the buffers to drain.</li>
+
+<li>
+Added Pa_AbortStream() that stops immediately without waiting.</li>
+
+<li>
+Added new test: patest_stop.c to test above two mods.</li>
+
+<li>
+Fixed Pa_StreamTime() so that it returns current play position instead
+of the write position. Added "patest_sync.c" to demo audio/video sync.</li>
+
+<li>
+Improved stability of Macintosh implementation. Added timeouts to prevent
+hangs.</li>
+
+<li>
+Added Pa_GetSampleSize( PaSampleFormat format );</li>
+
+<li>
+Changes some "int"s to "long"s so that PA works properly on Macintosh which
+often compiles using 16 bit ints.</li>
+
+<li>
+Added Implementation Guide</li>
+</ul>
+</blockquote>
+
+<h2>
+<b>V12 - 1/9/01</b></h2>
+
+<blockquote>
+<ul>
+<li>
+Mac now scans for and queries all devices. But it does not yet support
+selecting any other than the default device.</li>
+
+<li>
+Blocking I/O calls renamed to separate them from the PortAudio API.</li>
+
+<li>
+Cleaned up indentation problems with tabs versus spaces.</li>
+
+<li>
+Now attempts to correct bogus sample rate info returned from DirectSound
+device queries.</li>
+</ul>
+</blockquote>
+
+</body>
+</html>
diff --git a/pd/portaudio/fixdir.bat b/pd/portaudio/fixdir.bat
new file mode 100755
index 00000000..92d6c747
--- /dev/null
+++ b/pd/portaudio/fixdir.bat
@@ -0,0 +1,19 @@
+rem Use Astyle to fix style in 'C' files
+cd %1%
+
+fixlines -p *.c
+fixlines -p *.cpp
+fixlines -p *.cc
+
+astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.c
+astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cpp
+astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cc
+del *.orig
+@rem convert line terminators to Unix style LFs
+fixlines -u *.c
+fixlines -u *.cpp
+fixlines -u *.cc
+fixlines -u *.h
+del *.bak
+
+cd ..\
diff --git a/pd/portaudio/fixfile.bat b/pd/portaudio/fixfile.bat
new file mode 100755
index 00000000..48f6fbc2
--- /dev/null
+++ b/pd/portaudio/fixfile.bat
@@ -0,0 +1,7 @@
+rem Use Astyle to fix style in a file
+fixlines -p %1%
+astyle --style=ansi -c -o --convert-tabs --indent-preprocessor %1%
+del %1%.orig
+@rem convert line terminators to Unix style LFs
+fixlines -u %1%
+del %1%.bak
diff --git a/pd/portaudio/index.html b/pd/portaudio/index.html
new file mode 100644
index 00000000..91e5b4c3
--- /dev/null
+++ b/pd/portaudio/index.html
@@ -0,0 +1,89 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="PortAudio is a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Implementations for DirectSound</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio - Portable Audio Library</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>Last updated 5/6/02.
+<p>PortAudio is a cross platform, <a href="#License">open-source</a>, audio
+I/O library proposed by <b>Ross Bencina</b> to the <a href="http://shoko.calarts.edu/~glmrboy/musicdsp/music-dsp.html">music-dsp</a>
+mailing list. It lets you write simple audio programs in 'C' that will
+compile and run on <b>Windows, Macintosh, Unix, BeOS</b>. PortAudio is
+intended to promote the exchange of audio synthesis software between developers
+on different platforms.
+<p>For complete information on PortAudio and to download the latest releases,
+please visit "<b><font size=+2><a href="http://www.portaudio.com">http://www.portaudio.com</a></font></b>".
+<br>&nbsp;
+<br>&nbsp;
+<center>
+<h2>
+<b><a href="docs/index.html">Click here for Documentation</a></b></h2></center>
+
+<h2>
+<b><font size=+2></font></b></h2>
+
+<h2>
+<b><font size=+2>Contacts and E-Mail List</font></b></h2>
+
+<ul>
+<li>
+If you are using or implementing PortAudio then please join the <b><font size=+1><a href="http://techweb.rfa.org/mailman/listinfo/portaudio">PortAudio
+mail list</a></font><font size=+2> </font></b>generously administered by
+<b>Bill
+Eldridge</b>.</li>
+
+<li>
+If you find bugs in one of these implementations, or have suggestions,
+please e-mail them to <a href="mailto:philburk@softsynth.com">Phil Burk</a>.</li>
+
+<li>
+If you make improvements to the library, please send them to us so we can
+incorporate the improvements.</li>
+</ul>
+
+<h2>
+<a NAME="License"></a>License</h2>
+PortAudio Portable Real-Time Audio Library
+<br>Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+<p>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:
+<ul>
+<li>
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.</li>
+
+<li>
+Any person wishing to distribute modifications to the Software is requested
+to send the modifications to the original developer so that they can be
+incorporated into the canonical version.</li>
+</ul>
+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 ON INFRINGEMENT.
+<br>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.
+<br>&nbsp;
+</body>
+</html>
diff --git a/pd/portaudio/install-sh b/pd/portaudio/install-sh
new file mode 100755
index 00000000..e9de2384
--- /dev/null
+++ b/pd/portaudio/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/pd/portaudio/pa_asio/Callback_adaptation_.pdf b/pd/portaudio/pa_asio/Callback_adaptation_.pdf
new file mode 100644
index 00000000..76bf6786
--- /dev/null
+++ b/pd/portaudio/pa_asio/Callback_adaptation_.pdf
Binary files differ
diff --git a/pd/portaudio/pa_asio/Pa_ASIO.pdf b/pd/portaudio/pa_asio/Pa_ASIO.pdf
new file mode 100644
index 00000000..ac5ecadb
--- /dev/null
+++ b/pd/portaudio/pa_asio/Pa_ASIO.pdf
Binary files differ
diff --git a/pd/portaudio/pa_asio/borland_asio_readme.txt b/pd/portaudio/pa_asio/borland_asio_readme.txt
new file mode 100644
index 00000000..56e472b8
--- /dev/null
+++ b/pd/portaudio/pa_asio/borland_asio_readme.txt
@@ -0,0 +1,6 @@
+Steinberg's ASIO 2 SDK will compile but crash on
+initialization if compiled with a Borland compiler.
+
+The problem is described, and a solution provided on
+the following page:
+http://www.audiomulch.com/~rossb/code/calliasio \ No newline at end of file
diff --git a/pd/portaudio/pa_asio/pa_asio.cpp b/pd/portaudio/pa_asio/pa_asio.cpp
index baed8ed4..c8ba58f4 100644
--- a/pd/portaudio/pa_asio/pa_asio.cpp
+++ b/pd/portaudio/pa_asio/pa_asio.cpp
@@ -1,10 +1,10 @@
/*
- * $Id: pa_asio.cpp,v 1.7 2002/04/30 12:33:04 stephane Exp $
+ * $Id: pa_asio.cpp,v 1.7.2.30 2002/12/03 06:30:39 rossbencina Exp $
* Portable Audio I/O Library for ASIO Drivers
*
* Author: Stephane Letz
* Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 2000-2001 Stephane Letz, Phil Burk
+ * Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -57,2942 +57,2051 @@
12-04-02 Add Mac includes for <Devices.h> and <Timer.h> : Phil Burk
13-04-02 Removes another compiler warning : Stephane Letz
30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz
-
- TO DO :
-
- - Check Pa_StopSteam and Pa_AbortStream
- - Optimization for Input only or Ouput only (really necessary ??)
+ 12-06-02 Rehashed into new multi-api infrastructure, added support for all ASIO sample formats : Ross Bencina
+ 18-06-02 Added pa_asio.h, PaAsio_GetAvailableLatencyValues() : Ross B.
+ 21-06-02 Added SelectHostBufferSize() which selects host buffer size based on user latency parameters : Ross Bencina
+ ** NOTE maintanance history is now stored in CVS **
*/
+/** @file
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
+ @todo implement underflow/overflow streamCallback statusFlags, paNeverDropInput.
-#include "portaudio.h"
-#include "pa_host.h"
-#include "pa_trace.h"
+ @todo implement host api specific extension to set i/o buffer sizes in frames
-#include "asiosys.h"
-#include "asio.h"
-#include "asiodrivers.h"
+ @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.)
+ @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
-#if MAC
-#include <Devices.h>
-#include <Timer.h>
-#include <Math64.h>
-#else
-#include <math.h>
-#include <windows.h>
-#include <mmsystem.h>
-#endif
+ @todo implement IsFormatSupported
-enum {
- // number of input and outputs supported by the host application
- // you can change these to higher or lower values
- kMaxInputChannels = 32,
- kMaxOutputChannels = 32
-};
+ @todo work out how to implement stream stoppage from callback and
+ implement IsStreamActive properly
-/* ASIO specific device information. */
-typedef struct internalPortAudioDevice
-{
- PaDeviceInfo pad_Info;
-} internalPortAudioDevice;
+ @todo rigorously check asio return codes and convert to pa error codes
+ @todo Different channels of a multichannel stream can have different sample
+ formats, but we assume that all are the same as the first channel for now.
+ Fixing this will require the block processor to maintain per-channel
+ conversion functions - could get nasty.
-/* ASIO driver internal data storage */
-typedef struct PaHostSoundControl
-{
- // ASIOInit()
- ASIODriverInfo pahsc_driverInfo;
+ @todo investigate whether the asio processNow flag needs to be honoured
- // ASIOGetChannels()
- int32 pahsc_NumInputChannels;
- int32 pahsc_NumOutputChannels;
+ @todo handle asioMessages() callbacks in a useful way, or at least document
+ what cases we don't handle.
- // ASIOGetBufferSize() - sizes in frames per buffer
- int32 pahsc_minSize;
- int32 pahsc_maxSize;
- int32 pahsc_preferredSize;
- int32 pahsc_granularity;
+ @todo miscellaneous other FIXMEs
- // ASIOGetSampleRate()
- ASIOSampleRate pahsc_sampleRate;
+ @todo implement the following somewhere:
- // ASIOOutputReady()
- bool pahsc_postOutput;
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+*/
- // ASIOGetLatencies ()
- int32 pahsc_inputLatency;
- int32 pahsc_outputLatency;
- // ASIOCreateBuffers ()
- ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's
- // ASIOGetChannelInfo()
- ASIOChannelInfo pahsc_channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's
- // The above two arrays share the same indexing, as the data in them are linked together
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+//#include <values.h>
- // Information from ASIOGetSamplePosition()
- // data is converted to double floats for easier use, however 64 bit integer can be used, too
- double nanoSeconds;
- double samples;
- double tcSamples; // time code samples
+#include "portaudio.h"
+#include "pa_asio.h"
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
- // bufferSwitchTimeInfo()
- ASIOTime tInfo; // time info state
- unsigned long sysRefTime; // system reference time, when bufferSwitch() was called
+#include "asiosys.h"
+#include "asio.h"
+#include "asiodrivers.h"
- // Signal the end of processing in this example
- bool stopped;
-
- ASIOCallbacks pahsc_asioCallbacks;
-
-
- int32 pahsc_userInputBufferFrameOffset; // Position in Input user buffer
- int32 pahsc_userOutputBufferFrameOffset; // Position in Output user buffer
- int32 pahsc_hostOutputBufferFrameOffset; // Position in Output ASIO buffer
-
- int32 past_FramesPerHostBuffer; // Number of frames in ASIO buffer
-
- int32 pahsc_InputBufferOffset; // Number of null frames for input buffer alignement
- int32 pahsc_OutputBufferOffset; // Number of null frames for ouput buffer alignement
-
+/*
#if MAC
- UInt64 pahsc_EntryCount;
- UInt64 pahsc_LastExitCount;
-#elif WINDOWS
- LARGE_INTEGER pahsc_EntryCount;
- LARGE_INTEGER pahsc_LastExitCount;
-#endif
-
- PaTimestamp pahsc_NumFramesDone;
-
- internalPortAudioStream *past;
-
-} PaHostSoundControl;
-
+#include <Devices.h>
+#include <Timer.h>
+#include <Math64.h>
+#else
+*/
+/*
+#include <math.h>
+#include <windows.h>
+#include <mmsystem.h>
+*/
+/*
+#endif
+*/
-//----------------------------------------------------------
-#define PRINT(x) { printf x; fflush(stdout); }
-#define ERR_RPT(x) PRINT(x)
+/* external references */
+extern AsioDrivers* asioDrivers ;
+bool loadAsioDriver(char *name);
-#define DBUG(x) /* PRINT(x) */
-#define DBUGX(x) /* PRINT(x) /**/
/* We are trying to be compatible with CARBON but this has not been thoroughly tested. */
+/* not tested at all since new code was introduced. */
#define CARBON_COMPATIBLE (0)
-#define PA_MAX_DEVICE_INFO (32)
-
-#define MIN_INT8 (-0x80)
-#define MAX_INT8 (0x7F)
-
-#define MIN_INT8_FP ((float)-0x80)
-#define MAX_INT8_FP ((float)0x7F)
-#define MIN_INT16_FP ((float)-0x8000)
-#define MAX_INT16_FP ((float)0x7FFF)
-#define MIN_INT16 (-0x8000)
-#define MAX_INT16 (0x7FFF)
-#define MAX_INT32_FP (2147483520.0f) /* 0x0x7FFFFF80 - seems safe */
-/************************************************************************************/
-/****************** Data ************************************************************/
-/************************************************************************************/
-static int sNumDevices = 0;
-static internalPortAudioDevice sDevices[PA_MAX_DEVICE_INFO] = { 0 };
-static int32 sPaHostError = 0;
-static int sDefaultOutputDeviceID = 0;
-static int sDefaultInputDeviceID = 0;
+/* prototypes for functions declared in this file */
+
+extern "C" PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData );
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate );
+static PaError CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+static signed long GetStreamReadAvailable( PaStream* stream );
+static signed long GetStreamWriteAvailable( PaStream* stream );
+
+/* our ASIO callback functions */
-PaHostSoundControl asioDriverInfo = {0};
-
-#ifdef MAC
-static bool swap = true;
-#elif WINDOWS
-static bool swap = false;
-#endif
-
-// Prototypes
static void bufferSwitch(long index, ASIOBool processNow);
static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
static void sampleRateChanged(ASIOSampleRate sRate);
static long asioMessages(long selector, long value, void* message, double* opt);
-static void Pa_StartUsageCalculation( internalPortAudioStream *past );
-static void Pa_EndUsageCalculation( internalPortAudioStream *past );
-
-static void Pa_ASIO_Convert_Inter_Input(
- ASIOBufferInfo* nativeBuffer,
- void* inputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
- ASIOSampleType nativeFormat,
- PaSampleFormat paFormat,
- PaStreamFlags flags,
- long index);
-
-static void Pa_ASIO_Convert_Inter_Output(
- ASIOBufferInfo* nativeBuffer,
- void* outputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
- ASIOSampleType nativeFormat,
- PaSampleFormat paFormat,
- PaStreamFlags flags,
- long index);
-
-static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer,
- ASIOSampleType nativeFormat,
- long NumInputChannels,
- long NumOuputChannels,
- long index,
- long hostFrameOffset,
- long frames);
-
-static void Pa_ASIO_Callback_Input(long index);
-static void Pa_ASIO_Callback_Output(long index, long framePerBuffer);
-static void Pa_ASIO_Callback_End();
-static void Pa_ASIO_Clear_User_Buffers();
-
-// Some external references
-extern AsioDrivers* asioDrivers ;
-bool loadAsioDriver(char *name);
-unsigned long get_sys_reference_time();
-
-/************************************************************************************/
-/****************** Macro ************************************************************/
-/************************************************************************************/
+static ASIOCallbacks asioCallbacks_ =
+ { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo };
-#define SwapLong(v) ((((v)>>24)&0xFF)|(((v)>>8)&0xFF00)|(((v)&0xFF00)<<8)|(((v)&0xFF)<<24)) ;
-#define SwapShort(v) ((((v)>>8)&0xFF)|(((v)&0xFF)<<8)) ;
-
-#define ClipShort(v) (((v)<MIN_INT16)?MIN_INT16:(((v)>MAX_INT16)?MAX_INT16:(v)))
-#define ClipChar(v) (((v)<MIN_INT8)?MIN_INT8:(((v)>MAX_INT8)?MAX_INT8:(v)))
-#define ClipFloat(v) (((v)<-1.0f)?-1.0f:(((v)>1.0f)?1.0f:(v)))
-
-#ifndef min
-#define min(a,b) ((a)<(b)?(a):(b))
-#endif
-
-#ifndef max
-#define max(a,b) ((a)>=(b)?(a):(b))
-#endif
+#define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \
+ PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText )
-static bool Pa_ASIO_loadAsioDriver(char *name)
+static const char* PaAsio_GetAsioErrorText( ASIOError asioError )
{
- #ifdef WINDOWS
- CoInitialize(0);
- #endif
- return loadAsioDriver(name);
+ const char *result;
+
+ switch( asioError ){
+ case ASE_OK:
+ case ASE_SUCCESS: result = "Success"; break;
+ case ASE_NotPresent: result = "Hardware input or output is not present or available"; break;
+ case ASE_HWMalfunction: result = "Hardware is malfunctioning"; break;
+ case ASE_InvalidParameter: result = "Input parameter invalid"; break;
+ case ASE_InvalidMode: result = "Hardware is in a bad mode or used in a bad mode"; break;
+ case ASE_SPNotAdvancing: result = "Hardware is not running when sample position is inquired"; break;
+ case ASE_NoClock: result = "Sample clock or rate cannot be determined or is not present"; break;
+ case ASE_NoMemory: result = "Not enough memory for completing the request"; break;
+ default: result = "Unknown ASIO error"; break;
+ }
+
+ return result;
}
-
-// Utilities for alignement buffer size computation
-static int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);}
-static int PPCM (int a, int b) {return (a*b) / PGCD (a,b);}
+#define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \
+ PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) )
+
-// Takes the size of host buffer and user buffer : returns the number of frames needed for buffer alignement
-static int Pa_ASIO_CalcFrameShift (int M, int N)
-{
- int res = 0;
- for (int i = M; i < PPCM (M,N) ; i+=M) { res = max (res, i%N); }
- return res;
-}
+/* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */
-// We have the following relation :
-// Pa_ASIO_CalcFrameShift (M,N) + M = Pa_ASIO_CalcFrameShift (N,M) + N
-
-/* ASIO sample type to PortAudio sample type conversion */
-static PaSampleFormat Pa_ASIO_Convert_SampleFormat(ASIOSampleType type)
+typedef struct
{
- switch (type) {
-
- case ASIOSTInt16MSB:
- case ASIOSTInt16LSB:
- case ASIOSTInt32MSB16:
- case ASIOSTInt32LSB16:
- return paInt16;
-
- case ASIOSTFloat32MSB:
- case ASIOSTFloat32LSB:
- case ASIOSTFloat64MSB:
- case ASIOSTFloat64LSB:
- return paFloat32;
-
- case ASIOSTInt32MSB:
- case ASIOSTInt32LSB:
- case ASIOSTInt32MSB18:
- case ASIOSTInt32MSB20:
- case ASIOSTInt32MSB24:
- case ASIOSTInt32LSB18:
- case ASIOSTInt32LSB20:
- case ASIOSTInt32LSB24:
- return paInt32;
-
- case ASIOSTInt24MSB:
- case ASIOSTInt24LSB:
- return paInt24;
-
- default:
- return paCustomFormat;
- }
-}
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
-/* Allocate ASIO buffers, initialise channels */
-static ASIOError Pa_ASIO_CreateBuffers (PaHostSoundControl *asioDriverInfo, long InputChannels,
- long OutputChannels, long framesPerBuffer)
-{
- ASIOError err;
- int i;
-
- ASIOBufferInfo *info = asioDriverInfo->bufferInfos;
-
- // Check parameters
- if ((InputChannels > kMaxInputChannels) || (OutputChannels > kMaxInputChannels)) return ASE_InvalidParameter;
-
- for(i = 0; i < InputChannels; i++, info++){
- info->isInput = ASIOTrue;
- info->channelNum = i;
- info->buffers[0] = info->buffers[1] = 0;
- }
-
- for(i = 0; i < OutputChannels; i++, info++){
- info->isInput = ASIOFalse;
- info->channelNum = i;
- info->buffers[0] = info->buffers[1] = 0;
- }
-
- // Set up the asioCallback structure and create the ASIO data buffer
- asioDriverInfo->pahsc_asioCallbacks.bufferSwitch = &bufferSwitch;
- asioDriverInfo->pahsc_asioCallbacks.sampleRateDidChange = &sampleRateChanged;
- asioDriverInfo->pahsc_asioCallbacks.asioMessage = &asioMessages;
- asioDriverInfo->pahsc_asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
-
- DBUG(("PortAudio : ASIOCreateBuffers with size = %ld \n", framesPerBuffer));
-
- err = ASIOCreateBuffers( asioDriverInfo->bufferInfos, InputChannels+OutputChannels,
- framesPerBuffer, &asioDriverInfo->pahsc_asioCallbacks);
- if (err != ASE_OK) return err;
-
- // Initialise buffers
- for (i = 0; i < InputChannels + OutputChannels; i++)
- {
- asioDriverInfo->pahsc_channelInfos[i].channel = asioDriverInfo->bufferInfos[i].channelNum;
- asioDriverInfo->pahsc_channelInfos[i].isInput = asioDriverInfo->bufferInfos[i].isInput;
- err = ASIOGetChannelInfo(&asioDriverInfo->pahsc_channelInfos[i]);
- if (err != ASE_OK) break;
- }
+ PaUtilAllocationGroup *allocations;
- err = ASIOGetLatencies(&asioDriverInfo->pahsc_inputLatency, &asioDriverInfo->pahsc_outputLatency);
-
- DBUG(("PortAudio : InputLatency = %ld latency = %ld msec \n",
- asioDriverInfo->pahsc_inputLatency,
- (long)((asioDriverInfo->pahsc_inputLatency*1000)/ asioDriverInfo->past->past_SampleRate)));
- DBUG(("PortAudio : OuputLatency = %ld latency = %ld msec \n",
- asioDriverInfo->pahsc_outputLatency,
- (long)((asioDriverInfo->pahsc_outputLatency*1000)/ asioDriverInfo->past->past_SampleRate)));
-
- return err;
+ /* the ASIO C API only allows one ASIO driver to be open at a time,
+ so we kee track of whether we have the driver open here, and
+ use this information to return errors from OpenStream if the
+ driver is already open.
+ */
+ int driverOpen;
}
+PaAsioHostApiRepresentation;
/*
- Query ASIO driver info :
-
- First we get all available ASIO drivers located in the ASIO folder,
- then try to load each one. For each loaded driver, get all needed informations.
+ Retrieve <driverCount> driver names from ASIO, returned in a char**
+ allocated in <group>.
*/
-static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad )
+static char **GetAsioDriverNames( PaUtilAllocationGroup *group, long driverCount )
{
+ char **result = 0;
+ int i;
+
+ result =(char**)PaUtil_GroupAllocateMemory(
+ group, sizeof(char*) * driverCount );
+ if( !result )
+ goto error;
-#define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */
-#define NUM_CUSTOMSAMPLINGRATES 9 /* must be the same number of elements as in the array below */
-#define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES)
+ result[0] = (char*)PaUtil_GroupAllocateMemory(
+ group, 32 * driverCount );
+ if( !result[0] )
+ goto error;
- ASIOSampleRate possibleSampleRates[]
- = {8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0};
-
- ASIOChannelInfo channelInfos;
- long InputChannels,OutputChannels;
- double *sampleRates;
- char* names[PA_MAX_DEVICE_INFO] ;
- PaDeviceInfo *dev;
- int i;
- int numDrivers;
- ASIOError asioError;
-
- /* Allocate names */
- for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) {
- names[i] = (char*)PaHost_AllocateFastMemory(32);
- /* check memory */
- if(!names[i]) return paInsufficientMemory;
- }
-
- /* MUST BE CHECKED : to force fragments loading on Mac */
- Pa_ASIO_loadAsioDriver("dummy");
-
- /* Get names of all available ASIO drivers */
- asioDrivers->getDriverNames(names,PA_MAX_DEVICE_INFO);
-
- /* Check all available ASIO drivers */
-#if MAC
- numDrivers = asioDrivers->getNumFragments();
-#elif WINDOWS
- numDrivers = asioDrivers->asioGetNumDev();
-#endif
- DBUG(("PaASIO_QueryDeviceInfo: numDrivers = %d\n", numDrivers ));
+ for( i=0; i<driverCount; ++i )
+ result[i] = result[0] + (32 * i);
- for (int driver = 0 ; driver < numDrivers ; driver++)
- {
+ asioDrivers->getDriverNames( result, driverCount );
- #if WINDOWS
- asioDriverInfo.pahsc_driverInfo.asioVersion = 2; // FIXME - is this right? PLB
- asioDriverInfo.pahsc_driverInfo.sysRef = GetDesktopWindow(); // FIXME - is this right? PLB
- #endif
-
- /* If the driver can be loaded : */
- if ( !Pa_ASIO_loadAsioDriver(names[driver]) )
- {
- DBUG(("PaASIO_QueryDeviceInfo could not loadAsioDriver %s\n", names[driver]));
- }
- else if( (asioError = ASIOInit(&asioDriverInfo.pahsc_driverInfo)) != ASE_OK )
- {
- DBUG(("PaASIO_QueryDeviceInfo: ASIOInit returned %d for %s\n", asioError, names[driver]));
- }
- else if( (ASIOGetChannels(&InputChannels, &OutputChannels) != ASE_OK))
- {
- DBUG(("PaASIO_QueryDeviceInfo could not ASIOGetChannels for %s\n", names[driver]));
- }
- else
- {
- /* Gets the name */
- dev = &(ipad[sNumDevices].pad_Info);
- dev->name = names[driver];
- names[driver] = 0;
-
- /* Gets Input and Output channels number */
- dev->maxInputChannels = InputChannels;
- dev->maxOutputChannels = OutputChannels;
-
- DBUG(("PaASIO_QueryDeviceInfo: InputChannels = %d\n", InputChannels ));
- DBUG(("PaASIO_QueryDeviceInfo: OutputChannels = %d\n", OutputChannels ));
-
- /* Make room in case device supports all rates. */
- sampleRates = (double*)PaHost_AllocateFastMemory(MAX_NUMSAMPLINGRATES * sizeof(double));
- /* check memory */
- if (!sampleRates) {
- ASIOExit();
- return paInsufficientMemory;
- }
- dev->sampleRates = sampleRates;
- dev->numSampleRates = 0;
-
- /* Loop through the possible sampling rates and check each to see if the device supports it. */
- for (int index = 0; index < MAX_NUMSAMPLINGRATES; index++) {
- if (ASIOCanSampleRate(possibleSampleRates[index]) != ASE_NoClock) {
- DBUG(("PortAudio : possible sample rate = %d\n", (long)possibleSampleRates[index]));
- dev->numSampleRates += 1;
- *sampleRates = possibleSampleRates[index];
- sampleRates++;
- }
- }
-
- /* We assume that all channels have the same SampleType, so check the first */
- channelInfos.channel = 0;
- channelInfos.isInput = 1;
- ASIOGetChannelInfo(&channelInfos);
-
- dev->nativeSampleFormats = Pa_ASIO_Convert_SampleFormat(channelInfos.type);
-
- /* unload the driver */
- ASIOExit();
- sNumDevices++;
- }
- }
-
- /* free only unused names */
- for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) if (names[i]) PaHost_FreeFastMemory(names[i],32);
-
- return paNoError;
+error:
+ return result;
}
-//----------------------------------------------------------------------------------
-// TAKEN FROM THE ASIO SDK:
-static void sampleRateChanged(ASIOSampleRate sRate)
-{
- // do whatever you need to do if the sample rate changed
- // usually this only happens during external sync.
- // Audio processing is not stopped by the driver, actual sample rate
- // might not have even changed, maybe only the sample rate status of an
- // AES/EBU or S/PDIF digital input at the audio device.
- // You might have to update time/sample related conversion routines, etc.
-}
-//----------------------------------------------------------------------------------
-// TAKEN FROM THE ASIO SDK:
-long asioMessages(long selector, long value, void* message, double* opt)
+static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat(ASIOSampleType type)
{
- // currently the parameters "value", "message" and "opt" are not used.
- long ret = 0;
- switch(selector)
- {
- case kAsioSelectorSupported:
- if(value == kAsioResetRequest
- || value == kAsioEngineVersion
- || value == kAsioResyncRequest
- || value == kAsioLatenciesChanged
- // the following three were added for ASIO 2.0, you don't necessarily have to support them
- || value == kAsioSupportsTimeInfo
- || value == kAsioSupportsTimeCode
- || value == kAsioSupportsInputMonitor)
- ret = 1L;
- break;
-
- case kAsioBufferSizeChange:
- //printf("kAsioBufferSizeChange \n");
- break;
-
- case kAsioResetRequest:
- // defer the task and perform the reset of the driver during the next "safe" situation
- // You cannot reset the driver right now, as this code is called from the driver.
- // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
- // Afterwards you initialize the driver again.
- asioDriverInfo.stopped; // In this sample the processing will just stop
- ret = 1L;
- break;
- case kAsioResyncRequest:
- // This informs the application, that the driver encountered some non fatal data loss.
- // It is used for synchronization purposes of different media.
- // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
- // Windows Multimedia system, which could loose data because the Mutex was hold too long
- // by another thread.
- // However a driver can issue it in other situations, too.
- ret = 1L;
- break;
- case kAsioLatenciesChanged:
- // This will inform the host application that the drivers were latencies changed.
- // Beware, it this does not mean that the buffer sizes have changed!
- // You might need to update internal delay data.
- ret = 1L;
- //printf("kAsioLatenciesChanged \n");
- break;
- case kAsioEngineVersion:
- // return the supported ASIO version of the host application
- // If a host applications does not implement this selector, ASIO 1.0 is assumed
- // by the driver
- ret = 2L;
- break;
- case kAsioSupportsTimeInfo:
- // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
- // is supported.
- // For compatibility with ASIO 1.0 drivers the host application should always support
- // the "old" bufferSwitch method, too.
- ret = 1;
- break;
- case kAsioSupportsTimeCode:
- // informs the driver wether application is interested in time code info.
- // If an application does not need to know about time code, the driver has less work
- // to do.
- ret = 0;
- break;
- }
- return ret;
-}
+ switch (type) {
+ case ASIOSTInt16MSB:
+ case ASIOSTInt16LSB:
+ return paInt16;
+ case ASIOSTFloat32MSB:
+ case ASIOSTFloat32LSB:
+ case ASIOSTFloat64MSB:
+ case ASIOSTFloat64LSB:
+ return paFloat32;
-//----------------------------------------------------------------------------------
-// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
-#if NATIVE_INT64
- #define ASIO64toDouble(a) (a)
-#else
- const double twoRaisedTo32 = 4294967296.;
- #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
-#endif
+ case ASIOSTInt32MSB:
+ case ASIOSTInt32LSB:
+ case ASIOSTInt32MSB16:
+ case ASIOSTInt32LSB16:
+ case ASIOSTInt32MSB18:
+ case ASIOSTInt32MSB20:
+ case ASIOSTInt32MSB24:
+ case ASIOSTInt32LSB18:
+ case ASIOSTInt32LSB20:
+ case ASIOSTInt32LSB24:
+ return paInt32;
+ case ASIOSTInt24MSB:
+ case ASIOSTInt24LSB:
+ return paInt24;
-static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
-{
- // the actual processing callback.
- // Beware that this is normally in a seperate thread, hence be sure that you take care
- // about thread synchronization. This is omitted here for simplicity.
-
- // static processedSamples = 0;
- int result = 0;
-
- // store the timeInfo for later use
- asioDriverInfo.tInfo = *timeInfo;
-
- // get the time stamp of the buffer, not necessary if no
- // synchronization to other media is required
-
- if (timeInfo->timeInfo.flags & kSystemTimeValid)
- asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
- else
- asioDriverInfo.nanoSeconds = 0;
-
- if (timeInfo->timeInfo.flags & kSamplePositionValid)
- asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
- else
- asioDriverInfo.samples = 0;
+ default:
+ return paCustomFormat;
+ }
+}
- if (timeInfo->timeCode.flags & kTcValid)
- asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
- else
- asioDriverInfo.tcSamples = 0;
- // get the system reference time
- asioDriverInfo.sysRefTime = get_sys_reference_time();
+static int BytesPerAsioSample( ASIOSampleType sampleType )
+{
+ switch (sampleType) {
+ case ASIOSTInt16MSB:
+ case ASIOSTInt16LSB:
+ return 2;
-#if 0
- // a few debug messages for the Windows device driver developer
- // tells you the time when driver got its interrupt and the delay until the app receives
- // the event notification.
- static double last_samples = 0;
- char tmp[128];
- sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples));
- OutputDebugString (tmp);
- last_samples = asioDriverInfo.samples;
-#endif
+ case ASIOSTFloat64MSB:
+ case ASIOSTFloat64LSB:
+ return 8;
- // To avoid the callback accessing a desallocated stream
- if( asioDriverInfo.past == NULL) return 0L;
+ case ASIOSTFloat32MSB:
+ case ASIOSTFloat32LSB:
+ case ASIOSTInt32MSB:
+ case ASIOSTInt32LSB:
+ case ASIOSTInt32MSB16:
+ case ASIOSTInt32LSB16:
+ case ASIOSTInt32MSB18:
+ case ASIOSTInt32MSB20:
+ case ASIOSTInt32MSB24:
+ case ASIOSTInt32LSB18:
+ case ASIOSTInt32LSB20:
+ case ASIOSTInt32LSB24:
+ return 4;
- // Keep sample position
- asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo;
+ case ASIOSTInt24MSB:
+ case ASIOSTInt24LSB:
+ return 3;
- /* Has a user callback returned '1' to indicate finished at the last ASIO callback? */
- if( asioDriverInfo.past->past_StopSoon ) {
-
- Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos,
- asioDriverInfo.pahsc_channelInfos[0].type,
- asioDriverInfo.pahsc_NumInputChannels ,
- asioDriverInfo.pahsc_NumOutputChannels,
- index,
- 0,
- asioDriverInfo.past_FramesPerHostBuffer);
-
- asioDriverInfo.past->past_IsActive = 0;
-
- // Finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
- if (asioDriverInfo.pahsc_postOutput) ASIOOutputReady();
-
- }else {
-
- /* CPU usage */
- Pa_StartUsageCalculation(asioDriverInfo.past);
-
- Pa_ASIO_Callback_Input(index);
-
- // Finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
- if (asioDriverInfo.pahsc_postOutput) ASIOOutputReady();
-
- Pa_ASIO_Callback_End();
-
- /* CPU usage */
- Pa_EndUsageCalculation(asioDriverInfo.past);
- }
-
- return 0L;
+ default:
+ return 0;
+ }
}
-//----------------------------------------------------------------------------------
-void bufferSwitch(long index, ASIOBool processNow)
-{
- // the actual processing callback.
- // Beware that this is normally in a seperate thread, hence be sure that you take care
- // about thread synchronization. This is omitted here for simplicity.
-
- // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs to be created
- // though it will only set the timeInfo.samplePosition and timeInfo.systemTime fields and the according flags
-
- ASIOTime timeInfo;
- memset (&timeInfo, 0, sizeof (timeInfo));
+static void Swap16( void *buffer, long shift, long count )
+{
+ unsigned short *p = (unsigned short*)buffer;
+ unsigned short temp;
+ (void) shift; /* unused parameter */
- // get the time stamp of the buffer, not necessary if no
- // synchronization to other media is required
- if(ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
- timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
-
- // Call the real callback
- bufferSwitchTimeInfo (&timeInfo, index, processNow);
+ while( count-- )
+ {
+ temp = *p;
+ *p++ = (unsigned short)((temp<<8) | (temp>>8));
+ }
}
-//----------------------------------------------------------------------------------
-unsigned long get_sys_reference_time()
-{
- // get the system reference time
- #if WINDOWS
- return timeGetTime();
- #elif MAC
- static const double twoRaisedTo32 = 4294967296.;
- UnsignedWide ys;
- Microseconds(&ys);
- double r = ((double)ys.hi * twoRaisedTo32 + (double)ys.lo);
- return (unsigned long)(r / 1000.);
- #endif
+static void Swap24( void *buffer, long shift, long count )
+{
+ unsigned char *p = (unsigned char*)buffer;
+ unsigned char temp;
+ (void) shift; /* unused parameter */
+
+ while( count-- )
+ {
+ temp = *p;
+ *p = *(p+2);
+ *(p+2) = temp;
+ p += 3;
+ }
}
+#define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24));
-/*************************************************************
-** Calculate 2 LSB dither signal with a triangular distribution.
-** Ranged properly for adding to a 32 bit integer prior to >>15.
-*/
-#define DITHER_BITS (15)
-#define DITHER_SCALE (1.0f / ((1<<DITHER_BITS)-1))
-inline static long Pa_TriangularDither( void )
+static void Swap32( void *buffer, long shift, long count )
{
- static unsigned long previous = 0;
- static unsigned long randSeed1 = 22222;
- static unsigned long randSeed2 = 5555555;
- long current, highPass;
-/* Generate two random numbers. */
- randSeed1 = (randSeed1 * 196314165) + 907633515;
- randSeed2 = (randSeed2 * 196314165) + 907633515;
-/* Generate triangular distribution about 0. */
- current = (((long)randSeed1)>>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS));
- /* High pass filter to reduce audibility. */
- highPass = current - previous;
- previous = current;
- return highPass;
-}
+ unsigned long *p = (unsigned long*)buffer;
+ unsigned long temp;
+ (void) shift; /* unused parameter */
-// TO BE COMPLETED WITH ALL SUPPORTED PA SAMPLE TYPES
+ while( count-- )
+ {
+ temp = *p;
+ *p++ = PA_SWAP32_( temp);
+ }
+}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+static void SwapShiftLeft32( void *buffer, long shift, long count )
{
- long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- float *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- *userBufPtr = (1.0f / MAX_INT16_FP) * temp;
- userBufPtr += NumInputChannels;
- }
- }
-
+ unsigned long *p = (unsigned long*)buffer;
+ unsigned long temp;
+
+ while( count-- )
+ {
+ temp = *p;
+ temp = PA_SWAP32_( temp);
+ *p++ = temp << shift;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+static void ShiftRightSwap32( void *buffer, long shift, long count )
{
- long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- float *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (1.0f / MAX_INT32_FP) * temp;
- userBufPtr += NumInputChannels;
- }
- }
+ unsigned long *p = (unsigned long*)buffer;
+ unsigned long temp;
+
+ while( count-- )
+ {
+ temp = *p >> shift;
+ *p++ = PA_SWAP32_( temp);
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
-static void Input_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+static void ShiftLeft32( void *buffer, long shift, long count )
{
- unsigned long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- float *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (float)temp;
- userBufPtr += NumInputChannels;
- }
- }
+ unsigned long *p = (unsigned long*)buffer;
+ unsigned long temp;
+
+ while( count-- )
+ {
+ temp = *p;
+ *p++ = temp << shift;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+static void ShiftRight32( void *buffer, long shift, long count )
{
- long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- long *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- *userBufPtr = temp<<16;
- userBufPtr += NumInputChannels;
- }
- }
+ unsigned long *p = (unsigned long*)buffer;
+ unsigned long temp;
+
+ while( count-- )
+ {
+ temp = *p;
+ *p++ = temp >> shift;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+#define PA_SWAP_( x, y ) temp=x; x = y; y = temp;
+
+static void Swap64ConvertFloat64ToFloat32( void *buffer, long shift, long count )
{
- long temp;
- int i,j;
+ double *in = (double*)buffer;
+ float *out = (float*)buffer;
+ unsigned char *p;
+ unsigned char temp;
+ (void) shift; /* unused parameter */
+
+ while( count-- )
+ {
+ p = (unsigned char*)in;
+ PA_SWAP_( p[0], p[7] );
+ PA_SWAP_( p[1], p[6] );
+ PA_SWAP_( p[2], p[5] );
+ PA_SWAP_( p[3], p[4] );
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- long *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = temp;
- userBufPtr += NumInputChannels;
- }
- }
+ *out++ = (float) (*in++);
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
-static void Input_Float32_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+static void ConvertFloat64ToFloat32( void *buffer, long shift, long count )
{
- unsigned long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- long *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (long)((float)temp * MAX_INT32_FP); // Is temp a value between -1.0 and 1.0 ??
- userBufPtr += NumInputChannels;
- }
- }
-}
-
+ double *in = (double*)buffer;
+ float *out = (float*)buffer;
+ (void) shift; /* unused parameter */
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
-{
- long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- *userBufPtr = (short)temp;
- userBufPtr += NumInputChannels;
- }
- }
+ while( count-- )
+ *out++ = (float) (*in++);
}
-
- //-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
+
+static void ConvertFloat32ToFloat64Swap64( void *buffer, long shift, long count )
{
- long temp;
- int i,j;
+ float *in = ((float*)buffer) + (count-1);
+ double *out = ((double*)buffer) + (count-1);
+ unsigned char *p;
+ unsigned char temp;
+ (void) shift; /* unused parameter */
+
+ while( count-- )
+ {
+ *out = *in--;
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (short)(temp>>16);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = (temp >> 1) + Pa_TriangularDither();
- temp = temp >> 15;
- temp = (short) ClipShort(temp);
- *userBufPtr = (short)temp;
- userBufPtr += NumInputChannels;
- }
- }
+ p = (unsigned char*)out;
+ PA_SWAP_( p[0], p[7] );
+ PA_SWAP_( p[1], p[6] );
+ PA_SWAP_( p[2], p[5] );
+ PA_SWAP_( p[3], p[4] );
- }
+ out--;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
-static void Input_Float32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
+static void ConvertFloat32ToFloat64( void *buffer, long shift, long count )
{
- unsigned long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (short)((float)temp * MAX_INT16_FP); // Is temp a value between -1.0 and 1.0 ??
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = (short)(((float)temp * MAX_INT16_FP) + dither);
- temp = ClipShort(temp);
- *userBufPtr = (short)temp;
- userBufPtr += NumInputChannels;
- }
- }
- }
+ float *in = ((float*)buffer) + (count-1);
+ double *out = ((double*)buffer) + (count-1);
+ (void) shift; /* unused parameter */
+
+ while( count-- )
+ *out-- = *in--;
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+#ifdef MAC
+#define PA_MSB_IS_NATIVE_
+#undef PA_LSB_IS_NATIVE_
+#endif
+
+#ifdef WINDOWS
+#undef PA_MSB_IS_NATIVE_
+#define PA_LSB_IS_NATIVE_
+#endif
+
+typedef void PaAsioBufferConverter( void *, long, long );
+
+static void SelectAsioToPaConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
{
- long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- *userBufPtr = (char)(temp>>8);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- temp += Pa_TriangularDither() >> 8;
- temp = ClipShort(temp);
- *userBufPtr = (char)(temp>>8);
- userBufPtr += NumInputChannels;
- }
- }
- }
+ *shift = 0;
+ *converter = 0;
+
+ switch (type) {
+ case ASIOSTInt16MSB:
+ /* dest: paInt16, no conversion necessary, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap16;
+ #endif
+ break;
+ case ASIOSTInt16LSB:
+ /* dest: paInt16, no conversion necessary, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap16;
+ #endif
+ break;
+ case ASIOSTFloat32MSB:
+ /* dest: paFloat32, no conversion necessary, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTFloat32LSB:
+ /* dest: paFloat32, no conversion necessary, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTFloat64MSB:
+ /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap64ConvertFloat64ToFloat32;
+ #else
+ *converter = ConvertFloat64ToFloat32;
+ #endif
+ break;
+ case ASIOSTFloat64LSB:
+ /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap64ConvertFloat64ToFloat32;
+ #else
+ *converter = ConvertFloat64ToFloat32;
+ #endif
+ break;
+ case ASIOSTInt32MSB:
+ /* dest: paInt32, no conversion necessary, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTInt32LSB:
+ /* dest: paInt32, no conversion necessary, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTInt32MSB16:
+ /* dest: paInt32, 16 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 16;
+ break;
+ case ASIOSTInt32MSB18:
+ /* dest: paInt32, 14 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 14;
+ break;
+ case ASIOSTInt32MSB20:
+ /* dest: paInt32, 12 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 12;
+ break;
+ case ASIOSTInt32MSB24:
+ /* dest: paInt32, 8 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 8;
+ break;
+ case ASIOSTInt32LSB16:
+ /* dest: paInt32, 16 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 16;
+ break;
+ case ASIOSTInt32LSB18:
+ /* dest: paInt32, 14 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 14;
+ break;
+ case ASIOSTInt32LSB20:
+ /* dest: paInt32, 12 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 12;
+ break;
+ case ASIOSTInt32LSB24:
+ /* dest: paInt32, 8 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 8;
+ break;
+ case ASIOSTInt24MSB:
+ /* dest: paInt24, no conversion necessary, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap24;
+ #endif
+ break;
+ case ASIOSTInt24LSB:
+ /* dest: paInt24, no conversion necessary, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap24;
+ #endif
+ break;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset, uint32 flags,bool swap)
+
+static void SelectPaToAsioConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
{
- long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (char)(temp>>24);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = temp>>16; // Shift to get a 16 bit value, then use the 16 bits to 8 bits code (MUST BE CHECHED)
- temp += Pa_TriangularDither() >> 8;
- temp = ClipShort(temp);
- *userBufPtr = (char)(temp >> 8);
- userBufPtr += NumInputChannels;
- }
- }
- }
+ *shift = 0;
+ *converter = 0;
+
+ switch (type) {
+ case ASIOSTInt16MSB:
+ /* src: paInt16, no conversion necessary, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap16;
+ #endif
+ break;
+ case ASIOSTInt16LSB:
+ /* src: paInt16, no conversion necessary, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap16;
+ #endif
+ break;
+ case ASIOSTFloat32MSB:
+ /* src: paFloat32, no conversion necessary, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTFloat32LSB:
+ /* src: paFloat32, no conversion necessary, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTFloat64MSB:
+ /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = ConvertFloat32ToFloat64Swap64;
+ #else
+ *converter = ConvertFloat32ToFloat64;
+ #endif
+ break;
+ case ASIOSTFloat64LSB:
+ /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = ConvertFloat32ToFloat64Swap64;
+ #else
+ *converter = ConvertFloat32ToFloat64;
+ #endif
+ break;
+ case ASIOSTInt32MSB:
+ /* src: paInt32, no conversion necessary, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTInt32LSB:
+ /* src: paInt32, no conversion necessary, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTInt32MSB16:
+ /* src: paInt32, 16 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 16;
+ break;
+ case ASIOSTInt32MSB18:
+ /* src: paInt32, 14 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 14;
+ break;
+ case ASIOSTInt32MSB20:
+ /* src: paInt32, 12 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 12;
+ break;
+ case ASIOSTInt32MSB24:
+ /* src: paInt32, 8 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 8;
+ break;
+ case ASIOSTInt32LSB16:
+ /* src: paInt32, 16 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 16;
+ break;
+ case ASIOSTInt32LSB18:
+ /* src: paInt32, 14 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 14;
+ break;
+ case ASIOSTInt32LSB20:
+ /* src: paInt32, 12 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 12;
+ break;
+ case ASIOSTInt32LSB24:
+ /* src: paInt32, 8 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 8;
+ break;
+ case ASIOSTInt24MSB:
+ /* src: paInt24, no conversion necessary, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap24;
+ #endif
+ break;
+ case ASIOSTInt24LSB:
+ /* src: paInt24, no conversion necessary, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap24;
+ #endif
+ break;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
-static void Input_Float32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+typedef struct PaAsioDeviceInfo
{
- unsigned long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (char)((float)temp*MAX_INT8_FP); // Is temp a value between -1.0 and 1.0 ??
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = (char)(((float)temp * MAX_INT8_FP) + dither);
- temp = ClipChar(temp);
- *userBufPtr = (char)temp;
- userBufPtr += NumInputChannels;
- }
- }
- }
+ PaDeviceInfo commonDeviceInfo;
+ long minBufferSize;
+ long maxBufferSize;
+ long preferredBufferSize;
+ long bufferGranularity;
}
+PaAsioDeviceInfo;
+
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device,
+ long *minLatency, long *maxLatency, long *preferredLatency, long *granularity )
{
- long temp;
- int i,j;
+ PaError result;
+ PaUtilHostApiRepresentation *hostApi;
+ PaDeviceIndex hostApiDevice;
+
+ result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- *userBufPtr = (unsigned char)((temp>>8) + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- temp += Pa_TriangularDither() >> 8;
- temp = ClipShort(temp);
- *userBufPtr = (unsigned char)((temp>>8) + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
- }
-}
+ if( result == paNoError )
+ {
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
-{
- long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (unsigned char)((temp>>24) + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
+ if( result == paNoError )
{
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = temp>>16; // Shift to get a 16 bit value, then use the 16 bits to 8 bits code (MUST BE CHECHED)
- temp += Pa_TriangularDither() >> 8;
- temp = ClipShort(temp);
- *userBufPtr = (unsigned char)((temp>>8) + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
+ PaAsioDeviceInfo *asioDeviceInfo =
+ (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
+
+ *minLatency = asioDeviceInfo->minBufferSize;
+ *maxLatency = asioDeviceInfo->maxBufferSize;
+ *preferredLatency = asioDeviceInfo->preferredBufferSize;
+ *granularity = asioDeviceInfo->bufferGranularity;
}
+ }
+
+ return result;
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
-static void Input_Float32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
-{
- unsigned long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (unsigned char)(((float)temp*MAX_INT8_FP) + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = (char)(((float)temp * MAX_INT8_FP) + dither);
- temp = ClipChar(temp);
- *userBufPtr = (unsigned char)(temp + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
- }
-}
-
-// OUPUT
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Float32_Int16 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags, bool swap)
+typedef struct PaAsioDriverInfo
{
- long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- if( flags & paClipOff ) /* NOTHING */
- {
- for( j=0; j<NumOuputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
-
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = (short) (*userBufPtr * MAX_INT16_FP);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
- else /* CLIP */
- {
- for( j=0; j<NumOuputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
-
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = (long) (*userBufPtr * MAX_INT16_FP);
- temp = ClipShort(temp);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
- }
- else
- {
- /* If you dither then you have to clip because dithering could push the signal out of range! */
- for( j=0; j<NumOuputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
-
- for (i= 0; i < framePerBuffer; i++)
- {
- float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = (long) ((*userBufPtr * MAX_INT16_FP) + dither);
- temp = ClipShort(temp);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
+ ASIODriverInfo asioDriverInfo;
+ long numInputChannels, numOutputChannels;
+ long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity;
+ bool postOutput;
}
+PaAsioDriverInfo;
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Float32_Int32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
+/*
+ load the asio driver named by <driverName> and return statistics about
+ the driver in info. If no error occurred, the driver will remain open
+ and must be closed by the called by calling ASIOExit() - if an error
+ is returned the driver will already be closed.
+*/
+static PaError LoadAsioDriver( const char *driverName, PaAsioDriverInfo *info )
{
- long temp;
- int i,j;
-
- if( flags & paClipOff )
- {
- for (j= 0; j < NumOuputChannels; j++)
- {
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (long) (*userBufPtr * MAX_INT32_FP);
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
- else // CLIP *
- {
- for (j= 0; j < NumOuputChannels; j++)
- {
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- float temp1 = *userBufPtr;
- temp1 = ClipFloat(temp1);
- temp = (long) (temp1*MAX_INT32_FP);
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
+ PaError result = paNoError;
+ ASIOError asioError;
+ int asioIsInitialized = 0;
+
+ if( !loadAsioDriver( const_cast<char*>(driverName) ) )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
+ goto error;
+ }
+
+ if( (asioError = ASIOInit( &info->asioDriverInfo )) != ASE_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ goto error;
+ }
+ else
+ {
+ asioIsInitialized = 1;
+ }
+
+ if( (asioError = ASIOGetChannels(&info->numInputChannels,
+ &info->numOutputChannels)) != ASE_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ goto error;
+ }
+
+ if( (asioError = ASIOGetBufferSize(&info->bufferMinSize,
+ &info->bufferMaxSize, &info->bufferPreferredSize,
+ &info->bufferGranularity)) != ASE_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ goto error;
+ }
+
+ if( ASIOOutputReady() == ASE_OK )
+ info->postOutput = true;
+ else
+ info->postOutput = false;
+
+ return result;
+
+error:
+ if( asioIsInitialized )
+ ASIOExit();
+ return result;
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
+#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ 13 /* must be the same number of elements as in the array below */
+static ASIOSampleRate defaultSampleRateSearchOrder_[]
+ = {44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0,
+ 192000.0, 16000.0, 12000.0, 11025.0, 96000.0, 8000.0 };
+
- static void Output_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
+PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
{
- long temp;
- int i,j;
-
- if( flags & paClipOff )
- {
- for (j= 0; j < NumOuputChannels; j++)
- {
- float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (long) *userBufPtr;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = (float)temp;
- userBufPtr += NumOuputChannels;
- }
- }
-
- }
- else /* CLIP */
+ PaError result = paNoError;
+ int i, j, driverCount;
+ PaAsioHostApiRepresentation *asioHostApi;
+ PaAsioDeviceInfo *deviceInfoArray;
+ char **names;
+ PaAsioDriverInfo paAsioDriverInfo;
+ ASIOError asioError;
+ ASIODriverInfo asioDriverInfo;
+ ASIOChannelInfo asioChannelInfo;
+ double *sampleRates;
+
+
+ asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) );
+ if( !asioHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ asioHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !asioHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ asioHostApi->driverOpen = 0;
+
+ *hostApi = &asioHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+
+ (*hostApi)->info.type = paASIO;
+ (*hostApi)->info.name = "ASIO";
+ (*hostApi)->info.deviceCount = 0;
+
+ #ifdef WINDOWS
+ CoInitialize(0);
+ #endif
+
+ /* MUST BE CHECKED : to force fragments loading on Mac */
+ loadAsioDriver( "dummy" );
+
+
+ /* driverCount is the number of installed drivers - not necessarily
+ the number of installed physical devices. */
+ #if MAC
+ driverCount = asioDrivers->getNumFragments();
+ #elif WINDOWS
+ driverCount = asioDrivers->asioGetNumDev();
+ #endif
+
+ if( driverCount > 0 )
+ {
+ names = GetAsioDriverNames( asioHostApi->allocations, driverCount );
+ if( !names )
{
- for (j= 0; j < NumOuputChannels; j++)
- {
- float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- float temp1 = *userBufPtr;
- temp1 = ClipFloat(temp1); // Is is necessary??
- temp = (long) temp1;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = (float)temp;
- userBufPtr += NumOuputChannels;
- }
- }
+ result = paInsufficientMemory;
+ goto error;
}
-}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int32_Int16(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
-{
- long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for (j= 0; j < NumOuputChannels; j++)
- {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (short) ((*userBufPtr) >> 16);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
- else
+ /* allocate enough space for all drivers, even if some aren't installed */
+
+ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ asioHostApi->allocations, sizeof(PaDeviceInfo*) * driverCount );
+ if( !(*hostApi)->deviceInfos )
{
- for (j= 0; j < NumOuputChannels; j++)
- {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (*userBufPtr >> 1) + Pa_TriangularDither();
- temp = temp >> 15;
- temp = (short) ClipShort(temp);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
+ result = paInsufficientMemory;
+ goto error;
}
-}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
-{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
+ /* allocate all device info structs in a contiguous block */
+ deviceInfoArray = (PaAsioDeviceInfo*)PaUtil_GroupAllocateMemory(
+ asioHostApi->allocations, sizeof(PaAsioDeviceInfo) * driverCount );
+ if( !deviceInfoArray )
{
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = *userBufPtr;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
+ result = paInsufficientMemory;
+ goto error;
}
-}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE CHECKED
-static void Output_Int32_Float32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
-{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
+ #if WINDOWS
+ asioDriverInfo.asioVersion = 2; /* FIXME - is this right? PLB */
+ asioDriverInfo.sysRef = GetDesktopWindow(); /* FIXME - is this right? PLB */
+ #elif MAC
+ /* REVIEW: is anything needed here?? RDB */
+ #endif
+
+ for( i=0; i < driverCount; ++i )
{
- float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
+ /* Attempt to load the asio driver... */
+ if( LoadAsioDriver( names[i], &paAsioDriverInfo ) == paNoError )
+ {
+ PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
+ PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
+
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+
+ deviceInfo->name = names[i];
+
+ deviceInfo->maxInputChannels = paAsioDriverInfo.numInputChannels;
+ deviceInfo->maxOutputChannels = paAsioDriverInfo.numOutputChannels;
+
+ PA_DEBUG(("PaAsio_Initialize: inputChannels = %d\n", inputChannels ));
+ PA_DEBUG(("PaAsio_Initialize: outputChannels = %d\n", outputChannels ));
+
+
+ deviceInfo->defaultLowInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultLowOutputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighOutputLatency = 0.; /* @todo IMPLEMENT ME */
+
+ deviceInfo->defaultSampleRate = 0.;
+ for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j )
{
- temp = *userBufPtr;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = ((float)temp) * (1.0f / MAX_INT32_FP);
- userBufPtr += NumOuputChannels;
+ ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] );
+ if( asioError != ASE_NoClock && asioError != ASE_NotPresent ){
+ deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
+ break;
+ }
}
+
+ asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize;
+ asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize;
+ asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize;
+ asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity;
+
+
+ /* We assume that all channels have the same SampleType, so check the first, FIXME, probably shouldn't assume that */
+ asioChannelInfo.channel = 0;
+ asioChannelInfo.isInput = 1;
+ ASIOGetChannelInfo( &asioChannelInfo ); /* FIXME, check return code */
+
+
+ /* unload the driver */
+ ASIOExit();
+
+ (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
+ ++(*hostApi)->info.deviceCount;
+ }
}
-}
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int16_Int16(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,bool swap)
-{
- long temp;
- int i,j;
+ if( (*hostApi)->info.deviceCount > 0 )
+ {
+ (*hostApi)->info.defaultInputDevice = 0;
+ (*hostApi)->info.defaultOutputDevice = 0;
+ }
+ else
+ {
+ (*hostApi)->info.defaultInputDevice = paNoDevice;
+ (*hostApi)->info.defaultOutputDevice = paNoDevice;
+ }
+
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &asioHostApi->blockingStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
- for (j= 0; j < NumOuputChannels; j++)
+ return result;
+
+error:
+ if( asioHostApi )
+ {
+ if( asioHostApi->allocations )
{
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- short *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = *userBufPtr;
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
+ PaUtil_FreeAllAllocations( asioHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
}
+
+ PaUtil_FreeMemory( asioHostApi );
+ }
+ return result;
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int16_Int32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
- {
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- short *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (*userBufPtr)<<16;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
- }
+ PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
+
+ /*
+ IMPLEMENT ME:
+ - clean up any resources not handled by the allocation group
+ */
+
+ if( asioHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( asioHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( asioHostApi );
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE CHECKED
-static void Output_Int16_Float32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
- {
- float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- short *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = *userBufPtr;
- asioBufPtr[i] = ((float)temp) * (1.0f / MAX_INT16_FP);
- userBufPtr += NumOuputChannels;
- }
- }
+ int numInputChannels, numOutputChannels;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ if( inputParameters )
+ {
+ numInputChannels = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support numInputChannels */
+ if( numInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numInputChannels = 0;
+ }
+
+ if( outputParameters )
+ {
+ numOutputChannels = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support numInputChannels */
+ if( numOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numOutputChannels = 0;
+ }
+
+ /*
+ IMPLEMENT ME:
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+ */
+
+ return paFormatIsSupported;
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int8_Int16(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
-{
- long temp;
- int i,j;
- for (j= 0; j < NumOuputChannels; j++)
- {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (short)(*userBufPtr)<<8;
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
+
+
+/* PaAsioStream - a stream data structure specifically for this implementation */
+
+typedef struct PaAsioStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ PaAsioHostApiRepresentation *asioHostApi;
+ unsigned long framesPerHostCallback;
+
+ /* ASIO driver info - these may not be needed for the life of the stream,
+ but store them here until we work out how format conversion is going
+ to work. */
+
+ ASIOBufferInfo *asioBufferInfos;
+ ASIOChannelInfo *asioChannelInfos;
+ long inputLatency, outputLatency; // actual latencies returned by asio
+
+ long numInputChannels, numOutputChannels;
+ bool postOutput;
+
+ void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */
+ void **inputBufferPtrs[2];
+ void **outputBufferPtrs[2];
+
+ PaAsioBufferConverter *inputBufferConverter;
+ long inputShift;
+ PaAsioBufferConverter *outputBufferConverter;
+ long outputShift;
+
+ volatile int stopProcessing; /* stop thread once existing buffers have been returned */
+ volatile int abortProcessing; /* stop thread immediately */
}
+PaAsioStream;
+
+static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int8_Int32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+
+static void ZeroOutputBuffers( PaAsioStream *stream, long index )
{
- long temp;
- int i,j;
+ int i;
+
+ for( i=0; i < stream->numOutputChannels; ++i )
+ {
+ void *buffer = stream->asioBufferInfos[ i + stream->numInputChannels ].buffers[index];
- for (j= 0; j < NumOuputChannels; j++)
- {
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (short)(*userBufPtr)<<24;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
- }
+ int bytesPerSample = BytesPerAsioSample( stream->asioChannelInfos[ i + stream->numInputChannels ].type );
+
+ memset( buffer, 0, stream->framesPerHostCallback * bytesPerSample );
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE CHECKED
-static void Output_Int8_Float32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+static unsigned long SelectHostBufferSize( unsigned long suggestedLatencyFrames,
+ PaAsioDriverInfo *driverInfo )
{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
+ unsigned long result;
+
+ if( suggestedLatencyFrames == 0 )
+ {
+ result = driverInfo->bufferPreferredSize;
+ }
+ else{
+ if( suggestedLatencyFrames <= (unsigned long)driverInfo->bufferMinSize )
{
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = *userBufPtr;
- asioBufPtr[i] = (long)(((float)temp) * (1.0f / MAX_INT8_FP));
- userBufPtr += NumOuputChannels;
- }
+ result = driverInfo->bufferMinSize;
}
-}
+ else if( suggestedLatencyFrames >= (unsigned long)driverInfo->bufferMaxSize )
+ {
+ result = driverInfo->bufferMaxSize;
+ }
+ else
+ {
+ if( driverInfo->bufferGranularity == -1 )
+ {
+ /* power-of-two */
+ result = 2;
+
+ while( result < suggestedLatencyFrames )
+ result *= result;
+
+ if( result < (unsigned long)driverInfo->bufferMinSize )
+ result = driverInfo->bufferMinSize;
+
+ if( result > (unsigned long)driverInfo->bufferMaxSize )
+ result = driverInfo->bufferMaxSize;
+ }
+ else if( driverInfo->bufferGranularity == 0 )
+ {
+ result = driverInfo->bufferPreferredSize;
+ }
+ else
+ {
+ /* modulo granularity */
+
+ result = suggestedLatencyFrames +
+ (driverInfo->bufferGranularity -
+ (suggestedLatencyFrames % driverInfo->bufferGranularity));
+ if( result > (unsigned long)driverInfo->bufferMaxSize )
+ result = driverInfo->bufferMaxSize;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
+ PaAsioStream *stream = 0;
+ unsigned long framesPerHostBuffer;
+ int numInputChannels, numOutputChannels;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+ PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
+ unsigned long suggestedInputLatencyFrames;
+ unsigned long suggestedOutputLatencyFrames;
+ const char *driverName;
+ ASIOError asioError;
+ int asioIsInitialized = 0;
+ int asioBuffersCreated = 0;
+ PaAsioDriverInfo driverInfo;
+ int i;
+
+ /* unless we move to using lower level ASIO calls, we can only have
+ one device open at a time */
+ if( asioHostApi->driverOpen )
+ return paDeviceUnavailable;
+
+
+
+ if( inputParameters )
+ {
+ numInputChannels = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+ suggestedInputLatencyFrames = inputParameters->suggestedLatency * sampleRate;
+
+ driverName = asioHostApi->inheritedHostApiRep.deviceInfos[ inputParameters->device ]->name;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* validate hostApiSpecificStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numInputChannels = 0;
+ suggestedInputLatencyFrames = 0;
+ }
+
+ if( outputParameters )
+ {
+ numOutputChannels = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+ suggestedOutputLatencyFrames = outputParameters->suggestedLatency;
+
+ driverName = asioHostApi->inheritedHostApiRep.deviceInfos[ outputParameters->device ]->name;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* validate hostApiSpecificStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numOutputChannels = 0;
+ suggestedOutputLatencyFrames = 0;
+ }
+
+
+ if( inputParameters && outputParameters )
+ {
+ /* full duplex ASIO stream must use the same device for input and output */
+
+ if( inputParameters->device != outputParameters->device )
+ return paBadIODeviceCombination;
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_IntU8_Int16(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
-{
- long temp;
- int i,j;
+
- for (j= 0; j < NumOuputChannels; j++)
+ /* NOTE: we load the driver and use its current settings
+ rather than the ones in our device info structure which may be stale */
+
+ result = LoadAsioDriver( driverName, &driverInfo );
+ if( result == paNoError )
+ asioIsInitialized = 1;
+ else
+ goto error;
+
+ /* check that input device can support numInputChannels */
+ if( numInputChannels > 0 )
+ {
+ if( numInputChannels > driverInfo.numInputChannels )
{
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = ((short)((*userBufPtr) - 0x80)) << 8;
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
+ result = paInvalidChannelCount;
+ goto error;
}
-}
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_IntU8_Int32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
-{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
+ /* check that output device can support numOutputChannels */
+ if( numOutputChannels )
+ {
+ if( numOutputChannels > driverInfo.numOutputChannels )
{
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = ((short)((*userBufPtr) - 0x80)) << 24;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
- }
-}
+ result = paInvalidChannelCount;
+ goto error;
+ }
+ }
+
+ /* Set sample rate */
+ if( ASIOSetSampleRate( sampleRate ) != ASE_OK )
+ {
+ result = paInvalidSampleRate;
+ goto error;
+ }
+
+ framesPerHostBuffer = SelectHostBufferSize(
+ (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames )
+ ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames),
+ &driverInfo );
+
+ /*
+ IMPLEMENT ME:
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+ */
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE CHECKED
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
-static void Output_IntU8_Float32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
-{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
+
+ stream = (PaAsioStream*)PaUtil_AllocateMemory( sizeof(PaAsioStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ stream->asioBufferInfos = 0; /* for deallocation in error */
+ stream->asioChannelInfos = 0; /* for deallocation in error */
+ stream->bufferPtrs = 0; /* for deallocation in error */
+
+ if( streamCallback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &asioHostApi->callbackStreamInterface, streamCallback, userData );
+ }
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &asioHostApi->blockingStreamInterface, streamCallback, userData );
+ }
+
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+
+ stream->asioBufferInfos = (ASIOBufferInfo*)PaUtil_AllocateMemory(
+ sizeof(ASIOBufferInfo) * (numInputChannels + numOutputChannels) );
+ if( !stream->asioBufferInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+
+ for( i=0; i < numInputChannels; ++i )
+ {
+ ASIOBufferInfo *info = &stream->asioBufferInfos[i];
+
+ info->isInput = ASIOTrue;
+ info->channelNum = i;
+ info->buffers[0] = info->buffers[1] = 0;
+ }
+
+ for( i=0; i < numOutputChannels; ++i ){
+ ASIOBufferInfo *info = &stream->asioBufferInfos[numInputChannels+i];
+
+ info->isInput = ASIOFalse;
+ info->channelNum = i;
+ info->buffers[0] = info->buffers[1] = 0;
+ }
+
+ asioError = ASIOCreateBuffers( stream->asioBufferInfos, numInputChannels+numOutputChannels,
+ framesPerHostBuffer, &asioCallbacks_ );
+ if( asioError != ASE_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ goto error;
+ }
+
+ asioBuffersCreated = 1;
+
+ stream->asioChannelInfos = (ASIOChannelInfo*)PaUtil_AllocateMemory(
+ sizeof(ASIOChannelInfo) * (numInputChannels + numOutputChannels) );
+ if( !stream->asioChannelInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i=0; i < numInputChannels + numOutputChannels; ++i )
+ {
+ stream->asioChannelInfos[i].channel = stream->asioBufferInfos[i].channelNum;
+ stream->asioChannelInfos[i].isInput = stream->asioBufferInfos[i].isInput;
+ asioError = ASIOGetChannelInfo( &stream->asioChannelInfos[i] );
+ if( asioError != ASE_OK )
{
- float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = ((short)((*userBufPtr) - 0x80)) << 24;
- asioBufPtr[i] = ((float)temp) * (1.0f / MAX_INT32_FP);
- userBufPtr += NumOuputChannels;
- }
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ goto error;
+ }
+ }
+
+ stream->bufferPtrs = (void**)PaUtil_AllocateMemory(
+ 2 * sizeof(void*) * (numInputChannels + numOutputChannels) );
+ if( !stream->bufferPtrs )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( numInputChannels > 0 )
+ {
+ stream->inputBufferPtrs[0] = stream-> bufferPtrs;
+ stream->inputBufferPtrs[1] = &stream->bufferPtrs[numInputChannels];
+
+ for( i=0; i<numInputChannels; ++i )
+ {
+ stream->inputBufferPtrs[0][i] = stream->asioBufferInfos[i].buffers[0];
+ stream->inputBufferPtrs[1][i] = stream->asioBufferInfos[i].buffers[1];
+ }
+ }
+ else
+ {
+ stream->inputBufferPtrs[0] = 0;
+ stream->inputBufferPtrs[1] = 0;
+ }
+
+ if( numOutputChannels > 0 )
+ {
+ stream->outputBufferPtrs[0] = &stream->bufferPtrs[numInputChannels*2];
+ stream->outputBufferPtrs[1] = &stream->bufferPtrs[numInputChannels*2 + numOutputChannels];
+
+ for( i=0; i<numOutputChannels; ++i )
+ {
+ stream->outputBufferPtrs[0][i] = stream->asioBufferInfos[numInputChannels+i].buffers[0];
+ stream->outputBufferPtrs[1][i] = stream->asioBufferInfos[numInputChannels+i].buffers[1];
}
-}
+ }
+ else
+ {
+ stream->outputBufferPtrs[0] = 0;
+ stream->outputBufferPtrs[1] = 0;
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Clear_Output_16 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset)
-{
- int i,j;
- for( j=0; j<NumOuputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- for (i= 0; i < frames; i++) {asioBufPtr[i] = 0; }
- }
-}
+ ASIOGetLatencies( &stream->inputLatency, &stream->outputLatency );
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Clear_Output_32 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset)
-{
- int i,j;
+ stream->streamRepresentation.streamInfo.inputLatency = (double)stream->inputLatency / sampleRate; // seconds
+ stream->streamRepresentation.streamInfo.outputLatency = (double)stream->outputLatency / sampleRate; // seconds
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
- for( j=0; j<NumOuputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- for (i= 0; i < frames; i++) {asioBufPtr[i] = 0; }
- }
-}
+ PA_DEBUG(("PaAsio : InputLatency = %ld latency = %ld msec \n",
+ stream->inputLatency,
+ (long)((stream->inputLatency*1000)/ sampleRate)));
+ PA_DEBUG(("PaAsio : OuputLatency = %ld latency = %ld msec \n",
+ stream->outputLatency,
+ (long)((stream->outputLatency*1000)/ sampleRate)));
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Adaptor_Init()
-{
- if (asioDriverInfo.past->past_FramesPerUserBuffer <= asioDriverInfo.past_FramesPerHostBuffer) {
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset = asioDriverInfo.pahsc_OutputBufferOffset;
- asioDriverInfo.pahsc_userInputBufferFrameOffset = 0; // empty
- asioDriverInfo.pahsc_userOutputBufferFrameOffset = asioDriverInfo.past->past_FramesPerUserBuffer; // empty
- }else {
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0; // empty
- asioDriverInfo.pahsc_userInputBufferFrameOffset = asioDriverInfo.pahsc_InputBufferOffset;
- asioDriverInfo.pahsc_userOutputBufferFrameOffset = asioDriverInfo.past->past_FramesPerUserBuffer; // empty
- }
-}
+ if( numInputChannels > 0 )
+ {
+ /* FIXME: assume all channels use the same type for now */
+ ASIOSampleType inputType = stream->asioChannelInfos[0].type;
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// FIXME : optimization for Input only or output only modes (really necessary ??)
-static void Pa_ASIO_Callback_Input( long index)
-{
- internalPortAudioStream *past = asioDriverInfo.past;
- long framesInputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer; // number of frames available into the host input buffer
- long framesInputUserBuffer; // number of frames needed to complete the user input buffer
- long framesOutputHostBuffer; // number of frames needed to complete the host output buffer
- long framesOuputUserBuffer; // number of frames available into the user output buffer
- long userResult;
- long tmp;
-
- /* Fill host ASIO output with remaining frames in user output */
- framesOutputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer;
- framesOuputUserBuffer = asioDriverInfo.past->past_FramesPerUserBuffer - asioDriverInfo.pahsc_userOutputBufferFrameOffset;
- tmp = min(framesOutputHostBuffer, framesOuputUserBuffer);
- framesOutputHostBuffer -= tmp;
- Pa_ASIO_Callback_Output(index,tmp);
-
- /* Available frames in hostInputBuffer */
- while (framesInputHostBuffer > 0) {
-
- /* Number of frames needed to complete an user input buffer */
- framesInputUserBuffer = asioDriverInfo.past->past_FramesPerUserBuffer - asioDriverInfo.pahsc_userInputBufferFrameOffset;
-
- if (framesInputHostBuffer >= framesInputUserBuffer) {
-
- /* Convert ASIO input to user input */
- Pa_ASIO_Convert_Inter_Input (asioDriverInfo.bufferInfos,
- past->past_InputBuffer,
- asioDriverInfo.pahsc_NumInputChannels ,
- asioDriverInfo.pahsc_NumOutputChannels,
- framesInputUserBuffer,
- asioDriverInfo.past_FramesPerHostBuffer - framesInputHostBuffer,
- asioDriverInfo.pahsc_userInputBufferFrameOffset,
- asioDriverInfo.pahsc_channelInfos[0].type,
- past->past_InputSampleFormat,
- past->past_Flags,
- index);
-
- /* Call PortAudio callback */
- userResult = asioDriverInfo.past->past_Callback(past->past_InputBuffer, past->past_OutputBuffer,
- past->past_FramesPerUserBuffer,past->past_FrameCount,past->past_UserData );
-
- /* User callback has asked us to stop in the middle of the host buffer */
- if( userResult != 0) {
-
- /* Put 0 in the end of the output buffer */
- Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos,
- asioDriverInfo.pahsc_channelInfos[0].type,
- asioDriverInfo.pahsc_NumInputChannels ,
- asioDriverInfo.pahsc_NumOutputChannels,
- index,
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset,
- asioDriverInfo.past_FramesPerHostBuffer - asioDriverInfo.pahsc_hostOutputBufferFrameOffset);
-
- past->past_StopSoon = 1;
- return;
- }
-
-
- /* Full user ouput buffer : write offset */
- asioDriverInfo.pahsc_userOutputBufferFrameOffset = 0;
-
- /* Empty user input buffer : read offset */
- asioDriverInfo.pahsc_userInputBufferFrameOffset = 0;
-
- /* Fill host ASIO output */
- tmp = min (past->past_FramesPerUserBuffer,framesOutputHostBuffer);
- Pa_ASIO_Callback_Output(index,tmp);
-
- framesOutputHostBuffer -= tmp;
- framesInputHostBuffer -= framesInputUserBuffer;
-
- }else {
-
- /* Convert ASIO input to user input */
- Pa_ASIO_Convert_Inter_Input (asioDriverInfo.bufferInfos,
- past->past_InputBuffer,
- asioDriverInfo.pahsc_NumInputChannels ,
- asioDriverInfo.pahsc_NumOutputChannels,
- framesInputHostBuffer,
- asioDriverInfo.past_FramesPerHostBuffer - framesInputHostBuffer,
- asioDriverInfo.pahsc_userInputBufferFrameOffset,
- asioDriverInfo.pahsc_channelInfos[0].type,
- past->past_InputSampleFormat,
- past->past_Flags,
- index);
-
- /* Update pahsc_userInputBufferFrameOffset */
- asioDriverInfo.pahsc_userInputBufferFrameOffset += framesInputHostBuffer;
-
- /* Update framesInputHostBuffer */
- framesInputHostBuffer = 0;
- }
- }
+ hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( inputType );
-}
+ SelectAsioToPaConverter( inputType, &stream->inputBufferConverter, &stream->inputShift );
+ }
+ else
+ {
+ stream->inputBufferConverter = 0;
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Callback_Output(long index, long framePerBuffer)
-{
- internalPortAudioStream *past = asioDriverInfo.past;
+ if( numOutputChannels > 0 )
+ {
+ /* FIXME: assume all channels use the same type for now */
+ ASIOSampleType outputType = stream->asioChannelInfos[numInputChannels].type;
- if (framePerBuffer > 0) {
-
- /* Convert user output to ASIO ouput */
- Pa_ASIO_Convert_Inter_Output (asioDriverInfo.bufferInfos,
- past->past_OutputBuffer,
- asioDriverInfo.pahsc_NumInputChannels,
- asioDriverInfo.pahsc_NumOutputChannels,
- framePerBuffer,
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset,
- asioDriverInfo.pahsc_userOutputBufferFrameOffset,
- asioDriverInfo.pahsc_channelInfos[0].type,
- past->past_InputSampleFormat,
- past->past_Flags,
- index);
-
- /* Update hostOuputFrameOffset */
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset += framePerBuffer;
+ hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( outputType );
- /* Update userOutputFrameOffset */
- asioDriverInfo.pahsc_userOutputBufferFrameOffset += framePerBuffer;
- }
-}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Callback_End()
- {
- /* Empty ASIO ouput : write offset */
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0;
- }
-
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Clear_User_Buffers()
-{
- if( asioDriverInfo.past->past_InputBuffer != NULL )
- {
- memset( asioDriverInfo.past->past_InputBuffer, 0, asioDriverInfo.past->past_InputBufferSize );
- }
- if( asioDriverInfo.past->past_OutputBuffer != NULL )
- {
- memset( asioDriverInfo.past->past_OutputBuffer, 0, asioDriverInfo.past->past_OutputBufferSize );
- }
-}
+ SelectPaToAsioConverter( outputType, &stream->outputBufferConverter, &stream->outputShift );
+ }
+ else
+ {
+ stream->outputBufferConverter = 0;
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
- static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer,
- ASIOSampleType nativeFormat,
- long NumInputChannels,
- long NumOuputChannels,
- long index,
- long hostFrameOffset,
- long frames)
-{
-
- switch (nativeFormat) {
-
- case ASIOSTInt16MSB:
- case ASIOSTInt16LSB:
- case ASIOSTInt32MSB16:
- case ASIOSTInt32LSB16:
- Pa_ASIO_Clear_Output_16(nativeBuffer, frames, NumInputChannels, NumOuputChannels, index, hostFrameOffset);
- break;
-
- case ASIOSTFloat64MSB:
- case ASIOSTFloat64LSB:
- break;
-
- case ASIOSTFloat32MSB:
- case ASIOSTFloat32LSB:
- case ASIOSTInt32MSB:
- case ASIOSTInt32LSB:
- case ASIOSTInt32MSB18:
- case ASIOSTInt32MSB20:
- case ASIOSTInt32MSB24:
- case ASIOSTInt32LSB18:
- case ASIOSTInt32LSB20:
- case ASIOSTInt32LSB24:
- Pa_ASIO_Clear_Output_32(nativeBuffer, frames, NumInputChannels, NumOuputChannels, index, hostFrameOffset);
- break;
-
- case ASIOSTInt24MSB:
- case ASIOSTInt24LSB:
- break;
-
- default:
- break;
- }
-}
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ numInputChannels, inputSampleFormat, hostInputSampleFormat,
+ numOutputChannels, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer,
+ framesPerHostBuffer, paUtilFixedHostBufferSize,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+ stream->asioHostApi = asioHostApi;
+ stream->framesPerHostCallback = framesPerHostBuffer;
-//---------------------------------------------------------------------------------------
-static void Pa_ASIO_Convert_Inter_Input(
- ASIOBufferInfo* nativeBuffer,
- void* inputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
- ASIOSampleType nativeFormat,
- PaSampleFormat paFormat,
- PaStreamFlags flags,
- long index)
-{
-
- if((NumInputChannels > 0) && (nativeBuffer != NULL))
- {
- /* Convert from native format to PA format. */
- switch(paFormat)
- {
- case paFloat32:
- {
- float *inBufPtr = (float *) inputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
- break;
- case ASIOSTInt32LSB:
- Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap);
- break;
- case ASIOSTInt32MSB:
- Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
- break;
- case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap);
- break;
- case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
-
- break;
- }
-
- case paInt32:
- {
- long *inBufPtr = (long *)inputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Input_Int16_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Input_Int16_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTInt32LSB:
- Input_Int32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt32MSB:
- Input_Int32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
-
- }
- break;
- }
-
- case paInt16:
- {
- short *inBufPtr = (short *) inputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Input_Int16_Int16(nativeBuffer, inBufPtr, framePerBuffer , NumInputChannels, index , hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Input_Int16_Int16(nativeBuffer, inBufPtr, framePerBuffer , NumInputChannels, index , hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTInt32LSB:
- Input_Int32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTInt32MSB:
- Input_Int32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
-
- }
- break;
- }
-
- case paInt8:
- {
- /* Convert 16 bit data to 8 bit chars */
-
- char *inBufPtr = (char *) inputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Input_Int16_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap);
- break;
- case ASIOSTInt16MSB:
- Input_Int16_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTInt32LSB:
- Input_Int32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTInt32MSB:
- Input_Int32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
- break;
- }
-
- case paUInt8:
- {
- /* Convert 16 bit data to 8 bit unsigned chars */
-
- unsigned char *inBufPtr = (unsigned char *)inputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Input_Int16_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTInt16MSB:
- Input_Int16_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTInt32LSB:
- Input_Int32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap);
- break;
- case ASIOSTInt32MSB:
- Input_Int32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap);
- break;
- case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
-
- }
- break;
- }
-
- default:
- break;
- }
- }
-}
+ stream->numInputChannels = numInputChannels;
+ stream->numOutputChannels = numOutputChannels;
+ stream->postOutput = driverInfo.postOutput;
+ asioHostApi->driverOpen = 1;
-//---------------------------------------------------------------------------------------
-static void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer,
- void* outputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
- ASIOSampleType nativeFormat,
- PaSampleFormat paFormat,
- PaStreamFlags flags,
- long index)
-{
-
- if((NumOuputChannels > 0) && (nativeBuffer != NULL))
- {
- /* Convert from PA format to native format */
-
- switch(paFormat)
- {
- case paFloat32:
- {
- float *outBufPtr = (float *) outputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Output_Float32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags, swap);
- break;
- case ASIOSTInt16MSB:
- Output_Float32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags,!swap);
- break;
- case ASIOSTInt32LSB:
- Output_Float32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags,swap);
- break;
- case ASIOSTInt32MSB:
- Output_Float32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTFloat32LSB:
- Output_Float32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset,flags,swap);
- break;
- case ASIOSTFloat32MSB:
- Output_Float32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
- break;
- }
-
- case paInt32:
- {
- long *outBufPtr = (long *) outputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Output_Int32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTInt16MSB:
- Output_Int32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTInt32LSB:
- Output_Int32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTInt32MSB:
- Output_Int32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTFloat32LSB:
- Output_Int32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTFloat32MSB:
- Output_Int32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
- break;
- }
-
- case paInt16:
- {
- short *outBufPtr = (short *) outputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Output_Int16_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Output_Int16_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTInt32LSB:
- Output_Int16_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt32MSB:
- Output_Int16_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTFloat32LSB:
- Output_Int16_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTFloat32MSB:
- Output_Int16_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
-
- }
- break;
- }
-
-
- case paInt8:
- {
- char *outBufPtr = (char *) outputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Output_Int8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Output_Int8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTInt32LSB:
- Output_Int8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt32MSB:
- Output_Int8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTFloat32LSB:
- Output_Int8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTFloat32MSB:
- Output_Int8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
- break;
- }
-
- case paUInt8:
- {
- unsigned char *outBufPtr = (unsigned char *) outputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Output_IntU8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Output_IntU8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTInt32LSB:
- Output_IntU8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt32MSB:
- Output_IntU8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTFloat32LSB:
- Output_IntU8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTFloat32MSB:
- Output_IntU8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
- break;
- }
-
- default:
- break;
- }
- }
+ *s = (PaStream*)stream;
-}
+ return result;
+error:
+ if( stream )
+ {
+ if( stream->asioBufferInfos )
+ PaUtil_FreeMemory( stream->asioBufferInfos );
+ if( stream->asioChannelInfos )
+ PaUtil_FreeMemory( stream->asioChannelInfos );
-/* Load a ASIO driver corresponding to the required device */
-static PaError Pa_ASIO_loadDevice (long device)
-{
- PaDeviceInfo * dev = &(sDevices[device].pad_Info);
+ if( stream->bufferPtrs )
+ PaUtil_FreeMemory( stream->bufferPtrs );
- if (!Pa_ASIO_loadAsioDriver((char *) dev->name)) return paHostError;
- if (ASIOInit(&asioDriverInfo.pahsc_driverInfo) != ASE_OK) return paHostError;
- if (ASIOGetChannels(&asioDriverInfo.pahsc_NumInputChannels, &asioDriverInfo.pahsc_NumOutputChannels) != ASE_OK) return paHostError;
- if (ASIOGetBufferSize(&asioDriverInfo.pahsc_minSize, &asioDriverInfo.pahsc_maxSize, &asioDriverInfo.pahsc_preferredSize, &asioDriverInfo.pahsc_granularity) != ASE_OK) return paHostError;
-
- if(ASIOOutputReady() == ASE_OK)
- asioDriverInfo.pahsc_postOutput = true;
- else
- asioDriverInfo.pahsc_postOutput = false;
-
- return paNoError;
+ PaUtil_FreeMemory( stream );
+ }
+
+ if( asioBuffersCreated )
+ ASIODisposeBuffers();
+
+ if( asioIsInitialized )
+ ASIOExit();
+
+ return result;
}
-//---------------------------------------------------
-static int GetHighestBitPosition (unsigned long n)
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
{
- int pos = -1;
- while( n != 0 )
- {
- pos++;
- n = n >> 1;
- }
- return pos;
-}
+ PaError result = paNoError;
+ PaAsioStream *stream = (PaAsioStream*)s;
-//------------------------------------------------------------------------------------------
-static int GetFirstMultiple(long min, long val ){ return ((min + val - 1) / val) * val; }
+ /*
+ IMPLEMENT ME:
+ - additional stream closing + cleanup
+ */
-//------------------------------------------------------------------------------------------
-static int GetFirstPossibleDivisor(long max, long val )
-{
- for (int i = 2; i < 20; i++) {if (((val%i) == 0) && ((val/i) <= max)) return (val/i); }
- return val;
-}
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-//------------------------------------------------------------------------
-static int IsPowerOfTwo( unsigned long n ) { return ((n & (n-1)) == 0); }
+ stream->asioHostApi->driverOpen = 0;
+ PaUtil_FreeMemory( stream->asioBufferInfos );
+ PaUtil_FreeMemory( stream->asioChannelInfos );
+ PaUtil_FreeMemory( stream->bufferPtrs );
+ PaUtil_FreeMemory( stream );
-/*******************************************************************
-* Determine size of native ASIO audio buffer size
-* Input parameters : FramesPerUserBuffer, NumUserBuffers
-* Output values : FramesPerHostBuffer, OutputBufferOffset or InputtBufferOffset
-*/
+ ASIODisposeBuffers();
+ ASIOExit();
+
+ return result;
+}
-static PaError PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
+
+static void bufferSwitch(long index, ASIOBool processNow)
{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- long requestedBufferSize;
- long firstMultiple, firstDivisor;
-
- // Compute requestedBufferSize
- if( past->past_NumUserBuffers < 1 ){
- requestedBufferSize = past->past_FramesPerUserBuffer;
- }else{
- requestedBufferSize = past->past_NumUserBuffers * past->past_FramesPerUserBuffer;
- }
-
- // Adjust FramesPerHostBuffer using requestedBufferSize, ASIO minSize and maxSize,
- if (requestedBufferSize < asioDriverInfo.pahsc_minSize){
-
- firstMultiple = GetFirstMultiple(asioDriverInfo.pahsc_minSize, requestedBufferSize);
-
- if (firstMultiple <= asioDriverInfo.pahsc_maxSize)
- asioDriverInfo.past_FramesPerHostBuffer = firstMultiple;
- else
- asioDriverInfo.past_FramesPerHostBuffer = asioDriverInfo.pahsc_minSize;
-
- }else if (requestedBufferSize > asioDriverInfo.pahsc_maxSize){
-
- firstDivisor = GetFirstPossibleDivisor(asioDriverInfo.pahsc_maxSize, requestedBufferSize);
-
- if ((firstDivisor >= asioDriverInfo.pahsc_minSize) && (firstDivisor <= asioDriverInfo.pahsc_maxSize))
- asioDriverInfo.past_FramesPerHostBuffer = firstDivisor;
- else
- asioDriverInfo.past_FramesPerHostBuffer = asioDriverInfo.pahsc_maxSize;
- }else{
- asioDriverInfo.past_FramesPerHostBuffer = requestedBufferSize;
- }
+//TAKEN FROM THE ASIO SDK
+
+ // the actual processing callback.
+ // Beware that this is normally in a seperate thread, hence be sure that
+ // you take care about thread synchronization. This is omitted here for
+ // simplicity.
+
+ // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs
+ // to be created though it will only set the timeInfo.samplePosition and
+ // timeInfo.systemTime fields and the according flags
- // If ASIO buffer size needs to be a power of two
- if( asioDriverInfo.pahsc_granularity < 0 ){
- // Needs to be a power of two.
+ ASIOTime timeInfo;
+ memset( &timeInfo, 0, sizeof (timeInfo) );
+
+ // get the time stamp of the buffer, not necessary if no
+ // synchronization to other media is required
+ if( ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
+ timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
- if( !IsPowerOfTwo( asioDriverInfo.past_FramesPerHostBuffer ) )
- {
- int highestBit = GetHighestBitPosition(asioDriverInfo.past_FramesPerHostBuffer);
- asioDriverInfo.past_FramesPerHostBuffer = 1 << (highestBit + 1);
- }
- }
-
- DBUG(("----------------------------------\n"));
- DBUG(("PortAudio : minSize = %ld \n",asioDriverInfo.pahsc_minSize));
- DBUG(("PortAudio : preferredSize = %ld \n",asioDriverInfo.pahsc_preferredSize));
- DBUG(("PortAudio : maxSize = %ld \n",asioDriverInfo.pahsc_maxSize));
- DBUG(("PortAudio : granularity = %ld \n",asioDriverInfo.pahsc_granularity));
- DBUG(("PortAudio : User buffer size = %d\n", asioDriverInfo.past->past_FramesPerUserBuffer ));
- DBUG(("PortAudio : ASIO buffer size = %d\n", asioDriverInfo.past_FramesPerHostBuffer ));
-
- if (asioDriverInfo.past_FramesPerHostBuffer > past->past_FramesPerUserBuffer){
-
- // Computes the MINIMUM value of null frames shift for the output buffer alignement
- asioDriverInfo.pahsc_OutputBufferOffset = Pa_ASIO_CalcFrameShift (asioDriverInfo.past_FramesPerHostBuffer,past->past_FramesPerUserBuffer);
- asioDriverInfo.pahsc_InputBufferOffset = 0;
- DBUG(("PortAudio : Minimum BufferOffset for Output = %d\n", asioDriverInfo.pahsc_OutputBufferOffset));
- }else{
-
- //Computes the MINIMUM value of null frames shift for the input buffer alignement
- asioDriverInfo.pahsc_InputBufferOffset = Pa_ASIO_CalcFrameShift (asioDriverInfo.past_FramesPerHostBuffer,past->past_FramesPerUserBuffer);
- asioDriverInfo.pahsc_OutputBufferOffset = 0;
- DBUG(("PortAudio : Minimum BufferOffset for Input = %d\n", asioDriverInfo.pahsc_InputBufferOffset));
- }
-
- return paNoError;
+ // Call the real callback
+ bufferSwitchTimeInfo( &timeInfo, index, processNow );
}
-/***********************************************************************/
-int Pa_CountDevices()
+// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
+#if NATIVE_INT64
+ #define ASIO64toDouble(a) (a)
+#else
+ const double twoRaisedTo32 = 4294967296.;
+ #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
+#endif
+
+static ASIOTime *bufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool processNow )
{
- PaError err ;
-
- if( sNumDevices <= 0 )
- {
- /* Force loading of ASIO drivers */
- err = Pa_ASIO_QueryDeviceInfo(sDevices);
- if( err != paNoError ) goto error;
- }
-
- return sNumDevices;
+ // the actual processing callback.
+ // Beware that this is normally in a seperate thread, hence be sure that
+ // you take care about thread synchronization. This is omitted here for simplicity.
+
+
+ (void) processNow; /* unused parameter: FIXME: the sdk implies that we shouldn't process now if this parameter is false */
+
+#if 0
+ // store the timeInfo for later use
+ asioDriverInfo.tInfo = *timeInfo;
+
+ // get the time stamp of the buffer, not necessary if no
+ // synchronization to other media is required
-error:
- PaHost_Term();
- DBUG(("Pa_CountDevices: returns %d\n", err ));
- return err;
-}
+ if (timeInfo->timeInfo.flags & kSystemTimeValid)
+ asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
+ else
+ asioDriverInfo.nanoSeconds = 0;
-/***********************************************************************/
-PaError PaHost_Init( void )
-{
- /* Have we already initialized the device info? */
- PaError err = (PaError) Pa_CountDevices();
- return ( err < 0 ) ? err : paNoError;
-}
+ if (timeInfo->timeInfo.flags & kSamplePositionValid)
+ asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
+ else
+ asioDriverInfo.samples = 0;
-/***********************************************************************/
-PaError PaHost_Term( void )
-{
- int i;
- PaDeviceInfo *dev;
- double *rates;
- PaError result = paNoError;
-
- if (sNumDevices > 0) {
-
- /* Free allocated sample rate arrays and names*/
- for( i=0; i<sNumDevices; i++ ){
- dev = &sDevices[i].pad_Info;
- rates = (double *) dev->sampleRates;
- if ((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double));
- dev->sampleRates = NULL;
- if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32);
- dev->name = NULL;
-
- }
-
- sNumDevices = 0;
-
- /* Dispose : if not done by Pa_CloseStream */
- if(ASIODisposeBuffers() != ASE_OK) result = paHostError;
- if(ASIOExit() != ASE_OK) result = paHostError;
-
- /* remove the loaded ASIO driver */
- asioDrivers->removeCurrentDriver();
- }
-
- return result;
-}
+ if (timeInfo->timeCode.flags & kTcValid)
+ asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
+ else
+ asioDriverInfo.tcSamples = 0;
-/***********************************************************************/
-PaError PaHost_OpenStream( internalPortAudioStream *past )
-{
- PaError result = paNoError;
- ASIOError err;
- int32 device;
+ // get the system reference time
+ asioDriverInfo.sysRefTime = get_sys_reference_time();
+#endif
+
+#if 0
+ // a few debug messages for the Windows device driver developer
+ // tells you the time when driver got its interrupt and the delay until the app receives
+ // the event notification.
+ static double last_samples = 0;
+ char tmp[128];
+ sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples));
+ OutputDebugString (tmp);
+ last_samples = asioDriverInfo.samples;
+#endif
+
+ // Keep sample position
+ // FIXME: asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo;
+
+ if( theAsioStream->stopProcessing || theAsioStream->abortProcessing ) {
+
+ ZeroOutputBuffers( theAsioStream, index );
+
+ // Finally if the driver supports the ASIOOutputReady() optimization,
+ // do it here, all data are in place
+ if( theAsioStream->postOutput )
+ ASIOOutputReady();
+
+ }
+ else
+ {
+ int i;
- /* Check if a stream already runs */
- if (asioDriverInfo.past != NULL) return paHostError;
-
- /* Check the device number */
- if ((past->past_InputDeviceID != paNoDevice)
- &&(past->past_OutputDeviceID != paNoDevice)
- &&(past->past_InputDeviceID != past->past_OutputDeviceID))
+ PaUtil_BeginCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer );
+
+ PaStreamCallbackTimeInfo paTimeInfo;
+
+ // asio systemTime is supposed to be measured according to the same
+ // clock as timeGetTime
+ paTimeInfo.currentTime = (ASIO64toDouble( timeInfo->timeInfo.systemTime ) * .000000001);
+ paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - theAsioStream->streamRepresentation.streamInfo.inputLatency;
+ paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency;
+
+
+ if( theAsioStream->inputBufferConverter )
{
- return paInvalidDeviceId;
+ for( i=0; i<theAsioStream->numInputChannels; i++ )
+ {
+ theAsioStream->inputBufferConverter( theAsioStream->inputBufferPtrs[index][i],
+ theAsioStream->inputShift, theAsioStream->framesPerHostCallback );
+ }
}
- /* Allocation */
- memset(&asioDriverInfo, 0, sizeof(PaHostSoundControl));
- past->past_DeviceData = (void*) &asioDriverInfo;
-
+ PaUtil_BeginBufferProcessing( &theAsioStream->bufferProcessor, &paTimeInfo );
- /* FIXME */
- asioDriverInfo.past = past;
-
- /* load the ASIO device */
- device = (past->past_InputDeviceID < 0) ? past->past_OutputDeviceID : past->past_InputDeviceID;
- result = Pa_ASIO_loadDevice(device);
- if (result != paNoError) goto error;
-
- /* Check ASIO parameters and input parameters */
- if ((past->past_NumInputChannels > asioDriverInfo.pahsc_NumInputChannels)
- || (past->past_NumOutputChannels > asioDriverInfo.pahsc_NumOutputChannels)) {
- result = paInvalidChannelCount;
- goto error;
- }
+ PaUtil_SetInputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
+ for( i=0; i<theAsioStream->numInputChannels; ++i )
+ PaUtil_SetNonInterleavedInputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i] );
+
+ PaUtil_SetOutputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
+ for( i=0; i<theAsioStream->numOutputChannels; ++i )
+ PaUtil_SetNonInterleavedOutputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i] );
+
+ int callbackResult;
+ unsigned long framesProcessed = PaUtil_EndBufferProcessing( &theAsioStream->bufferProcessor, &callbackResult );
- /* Set sample rate */
- if (ASIOSetSampleRate(past->past_SampleRate) != ASE_OK) {
- result = paInvalidSampleRate;
- goto error;
+ if( theAsioStream->outputBufferConverter )
+ {
+ for( i=0; i<theAsioStream->numOutputChannels; i++ )
+ {
+ theAsioStream->outputBufferConverter( theAsioStream->outputBufferPtrs[index][i],
+ theAsioStream->outputShift, theAsioStream->framesPerHostCallback );
+ }
}
-
- /* if OK calc buffer size */
- result = PaHost_CalcNumHostBuffers( past );
- if (result != paNoError) goto error;
-
-
- /*
- Allocating input and output buffers number for the real past_NumInputChannels and past_NumOutputChannels
- optimize the data transfer.
- */
-
- asioDriverInfo.pahsc_NumInputChannels = past->past_NumInputChannels;
- asioDriverInfo.pahsc_NumOutputChannels = past->past_NumOutputChannels;
-
- /* Allocate ASIO buffers and callback*/
- err = Pa_ASIO_CreateBuffers(&asioDriverInfo,
- asioDriverInfo.pahsc_NumInputChannels,
- asioDriverInfo.pahsc_NumOutputChannels,
- asioDriverInfo.past_FramesPerHostBuffer);
-
- if (err == ASE_OK)
- return paNoError;
- else if (err == ASE_NoMemory)
- result = paInsufficientMemory;
- else if (err == ASE_InvalidParameter)
- result = paInvalidChannelCount;
- else if (err == ASE_InvalidMode)
- result = paBufferTooBig;
- else
- result = paHostError;
-
-error:
- ASIOExit();
- return result;
-}
+ PaUtil_EndCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer, framesProcessed );
-/***********************************************************************/
-PaError PaHost_CloseStream( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc;
- PaError result = paNoError;
+ // Finally if the driver supports the ASIOOutputReady() optimization,
+ // do it here, all data are in place
+ if( theAsioStream->postOutput )
+ ASIOOutputReady();
- if( past == NULL ) return paBadStreamPtr;
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return paNoError;
+ if( callbackResult == paContinue )
+ {
+ /* nothing special to do */
+ }
+ else if( callbackResult == paAbort )
+ {
+ /* IMPLEMENT ME - finish playback immediately */
+ }
+ else
+ {
+ /* User callback has asked us to stop with paComplete or other non-zero value */
- #if PA_TRACE_START_STOP
- AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
- #endif
-
- /* Dispose */
- if(ASIODisposeBuffers() != ASE_OK) result = paHostError;
- if(ASIOExit() != ASE_OK) result = paHostError;
-
- /* Free data and device for output. */
- past->past_DeviceData = NULL;
- asioDriverInfo.past = NULL;
-
- return result;
+ /* IMPLEMENT ME - finish playback once currently queued audio has completed */
+ }
+ }
+
+ return 0L;
}
-/***********************************************************************/
-PaError PaHost_StartOutput( internalPortAudioStream *past )
+
+static void sampleRateChanged(ASIOSampleRate sRate)
{
- /* Clear the index 0 host output buffer */
- Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos,
- asioDriverInfo.pahsc_channelInfos[0].type,
- asioDriverInfo.pahsc_NumInputChannels,
- asioDriverInfo.pahsc_NumOutputChannels,
- 0,
- 0,
- asioDriverInfo.past_FramesPerHostBuffer);
-
- /* Clear the index 1 host output buffer */
- Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos,
- asioDriverInfo.pahsc_channelInfos[0].type,
- asioDriverInfo.pahsc_NumInputChannels,
- asioDriverInfo.pahsc_NumOutputChannels,
- 1,
- 0,
- asioDriverInfo.past_FramesPerHostBuffer);
-
- Pa_ASIO_Clear_User_Buffers();
-
- Pa_ASIO_Adaptor_Init();
+ // TAKEN FROM THE ASIO SDK
+ // do whatever you need to do if the sample rate changed
+ // usually this only happens during external sync.
+ // Audio processing is not stopped by the driver, actual sample rate
+ // might not have even changed, maybe only the sample rate status of an
+ // AES/EBU or S/PDIF digital input at the audio device.
+ // You might have to update time/sample related conversion routines, etc.
- return paNoError;
+ (void) sRate; /* unused parameter */
}
-/***********************************************************************/
-PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+static long asioMessages(long selector, long value, void* message, double* opt)
{
- /* Nothing to do ?? */
- return paNoError;
-}
+// TAKEN FROM THE ASIO SDK
+ // currently the parameters "value", "message" and "opt" are not used.
+ long ret = 0;
-/***********************************************************************/
-PaError PaHost_StartInput( internalPortAudioStream *past )
-{
- /* Nothing to do ?? */
- return paNoError;
-}
+ (void) message; /* unused parameters */
+ (void) opt;
+
+ switch(selector)
+ {
+ case kAsioSelectorSupported:
+ if(value == kAsioResetRequest
+ || value == kAsioEngineVersion
+ || value == kAsioResyncRequest
+ || value == kAsioLatenciesChanged
+ // the following three were added for ASIO 2.0, you don't necessarily have to support them
+ || value == kAsioSupportsTimeInfo
+ || value == kAsioSupportsTimeCode
+ || value == kAsioSupportsInputMonitor)
+ ret = 1L;
+ break;
+
+ case kAsioBufferSizeChange:
+ //printf("kAsioBufferSizeChange \n");
+ break;
+
+ case kAsioResetRequest:
+ // defer the task and perform the reset of the driver during the next "safe" situation
+ // You cannot reset the driver right now, as this code is called from the driver.
+ // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
+ // Afterwards you initialize the driver again.
+
+ /*FIXME: commented the next line out */
+ //asioDriverInfo.stopped; // In this sample the processing will just stop
+ ret = 1L;
+ break;
+
+ case kAsioResyncRequest:
+ // This informs the application, that the driver encountered some non fatal data loss.
+ // It is used for synchronization purposes of different media.
+ // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
+ // Windows Multimedia system, which could loose data because the Mutex was hold too long
+ // by another thread.
+ // However a driver can issue it in other situations, too.
+ ret = 1L;
+ break;
+
+ case kAsioLatenciesChanged:
+ // This will inform the host application that the drivers were latencies changed.
+ // Beware, it this does not mean that the buffer sizes have changed!
+ // You might need to update internal delay data.
+ ret = 1L;
+ //printf("kAsioLatenciesChanged \n");
+ break;
+
+ case kAsioEngineVersion:
+ // return the supported ASIO version of the host application
+ // If a host applications does not implement this selector, ASIO 1.0 is assumed
+ // by the driver
+ ret = 2L;
+ break;
+
+ case kAsioSupportsTimeInfo:
+ // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
+ // is supported.
+ // For compatibility with ASIO 1.0 drivers the host application should always support
+ // the "old" bufferSwitch method, too.
+ ret = 1;
+ break;
+
+ case kAsioSupportsTimeCode:
+ // informs the driver wether application is interested in time code info.
+ // If an application does not need to know about time code, the driver has less work
+ // to do.
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaAsioStream *stream = (PaAsioStream*)s;
+ ASIOError asioError;
+
+ if( stream->numOutputChannels > 0 )
+ {
+ ZeroOutputBuffers( stream, 0 );
+ ZeroOutputBuffers( stream, 1 );
+ }
+
+ stream->stopProcessing = 0;
+ stream->abortProcessing = 0;
+
+ theAsioStream = stream;
+ asioError = ASIOStart();
+ if( asioError != ASE_OK )
+ {
+ theAsioStream = 0;
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ }
-/***********************************************************************/
-PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
-{
- /* Nothing to do */
- return paNoError;
+ return result;
}
-/***********************************************************************/
-PaError PaHost_StartEngine( internalPortAudioStream *past )
-{
- // TO DO : count of samples
- past->past_IsActive = 1;
- return (ASIOStart() == ASE_OK) ? paNoError : paHostError;
-}
-/***********************************************************************/
-PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+static PaError StopStream( PaStream *s )
{
- // TO DO : count of samples
- past->past_IsActive = 0;
- return (ASIOStop() == ASE_OK) ? paNoError : paHostError;
-}
+ PaError result = paNoError;
+ PaAsioStream *stream = (PaAsioStream*)s;
+ ASIOError asioError;
-/***********************************************************************/
-// TO BE CHECKED
-PaError PaHost_StreamActive( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc;
- if( past == NULL ) return paBadStreamPtr;
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return paInternalError;
- return (PaError) past->past_IsActive;
+ stream->stopProcessing = 1;
+ stream->abortProcessing = 1;
+
+ asioError = ASIOStop();
+ if( asioError != ASE_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ }
+
+ theAsioStream = 0;
+
+ return result;
}
-/*************************************************************************/
-PaTimestamp Pa_StreamTime( PortAudioStream *stream )
-{
- PaHostSoundControl *pahsc;
- internalPortAudioStream *past = (internalPortAudioStream *) stream;
- if( past == NULL ) return paBadStreamPtr;
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
- return pahsc->pahsc_NumFramesDone;
-}
-/*************************************************************************
- * Allocate memory that can be accessed in real-time.
- * This may need to be held in physical memory so that it is not
- * paged to virtual memory.
- * This call MUST be balanced with a call to PaHost_FreeFastMemory().
- */
-void *PaHost_AllocateFastMemory( long numBytes )
+static PaError AbortStream( PaStream *s )
{
- #if MAC
- void *addr = NewPtrClear( numBytes );
- if( (addr == NULL) || (MemError () != 0) ) return NULL;
-
- #if (CARBON_COMPATIBLE == 0)
- if( HoldMemory( addr, numBytes ) != noErr )
- {
- DisposePtr( (Ptr) addr );
- return NULL;
- }
- #endif
- return addr;
- #elif WINDOWS
- void *addr = malloc( numBytes ); /* FIXME - do we need physical memory? */
- if( addr != NULL ) memset( addr, 0, numBytes );
- return addr;
- #endif
+ /* ASIO doesn't provide Abort behavior, so just stop instead */
+ return StopStream( s );
}
-/*************************************************************************
- * Free memory that could be accessed in real-time.
- * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
- */
-void PaHost_FreeFastMemory( void *addr, long numBytes )
+
+static PaError IsStreamStopped( PaStream *s )
{
- #if MAC
- if( addr == NULL ) return;
- #if CARBON_COMPATIBLE
- (void) numBytes;
- #else
- UnholdMemory( addr, numBytes );
- #endif
- DisposePtr( (Ptr) addr );
- #elif WINDOWS
- if( addr != NULL ) free( addr );
- #endif
+ //PaAsioStream *stream = (PaAsioStream*)s;
+ (void) s; /* unused parameter */
+ return theAsioStream == 0;
}
-/*************************************************************************/
-void Pa_Sleep( long msec )
+static PaError IsStreamActive( PaStream *s )
{
- #if MAC
- int32 sleepTime, endTime;
- /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */
- sleepTime = ((msec * 60) + 999) / 1000;
- if( sleepTime < 1 ) sleepTime = 1;
- endTime = TickCount() + sleepTime;
- do{
- DBUGX(("Sleep for %d ticks.\n", sleepTime ));
- WaitNextEvent( 0, NULL, sleepTime, NULL ); /* Use this just to sleep without getting events. */
- sleepTime = endTime - TickCount();
- } while( sleepTime > 0 );
- #elif WINDOWS
- Sleep( msec );
- #endif
+ //PaAsioStream *stream = (PaAsioStream*)s;
+ (void) s; /* unused parameter */
+ return theAsioStream != 0; /* FIXME: currently there is no way to stop the stream from the callback */
}
-/*************************************************************************/
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
-{
- if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
- return &sDevices[id].pad_Info;
-}
-/*************************************************************************/
-PaDeviceID Pa_GetDefaultInputDeviceID( void )
+static PaTime GetStreamTime( PaStream *s )
{
- return sDefaultInputDeviceID;
+ (void) s; /* unused parameter */
+ return (double)timeGetTime() * .001;
}
-/*************************************************************************/
-PaDeviceID Pa_GetDefaultOutputDeviceID( void )
-{
- return sDefaultOutputDeviceID;
-}
-/*************************************************************************/
-int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate )
+static double GetStreamCpuLoad( PaStream* s )
{
- // TO BE IMPLEMENTED : using the ASIOGetLatency call??
- return 2;
-}
+ PaAsioStream *stream = (PaAsioStream*)s;
-/*************************************************************************/
-int32 Pa_GetHostError( void )
-{
- int32 err = sPaHostError;
- sPaHostError = 0;
- return err;
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
}
-#ifdef MAC
+/*
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
-/**************************************************************************/
-static void Pa_StartUsageCalculation( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- UnsignedWide widePad;
- if( pahsc == NULL ) return;
-/* Query system timer for usage analysis and to prevent overuse of CPU. */
- Microseconds( &widePad );
- pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad );
-}
-/**************************************************************************/
-static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+static PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
{
- UnsignedWide widePad;
- UInt64 CurrentCount;
- long InsideCount;
- long TotalCount;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return;
-/* Measure CPU utilization during this callback. Note that this calculation
-** assumes that we had the processor the whole time.
-*/
-#define LOWPASS_COEFFICIENT_0 (0.9)
-#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
- Microseconds( &widePad );
- CurrentCount = UnsignedWideToUInt64( widePad );
- if( past->past_IfLastExitValid )
- {
- InsideCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_EntryCount);
- TotalCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_LastExitCount);
-/* Low pass filter the result because sometimes we get called several times in a row.
-* That can cause the TotalCount to be very low which can cause the usage to appear
-* unnaturally high. So we must filter numerator and denominator separately!!!
-*/
- past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
- (LOWPASS_COEFFICIENT_1 * InsideCount));
- past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
- (LOWPASS_COEFFICIENT_1 * TotalCount));
- past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
- }
- pahsc->pahsc_LastExitCount = CurrentCount;
- past->past_IfLastExitValid = 1;
+ PaAsioStream *stream = (PaAsioStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameters */
+ (void) buffer;
+ (void) frames;
+
+ return paNoError;
}
-#elif WINDOWS
-/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
-static void Pa_StartUsageCalculation( internalPortAudioStream *past )
+static PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return;
-/* Query system timer for usage analysis and to prevent overuse of CPU. */
- QueryPerformanceCounter( &pahsc->pahsc_EntryCount );
+ PaAsioStream *stream = (PaAsioStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameters */
+ (void) buffer;
+ (void) frames;
+
+ return paNoError;
}
-static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+
+static signed long GetStreamReadAvailable( PaStream* s )
{
- LARGE_INTEGER CurrentCount = { 0, 0 };
- LONGLONG InsideCount;
- LONGLONG TotalCount;
-/*
-** Measure CPU utilization during this callback. Note that this calculation
-** assumes that we had the processor the whole time.
-*/
-#define LOWPASS_COEFFICIENT_0 (0.9)
-#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+ PaAsioStream *stream = (PaAsioStream*)s;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return;
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameter */
- if( QueryPerformanceCounter( &CurrentCount ) )
- {
- if( past->past_IfLastExitValid )
- {
- InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart;
- TotalCount = CurrentCount.QuadPart - pahsc->pahsc_LastExitCount.QuadPart;
-/* Low pass filter the result because sometimes we get called several times in a row.
- * That can cause the TotalCount to be very low which can cause the usage to appear
- * unnaturally high. So we must filter numerator and denominator separately!!!
- */
- past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
- (LOWPASS_COEFFICIENT_1 * InsideCount));
- past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
- (LOWPASS_COEFFICIENT_1 * TotalCount));
- past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
- }
- pahsc->pahsc_LastExitCount = CurrentCount;
- past->past_IfLastExitValid = 1;
- }
+ return 0;
}
-#endif
-
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+ PaAsioStream *stream = (PaAsioStream*)s;
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameter */
+
+ return 0;
+}
diff --git a/pd/portaudio/pa_asio/pa_asio.h b/pd/portaudio/pa_asio/pa_asio.h
new file mode 100644
index 00000000..c2775928
--- /dev/null
+++ b/pd/portaudio/pa_asio/pa_asio.h
@@ -0,0 +1,68 @@
+#ifndef PA_ASIO_H
+#define PA_ASIO_H
+/*
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * ASIO specific extensions
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+
+#include "portaudio.h"
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+/** Retrieve legal latency settings for the specificed device, in samples.
+
+ @param device The global index of the device about which the query is being made.
+ @param minLatency A pointer to the location which will recieve the minimum latency value.
+ @param maxLatency A pointer to the location which will recieve the maximum latency value.
+ @param minLatency A pointer to the location which will recieve the preferred latency value.
+ @param granularity A pointer to the location which will recieve the granularity. This value
+ determines which values between minLatency and maxLatency are available. ie the step size,
+ if granularity is -1 then available latency settings are powers of two.
+
+ @see ASIOGetBufferSize in the ASIO SDK.
+
+ @todo This function should have a better name, any suggestions?
+*/
+PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device,
+ long *minLatency, long *maxLatency, long *preferredLatency, long *granularity );
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PA_ASIO_H */
diff --git a/pd/portaudio/pa_asio/readme_asio_sdk_patch.txt b/pd/portaudio/pa_asio/readme_asio_sdk_patch.txt
new file mode 100755
index 00000000..c0fdca7f
--- /dev/null
+++ b/pd/portaudio/pa_asio/readme_asio_sdk_patch.txt
@@ -0,0 +1,25 @@
+There is a bug in the ASIO SDK that causes the Macintosh version to often fail during initialization. Here is a patch that you can apply.
+
+In codefragments.cpp replace getFrontProcessDirectory function with
+the following one (GetFrontProcess replaced by GetCurrentProcess)
+
+
+bool CodeFragments::getFrontProcessDirectory(void *specs)
+{
+ FSSpec *fss = (FSSpec *)specs;
+ ProcessInfoRec pif;
+ ProcessSerialNumber psn;
+
+ memset(&psn,0,(long)sizeof(ProcessSerialNumber));
+ // if(GetFrontProcess(&psn) == noErr) // wrong !!!
+ if(GetCurrentProcess(&psn) == noErr) // correct !!!
+ {
+ pif.processName = 0;
+ pif.processAppSpec = fss;
+ pif.processInfoLength = sizeof(ProcessInfoRec);
+ if(GetProcessInformation(&psn, &pif) == noErr)
+ return true;
+ }
+ return false;
+}
+
diff --git a/pd/portaudio/pa_beos/PlaybackNode.cc b/pd/portaudio/pa_beos/PlaybackNode.cc
new file mode 100644
index 00000000..41cbae34
--- /dev/null
+++ b/pd/portaudio/pa_beos/PlaybackNode.cc
@@ -0,0 +1,538 @@
+/*
+ * $Id: PlaybackNode.cc,v 1.1.1.1 2003-05-09 16:03:53 ggeiger Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * BeOS Media Kit Implementation by Joshua Haberman
+ *
+ * Copyright (c) 2001 Joshua Haberman <joshua@haberman.com>
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ * ---
+ *
+ * Significant portions of this file are based on sample code from Be. The
+ * Be Sample Code Licence follows:
+ *
+ * Copyright 1991-1999, Be Incorporated.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions, and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+#include <be/media/BufferGroup.h>
+#include <be/media/Buffer.h>
+#include <be/media/TimeSource.h>
+
+#include "PlaybackNode.h"
+
+#define PRINT(x) { printf x; fflush(stdout); }
+
+#ifdef DEBUG
+#define DBUG(x) PRINT(x)
+#else
+#define DBUG(x)
+#endif
+
+
+PaPlaybackNode::PaPlaybackNode(uint32 channels, float frame_rate, uint32 frames_per_buffer,
+ PortAudioCallback* callback, void *user_data) :
+ BMediaNode("PortAudio input node"),
+ BBufferProducer(B_MEDIA_RAW_AUDIO),
+ BMediaEventLooper(),
+ mAborted(false),
+ mRunning(false),
+ mBufferGroup(NULL),
+ mDownstreamLatency(0),
+ mStartTime(0),
+ mCallback(callback),
+ mUserData(user_data),
+ mFramesPerBuffer(frames_per_buffer)
+{
+ DBUG(("Constructor called.\n"));
+
+ mPreferredFormat.type = B_MEDIA_RAW_AUDIO;
+ mPreferredFormat.u.raw_audio.channel_count = channels;
+ mPreferredFormat.u.raw_audio.frame_rate = frame_rate;
+ mPreferredFormat.u.raw_audio.byte_order =
+ (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
+ mPreferredFormat.u.raw_audio.buffer_size =
+ media_raw_audio_format::wildcard.buffer_size;
+
+ mOutput.destination = media_destination::null;
+ mOutput.format = mPreferredFormat;
+
+ /* The amount of time it takes for this node to produce a buffer when
+ * asked. Essentially, it is how long the user's callback takes to run.
+ * We set this to be the length of the sound data each buffer of the
+ * requested size can hold. */
+ //mInternalLatency = (bigtime_t)(1000000 * frames_per_buffer / frame_rate);
+
+ /* ACK! it seems that the mixer (at least on my machine) demands that IT
+ * specify the buffer size, so for now I'll just make a generic guess here */
+ mInternalLatency = 1000000 / 20;
+}
+
+
+
+PaPlaybackNode::~PaPlaybackNode()
+{
+ DBUG(("Destructor called.\n"));
+ Quit(); /* Stop the BMediaEventLooper thread */
+}
+
+
+/*************************
+ *
+ * Local methods
+ *
+ */
+
+bool PaPlaybackNode::IsRunning()
+{
+ return mRunning;
+}
+
+
+PaTimestamp PaPlaybackNode::GetStreamTime()
+{
+ BTimeSource *timeSource = TimeSource();
+ PaTimestamp time = (timeSource->Now() - mStartTime) *
+ mPreferredFormat.u.raw_audio.frame_rate / 1000000;
+ return time;
+}
+
+
+void PaPlaybackNode::SetSampleFormat(PaSampleFormat inFormat,
+ PaSampleFormat outFormat)
+{
+ uint32 beOutFormat;
+
+ switch(outFormat)
+ {
+ case paFloat32:
+ beOutFormat = media_raw_audio_format::B_AUDIO_FLOAT;
+ mOutputSampleWidth = 4;
+ break;
+
+ case paInt16:
+ beOutFormat = media_raw_audio_format::B_AUDIO_SHORT;
+ mOutputSampleWidth = 2;
+ break;
+
+ case paInt32:
+ beOutFormat = media_raw_audio_format::B_AUDIO_INT;
+ mOutputSampleWidth = 4;
+ break;
+
+ case paInt8:
+ beOutFormat = media_raw_audio_format::B_AUDIO_CHAR;
+ mOutputSampleWidth = 1;
+ break;
+
+ case paUInt8:
+ beOutFormat = media_raw_audio_format::B_AUDIO_UCHAR;
+ mOutputSampleWidth = 1;
+ break;
+
+ case paInt24:
+ case paPackedInt24:
+ case paCustomFormat:
+ DBUG(("Unsupported output format: %x\n", outFormat));
+ break;
+
+ default:
+ DBUG(("Unknown output format: %x\n", outFormat));
+ }
+
+ mPreferredFormat.u.raw_audio.format = beOutFormat;
+ mFramesPerBuffer * mPreferredFormat.u.raw_audio.channel_count * mOutputSampleWidth;
+}
+
+BBuffer *PaPlaybackNode::FillNextBuffer(bigtime_t time)
+{
+ /* Get a buffer from the buffer group */
+ BBuffer *buf = mBufferGroup->RequestBuffer(
+ mOutput.format.u.raw_audio.buffer_size, BufferDuration());
+ unsigned long frames = mOutput.format.u.raw_audio.buffer_size /
+ mOutputSampleWidth / mOutput.format.u.raw_audio.channel_count;
+ bigtime_t start_time;
+ int ret;
+
+ if( !buf )
+ {
+ DBUG(("Unable to allocate a buffer\n"));
+ return NULL;
+ }
+
+ start_time = mStartTime +
+ (bigtime_t)((double)mSamplesSent /
+ (double)mOutput.format.u.raw_audio.frame_rate /
+ (double)mOutput.format.u.raw_audio.channel_count *
+ 1000000.0);
+
+ /* Now call the user callback to get the data */
+ ret = mCallback(NULL, /* Input buffer */
+ buf->Data(), /* Output buffer */
+ frames, /* Frames per buffer */
+ mSamplesSent / mOutput.format.u.raw_audio.channel_count, /* timestamp */
+ mUserData);
+
+ if( ret )
+ mAborted = true;
+
+ media_header *hdr = buf->Header();
+
+ hdr->type = B_MEDIA_RAW_AUDIO;
+ hdr->size_used = mOutput.format.u.raw_audio.buffer_size;
+ hdr->time_source = TimeSource()->ID();
+ hdr->start_time = start_time;
+
+ return buf;
+}
+
+
+
+
+/*************************
+ *
+ * BMediaNode methods
+ *
+ */
+
+BMediaAddOn *PaPlaybackNode::AddOn( int32 * ) const
+{
+ DBUG(("AddOn() called.\n"));
+ return NULL; /* we don't provide service to outside applications */
+}
+
+
+status_t PaPlaybackNode::HandleMessage( int32 message, const void *data,
+ size_t size )
+{
+ DBUG(("HandleMessage() called.\n"));
+ return B_ERROR; /* we don't define any custom messages */
+}
+
+
+
+
+/*************************
+ *
+ * BMediaEventLooper methods
+ *
+ */
+
+void PaPlaybackNode::NodeRegistered()
+{
+ DBUG(("NodeRegistered() called.\n"));
+
+ /* Start the BMediaEventLooper thread */
+ SetPriority(B_REAL_TIME_PRIORITY);
+ Run();
+
+ /* set up as much information about our output as we can */
+ mOutput.source.port = ControlPort();
+ mOutput.source.id = 0;
+ mOutput.node = Node();
+ ::strcpy(mOutput.name, "PortAudio Playback");
+}
+
+
+void PaPlaybackNode::HandleEvent( const media_timed_event *event,
+ bigtime_t lateness, bool realTimeEvent )
+{
+ // DBUG(("HandleEvent() called.\n"));
+ status_t err;
+
+ switch(event->type)
+ {
+ case BTimedEventQueue::B_START:
+ DBUG((" Handling a B_START event\n"));
+ if( RunState() != B_STARTED )
+ {
+ mStartTime = event->event_time + EventLatency();
+ mSamplesSent = 0;
+ mAborted = false;
+ mRunning = true;
+ media_timed_event firstEvent( mStartTime,
+ BTimedEventQueue::B_HANDLE_BUFFER );
+ EventQueue()->AddEvent( firstEvent );
+ }
+ break;
+
+ case BTimedEventQueue::B_STOP:
+ DBUG((" Handling a B_STOP event\n"));
+ mRunning = false;
+ EventQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true,
+ BTimedEventQueue::B_HANDLE_BUFFER );
+ break;
+
+ case BTimedEventQueue::B_HANDLE_BUFFER:
+ //DBUG((" Handling a B_HANDLE_BUFFER event\n"));
+
+ /* make sure we're started and connected */
+ if( RunState() != BMediaEventLooper::B_STARTED ||
+ mOutput.destination == media_destination::null )
+ break;
+
+ BBuffer *buffer = FillNextBuffer(event->event_time);
+
+ /* make sure we weren't aborted while this routine was running.
+ * this can happen in one of two ways: either the callback returned
+ * nonzero (in which case mAborted is set in FillNextBuffer() ) or
+ * the client called AbortStream */
+ if( mAborted )
+ {
+ if( buffer )
+ buffer->Recycle();
+ Stop(0, true);
+ break;
+ }
+
+ if( buffer )
+ {
+ err = SendBuffer(buffer, mOutput.destination);
+ if( err != B_OK )
+ buffer->Recycle();
+ }
+
+ mSamplesSent += mOutput.format.u.raw_audio.buffer_size / mOutputSampleWidth;
+
+ /* Now schedule the next buffer event, so we can send another
+ * buffer when this one runs out. We calculate when it should
+ * happen by calculating when the data we just sent will finish
+ * playing.
+ *
+ * NOTE, however, that the event will actually get generated
+ * earlier than we specify, to account for the latency it will
+ * take to produce the buffer. It uses the latency value we
+ * specified in SetEventLatency() to determine just how early
+ * to generate it. */
+
+ /* totalPerformanceTime includes the time represented by the buffer
+ * we just sent */
+ bigtime_t totalPerformanceTime = (bigtime_t)((double)mSamplesSent /
+ (double)mOutput.format.u.raw_audio.channel_count /
+ (double)mOutput.format.u.raw_audio.frame_rate * 1000000.0);
+
+ bigtime_t nextEventTime = mStartTime + totalPerformanceTime;
+
+ media_timed_event nextBufferEvent(nextEventTime,
+ BTimedEventQueue::B_HANDLE_BUFFER);
+ EventQueue()->AddEvent(nextBufferEvent);
+
+ break;
+
+ }
+}
+
+
+
+
+/*************************
+ *
+ * BBufferProducer methods
+ *
+ */
+
+status_t PaPlaybackNode::FormatSuggestionRequested( media_type type,
+ int32 /*quality*/, media_format* format )
+{
+ /* the caller wants to know this node's preferred format and provides
+ * a suggestion, asking if we support it */
+ DBUG(("FormatSuggestionRequested() called.\n"));
+
+ if(!format)
+ return B_BAD_VALUE;
+
+ *format = mPreferredFormat;
+
+ /* we only support raw audio (a wildcard is okay too) */
+ if ( type == B_MEDIA_UNKNOWN_TYPE || type == B_MEDIA_RAW_AUDIO )
+ return B_OK;
+ else
+ return B_MEDIA_BAD_FORMAT;
+}
+
+
+status_t PaPlaybackNode::FormatProposal( const media_source& output,
+ media_format* format )
+{
+ /* This is similar to FormatSuggestionRequested(), but it is actually part
+ * of the negotiation process. We're given the opportunity to specify any
+ * properties that are wildcards (ie. properties that the other node doesn't
+ * care one way or another about) */
+ DBUG(("FormatProposal() called.\n"));
+
+ /* Make sure this proposal really applies to our output */
+ if( output != mOutput.source )
+ return B_MEDIA_BAD_SOURCE;
+
+ /* We return two things: whether we support the proposed format, and our own
+ * preferred format */
+ *format = mPreferredFormat;
+
+ if( format->type == B_MEDIA_UNKNOWN_TYPE || format->type == B_MEDIA_RAW_AUDIO )
+ return B_OK;
+ else
+ return B_MEDIA_BAD_FORMAT;
+}
+
+
+status_t PaPlaybackNode::FormatChangeRequested( const media_source& source,
+ const media_destination& destination, media_format* io_format, int32* )
+{
+ /* we refuse to change formats, supporting only 1 */
+ DBUG(("FormatChangeRequested() called.\n"));
+
+ return B_ERROR;
+}
+
+
+status_t PaPlaybackNode::GetNextOutput( int32* cookie, media_output* out_output )
+{
+ /* this is where we allow other to enumerate our outputs -- the cookie is
+ * an integer we can use to keep track of where we are in enumeration. */
+ DBUG(("GetNextOutput() called.\n"));
+
+ if( *cookie == 0 )
+ {
+ *out_output = mOutput;
+ *cookie = 1;
+ return B_OK;
+ }
+
+ return B_BAD_INDEX;
+}
+
+
+status_t PaPlaybackNode::DisposeOutputCookie( int32 cookie )
+{
+ DBUG(("DisposeOutputCookie() called.\n"));
+ return B_OK;
+}
+
+
+void PaPlaybackNode::LateNoticeReceived( const media_source& what,
+ bigtime_t how_much, bigtime_t performance_time )
+{
+ /* This function is called as notification that a buffer we sent wasn't
+ * received by the time we stamped it with -- it got there late. Basically,
+ * it means we underestimated our own latency, so we should increase it */
+ DBUG(("LateNoticeReceived() called.\n"));
+
+ if( what != mOutput.source )
+ return;
+
+ if( RunMode() == B_INCREASE_LATENCY )
+ {
+ mInternalLatency += how_much;
+ SetEventLatency( mDownstreamLatency + mInternalLatency );
+ DBUG(("Increasing latency to %Ld\n", mDownstreamLatency + mInternalLatency));
+ }
+ else
+ DBUG(("I don't know what to do with this notice!"));
+}
+
+
+void PaPlaybackNode::EnableOutput( const media_source& what, bool enabled,
+ int32* )
+{
+ DBUG(("EnableOutput() called.\n"));
+ /* stub -- we don't support this yet */
+}
+
+
+status_t PaPlaybackNode::PrepareToConnect( const media_source& what,
+ const media_destination& where, media_format* format,
+ media_source* out_source, char* out_name )
+{
+ /* the final stage of format negotiations. here we _must_ make specific any
+ * remaining wildcards */
+ DBUG(("PrepareToConnect() called.\n"));
+
+ /* make sure this really refers to our source */
+ if( what != mOutput.source )
+ return B_MEDIA_BAD_SOURCE;
+
+ /* make sure we're not already connected */
+ if( mOutput.destination != media_destination::null )
+ return B_MEDIA_ALREADY_CONNECTED;
+
+ if( format->type != B_MEDIA_RAW_AUDIO )
+ return B_MEDIA_BAD_FORMAT;
+
+ if( format->u.raw_audio.format != mPreferredFormat.u.raw_audio.format )
+ return B_MEDIA_BAD_FORMAT;
+
+ if( format->u.raw_audio.buffer_size ==
+ media_raw_audio_format::wildcard.buffer_size )
+ {
+ DBUG(("We were left to decide buffer size: choosing 2048"));
+ format->u.raw_audio.buffer_size = 2048;
+ }
+ else
+ DBUG(("Using consumer specified buffer size of %lu.\n",
+ format->u.raw_audio.buffer_size));
+
+ /* Reserve the connection, return the information */
+ mOutput.destination = where;
+ mOutput.format = *format;
+ *out_source = mOutput.source;
+ strncpy( out_name, mOutput.name, B_MEDIA_NAME_LENGTH );
+
+ return B_OK;
+}
+
+
+void PaPlaybackNode::Connect(status_t error, const media_source& source,
+ const media_destination& destination, const media_format& format, char* io_name)
+{
+ DBUG(("Connect() called.\n"));
+
diff --git a/pd/portaudio/pa_beos/PlaybackNode.h b/pd/portaudio/pa_beos/PlaybackNode.h
new file mode 100644
index 00000000..db978a59
--- /dev/null
+++ b/pd/portaudio/pa_beos/PlaybackNode.h
@@ -0,0 +1,108 @@
+/*
+ * $Id: PlaybackNode.h,v 1.1.1.1 2003-05-09 16:03:53 ggeiger Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * BeOS Media Kit Implementation by Joshua Haberman
+ *
+ * Copyright (c) 2001 Joshua Haberman <joshua@haberman.com>
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+#include <be/media/MediaRoster.h>
+#include <be/media/MediaEventLooper.h>
+#include <be/media/BufferProducer.h>
+
+#include "portaudio.h"
+
+class PaPlaybackNode :
+ public BBufferProducer,
+ public BMediaEventLooper
+{
+
+public:
+ PaPlaybackNode( uint32 channels, float frame_rate, uint32 frames_per_buffer,
+ PortAudioCallback *callback, void *user_data );
+ ~PaPlaybackNode();
+
+
+ /* Local methods ******************************************/
+
+ BBuffer *FillNextBuffer(bigtime_t time);
+ void SetSampleFormat(PaSampleFormat inFormat, PaSampleFormat outFormat);
+ bool IsRunning();
+ PaTimestamp GetStreamTime();
+
+ /* BMediaNode methods *************************************/
+
+ BMediaAddOn* AddOn( int32 * ) const;
+ status_t HandleMessage( int32 message, const void *data, size_t size );
+
+ /* BMediaEventLooper methods ******************************/
+
+ void HandleEvent( const media_timed_event *event, bigtime_t lateness,
+ bool realTimeEvent );
+ void NodeRegistered();
+
+ /* BBufferProducer methods ********************************/
+
+ status_t FormatSuggestionRequested( media_type type, int32 quality,
+ media_format* format );
+ status_t FormatProposal( const media_source& output, media_format* format );
+ status_t FormatChangeRequested( const media_source& source,
+ const media_destination& destination, media_format* io_format, int32* );
+
+ status_t GetNextOutput( int32* cookie, media_output* out_output );
+ status_t DisposeOutputCookie( int32 cookie );
+
+ void LateNoticeReceived( const media_source& what, bigtime_t how_much,
+ bigtime_t performance_time );
+ void EnableOutput( const media_source& what, bool enabled, int32* _deprecated_ );
+
+ status_t PrepareToConnect( const media_source& what,
+ const media_destination& where, media_format* format,
+ media_source* out_source, char* out_name );
+ void Connect(status_t error, const media_source& source,
+ const media_destination& destination, const media_format& format,
+ char* io_name);
+ void Disconnect(const media_source& what, const media_destination& where);
+
+ status_t SetBufferGroup(const media_source& for_source, BBufferGroup* newGroup);
+
+ bool mAborted;
+
+private:
+ media_output mOutput;
+ media_format mPreferredFormat;
+ uint32 mOutputSampleWidth, mFramesPerBuffer;
+ BBufferGroup *mBufferGroup;
+ bigtime_t mDownstreamLatency, mInternalLatency, mStartTime;
+ uint64 mSamplesSent;
+ PortAudioCallback *mCallback;
+ void *mUserData;
+ bool mRunning;
+
+};
+
diff --git a/pd/portaudio/pa_beos/pa_beos_mk.cc b/pd/portaudio/pa_beos/pa_beos_mk.cc
new file mode 100644
index 00000000..3307a2ff
--- /dev/null
+++ b/pd/portaudio/pa_beos/pa_beos_mk.cc
@@ -0,0 +1,441 @@
+/*
+ * $Id: pa_beos_mk.cc,v 1.1.1.1 2003-05-09 16:03:53 ggeiger Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * BeOS Media Kit Implementation by Joshua Haberman
+ *
+ * Copyright (c) 2001 Joshua Haberman <joshua@haberman.com>
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+#include <be/app/Application.h>
+#include <be/kernel/OS.h>
+#include <be/media/RealtimeAlloc.h>
+#include <be/media/MediaRoster.h>
+#include <be/media/TimeSource.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+
+#include "PlaybackNode.h"
+
+#define PRINT(x) { printf x; fflush(stdout); }
+
+#ifdef DEBUG
+#define DBUG(x) PRINT(x)
+#else
+#define DBUG(x)
+#endif
+
+typedef struct PaHostSoundControl
+{
+ /* These members are common to all modes of operation */
+ media_node pahsc_TimeSource; /* the sound card's DAC. */
+ media_format pahsc_Format;
+
+ /* These methods are specific to playing mode */
+ media_node pahsc_OutputNode; /* output to the mixer */
+ media_node pahsc_InputNode; /* reads data from user callback -- PA specific */
+
+ media_input pahsc_MixerInput; /* input jack on the soundcard's mixer. */
+ media_output pahsc_PaOutput; /* output jack from the PA node */
+
+ PaPlaybackNode *pahsc_InputNodeInstance;
+
+}
+PaHostSoundControl;
+
+/*************************************************************************/
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
+{
+ /* stub */
+ return 0;
+}
+
+/*************************************************************************/
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
+{
+ /* stub */
+ return 0;
+}
+
+/*************************************************************************/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ /* stub */
+ return NULL;
+}
+
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ /* stub */
+ return 1;
+}
+
+/*************************************************************************/
+PaError PaHost_Init( void )
+{
+ /* we have to create this in order to use BMediaRoster. I hope it doesn't
+ * cause problems */
+ be_app = new BApplication("application/x-vnd.portaudio-app");
+
+ return paNoError;
+}
+
+PaError PaHost_Term( void )
+{
+ delete be_app;
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+ DBUG(("IsRunning returning: %s\n",
+ pahsc->pahsc_InputNodeInstance->IsRunning() ? "true" : "false"));
+
+ return (PaError)pahsc->pahsc_InputNodeInstance->IsRunning();
+}
+
+PaError PaHost_StartOutput( internalPortAudioStream *past )
+{
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StartInput( internalPortAudioStream *past )
+{
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+
+/*************************************************************************/
+PaError PaHost_StartEngine( internalPortAudioStream *past )
+{
+ bigtime_t very_soon, start_latency;
+ status_t err;
+ BMediaRoster *roster = BMediaRoster::Roster(&err);
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+
+ /* for some reason, err indicates an error (though nothing it wrong)
+ * when the DBUG macro in pa_lib.c is enabled. It's reproducably
+ * linked. Weird. */
+ if( !roster /* || err != B_OK */ )
+ {
+ DBUG(("No media server! err=%d, roster=%x\n", err, roster));
+ return paHostError;
+ }
+
+ /* tell the node when to start -- since there aren't any other nodes
+ * starting that we have to wait for, just tell it to start now
+ */
+
+ BTimeSource *timeSource = roster->MakeTimeSourceFor(pahsc->pahsc_TimeSource);
+ very_soon = timeSource->PerformanceTimeFor( BTimeSource::RealTime() );
+ timeSource->Release();
+
+ /* Add the latency of starting the network of nodes */
+ err = roster->GetStartLatencyFor( pahsc->pahsc_TimeSource, &start_latency );
+ very_soon += start_latency;
+
+ err = roster->StartNode( pahsc->pahsc_InputNode, very_soon );
+ /* No need to start the mixer -- it's always running */
+
+ return paNoError;
+}
+
+
+/*************************************************************************/
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+ BMediaRoster *roster = BMediaRoster::Roster();
+
+ if( !roster )
+ {
+ DBUG(("No media roster!\n"));
+ return paHostError;
+ }
+
+ if( !pahsc )
+ return paHostError;
+
+ /* this crashes, and I don't know why yet */
+ // if( abort )
+ // pahsc->pahsc_InputNodeInstance->mAborted = true;
+
+ roster->StopNode(pahsc->pahsc_InputNode, 0, /* immediate = */ true);
+
+ return paNoError;
+}
+
+
+/*************************************************************************/
+PaError PaHost_OpenStream( internalPortAudioStream *past )
+{
+ status_t err;
+ BMediaRoster *roster = BMediaRoster::Roster(&err);
+ PaHostSoundControl *pahsc;
+
+ /* Allocate and initialize host data. */
+ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
+ if( pahsc == NULL )
+ {
+ goto error;
+ }
+ memset( pahsc, 0, sizeof(PaHostSoundControl) );
+ past->past_DeviceData = (void *) pahsc;
+
+ if( !roster /* || err != B_OK */ )
+ {
+ /* no media server! */
+ DBUG(("No media server.\n"));
+ goto error;
+ }
+
+ if ( past->past_NumInputChannels > 0 && past->past_NumOutputChannels > 0 )
+ {
+ /* filter -- not implemented yet */
+ goto error;
+ }
+ else if ( past->past_NumInputChannels > 0 )
+ {
+ /* recorder -- not implemented yet */
+ goto error;
+ }
+ else
+ {
+ /* player ****************************************************************/
+
+ status_t err;
+ int32 num;
+
+ /* First we need to create the three components (like components in a stereo
+ * system). The mixer component is our interface to the sound card, data
+ * we write there will get played. The BePA_InputNode component is the node
+ * which represents communication with the PA client (it is what calls the
+ * client's callbacks). The time source component is the sound card's DAC,
+ * which allows us to slave the other components to it instead of the system
+ * clock. */
+ err = roster->GetAudioMixer( &pahsc->pahsc_OutputNode );
+ if( err != B_OK )
+ {
+ DBUG(("Couldn't get default mixer.\n"));
+ goto error;
+ }
+
+ err = roster->GetTimeSource( &pahsc->pahsc_TimeSource );
+ if( err != B_OK )
+ {
+ DBUG(("Couldn't get time source.\n"));
+ goto error;
+ }
+
+ pahsc->pahsc_InputNodeInstance = new PaPlaybackNode(2, 44100,
+ past->past_FramesPerUserBuffer, past->past_Callback, past->past_UserData );
+ pahsc->pahsc_InputNodeInstance->SetSampleFormat(0,
+ past->past_OutputSampleFormat);
+ err = roster->RegisterNode( pahsc->pahsc_InputNodeInstance );
+ if( err != B_OK )
+ {
+ DBUG(("Unable to register node.\n"));
+ goto error;
+ }
+
+ roster->GetNodeFor( pahsc->pahsc_InputNodeInstance->Node().node,
+ &pahsc->pahsc_InputNode );
+ if( err != B_OK )
+ {
+ DBUG(("Unable to get input node.\n"));
+ goto error;
+ }
+
+ /* Now we have three components (nodes) sitting next to each other. The
+ * next step is to look at them and find their inputs and outputs so we can
+ * wire them together. */
+ err = roster->GetFreeInputsFor( pahsc->pahsc_OutputNode,
+ &pahsc->pahsc_MixerInput, 1, &num, B_MEDIA_RAW_AUDIO );
+ if( err != B_OK || num < 1 )
+ {
+ DBUG(("Couldn't get the mixer input.\n"));
+ goto error;
+ }
+
+ err = roster->GetFreeOutputsFor( pahsc->pahsc_InputNode,
+ &pahsc->pahsc_PaOutput, 1, &num, B_MEDIA_RAW_AUDIO );
+ if( err != B_OK || num < 1 )
+ {
+ DBUG(("Couldn't get PortAudio output.\n"));
+ goto error;
+ }
+
+
+ /* We've found the input and output -- the final step is to run a wire
+ * between them so they are connected. */
+
+ /* try to make the mixer input adapt to what PA sends it */
+ pahsc->pahsc_Format = pahsc->pahsc_PaOutput.format;
+ roster->Connect( pahsc->pahsc_PaOutput.source,
+ pahsc->pahsc_MixerInput.destination, &pahsc->pahsc_Format,
+ &pahsc->pahsc_PaOutput, &pahsc->pahsc_MixerInput );
+
+
+ /* Actually, there's one final step -- tell them all to sync to the
+ * sound card's DAC */
+ roster->SetTimeSourceFor( pahsc->pahsc_InputNode.node,
+ pahsc->pahsc_TimeSource.node );
+ roster->SetTimeSourceFor( pahsc->pahsc_OutputNode.node,
+ pahsc->pahsc_TimeSource.node );
+
+ }
+
+ return paNoError;
+
+error:
+ PaHost_CloseStream( past );
+ return paHostError;
+}
+
+/*************************************************************************/
+PaError PaHost_CloseStream( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+ status_t err;
+ BMediaRoster *roster = BMediaRoster::Roster(&err);
+
+ if( !roster )
+ {
+ DBUG(("Couldn't get media roster\n"));
+ return paHostError;
+ }
+
+ if( !pahsc )
+ return paHostError;
+
+ /* Disconnect all the connections we made when opening the stream */
+
+ roster->Disconnect(pahsc->pahsc_InputNode.node, pahsc->pahsc_PaOutput.source,
+ pahsc->pahsc_OutputNode.node, pahsc->pahsc_MixerInput.destination);
+
+ DBUG(("Calling ReleaseNode()"));
+ roster->ReleaseNode(pahsc->pahsc_InputNode);
+
+ /* deleting the node shouldn't be necessary -- it is reference counted, and will
+ * delete itself when its references drop to zero. the call to ReleaseNode()
+ * above should decrease its reference count */
+ pahsc->pahsc_InputNodeInstance = NULL;
+
+ return paNoError;
+}
+
+/*************************************************************************/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+
+ return pahsc->pahsc_InputNodeInstance->GetStreamTime();
+}
+
+/*************************************************************************/
+void Pa_Sleep( long msec )
+{
+ /* snooze() takes microseconds */
+ snooze( msec * 1000 );
+}
+
+/*************************************************************************
+ * Allocate memory that can be accessed in real-time.
+ * This may need to be held in physical memory so that it is not
+ * paged to virtual memory.
+ * This call MUST be balanced with a call to PaHost_FreeFastMemory().
+ * Memory will be set to zero.
+ */
+void *PaHost_AllocateFastMemory( long numBytes )
+{
+ /* BeOS supports non-pagable memory through pools -- a pool is an area
+ * of physical memory that is locked. It would be best to pre-allocate
+ * that pool and then hand out memory from it, but we don't know in
+ * advance how much we'll need. So for now, we'll allocate a pool
+ * for every request we get, storing a pointer to the pool at the
+ * beginning of the allocated memory */
+ rtm_pool *pool;
+ void *addr;
+ long size = numBytes + sizeof(rtm_pool *);
+ static int counter = 0;
+ char pool_name[100];
+
+ /* Every pool needs a unique name. */
+ sprintf(pool_name, "PaPoolNumber%d", counter++);
+
+ if( rtm_create_pool( &pool, size, pool_name ) != B_OK )
+ return 0;
+
+ addr = rtm_alloc( pool, size );
+ if( addr == NULL )
+ return 0;
+
+ memset( addr, 0, numBytes );
+ *((rtm_pool **)addr) = pool; // store the pointer to the pool
+ addr = (rtm_pool **)addr + 1; // and return the next location in memory
+
+ return addr;
+}
+
+/*************************************************************************
+ * Free memory that could be accessed in real-time.
+ * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
+ */
+void PaHost_FreeFastMemory( void *addr, long numBytes )
+{
+ rtm_pool *pool;
+
+ if( addr == NULL )
+ return;
+
+ addr = (rtm_pool **)addr - 1;
+ pool = *((rtm_pool **)addr);
+
+ rtm_free( addr );
+ rtm_delete_pool( pool );
+}
diff --git a/pd/portaudio/pa_common/pa_allocation.c b/pd/portaudio/pa_common/pa_allocation.c
new file mode 100644
index 00000000..5eefeabb
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_allocation.c
@@ -0,0 +1,217 @@
+/*
+ * Id:
+ * Portable Audio I/O Library allocation group implementation
+ * memory allocation group for tracking allocation groups
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include "pa_allocation.h"
+#include "pa_util.h"
+
+/*
+ Maintain 3 singly linked lists...
+ linkBlocks: the buffers used to allocate the links
+ spareLinks: links available for use in the allocations list
+ allocations: the buffers currently allocated using PaUtil_ContextAllocateMemory()
+
+ Link block size is doubled every time new links are allocated.
+*/
+
+
+#define PA_INITIAL_LINK_COUNT_ 16
+
+struct PaUtilAllocationGroupLink
+{
+ struct PaUtilAllocationGroupLink *next;
+ void *buffer;
+};
+
+/*
+ Allocate a block of links. The first link will have it's buffer member
+ pointing to the block, and it's next member set to <nextBlock>. The remaining
+ links will have NULL buffer members, and each link will point to
+ the next link except the last, which will point to <nextSpare>
+*/
+static struct PaUtilAllocationGroupLink *AllocateLinks( long count,
+ struct PaUtilAllocationGroupLink *nextBlock,
+ struct PaUtilAllocationGroupLink *nextSpare )
+{
+ struct PaUtilAllocationGroupLink *result;
+ int i;
+
+ result = PaUtil_AllocateMemory( sizeof(struct PaUtilAllocationGroupLink) * count );
+ if( result )
+ {
+ /* the block link */
+ result[0].buffer = result;
+ result[0].next = nextBlock;
+
+ /* the spare links */
+ for( i=1; i<count; ++i )
+ {
+ result[i].buffer = 0;
+ result[i].next = &result[i+1];
+ }
+ result[count-1].next = nextSpare;
+ }
+
+ return result;
+}
+
+
+PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void )
+{
+ PaUtilAllocationGroup* result = 0;
+ struct PaUtilAllocationGroupLink *links;
+
+
+ links = AllocateLinks( PA_INITIAL_LINK_COUNT_, 0, 0 );
+ if( links != 0 )
+ {
+ result = (PaUtilAllocationGroup*)PaUtil_AllocateMemory( sizeof(PaUtilAllocationGroup) );
+ if( result )
+ {
+ result->linkCount = PA_INITIAL_LINK_COUNT_;
+ result->linkBlocks = &links[0];
+ result->spareLinks = &links[1];
+ result->allocations = 0;
+ }
+ else
+ {
+ PaUtil_FreeMemory( links );
+ }
+ }
+
+ return result;
+}
+
+
+void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group )
+{
+ struct PaUtilAllocationGroupLink *current = group->linkBlocks;
+ struct PaUtilAllocationGroupLink *next;
+
+ while( current )
+ {
+ next = current->next;
+ PaUtil_FreeMemory( current->buffer );
+ current = next;
+ }
+
+ PaUtil_FreeMemory( group );
+}
+
+
+void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size )
+{
+ struct PaUtilAllocationGroupLink *links, *link;
+ void *result = 0;
+
+ /* allocate more links if necessary */
+ if( !group->spareLinks )
+ {
+ /* double the link count on each block allocation */
+ links = AllocateLinks( group->linkCount, group->linkBlocks, group->spareLinks );
+ if( links )
+ {
+ group->linkCount += group->linkCount;
+ group->linkBlocks = &links[0];
+ group->spareLinks = &links[1];
+ }
+ }
+
+ if( group->spareLinks )
+ {
+ result = PaUtil_AllocateMemory( size );
+ if( result )
+ {
+ link = group->spareLinks;
+ group->spareLinks = link->next;
+
+ link->buffer = result;
+ link->next = group->allocations;
+
+ group->allocations = link;
+ }
+ }
+
+ return result;
+}
+
+
+void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer )
+{
+ struct PaUtilAllocationGroupLink *current = group->allocations;
+ struct PaUtilAllocationGroupLink *previous = 0;
+
+ if( buffer == 0 )
+ return;
+
+ /* find the right link and remove it */
+ while( current )
+ {
+ if( current->buffer == buffer )
+ {
+ previous->next = current->next;
+
+ current->buffer = 0;
+ current->next = group->spareLinks;
+ group->spareLinks = current;
+ }
+ previous = current;
+ current = current->next;
+ }
+
+ PaUtil_FreeMemory( buffer ); /* free the memory whether we found it in the list or not */
+}
+
+
+void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group )
+{
+ struct PaUtilAllocationGroupLink *current = group->allocations;
+ struct PaUtilAllocationGroupLink *previous = 0;
+
+ /* free all buffers in the allocations list */
+ while( current )
+ {
+ PaUtil_FreeMemory( current->buffer );
+ current->buffer = 0;
+
+ previous = current;
+ current = current->next;
+ }
+
+ /* link the former allocations list onto the front of the spareLinks list */
+ if( previous )
+ {
+ previous->next = group->spareLinks;
+ group->spareLinks = group->allocations;
+ group->allocations = 0;
+ }
+}
+
diff --git a/pd/portaudio/pa_common/pa_allocation.h b/pd/portaudio/pa_common/pa_allocation.h
new file mode 100644
index 00000000..b906c14b
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_allocation.h
@@ -0,0 +1,92 @@
+#ifndef PA_ALLOCATION_H
+#define PA_ALLOCATION_H
+/*
+ * Id:
+ * Portable Audio I/O Library allocation context header
+ * memory allocation context for tracking allocation groups
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/** @file
+ An allocation group is useful for keeping track of multiple blocks
+ of memory which are allocated at the same time (such as during initialization)
+ and need to be deallocated at the same time. The allocation group maintains
+ a list of allocated blocks, and can deallocate them all simultaneously which
+ can be usefull for cleaning up after a partially initialized object fails.
+
+ The allocation group implementation is built on top of the lower
+ level allocation functions defined in pa_util.h
+*/
+
+
+
+typedef struct
+{
+ long linkCount;
+ struct PaUtilAllocationGroupLink *linkBlocks;
+ struct PaUtilAllocationGroupLink *spareLinks;
+ struct PaUtilAllocationGroupLink *allocations;
+}PaUtilAllocationGroup;
+
+
+
+/** Create an allocation group.
+*/
+PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void );
+
+/** Destroy an allocation group, but not the memory allocated through the group.
+*/
+void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group );
+
+/** Allocate a block of memory though an allocation group.
+*/
+void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size );
+
+/** Free a block of memory that was previously allocated though an allocation
+ group. Calling this function is a relatively time consuming operation.
+ Under normal circumstances clients should call PaUtil_FreeAllAllocations to
+ free all allocated blocks simultaneously.
+ @see PaUtil_FreeAllAllocations
+*/
+void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer );
+
+/** Free all blocks of memory which have been allocated through the allocation
+ group. This function doesn't destroy the group itself.
+*/
+void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group );
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_ALLOCATION_H */
diff --git a/pd/portaudio/pa_common/pa_allocation.o b/pd/portaudio/pa_common/pa_allocation.o
new file mode 100644
index 00000000..43ac4148
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_allocation.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_converters.c b/pd/portaudio/pa_common/pa_converters.c
new file mode 100644
index 00000000..39e5e47f
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_converters.c
@@ -0,0 +1,1653 @@
+/*
+ * $Id: pa_converters.c,v 1.1.2.13 2003/02/28 01:49:59 rossbencina Exp $
+ * Portable Audio I/O Library sample conversion mechanism
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+/** @file
+
+ @todo implement the converters marked IMPLEMENT ME: Float32_To_UInt8_Dither,
+ Float32_To_UInt8_Clip, Float32_To_UInt8_DitherClip, Int32_To_Int24,
+ Int32_To_Int24_Dither, Int32_To_Int16, Int32_To_Int16_Dither, Int32_To_Int8,
+ Int32_To_Int8_Dither, Int32_To_UInt8, Int32_To_UInt8_Dither, Int24_To_Int32,
+ Int24_To_Int16, Int24_To_Int16_Dither, Int24_To_Int8, Int24_To_Int8_Dither,
+ Int24_To_UInt8, Int24_To_UInt8_Dither, Int16_To_Int32, Int16_To_Int24,
+ Int16_To_Int8, Int16_To_Int8_Dither, Int16_To_UInt8, Int16_To_UInt8_Dither,
+ Int8_To_Int32, Int8_To_Int24, Int8_To_Int16, Int8_To_UInt8, UInt8_To_Int32,
+ UInt8_To_Int24, UInt8_To_Int16, UInt8_To_Int8
+
+ @todo review the converters marked REVIEW: Float32_To_Int32,
+ Float32_To_Int32_Dither, Float32_To_Int32_Clip, Float32_To_Int32_DitherClip
+*/
+
+
+#include "pa_converters.h"
+#include "pa_dither.h"
+#include "pa_endianness.h"
+
+
+PaSampleFormat PaUtil_SelectClosestAvailableFormat(
+ PaSampleFormat availableFormats, PaSampleFormat format )
+{
+ PaSampleFormat result;
+
+ format &= ~paNonInterleaved;
+ availableFormats &= ~paNonInterleaved;
+
+ if( (format & availableFormats) == 0 )
+ {
+ /* NOTE: this code depends on the sample format constants being in
+ descending order of quality - ie best quality is 0
+ FIXME: should write an assert which checks that all of the
+ known constants conform to that requirement.
+ */
+
+ if( format != 0x01 )
+ {
+ /* scan for better formats */
+ result = format;
+ do
+ {
+ result >>= 1;
+ }
+ while( (result & availableFormats) == 0 && result != 0 );
+ }
+ else
+ {
+ result = 0;
+ }
+
+ if( result == 0 ){
+ /* scan for worse formats */
+ result = format;
+ do
+ {
+ result <<= 1;
+ }
+ while( (result & availableFormats) == 0 && result != paCustomFormat );
+
+ if( (result & availableFormats) == 0 )
+ result = paSampleFormatNotSupported;
+ }
+
+ }else{
+ result = format;
+ }
+
+ return result;
+}
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_SELECT_FORMAT_( format, float32, int32, int24, int16, int8, uint8 ) \
+ switch( format & ~paNonInterleaved ){ \
+ case paFloat32: \
+ float32 \
+ case paInt32: \
+ int32 \
+ case paInt24: \
+ int24 \
+ case paInt16: \
+ int16 \
+ case paInt8: \
+ int8 \
+ case paUInt8: \
+ uint8 \
+ default: return 0; \
+ }
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_SELECT_CONVERTER_DITHER_CLIP_( flags, source, destination ) \
+ if( flags & paClipOff ){ /* no clip */ \
+ if( flags & paDitherOff ){ /* no dither */ \
+ return paConverters. source ## _To_ ## destination; \
+ }else{ /* dither */ \
+ return paConverters. source ## _To_ ## destination ## _Dither; \
+ } \
+ }else{ /* clip */ \
+ if( flags & paDitherOff ){ /* no dither */ \
+ return paConverters. source ## _To_ ## destination ## _Clip; \
+ }else{ /* dither */ \
+ return paConverters. source ## _To_ ## destination ## _DitherClip;\
+ } \
+ }
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_SELECT_CONVERTER_DITHER_( flags, source, destination ) \
+ if( flags & paDitherOff ){ /* no dither */ \
+ return paConverters. source ## _To_ ## destination; \
+ }else{ /* dither */ \
+ return paConverters. source ## _To_ ## destination ## _Dither; \
+ }
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_USE_CONVERTER_( source, destination )\
+ return paConverters. source ## _To_ ## destination;
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_UNITY_CONVERSION_( wordlength )\
+ return paConverters.Copy_ ## wordlength ## _To_ ## wordlength;
+
+/* -------------------------------------------------------------------------- */
+
+PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat,
+ PaSampleFormat destinationFormat, PaStreamFlags flags )
+{
+ PA_SELECT_FORMAT_( sourceFormat,
+ /* paFloat32: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_UNITY_CONVERSION_( 32 ),
+ /* paInt32: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int32 ),
+ /* paInt24: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int24 ),
+ /* paInt16: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int16 ),
+ /* paInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int8 ),
+ /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, UInt8 )
+ ),
+ /* paInt32: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_USE_CONVERTER_( Int32, Float32 ),
+ /* paInt32: */ PA_UNITY_CONVERSION_( 32 ),
+ /* paInt24: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int24 ),
+ /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int16 ),
+ /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int8 ),
+ /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, UInt8 )
+ ),
+ /* paInt24: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_USE_CONVERTER_( Int24, Float32 ),
+ /* paInt32: */ PA_USE_CONVERTER_( Int24, Int32 ),
+ /* paInt24: */ PA_UNITY_CONVERSION_( 24 ),
+ /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int16 ),
+ /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int8 ),
+ /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, UInt8 )
+ ),
+ /* paInt16: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_USE_CONVERTER_( Int16, Float32 ),
+ /* paInt32: */ PA_USE_CONVERTER_( Int16, Int32 ),
+ /* paInt24: */ PA_USE_CONVERTER_( Int16, Int24 ),
+ /* paInt16: */ PA_UNITY_CONVERSION_( 16 ),
+ /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, Int8 ),
+ /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, UInt8 )
+ ),
+ /* paInt8: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_USE_CONVERTER_( Int8, Float32 ),
+ /* paInt32: */ PA_USE_CONVERTER_( Int8, Int32 ),
+ /* paInt24: */ PA_USE_CONVERTER_( Int8, Int24 ),
+ /* paInt16: */ PA_USE_CONVERTER_( Int8, Int16 ),
+ /* paInt8: */ PA_UNITY_CONVERSION_( 8 ),
+ /* paUInt8: */ PA_USE_CONVERTER_( Int8, UInt8 )
+ ),
+ /* paUInt8: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_USE_CONVERTER_( UInt8, Float32 ),
+ /* paInt32: */ PA_USE_CONVERTER_( UInt8, Int32 ),
+ /* paInt24: */ PA_USE_CONVERTER_( UInt8, Int24 ),
+ /* paInt16: */ PA_USE_CONVERTER_( UInt8, Int16 ),
+ /* paInt8: */ PA_USE_CONVERTER_( UInt8, Int8 ),
+ /* paUInt8: */ PA_UNITY_CONVERSION_( 8 )
+ )
+ )
+}
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef PA_NO_STANDARD_CONVERTERS
+
+/* -------------------------------------------------------------------------- */
+
+PaUtilConverterTable paConverters = {
+ 0, /* PaUtilConverter *Float32_To_Int32; */
+ 0, /* PaUtilConverter *Float32_To_Int32_Dither; */
+ 0, /* PaUtilConverter *Float32_To_Int32_Clip; */
+ 0, /* PaUtilConverter *Float32_To_Int32_DitherClip; */
+
+ 0, /* PaUtilConverter *Float32_To_Int24; */
+ 0, /* PaUtilConverter *Float32_To_Int24_Dither; */
+ 0, /* PaUtilConverter *Float32_To_Int24_Clip; */
+ 0, /* PaUtilConverter *Float32_To_Int24_DitherClip; */
+
+ 0, /* PaUtilConverter *Float32_To_Int16; */
+ 0, /* PaUtilConverter *Float32_To_Int16_Dither; */
+ 0, /* PaUtilConverter *Float32_To_Int16_Clip; */
+ 0, /* PaUtilConverter *Float32_To_Int16_DitherClip; */
+
+ 0, /* PaUtilConverter *Float32_To_Int8; */
+ 0, /* PaUtilConverter *Float32_To_Int8_Dither; */
+ 0, /* PaUtilConverter *Float32_To_Int8_Clip; */
+ 0, /* PaUtilConverter *Float32_To_Int8_DitherClip; */
+
+ 0, /* PaUtilConverter *Float32_To_UInt8; */
+ 0, /* PaUtilConverter *Float32_To_UInt8_Dither; */
+ 0, /* PaUtilConverter *Float32_To_UInt8_Clip; */
+ 0, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */
+
+ 0, /* PaUtilConverter *Int32_To_Float32; */
+ 0, /* PaUtilConverter *Int32_To_Int24; */
+ 0, /* PaUtilConverter *Int32_To_Int24_Dither; */
+ 0, /* PaUtilConverter *Int32_To_Int16; */
+ 0, /* PaUtilConverter *Int32_To_Int16_Dither; */
+ 0, /* PaUtilConverter *Int32_To_Int8; */
+ 0, /* PaUtilConverter *Int32_To_Int8_Dither; */
+ 0, /* PaUtilConverter *Int32_To_UInt8; */
+ 0, /* PaUtilConverter *Int32_To_UInt8_Dither; */
+
+ 0, /* PaUtilConverter *Int24_To_Float32; */
+ 0, /* PaUtilConverter *Int24_To_Int32; */
+ 0, /* PaUtilConverter *Int24_To_Int16; */
+ 0, /* PaUtilConverter *Int24_To_Int16_Dither; */
+ 0, /* PaUtilConverter *Int24_To_Int8; */
+ 0, /* PaUtilConverter *Int24_To_Int8_Dither; */
+ 0, /* PaUtilConverter *Int24_To_UInt8; */
+ 0, /* PaUtilConverter *Int24_To_UInt8_Dither; */
+
+ 0, /* PaUtilConverter *Int16_To_Float32; */
+ 0, /* PaUtilConverter *Int16_To_Int32; */
+ 0, /* PaUtilConverter *Int16_To_Int24; */
+ 0, /* PaUtilConverter *Int16_To_Int8; */
+ 0, /* PaUtilConverter *Int16_To_Int8_Dither; */
+ 0, /* PaUtilConverter *Int16_To_UInt8; */
+ 0, /* PaUtilConverter *Int16_To_UInt8_Dither; */
+
+ 0, /* PaUtilConverter *Int8_To_Float32; */
+ 0, /* PaUtilConverter *Int8_To_Int32; */
+ 0, /* PaUtilConverter *Int8_To_Int24 */
+ 0, /* PaUtilConverter *Int8_To_Int16; */
+ 0, /* PaUtilConverter *Int8_To_UInt8; */
+
+ 0, /* PaUtilConverter *UInt8_To_Float32; */
+ 0, /* PaUtilConverter *UInt8_To_Int32; */
+ 0, /* PaUtilConverter *UInt8_To_Int24; */
+ 0, /* PaUtilConverter *UInt8_To_Int16; */
+ 0, /* PaUtilConverter *UInt8_To_Int8; */
+
+ 0, /* PaUtilConverter *Copy_8_To_8; */
+ 0, /* PaUtilConverter *Copy_16_To_16; */
+ 0, /* PaUtilConverter *Copy_24_To_24; */
+ 0 /* PaUtilConverter *Copy_32_To_32; */
+};
+
+/* -------------------------------------------------------------------------- */
+
+#else /* PA_NO_STANDARD_CONVERTERS is not defined */
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_CLIP_( val, min, max )\
+ { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
+
+
+static const float const_1_div_128_ = 1.0f / 128.0f; /* 8 bit multiplier */
+
+static const float const_1_div_32768_ = 1.0f / 32768.f; /* 16 bit multiplier */
+
+static const double const_1_div_2147483648_ = 1.0 / 2147483648.0; /* 32 bit multiplier */
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ /* REVIEW */
+ double scaled = *src * 0x7FFFFFFF;
+ *dest = (signed long) scaled;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+
+ while( count-- )
+ {
+ /* REVIEW */
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ double dithered = ((double)*src * (2147483646.0)) + dither;
+ *dest = (signed long) dithered;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ /* REVIEW */
+ double scaled = *src * 0x7FFFFFFF;
+ PA_CLIP_( scaled, -2147483648., 2147483647. );
+ *dest = (signed long) scaled;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+
+ while( count-- )
+ {
+ /* REVIEW */
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ double dithered = ((double)*src * (2147483646.0)) + dither;
+ PA_CLIP_( dithered, -2147483648., 2147483647. );
+ *dest = (signed long) dithered;
+
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ /* convert to 32 bit and drop the low 8 bits */
+ double scaled = *src * 0x7FFFFFFF;
+ temp = (signed long) scaled;
+
+#if defined(PA_LITTLE_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+#elif defined(PA_BIG_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 24);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 8);
+#endif
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ while( count-- )
+ {
+ /* convert to 32 bit and drop the low 8 bits */
+
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ double dithered = ((double)*src * (2147483646.0)) + dither;
+
+ temp = (signed long) dithered;
+
+#if defined(PA_LITTLE_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+#elif defined(PA_BIG_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 24);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 8);
+#endif
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ /* convert to 32 bit and drop the low 8 bits */
+ double scaled = *src * 0x7FFFFFFF;
+ PA_CLIP_( scaled, -2147483648., 2147483647. );
+ temp = (signed long) scaled;
+
+#if defined(PA_LITTLE_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+#elif defined(PA_BIG_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 24);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 8);
+#endif
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ while( count-- )
+ {
+ /* convert to 32 bit and drop the low 8 bits */
+
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ double dithered = ((double)*src * (2147483646.0)) + dither;
+ PA_CLIP_( dithered, -2147483648., 2147483647. );
+
+ temp = (signed long) dithered;
+
+#if defined(PA_LITTLE_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+#elif defined(PA_BIG_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 24);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 8);
+#endif
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ short samp = (short) (*src * (32767.0f));
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+
+ while( count-- )
+ {
+
+ float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ float dithered = (*src * (32766.0f)) + dither;
+ *dest = (signed short) dithered;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ long samp = (signed long) (*src * (32767.0f));
+ PA_CLIP_( samp, -0x8000, 0x7FFF );
+ *dest = (signed short) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ float dithered = (*src * (32766.0f)) + dither;
+ signed long samp = (signed long) dithered;
+ PA_CLIP_( samp, -0x8000, 0x7FFF );
+ *dest = (signed short) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ signed char samp = (signed char) (*src * (127.0f));
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ float dithered = (*src * (126.0f)) + dither;
+ signed long samp = (signed long) dithered;
+ *dest = (signed char) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int8_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ signed long samp = (signed long)(*src * (127.0f));
+ PA_CLIP_( samp, -0x80, 0x7F );
+ *dest = (signed char) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int8_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ float dithered = (*src * (126.0f)) + dither;
+ signed long samp = (signed long) dithered;
+ PA_CLIP_( samp, -0x80, 0x7F );
+ *dest = (signed char) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_UInt8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ unsigned char samp = (unsigned char)(128 + ((unsigned char) (*src * (127.0f))));
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_UInt8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_UInt8_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_UInt8_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Float32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ *dest = (double)*src * const_1_div_2147483648_;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int24_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int16_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_UInt8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_UInt8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Float32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ signed long temp;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+#if defined(PA_LITTLE_ENDIAN)
+ temp = (((long)src[0]) << 8);
+ temp = temp | (((long)src[1]) << 16);
+ temp = temp | (((long)src[2]) << 24);
+#elif defined(PA_BIG_ENDIAN)
+ temp = (((long)src[0]) << 24);
+ temp = temp | (((long)src[1]) << 16);
+ temp = temp | (((long)src[2]) << 8);
+#endif
+
+ *dest = (double)temp * const_1_div_2147483648_;
+
+ src += sourceStride * 3;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Int16_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Int8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Int8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_UInt8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_UInt8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_Float32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ float samp = *src * const_1_div_32768_; /* FIXME: i'm concerned about this being asymetrical with float->int16 -rb */
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_Int8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_Int8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_UInt8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_UInt8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int8_To_Float32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed char *src = (signed char*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ float samp = *src * const_1_div_128_;
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int8_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed char *src = (signed char*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int8_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed char *src = (signed char*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int8_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed char *src = (signed char*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int8_To_UInt8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed char *src = (signed char*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void UInt8_To_Float32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ float samp = (*src - 128) * const_1_div_128_;
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void UInt8_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void UInt8_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void UInt8_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void UInt8_To_Int8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Copy_8_To_8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ *dest = *src;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Copy_16_To_16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned short *src = (unsigned short*)sourceBuffer;
+ unsigned short *dest = (unsigned short*)destinationBuffer;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ *dest = *src;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Copy_24_To_24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+
+ src += sourceStride * 3;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Copy_32_To_32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned long *dest = (unsigned long*)destinationBuffer;
+ unsigned long *src = (unsigned long*)sourceBuffer;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ *dest = *src;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+PaUtilConverterTable paConverters = {
+ Float32_To_Int32, /* PaUtilConverter *Float32_To_Int32; */
+ Float32_To_Int32_Dither, /* PaUtilConverter *Float32_To_Int32_Dither; */
+ Float32_To_Int32_Clip, /* PaUtilConverter *Float32_To_Int32_Clip; */
+ Float32_To_Int32_DitherClip, /* PaUtilConverter *Float32_To_Int32_DitherClip; */
+
+ Float32_To_Int24, /* PaUtilConverter *Float32_To_Int24; */
+ Float32_To_Int24_Dither, /* PaUtilConverter *Float32_To_Int24_Dither; */
+ Float32_To_Int24_Clip, /* PaUtilConverter *Float32_To_Int24_Clip; */
+ Float32_To_Int24_DitherClip, /* PaUtilConverter *Float32_To_Int24_DitherClip; */
+
+ Float32_To_Int16, /* PaUtilConverter *Float32_To_Int16; */
+ Float32_To_Int16_Dither, /* PaUtilConverter *Float32_To_Int16_Dither; */
+ Float32_To_Int16_Clip, /* PaUtilConverter *Float32_To_Int16_Clip; */
+ Float32_To_Int16_DitherClip, /* PaUtilConverter *Float32_To_Int16_DitherClip; */
+
+ Float32_To_Int8, /* PaUtilConverter *Float32_To_Int8; */
+ Float32_To_Int8_Dither, /* PaUtilConverter *Float32_To_Int8_Dither; */
+ Float32_To_Int8_Clip, /* PaUtilConverter *Float32_To_Int8_Clip; */
+ Float32_To_Int8_DitherClip, /* PaUtilConverter *Float32_To_Int8_DitherClip; */
+
+ Float32_To_UInt8, /* PaUtilConverter *Float32_To_UInt8; */
+ Float32_To_UInt8_Dither, /* PaUtilConverter *Float32_To_UInt8_Dither; */
+ Float32_To_UInt8_Clip, /* PaUtilConverter *Float32_To_UInt8_Clip; */
+ Float32_To_UInt8_DitherClip, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */
+
+ Int32_To_Float32, /* PaUtilConverter *Int32_To_Float32; */
+ Int32_To_Int24, /* PaUtilConverter *Int32_To_Int24; */
+ Int32_To_Int24_Dither, /* PaUtilConverter *Int32_To_Int24_Dither; */
+ Int32_To_Int16, /* PaUtilConverter *Int32_To_Int16; */
+ Int32_To_Int16_Dither, /* PaUtilConverter *Int32_To_Int16_Dither; */
+ Int32_To_Int8, /* PaUtilConverter *Int32_To_Int8; */
+ Int32_To_Int8_Dither, /* PaUtilConverter *Int32_To_Int8_Dither; */
+ Int32_To_UInt8, /* PaUtilConverter *Int32_To_UInt8; */
+ Int32_To_UInt8_Dither, /* PaUtilConverter *Int32_To_UInt8_Dither; */
+
+ Int24_To_Float32, /* PaUtilConverter *Int24_To_Float32; */
+ Int24_To_Int32, /* PaUtilConverter *Int24_To_Int32; */
+ Int24_To_Int16, /* PaUtilConverter *Int24_To_Int16; */
+ Int24_To_Int16_Dither, /* PaUtilConverter *Int24_To_Int16_Dither; */
+ Int24_To_Int8, /* PaUtilConverter *Int24_To_Int8; */
+ Int24_To_Int8_Dither, /* PaUtilConverter *Int24_To_Int8_Dither; */
+ Int24_To_UInt8, /* PaUtilConverter *Int24_To_UInt8; */
+ Int24_To_UInt8_Dither, /* PaUtilConverter *Int24_To_UInt8_Dither; */
+
+ Int16_To_Float32, /* PaUtilConverter *Int16_To_Float32; */
+ Int16_To_Int32, /* PaUtilConverter *Int16_To_Int32; */
+ Int16_To_Int24, /* PaUtilConverter *Int16_To_Int24; */
+ Int16_To_Int8, /* PaUtilConverter *Int16_To_Int8; */
+ Int16_To_Int8_Dither, /* PaUtilConverter *Int16_To_Int8_Dither; */
+ Int16_To_UInt8, /* PaUtilConverter *Int16_To_UInt8; */
+ Int16_To_UInt8_Dither, /* PaUtilConverter *Int16_To_UInt8_Dither; */
+
+ Int8_To_Float32, /* PaUtilConverter *Int8_To_Float32; */
+ Int8_To_Int32, /* PaUtilConverter *Int8_To_Int32; */
+ Int8_To_Int24, /* PaUtilConverter *Int8_To_Int24 */
+ Int8_To_Int16, /* PaUtilConverter *Int8_To_Int16; */
+ Int8_To_UInt8, /* PaUtilConverter *Int8_To_UInt8; */
+
+ UInt8_To_Float32, /* PaUtilConverter *UInt8_To_Float32; */
+ UInt8_To_Int32, /* PaUtilConverter *UInt8_To_Int32; */
+ UInt8_To_Int24, /* PaUtilConverter *UInt8_To_Int24; */
+ UInt8_To_Int16, /* PaUtilConverter *UInt8_To_Int16; */
+ UInt8_To_Int8, /* PaUtilConverter *UInt8_To_Int8; */
+
+ Copy_8_To_8, /* PaUtilConverter *Copy_8_To_8; */
+ Copy_16_To_16, /* PaUtilConverter *Copy_16_To_16; */
+ Copy_24_To_24, /* PaUtilConverter *Copy_24_To_24; */
+ Copy_32_To_32 /* PaUtilConverter *Copy_32_To_32; */
+};
+
+/* -------------------------------------------------------------------------- */
+
+#endif /* PA_NO_STANDARD_CONVERTERS */
diff --git a/pd/portaudio/pa_common/pa_converters.h b/pd/portaudio/pa_common/pa_converters.h
new file mode 100644
index 00000000..8fa0fda7
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_converters.h
@@ -0,0 +1,197 @@
+#ifndef PA_CONVERTERS_H
+#define PA_CONVERTERS_H
+/*
+ * $Id: pa_converters.h,v 1.1.2.7 2002/10/22 08:58:17 rossbencina Exp $
+ * Portable Audio I/O Library sample conversion mechanism
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include "portaudio.h" /* for PaSampleFormat */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+struct PaUtilTriangularDitherGenerator;
+
+
+/** Choose an available sample format which is most appropriate for
+ representing the requested format. If the requested format is not available
+ higher quality formats are considered before lower quality formates.
+ @param availableFormats A variable containing the logical OR of all available
+ formats.
+ @param format The desired format.
+ @return The most appropriate available format for representing the requested
+ format.
+*/
+PaSampleFormat PaUtil_SelectClosestAvailableFormat(
+ PaSampleFormat availableFormats, PaSampleFormat format );
+
+
+/* high level conversions functions for use by implementations */
+
+
+/** The generic sample converter prototype. Sample converters convert count
+ samples from sourceBuffer to destinationBuffer. The actual type of the data
+ pointed to by these parameters varys for different converter functions.
+ @param destinationBuffer A pointer to the first sample of the destination.
+ @param destinationStride An offset between successive destination samples
+ expressed in samples (not bytes.) It may be negative.
+ @param sourceBuffer A pointer to the first sample of the source.
+ @param sourceStride An offset between successive source samples
+ expressed in samples (not bytes.) It may be negative.
+ @param count The number of samples to convert.
+ @param ditherState State information used to calculate dither. Converters
+ that do not perform dithering will ignore this parameter, in which case
+ NULL or invalid dither state may be passed.
+*/
+typedef void PaUtilConverter(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator );
+
+
+/** Find a sample converter function for the given source and destinations
+ formats and flags (clip and dither.)
+ @return
+ A pointer to a PaUtil_Converter which will perform the requested
+ conversion, or NULL if the given format conversion is not supported.
+ For conversions where clipping or dithering is not necessary, the
+ clip and dither flags are ignored and a non-clipping or dithering
+ version is returned.
+ If the source and destination formats are the same, a function which
+ copies data of the appropriate size will be returned.
+*/
+PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat,
+ PaSampleFormat destinationFormat, PaStreamFlags flags );
+
+
+/* low level functions and data structures which may be used for
+ substituting additional conversion functions */
+
+
+/** The type used to store all sample conversion functions.
+ @see paConverters;
+*/
+typedef struct{
+ PaUtilConverter *Float32_To_Int32;
+ PaUtilConverter *Float32_To_Int32_Dither;
+ PaUtilConverter *Float32_To_Int32_Clip;
+ PaUtilConverter *Float32_To_Int32_DitherClip;
+
+ PaUtilConverter *Float32_To_Int24;
+ PaUtilConverter *Float32_To_Int24_Dither;
+ PaUtilConverter *Float32_To_Int24_Clip;
+ PaUtilConverter *Float32_To_Int24_DitherClip;
+
+ PaUtilConverter *Float32_To_Int16;
+ PaUtilConverter *Float32_To_Int16_Dither;
+ PaUtilConverter *Float32_To_Int16_Clip;
+ PaUtilConverter *Float32_To_Int16_DitherClip;
+
+ PaUtilConverter *Float32_To_Int8;
+ PaUtilConverter *Float32_To_Int8_Dither;
+ PaUtilConverter *Float32_To_Int8_Clip;
+ PaUtilConverter *Float32_To_Int8_DitherClip;
+
+ PaUtilConverter *Float32_To_UInt8;
+ PaUtilConverter *Float32_To_UInt8_Dither;
+ PaUtilConverter *Float32_To_UInt8_Clip;
+ PaUtilConverter *Float32_To_UInt8_DitherClip;
+
+ PaUtilConverter *Int32_To_Float32;
+ PaUtilConverter *Int32_To_Int24;
+ PaUtilConverter *Int32_To_Int24_Dither;
+ PaUtilConverter *Int32_To_Int16;
+ PaUtilConverter *Int32_To_Int16_Dither;
+ PaUtilConverter *Int32_To_Int8;
+ PaUtilConverter *Int32_To_Int8_Dither;
+ PaUtilConverter *Int32_To_UInt8;
+ PaUtilConverter *Int32_To_UInt8_Dither;
+
+ PaUtilConverter *Int24_To_Float32;
+ PaUtilConverter *Int24_To_Int32;
+ PaUtilConverter *Int24_To_Int16;
+ PaUtilConverter *Int24_To_Int16_Dither;
+ PaUtilConverter *Int24_To_Int8;
+ PaUtilConverter *Int24_To_Int8_Dither;
+ PaUtilConverter *Int24_To_UInt8;
+ PaUtilConverter *Int24_To_UInt8_Dither;
+
+ PaUtilConverter *Int16_To_Float32;
+ PaUtilConverter *Int16_To_Int32;
+ PaUtilConverter *Int16_To_Int24;
+ PaUtilConverter *Int16_To_Int8;
+ PaUtilConverter *Int16_To_Int8_Dither;
+ PaUtilConverter *Int16_To_UInt8;
+ PaUtilConverter *Int16_To_UInt8_Dither;
+
+ PaUtilConverter *Int8_To_Float32;
+ PaUtilConverter *Int8_To_Int32;
+ PaUtilConverter *Int8_To_Int24;
+ PaUtilConverter *Int8_To_Int16;
+ PaUtilConverter *Int8_To_UInt8;
+
+ PaUtilConverter *UInt8_To_Float32;
+ PaUtilConverter *UInt8_To_Int32;
+ PaUtilConverter *UInt8_To_Int24;
+ PaUtilConverter *UInt8_To_Int16;
+ PaUtilConverter *UInt8_To_Int8;
+
+ PaUtilConverter *Copy_8_To_8; /* copy without any conversion */
+ PaUtilConverter *Copy_16_To_16; /* copy without any conversion */
+ PaUtilConverter *Copy_24_To_24; /* copy without any conversion */
+ PaUtilConverter *Copy_32_To_32; /* copy without any conversion */
+} PaUtilConverterTable;
+
+
+/** A table of pointers to all required converter functions.
+ PaUtil_SelectConverter() uses this table to lookup the appropriate
+ conversion functions. The fields of this structure are initialized
+ with default conversion functions. Fields may be NULL, indicating that
+ no conversion function is available. User code may substitue optimised
+ conversion functions by assigning different function pointers to
+ these fields.
+
+ @note
+ If the PA_NO_STANDARD_CONVERTERS preprocessor variable is defined,
+ PortAudio's standard converters will not be compiled, and all fields
+ of this structure will be initialized to NULL. In such cases, users
+ should supply their own conversion functions if the require PortAudio
+ to open a stream that requires sample conversion.
+
+ @see PaUtilConverterTable, PaUtilConverter, PaUtil_SelectConverter
+*/
+extern PaUtilConverterTable paConverters;
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_CONVERTERS_H */
diff --git a/pd/portaudio/pa_common/pa_converters.o b/pd/portaudio/pa_common/pa_converters.o
new file mode 100644
index 00000000..3baede8e
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_converters.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_cpuload.c b/pd/portaudio/pa_common/pa_cpuload.c
new file mode 100644
index 00000000..bce82aff
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_cpuload.c
@@ -0,0 +1,79 @@
+/*
+ * $Id: pa_cpuload.c,v 1.1.2.9 2002/10/22 08:58:17 rossbencina Exp $
+ * Portable Audio I/O Library CPU Load measurement functions
+ * Portable CPU load measurement facility.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 2002 Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include "pa_cpuload.h"
+
+#include <assert.h>
+
+#include "pa_util.h" /* for PaUtil_GetTime() */
+
+
+void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate )
+{
+ assert( sampleRate > 0 );
+
+ measurer->samplingPeriod = 1. / sampleRate;
+}
+
+
+void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer )
+{
+ measurer->measurementStartTime = PaUtil_GetTime();
+}
+
+
+void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed )
+{
+ double measurementEndTime, secondsFor100Percent, measuredLoad;
+
+ if( framesProcessed > 0 ){
+ measurementEndTime = PaUtil_GetTime();
+
+ assert( framesProcessed > 0 );
+ secondsFor100Percent = framesProcessed * measurer->samplingPeriod;
+
+ measuredLoad = (measurementEndTime - measurer->measurementStartTime) / secondsFor100Percent;
+
+ /* Low pass filter the calculated CPU load to reduce jitter using a simple IIR low pass filter. */
+#define LOWPASS_COEFFICIENT_0 (0.9)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+
+ measurer->averageLoad = (LOWPASS_COEFFICIENT_0 * measurer->averageLoad) +
+ (LOWPASS_COEFFICIENT_1 * measuredLoad);
+ }
+}
+
+
+double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer )
+{
+ return measurer->averageLoad;
+}
diff --git a/pd/portaudio/pa_common/pa_cpuload.h b/pd/portaudio/pa_common/pa_cpuload.h
new file mode 100644
index 00000000..28c4c29a
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_cpuload.h
@@ -0,0 +1,56 @@
+#ifndef PA_CPULOAD_H
+#define PA_CPULOAD_H
+/*
+ * $Id: pa_cpuload.h,v 1.1.2.8 2002/10/22 08:58:17 rossbencina Exp $
+ * Portable Audio I/O Library CPU Load measurement functions
+ * Portable CPU load measurement facility.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 2002 Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+typedef struct {
+ double samplingPeriod;
+ double measurementStartTime;
+ double averageLoad;
+} PaUtilCpuLoadMeasurer; /** @todo need better name than measurer */
+
+void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate );
+void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer );
+void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed );
+double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer );
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_CPULOAD_H */
diff --git a/pd/portaudio/pa_common/pa_cpuload.o b/pd/portaudio/pa_common/pa_cpuload.o
new file mode 100644
index 00000000..bc599f45
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_cpuload.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_dither.c b/pd/portaudio/pa_common/pa_dither.c
new file mode 100644
index 00000000..10f43e69
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_dither.c
@@ -0,0 +1,91 @@
+/*
+ * $Id: pa_dither.c,v 1.1.2.3 2002/06/16 13:11:02 rossbencina Exp $
+ * Portable Audio I/O Library triangular dither generator
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include "pa_dither.h"
+
+#define PA_DITHER_BITS_ (15)
+
+
+void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *state )
+{
+ state->previous = 0;
+ state->randSeed1 = 22222;
+ state->randSeed2 = 5555555;
+}
+
+
+signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *state )
+{
+ signed long current, highPass;
+
+ /* Generate two random numbers. */
+ state->randSeed1 = (state->randSeed1 * 196314165) + 907633515;
+ state->randSeed2 = (state->randSeed2 * 196314165) + 907633515;
+
+ /* Generate triangular distribution about 0.
+ * Shift before adding to prevent overflow which would skew the distribution.
+ * Also shift an extra bit for the high pass filter.
+ */
+#define DITHER_SHIFT_ ((32 - PA_DITHER_BITS_) + 1)
+ current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
+ (((signed long)state->randSeed2)>>DITHER_SHIFT_);
+
+ /* High pass filter to reduce audibility. */
+ highPass = current - state->previous;
+ state->previous = current;
+ return highPass;
+}
+
+/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */
+#define PA_FLOAT_DITHER_SCALE_ (1.0f / ((1<<PA_DITHER_BITS_)-1))
+static const float const_float_dither_scale_ = PA_FLOAT_DITHER_SCALE_;
+
+float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *state )
+{
+ signed long current, highPass;
+
+ /* Generate two random numbers. */
+ state->randSeed1 = (state->randSeed1 * 196314165) + 907633515;
+ state->randSeed2 = (state->randSeed2 * 196314165) + 907633515;
+
+ /* Generate triangular distribution about 0.
+ * Shift before adding to prevent overflow which would skew the distribution.
+ * Also shift an extra bit for the high pass filter.
+ */
+#define DITHER_SHIFT_ ((32 - PA_DITHER_BITS_) + 1)
+ current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
+ (((signed long)state->randSeed2)>>DITHER_SHIFT_);
+
+ /* High pass filter to reduce audibility. */
+ highPass = current - state->previous;
+ state->previous = current;
+ return ((float)highPass) * const_float_dither_scale_;
+}
diff --git a/pd/portaudio/pa_common/pa_dither.h b/pd/portaudio/pa_common/pa_dither.h
new file mode 100644
index 00000000..97116f0f
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_dither.h
@@ -0,0 +1,189 @@
+#ifndef PA_DITHER_H
+#define PA_DITHER_H
+/*
+ * $Id: pa_dither.h,v 1.1.2.2 2002/06/05 22:37:03 rossb Exp $
+ * Portable Audio I/O Library triangular dither generator
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+typedef struct PaUtilTriangularDitherGenerator{
+ unsigned long previous;
+ unsigned long randSeed1;
+ unsigned long randSeed2;
+} PaUtilTriangularDitherGenerator;
+/**< State needed to generate a dither signal */
+
+
+void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *ditherState );
+/**< Initialize dither state */
+
+signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *ditherState );
+/**<
+ Calculate 2 LSB dither signal with a triangular distribution.
+ Ranged for adding to a 1 bit right-shifted 32 bit integer
+ prior to >>15. eg:
+<pre>
+ signed long in = *
+ signed long dither = PaUtil_Generate16BitTriangularDither( ditherState );
+ signed short out = (signed short)(((in>>1) + dither) >> 15);
+</pre>
+ @return
+ A signed long with a range of +32767 to -32768
+*/
+
+
+float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *ditherState );
+/**<
+ Calculate 2 LSB dither signal with a triangular distribution.
+ Ranged for adding to a pre-scaled float.
+<pre>
+ float in = *
+ float dither = PaUtil_GenerateFloatTriangularDither( ditherState );
+ // use smaller scaler to prevent overflow when we add the dither
+ signed short out = (signed short)(in*(32766.0f) + dither );
+</pre>
+ @return
+ A float with a range of -2.0 to +1.99999.
+*/
+
+
+
+/*
+The following alternate dither algorithms are known...
+*/
+
+/*Noise shaped dither (March 2000)
+-------------------
+
+This is a simple implementation of highpass triangular-PDF dither with
+2nd-order noise shaping, for use when truncating floating point audio
+data to fixed point.
+
+The noise shaping lowers the noise floor by 11dB below 5kHz (@ 44100Hz
+sample rate) compared to triangular-PDF dither. The code below assumes
+input data is in the range +1 to -1 and doesn't check for overloads!
+
+To save time when generating dither for multiple channels you can do
+things like this: r3=(r1 & 0x7F)<<8; instead of calling rand() again.
+
+
+
+ int r1, r2; //rectangular-PDF random numbers
+ float s1, s2; //error feedback buffers
+ float s = 0.5f; //set to 0.0f for no noise shaping
+ float w = pow(2.0,bits-1); //word length (usually bits=16)
+ float wi= 1.0f/w;
+ float d = wi / RAND_MAX; //dither amplitude (2 lsb)
+ float o = wi * 0.5f; //remove dc offset
+ float in, tmp;
+ int out;
+
+
+//for each sample...
+
+ r2=r1; //can make HP-TRI dither by
+ r1=rand(); //subtracting previous rand()
+
+ in += s * (s1 + s1 - s2); //error feedback
+ tmp = in + o + d * (float)(r1 - r2); //dc offset and dither
+
+ out = (int)(w * tmp); //truncate downwards
+ if(tmp<0.0f) out--; //this is faster than floor()
+
+ s2 = s1;
+ s1 = in - wi * (float)out; //error
+
+
+
+--
+paul.kellett@maxim.abel.co.uk
+http://www.maxim.abel.co.uk
+*/
+
+
+/*
+16-to-8-bit first-order dither
+
+Type : First order error feedforward dithering code
+References : Posted by Jon Watte
+
+Notes :
+This is about as simple a dithering algorithm as you can implement, but it's
+likely to sound better than just truncating to N bits.
+
+Note that you might not want to carry forward the full difference for infinity.
+It's probably likely that the worst performance hit comes from the saturation
+conditionals, which can be avoided with appropriate instructions on many DSPs
+and integer SIMD type instructions, or CMOV.
+
+Last, if sound quality is paramount (such as when going from > 16 bits to 16
+bits) you probably want to use a higher-order dither function found elsewhere
+on this site.
+
+
+Code :
+// This code will down-convert and dither a 16-bit signed short
+// mono signal into an 8-bit unsigned char signal, using a first
+// order forward-feeding error term dither.
+
+#define uchar unsigned char
+
+void dither_one_channel_16_to_8( short * input, uchar * output, int count, int * memory )
+{
+ int m = *memory;
+ while( count-- > 0 ) {
+ int i = *input++;
+ i += m;
+ int j = i + 32768 - 128;
+ uchar o;
+ if( j < 0 ) {
+ o = 0;
+ }
+ else if( j > 65535 ) {
+ o = 255;
+ }
+ else {
+ o = (uchar)((j>>8)&0xff);
+ }
+ m = ((j-32768+128)-i);
+ *output++ = o;
+ }
+ *memory = m;
+}
+*/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_DITHER_H */
diff --git a/pd/portaudio/pa_common/pa_dither.o b/pd/portaudio/pa_common/pa_dither.o
new file mode 100644
index 00000000..fc7a4bb4
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_dither.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_endianness.h b/pd/portaudio/pa_common/pa_endianness.h
new file mode 100644
index 00000000..aaccaf75
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_endianness.h
@@ -0,0 +1,108 @@
+#ifndef PA_ENDIANNESS_H
+#define PA_ENDIANNESS_H
+/*
+ * $Id: pa_endianness.h,v 1.1.2.1 2003/02/28 01:49:59 rossbencina Exp $
+ * Portable Audio I/O Library current platform endianness macros
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/** @file
+ Arrange for either the PA_LITTLE_ENDIAN or PA_BIG_ENDIAN preprocessor symbols
+ to be defined. The one that is defined reflects the endianness of the target
+ platform and may be used to implement conditional compilation of byte-order
+ dependent code.
+
+ If either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN is defined already, then no attempt
+ is made to override that setting. This may be useful if you have a better way
+ of determining the platform's endianness. The autoconf mechanism uses this for
+ example.
+
+ A PA_VALIDATE_ENDIANNESS macro is provided to compare the compile time
+ and runtime endiannes and raise an assertion if they don't match.
+*/
+
+
+#if defined(PA_LITTLE_ENDIAN) || defined(PA_BIG_ENDIAN)
+ /* endianness define has been set externally, such as by autoconf */
+
+ #if defined(PA_LITTLE_ENDIAN) && defined(PA_BIG_ENDIAN)
+ #error both PA_LITTLE_ENDIAN and PA_BIG_ENDIAN have been defined externally to pa_endianness.h - only one endianness at a time please
+ #endif
+
+#else
+ /* endianness define has not been set externally */
+
+ /* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */
+
+ #ifdef WIN32
+
+ #define PA_LITTLE_ENDIAN /* win32, assume intel byte order */
+
+ #else
+
+#endif
+
+ #if !defined(PA_LITTLE_ENDIAN) && !defined(PA_BIG_ENDIAN)
+ /*
+ If the following error is raised, you either need to modify the code above
+ to automatically determine the endianness from other symbols defined on your
+ platform, or define either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN externally.
+ */
+ #error pa_endianness.h was unable to automatically determine the endianness of the target platform
+ #endif
+
+#endif
+
+/* PA_VALIDATE_ENDIANNESS compares the compile time and runtime endianness,
+ and raises an assertion if they don't match. <assert.h> must be included in
+ the context in which this macro is used.
+*/
+#if defined(PA_LITTLE_ENDIAN)
+ #define PA_VALIDATE_ENDIANNESS \
+ { \
+ const long nativeOne = 1; \
+ assert( "compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 1 ); \
+ }
+#elif defined(PA_BIG_ENDIAN)
+ #define PA_VALIDATE_ENDIANNESS \
+ { \
+ const long nativeOne = 1; \
+ assert( "compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 0 ); \
+ }
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_ENDIANNESS_H */
diff --git a/pd/portaudio/pa_common/pa_front.c b/pd/portaudio/pa_common/pa_front.c
new file mode 100644
index 00000000..27293b20
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_front.c
@@ -0,0 +1,1884 @@
+/*
+ * $Id: pa_front.c,v 1.1.2.36 2003/02/28 01:49:59 rossbencina Exp $
+ * Portable Audio I/O Library Multi-Host API front end
+ * Validate function parameters and manage multiple host APIs.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+/* doxygen index page */
+/** @mainpage
+
+PortAudio is an open-source cross-platform ‘C’ library for audio input
+and output. It is designed to simplify the porting of audio applications
+between various platforms, and also to simplify the development of audio
+software in general by hiding the complexities of device interfacing.
+
+See the PortAudio website for further information http://www.portaudio.com/
+
+This documentation pertains to PortAudio V19, API version 2.0 which is
+currently under development. API version 2.0 differs in a number of ways from
+previous versions, please consult the enhancement proposals for further details:
+http://www.portaudio.com/docs/proposals/index.html
+
+This documentation is under construction. Things you might be interested in
+include:
+
+- The PortAudio API 2.0 documented in portaudio.h
+
+- The possibly incomplete and totally unorganised <a href="todo.html">Todo List</a>
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <memory.h>
+#include <string.h>
+#include <assert.h> /* needed by PA_VALIDATE_ENDIANNESS */
+
+#include "portaudio.h"
+#include "pa_util.h"
+#include "pa_endianness.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+
+#include "pa_trace.h"
+
+
+#define PA_VERSION_ 1899
+#define PA_VERSION_TEXT_ "PortAudio V19-devel"
+
+
+
+/* #define PA_LOG_API_CALLS */
+
+/*
+ The basic format for log messages is as follows:
+
+ - entry (void function):
+
+ "FunctionName called.\n"
+
+ - entry (non void function):
+
+ "FunctionName called:\n"
+ "\tParam1Type param1: param1Value\n"
+ "\tParam2Type param2: param2Value\n" (etc...)
+
+
+ - exit (no return value)
+
+ "FunctionName returned.\n"
+
+ - exit (simple return value)
+
+ "FunctionName returned:\n"
+ "\tReturnType: returnValue\n\n"
+
+ if the return type is an error code, the error text is displayed in ()
+
+ if the return type is not an error code, but has taken a special value
+ because an error occurred, then the reason for the error is shown in []
+
+ if the return type is a struct ptr, the struct is dumped.
+
+ see the code for more detailed examples
+*/
+
+int Pa_GetVersion( void )
+{
+ return PA_VERSION_;
+}
+
+
+const char* Pa_GetVersionText( void )
+{
+ return PA_VERSION_TEXT_;
+}
+
+
+
+#define PA_LAST_HOST_ERROR_TEXT_LENGTH_ 1024
+
+static char lastHostErrorText_[ PA_LAST_HOST_ERROR_TEXT_LENGTH_ + 1 ] = {0};
+
+static PaHostErrorInfo lastHostErrorInfo_ = { -1, 0, lastHostErrorText_ };
+
+
+void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
+ const char *errorText )
+{
+ lastHostErrorInfo_.hostApiType = hostApiType;
+ lastHostErrorInfo_.errorCode = errorCode;
+
+ strncpy( lastHostErrorText_, errorText, PA_LAST_HOST_ERROR_TEXT_LENGTH_ );
+}
+
+
+void PaUtil_DebugPrint( const char *format, ... )
+{
+ va_list ap;
+
+ va_start( ap, format );
+ vfprintf( stderr, format, ap );
+ va_end( ap );
+
+ fflush( stderr );
+}
+
+
+static PaUtilHostApiRepresentation **hostApis_ = 0;
+static int hostApisCount_ = 0;
+static int initializationCount_ = 0;
+static int deviceCount_ = 0;
+
+PaUtilStreamRepresentation *firstOpenStream_ = NULL;
+
+
+#define PA_IS_INITIALISED_ (initializationCount_ != 0)
+
+
+static int CountHostApiInitializers( void )
+{
+ int result = 0;
+
+ while( paHostApiInitializers[ result ] != 0 )
+ ++result;
+ return result;
+}
+
+
+static void TerminateHostApis( void )
+{
+ /* terminate in reverse order from initialization */
+
+ while( hostApisCount_ > 0 )
+ {
+ --hostApisCount_;
+ hostApis_[hostApisCount_]->Terminate( hostApis_[hostApisCount_] );
+ }
+ hostApisCount_ = 0;
+ deviceCount_ = 0;
+
+ if( hostApis_ != 0 )
+ PaUtil_FreeMemory( hostApis_ );
+ hostApis_ = 0;
+}
+
+
+static PaError InitializeHostApis( void )
+{
+ PaError result = paNoError;
+ int i, initializerCount, baseDeviceIndex;
+
+ initializerCount = CountHostApiInitializers();
+
+ hostApis_ = PaUtil_AllocateMemory( sizeof(PaUtilHostApiRepresentation*) * initializerCount );
+ if( !hostApis_ )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ hostApisCount_ = 0;
+ deviceCount_ = 0;
+ baseDeviceIndex = 0;
+
+ for( i=0; i< initializerCount; ++i )
+ {
+ hostApis_[hostApisCount_] = NULL;
+ result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ );
+ if( result != paNoError )
+ goto error;
+
+ if( hostApis_[hostApisCount_] )
+ {
+
+ hostApis_[hostApisCount_]->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;
+
+ if( hostApis_[hostApisCount_]->info.defaultInputDevice != paNoDevice )
+ hostApis_[hostApisCount_]->info.defaultInputDevice += baseDeviceIndex;
+
+ if( hostApis_[hostApisCount_]->info.defaultOutputDevice != paNoDevice )
+ hostApis_[hostApisCount_]->info.defaultOutputDevice += baseDeviceIndex;
+
+ baseDeviceIndex += hostApis_[hostApisCount_]->info.deviceCount;
+ deviceCount_ += hostApis_[hostApisCount_]->info.deviceCount;
+
+ ++hostApisCount_;
+ }
+ }
+
+ return result;
+
+error:
+ TerminateHostApis();
+ return result;
+}
+
+
+/*
+ FindHostApi() finds the index of the host api to which
+ <device> belongs and returns it. if <hostSpecificDeviceIndex> is
+ non-null, the host specific device index is returned in it.
+ returns -1 if <device> is out of range.
+
+*/
+static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex )
+{
+ int i=0;
+
+ if( !PA_IS_INITIALISED_ )
+ return -1;
+
+ if( device < 0 )
+ return -1;
+
+ while( i < hostApisCount_
+ && device >= hostApis_[i]->info.deviceCount )
+ {
+
+ device -= hostApis_[i]->info.deviceCount;
+ ++i;
+ }
+
+ if( i >= hostApisCount_ )
+ return -1;
+
+ if( hostSpecificDeviceIndex )
+ *hostSpecificDeviceIndex = device;
+
+ return i;
+}
+
+
+static void AddOpenStream( PaStream* stream )
+{
+ ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_;
+ firstOpenStream_ = (PaUtilStreamRepresentation*)stream;
+}
+
+
+static void RemoveOpenStream( PaStream* stream )
+{
+ PaUtilStreamRepresentation *previous = NULL;
+ PaUtilStreamRepresentation *current = firstOpenStream_;
+
+ while( current != NULL )
+ {
+ if( ((PaStream*)current) == stream )
+ {
+ if( previous == NULL )
+ {
+ firstOpenStream_ = current->nextOpenStream;
+ }
+ else
+ {
+ previous->nextOpenStream = current->nextOpenStream;
+ }
+ return;
+ }
+ else
+ {
+ previous = current;
+ current = current->nextOpenStream;
+ }
+ }
+}
+
+
+static void CloseOpenStreams( void )
+{
+ /* we call Pa_CloseStream() here to ensure that the same destruction
+ logic is used for automatically closed streams */
+
+ while( firstOpenStream_ != NULL )
+ Pa_CloseStream( firstOpenStream_ );
+}
+
+
+PaError Pa_Initialize( void )
+{
+ PaError result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint( "Pa_Initialize called.\n" );
+#endif
+
+ if( PA_IS_INITIALISED_ )
+ {
+ ++initializationCount_;
+ result = paNoError;
+ }
+ else
+ {
+ PA_VALIDATE_ENDIANNESS;
+
+ PaUtil_InitializeClock();
+ PaUtil_ResetTraceMessages();
+
+ result = InitializeHostApis();
+ if( result == paNoError )
+ ++initializationCount_;
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint( "Pa_Initialize returned:\n" );
+ PaUtil_DebugPrint( "\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_Terminate( void )
+{
+ PaError result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_Terminate called.\n" );
+#endif
+
+ if( PA_IS_INITIALISED_ )
+ {
+ if( --initializationCount_ == 0 )
+ {
+ CloseOpenStreams();
+
+ TerminateHostApis();
+
+ PaUtil_DumpTraceMessages();
+ }
+ result = paNoError;
+ }
+ else
+ {
+ result= paNotInitialized;
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_Terminate returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void )
+{
+ return &lastHostErrorInfo_;
+}
+
+
+const char *Pa_GetErrorText( PaError errorNumber )
+{
+ const char *result;
+
+ switch( errorNumber )
+ {
+ case paNoError: result = "Success"; break;
+ case paNotInitialized: result = "PortAudio not initialized"; break;
+ /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError */
+ case paUnanticipatedHostError: result = "Unanticipated host error"; break;
+ case paInvalidChannelCount: result = "Invalid number of channels"; break;
+ case paInvalidSampleRate: result = "Invalid sample rate"; break;
+ case paInvalidDevice: result = "Invalid device"; break;
+ case paInvalidFlag: result = "Invalid flag"; break;
+ case paSampleFormatNotSupported: result = "Sample format not supported"; break;
+ case paBadIODeviceCombination: result = "Illegal combination of I/O devices"; break;
+ case paInsufficientMemory: result = "Insufficient memory"; break;
+ case paBufferTooBig: result = "Buffer too big"; break;
+ case paBufferTooSmall: result = "Buffer too small"; break;
+ case paNullCallback: result = "No callback routine specified"; break;
+ case paBadStreamPtr: result = "Invalid stream pointer"; break;
+ case paTimedOut: result = "Wait timed out"; break;
+ case paInternalError: result = "Internal PortAudio error"; break;
+ case paDeviceUnavailable: result = "Device unavailable"; break;
+ case paIncompatibleHostApiSpecificStreamInfo: result = "Incompatible host API specific stream info"; break;
+ case paStreamIsStopped: result = "Stream is stopped"; break;
+ case paStreamIsNotStopped: result = "Stream is not stopped"; break;
+ default: result = "Illegal error number"; break;
+ }
+ return result;
+}
+
+
+PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type )
+{
+ PaHostApiIndex result;
+ int i;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex called:\n" );
+ PaUtil_DebugPrint("\PaHostApiTypeId type: %d\n", type );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+
+ result = -1;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex: -1 [ PortAudio not initialized ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ result = -1;
+
+ for( i=0; i < hostApisCount_; ++i )
+ {
+ if( hostApis_[i]->info.type == type )
+ {
+ result = i;
+ break;
+ }
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex: %d\n\n", result );
+#endif
+ }
+
+ return result;
+}
+
+
+PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,
+ PaHostApiTypeId type )
+{
+ PaError result;
+ int i;
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNotInitialized;
+ }
+ else
+ {
+ result = paInternalError; /* @todo should return host API not found */
+
+ for( i=0; i < hostApisCount_; ++i )
+ {
+ if( hostApis_[i]->info.type == type )
+ {
+ *hostApi = hostApis_[i];
+ result = paNoError;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+PaError PaUtil_DeviceIndexToHostApiDeviceIndex(
+ PaDeviceIndex *hostApiDevice, PaDeviceIndex device, struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaError result;
+ PaDeviceIndex x;
+
+ x = device - hostApi->privatePaFrontInfo.baseDeviceIndex;
+
+ if( x < 0 || x >= hostApi->info.deviceCount )
+ {
+ result = paInvalidDevice;
+ }
+ else
+ {
+ *hostApiDevice = x;
+ result = paNoError;
+ }
+
+ return result;
+}
+
+
+PaHostApiIndex Pa_CountHostApis( void )
+{
+ int result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountHostApis called.\n" );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNotInitialized;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountHostApis returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+ }
+ else
+ {
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountHostApis returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", hostApisCount_ );
+#endif
+
+ return hostApisCount_;
+ }
+}
+
+
+PaHostApiIndex Pa_GetDefaultHostApi( void )
+{
+ int result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultHostApi called.\n" );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNotInitialized;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+ }
+ else
+ {
+ result = paDefaultHostApiIndex;
+
+ /* internal consistency check: make sure that the default host api
+ index is within range */
+
+ if( result < 0 || result >= hostApisCount_ )
+ {
+ result = paInternalError;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ }
+ else
+ {
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", result );
+#endif
+ }
+
+ return result;
+ }
+}
+
+
+const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi )
+{
+ PaHostApiInfo *info;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetHostApiInfo called:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ info = NULL;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ PortAudio not initialized ]\n\n" );
+#endif
+
+ }
+ else if( hostApi < 0 || hostApi >= hostApisCount_ )
+ {
+ info = NULL;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ info = &hostApis_[hostApi]->info;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiInfo*: 0x%p\n", info );
+ PaUtil_DebugPrint("\t{" );
+ PaUtil_DebugPrint("\t\tint structVersion: %d\n", info->structVersion );
+ PaUtil_DebugPrint("\t\tPaHostApiTypeId type: %d\n", info->type );
+ PaUtil_DebugPrint("\t\tconst char *name: %s\n\n", info->name );
+ PaUtil_DebugPrint("\t}\n\n" );
+#endif
+
+ }
+
+ return info;
+}
+
+
+PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int hostApiDeviceIndex )
+{
+ PaDeviceIndex result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex called:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi );
+ PaUtil_DebugPrint("\tint hostApiDeviceIndex: %d\n", hostApiDeviceIndex );
+#endif
+
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNoDevice;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: paNoDevice [ PortAudio not initialized ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ if( hostApi < 0 || hostApi >= hostApisCount_ )
+ {
+ result = paNoDevice;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: paNoDevice [ hostApi out of range ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ if( hostApiDeviceIndex < 0 ||
+ hostApiDeviceIndex >= hostApis_[hostApi]->info.deviceCount )
+ {
+ result = paNoDevice;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: paNoDevice [ hostApiDeviceIndex out of range ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ result = hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
+#endif
+ }
+ }
+ }
+
+ return result;
+}
+
+
+PaDeviceIndex Pa_CountDevices( void )
+{
+ PaDeviceIndex result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountDevices called.\n" );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = 0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountDevices returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: 0 [ PortAudio not initialized ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ result = deviceCount_;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountDevices returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
+#endif
+
+ }
+
+ return result;
+}
+
+
+PaDeviceIndex Pa_GetDefaultInputDevice( void )
+{
+ PaHostApiIndex hostApi;
+ PaDeviceIndex result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultInputDevice called.\n" );
+#endif
+
+ hostApi = Pa_GetDefaultHostApi();
+ if( hostApi < 0 )
+ {
+ result = paNoDevice;
+ }
+ else
+ {
+ result = hostApis_[hostApi]->info.defaultInputDevice;
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultInputDevice returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
+#endif
+
+ return result;
+}
+
+
+PaDeviceIndex Pa_GetDefaultOutputDevice( void )
+{
+ PaHostApiIndex hostApi;
+ PaDeviceIndex result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultOutputDevice called.\n" );
+#endif
+
+ hostApi = Pa_GetDefaultHostApi();
+ if( hostApi < 0 )
+ {
+ result = paNoDevice;
+ }
+ else
+ {
+ result = hostApis_[hostApi]->info.defaultOutputDevice;
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultOutputDevice returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
+#endif
+
+ return result;
+}
+
+
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
+{
+ int hostSpecificDeviceIndex;
+ int hostApiIndex = FindHostApi( device, &hostSpecificDeviceIndex );
+ PaDeviceInfo *result;
+
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDeviceInfo called:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex device: %d\n", device );
+#endif
+
+ if( hostApiIndex < 0 )
+ {
+ result = NULL;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceInfo* NULL [ invalid device index ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ result = hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ];
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceInfo*: 0x%p:\n", result );
+ PaUtil_DebugPrint("\t{" );
+
+ PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion );
+ PaUtil_DebugPrint("\t\tconst char *name: %s\n", result->name );
+ PaUtil_DebugPrint("\t\tPaHostApiIndex hostApi: %d\n", result->hostApi );
+ PaUtil_DebugPrint("\t\tint maxInputChannels: %d\n", result->maxInputChannels );
+ PaUtil_DebugPrint("\t\tint maxOutputChannels: %d\n", result->maxOutputChannels );
+ PaUtil_DebugPrint("\t}\n\n" );
+#endif
+
+ }
+
+ return result;
+}
+
+
+/*
+ SampleFormatIsValid() returns 1 if sampleFormat is a sample format
+ defined in portaudio.h, or 0 otherwise.
+*/
+static int SampleFormatIsValid( PaSampleFormat format )
+{
+ switch( format & ~paNonInterleaved )
+ {
+ case paFloat32: return 1;
+ case paInt16: return 1;
+ case paInt32: return 1;
+ case paInt24: return 1;
+ case paInt8: return 1;
+ case paUInt8: return 1;
+ case paCustomFormat: return 1;
+ default: return 0;
+ }
+}
+
+/*
+ NOTE: make sure this validation list is kept syncronised with the one in
+ pa_hostapi.h
+
+ ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream()
+ conform to the expected values as described below. This function is
+ also designed to be used with the proposed Pa_IsFormatSupported() function.
+
+ There are basically two types of validation that could be performed:
+ Generic conformance validation, and device capability mismatch
+ validation. This function performs only generic conformance validation.
+ Validation that would require knowledge of device capabilities is
+ not performed because of potentially complex relationships between
+ combinations of parameters - for example, even if the sampleRate
+ seems ok, it might not be for a duplex stream - we have no way of
+ checking this in an API-neutral way, so we don't try.
+
+ On success the function returns PaNoError and fills in hostApi,
+ hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure
+ the function returns an error code indicating the first encountered
+ parameter error.
+
+
+ If ValidateOpenStreamParameters() returns paNoError, the following
+ assertions are guaranteed to be true.
+
+ - at least one of inputParameters & outputParmeters is valid (not NULL)
+
+ - if inputParameters & outputParmeters are both valid, that
+ inputParameters->device & outputParmeters->device both use the same host api
+
+ PaDeviceIndex inputParameters->device
+ - is within range (0 to Pa_CountDevices-1) Or:
+ - is paUseHostApiSpecificDeviceSpecification and
+ inputParameters->hostApiSpecificStreamInfo is non-NULL and refers
+ to a valid host api
+
+ int inputParameters->channelCount
+ - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0
+ - upper bound is NOT validated against device capabilities
+
+ PaSampleFormat inputParameters->sampleFormat
+ - is one of the sample formats defined in portaudio.h
+
+ void *inputParameters->hostApiSpecificStreamInfo
+ - if supplied its hostApi field matches the input device's host Api
+
+ PaDeviceIndex outputParmeters->device
+ - is within range (0 to Pa_CountDevices-1)
+
+ int outputParmeters->channelCount
+ - if inputDevice is valid, channelCount is > 0
+ - upper bound is NOT validated against device capabilities
+
+ PaSampleFormat outputParmeters->sampleFormat
+ - is one of the sample formats defined in portaudio.h
+
+ void *outputParmeters->hostApiSpecificStreamInfo
+ - if supplied its hostApi field matches the output device's host Api
+
+ double sampleRate
+ - is not an 'absurd' rate (less than 1000. or greater than 200000.)
+ - sampleRate is NOT validated against device capabilities
+
+ PaStreamFlags streamFlags
+ - unused platform neutral flags are zero
+*/
+static PaError ValidateOpenStreamParameters(
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ PaStreamFlags streamFlags,
+ PaUtilHostApiRepresentation **hostApi,
+ PaDeviceIndex *hostApiInputDevice,
+ PaDeviceIndex *hostApiOutputDevice )
+{
+ int inputHostApiIndex=0, outputHostApiIndex=0;
+
+ if( (inputParameters == NULL) && (outputParameters == NULL) )
+ {
+
+ return paInvalidDevice; /* @todo should be a new error code "invalid device parameters" or something */
+
+ }
+ else
+ {
+ if( inputParameters == NULL )
+ {
+ *hostApiInputDevice = paNoDevice;
+ }
+ else if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ {
+ if( inputParameters->hostApiSpecificStreamInfo )
+ {
+ inputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(
+ ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType );
+
+ if( inputHostApiIndex != -1 )
+ {
+ *hostApiInputDevice = paUseHostApiSpecificDeviceSpecification;
+ *hostApi = hostApis_[inputHostApiIndex];
+ }
+ else
+ {
+ return paInvalidDevice;
+ }
+ }
+ else
+ {
+ return paInvalidDevice;
+ }
+ }
+ else
+ {
+ if( inputParameters->device < 0 || inputParameters->device >= deviceCount_ )
+ return paInvalidDevice;
+
+ inputHostApiIndex = FindHostApi( inputParameters->device, hostApiInputDevice );
+ if( inputHostApiIndex < 0 )
+ return paInternalError;
+
+ *hostApi = hostApis_[inputHostApiIndex];
+
+ if( inputParameters->channelCount <= 0 )
+ return paInvalidChannelCount;
+
+ if( !SampleFormatIsValid( inputParameters->sampleFormat ) )
+ return paSampleFormatNotSupported;
+
+ if( inputParameters->hostApiSpecificStreamInfo != NULL )
+ {
+ if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType
+ != (*hostApi)->info.type )
+ return paIncompatibleHostApiSpecificStreamInfo;
+ }
+ }
+
+ if( outputParameters == NULL )
+ {
+ *hostApiOutputDevice = paNoDevice;
+ }
+ else if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ {
+ if( outputParameters->hostApiSpecificStreamInfo )
+ {
+ outputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(
+ ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType );
+
+ if( outputHostApiIndex != -1 )
+ {
+ *hostApiOutputDevice = paUseHostApiSpecificDeviceSpecification;
+ *hostApi = hostApis_[outputHostApiIndex];
+ }
+ else
+ {
+ return paInvalidDevice;
+ }
+ }
+ else
+ {
+ return paInvalidDevice;
+ }
+ }
+ else
+ {
+ if( outputParameters->device < 0 || outputParameters->device >= deviceCount_ )
+ return paInvalidDevice;
+
+ outputHostApiIndex = FindHostApi( outputParameters->device, hostApiOutputDevice );
+ if( outputHostApiIndex < 0 )
+ return paInternalError;
+
+ *hostApi = hostApis_[outputHostApiIndex];
+
+ if( outputParameters->channelCount <= 0 )
+ return paInvalidChannelCount;
+
+ if( !SampleFormatIsValid( outputParameters->sampleFormat ) )
+ return paSampleFormatNotSupported;
+
+ if( outputParameters->hostApiSpecificStreamInfo != NULL )
+ {
+ if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType
+ != (*hostApi)->info.type )
+ return paIncompatibleHostApiSpecificStreamInfo;
+ }
+ }
+
+ if( (inputParameters != NULL) && (outputParameters != NULL) )
+ {
+ /* ensure that both devices use the same API */
+ if( inputHostApiIndex != outputHostApiIndex )
+ return paBadIODeviceCombination;
+ }
+ }
+
+
+ /* Check for absurd sample rates. */
+ if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
+ return paInvalidSampleRate;
+
+ if( ((streamFlags & ~paPlatformSpecificFlags) & ~(paClipOff | paDitherOff | paNeverDropInput | paPrimeOutputBuffersUsingStreamCallback ) ) != 0 )
+ return paInvalidFlag;
+
+ return paNoError;
+}
+
+
+PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
+{
+ PaError result;
+ PaUtilHostApiRepresentation *hostApi;
+ PaDeviceIndex hostApiInputDevice, hostApiOutputDevice;
+ PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
+ PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
+
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsFormatSupported called:\n" );
+
+ if( inputParameters == NULL ){
+ PaUtil_DebugPrint("\PaStreamParameters *inputParameters: NULL\n" );
+ }else{
+ PaUtil_DebugPrint("\PaStreamParameters *inputParameters: 0x%p\n", inputParameters );
+ PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device );
+ PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount );
+ PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat );
+ PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency );
+ PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo );
+ }
+
+ if( outputParameters == NULL ){
+ PaUtil_DebugPrint("\PaStreamParameters *outputParameters: NULL\n" );
+ }else{
+ PaUtil_DebugPrint("\PaStreamParameters *outputParameters: 0x%p\n", outputParameters );
+ PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device );
+ PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount );
+ PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat );
+ PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency );
+ PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo );
+ }
+
+ PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNotInitialized;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ return result;
+ }
+
+ result = ValidateOpenStreamParameters( inputParameters,
+ outputParameters,
+ sampleRate, paNoFlag,
+ &hostApi,
+ &hostApiInputDevice,
+ &hostApiOutputDevice );
+ if( result != paNoError )
+ {
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ return result;
+ }
+
+
+ if( inputParameters )
+ {
+ hostApiInputParameters.device = hostApiInputDevice;
+ hostApiInputParameters.channelCount = inputParameters->channelCount;
+ hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;
+ hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;
+ hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;
+ hostApiInputParametersPtr = &hostApiInputParameters;
+ }
+ else
+ {
+ hostApiInputParametersPtr = NULL;
+ }
+
+ if( outputParameters )
+ {
+ hostApiOutputParameters.device = hostApiOutputDevice;
+ hostApiOutputParameters.channelCount = outputParameters->channelCount;
+ hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;
+ hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;
+ hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;
+ hostApiOutputParametersPtr = &hostApiOutputParameters;
+ }
+ else
+ {
+ hostApiOutputParametersPtr = NULL;
+ }
+
+ result = hostApi->IsFormatSupported( hostApi,
+ hostApiInputParametersPtr, hostApiOutputParametersPtr,
+ sampleRate );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
+ if( result == paFormatIsSupported )
+ PaUtil_DebugPrint("\tPaError: 0 [ paFormatIsSupported ]\n\n" );
+ else
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_OpenStream( PaStream** stream,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result;
+ PaUtilHostApiRepresentation *hostApi;
+ PaDeviceIndex hostApiInputDevice, hostApiOutputDevice;
+ PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
+ PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
+
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream );
+
+ if( inputParameters == NULL ){
+ PaUtil_DebugPrint("\PaStreamParameters *inputParameters: NULL\n" );
+ }else{
+ PaUtil_DebugPrint("\PaStreamParameters *inputParameters: 0x%p\n", inputParameters );
+ PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device );
+ PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount );
+ PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat );
+ PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency );
+ PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo );
+ }
+
+ if( outputParameters == NULL ){
+ PaUtil_DebugPrint("\PaStreamParameters *outputParameters: NULL\n" );
+ }else{
+ PaUtil_DebugPrint("\PaStreamParameters *outputParameters: 0x%p\n", outputParameters );
+ PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device );
+ PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount );
+ PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat );
+ PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency );
+ PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo );
+ }
+
+ PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
+ PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer );
+ PaUtil_DebugPrint("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags );
+ PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback );
+ PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNotInitialized;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
+ PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ return result;
+ }
+
+ /* Check for parameter errors. */
+
+ if( stream == NULL )
+ {
+ result = paBadStreamPtr;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
+ PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ return result;
+ }
+
+ result = ValidateOpenStreamParameters( inputParameters,
+ outputParameters,
+ sampleRate, streamFlags,
+ &hostApi,
+ &hostApiInputDevice,
+ &hostApiOutputDevice );
+ if( result != paNoError )
+ {
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
+ PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ return result;
+ }
+
+
+ if( inputParameters )
+ {
+ hostApiInputParameters.device = hostApiInputDevice;
+ hostApiInputParameters.channelCount = inputParameters->channelCount;
+ hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;
+ hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;
+ hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;
+ hostApiInputParametersPtr = &hostApiInputParameters;
+ }
+ else
+ {
+ hostApiInputParametersPtr = NULL;
+ }
+
+ if( outputParameters )
+ {
+ hostApiOutputParameters.device = hostApiOutputDevice;
+ hostApiOutputParameters.channelCount = outputParameters->channelCount;
+ hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;
+ hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;
+ hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;
+ hostApiOutputParametersPtr = &hostApiOutputParameters;
+ }
+ else
+ {
+ hostApiOutputParametersPtr = NULL;
+ }
+
+ result = hostApi->OpenStream( hostApi, stream,
+ hostApiInputParametersPtr, hostApiOutputParametersPtr,
+ sampleRate, framesPerBuffer, streamFlags, streamCallback, userData );
+
+ if( result == paNoError )
+ AddOpenStream( *stream );
+
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
+ PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p\n", *stream );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_OpenDefaultStream( PaStream** stream,
+ int inputChannelCount,
+ int outputChannelCount,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result;
+ PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
+ PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenDefaultStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream );
+ PaUtil_DebugPrint("\tint inputChannelCount: %d\n", inputChannelCount );
+ PaUtil_DebugPrint("\tint outputChannelCount: %d\n", outputChannelCount );
+ PaUtil_DebugPrint("\tPaSampleFormat sampleFormat: %d\n", sampleFormat );
+ PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
+ PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer );
+ PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback );
+ PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData );
+#endif
+
+
+ if( inputChannelCount > 0 )
+ {
+ hostApiInputParameters.device = Pa_GetDefaultInputDevice();
+ hostApiInputParameters.channelCount = inputChannelCount;
+ hostApiInputParameters.sampleFormat = sampleFormat;
+ hostApiInputParameters.suggestedLatency = /* REVIEW: should we be using high input latency here? */
+ Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency;
+ hostApiInputParameters.hostApiSpecificStreamInfo = NULL;
+ hostApiInputParametersPtr = &hostApiInputParameters;
+ }
+ else
+ {
+ hostApiInputParametersPtr = NULL;
+ }
+
+ if( outputChannelCount > 0 )
+ {
+ hostApiOutputParameters.device = Pa_GetDefaultOutputDevice();
+ hostApiOutputParameters.channelCount = outputChannelCount;
+ hostApiOutputParameters.sampleFormat = sampleFormat;
+ hostApiOutputParameters.suggestedLatency = /* REVIEW: should we be using high input latency here? */
+ Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency;
+ hostApiOutputParameters.hostApiSpecificStreamInfo = NULL;
+ hostApiOutputParametersPtr = &hostApiOutputParameters;
+ }
+ else
+ {
+ hostApiOutputParametersPtr = NULL;
+ }
+
+
+ result = Pa_OpenStream(
+ stream, hostApiInputParametersPtr, hostApiOutputParametersPtr,
+ sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenDefaultStream returned:\n" );
+ PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p", *stream );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+static PaError ValidateStream( PaStream* stream )
+{
+ if( !PA_IS_INITIALISED_ ) return paNotInitialized;
+
+ if( stream == NULL ) return paBadStreamPtr;
+
+ if( ((PaUtilStreamRepresentation*)stream)->magic != PA_STREAM_MAGIC )
+ return paBadStreamPtr;
+
+ return paNoError;
+}
+
+
+PaError Pa_CloseStream( PaStream* stream )
+{
+ PaUtilStreamInterface *interface;
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CloseStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ /* always remove the open stream from our list, even if this function
+ eventually returns an error. Otherwise CloseOpenStreams() will
+ get stuck in an infinite loop */
+ RemoveOpenStream( stream ); /* be sure to call this _before_ closing the stream */
+
+ if( result == paNoError )
+ {
+ interface = PA_STREAM_INTERFACE(stream);
+ if( !interface->IsStopped( stream ) )
+ {
+ result = interface->Abort( stream );
+ }
+
+ if( result == paNoError ) /* REVIEW: shouldn't we close anyway? */
+ result = interface->Close( stream );
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CloseStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_SetStreamFinishedCallback called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+ PaUtil_DebugPrint("\tPaStreamFinishedCallback* streamFinishedCallback: 0x%p\n", streamFinishedCallback );
+#endif
+
+ if( result == paNoError )
+ {
+ if( !PA_STREAM_INTERFACE(stream)->IsStopped( stream ) )
+ {
+ result = paStreamIsNotStopped ;
+ }
+ else
+ {
+ PA_STREAM_REP( stream )->streamFinishedCallback = streamFinishedCallback;
+ }
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_SetStreamFinishedCallback returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+
+}
+
+
+PaError Pa_StartStream( PaStream *stream )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_StartStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( result == paNoError )
+ {
+ if( !PA_STREAM_INTERFACE(stream)->IsStopped( stream ) )
+ {
+ result = paStreamIsNotStopped ;
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->Start( stream );
+ }
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_StartStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_StopStream( PaStream *stream )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_StopStream called\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( result == paNoError )
+ {
+ if( PA_STREAM_INTERFACE(stream)->IsStopped( stream ) )
+ {
+ result = paStreamIsStopped;
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->Stop( stream );
+ }
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_StopStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_AbortStream( PaStream *stream )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_AbortStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( result == paNoError )
+ {
+ if( PA_STREAM_INTERFACE(stream)->IsStopped( stream ) )
+ {
+ result = paStreamIsStopped;
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->Abort( stream );
+ }
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_AbortStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_IsStreamStopped( PaStream *stream )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsStreamStopped called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( result == paNoError )
+ result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsStreamStopped returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_IsStreamActive( PaStream *stream )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsStreamActive called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( result == paNoError )
+ result = PA_STREAM_INTERFACE(stream)->IsActive( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsStreamActive returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream )
+{
+ PaError error = ValidateStream( stream );
+ const PaStreamInfo *result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamInfo called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( error != paNoError )
+ {
+ result = 0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" );
+ PaUtil_DebugPrint("\const PaStreamInfo*: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) );
+#endif
+
+ }
+ else
+ {
+ result = &PA_STREAM_REP( stream )->streamInfo;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" );
+ PaUtil_DebugPrint("\tconst PaStreamInfo*: 0x%p:\n", result );
+ PaUtil_DebugPrint("\t{" );
+
+ PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion );
+ PaUtil_DebugPrint("\t\tPaTime inputLatency: %f\n", result->inputLatency );
+ PaUtil_DebugPrint("\t\tPaTime outputLatency: %f\n", result->outputLatency );
+ PaUtil_DebugPrint("\t\tdouble sampleRate: %f\n", result->sampleRate );
+ PaUtil_DebugPrint("\t}\n\n" );
+#endif
+
+ }
+
+ return result;
+}
+
+
+PaTime Pa_GetStreamTime( PaStream *stream )
+{
+ PaError error = ValidateStream( stream );
+ PaTime result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamTime called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( error != paNoError )
+ {
+ result = 0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" );
+ PaUtil_DebugPrint("\tPaTime: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) );
+#endif
+
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->GetTime( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" );
+ PaUtil_DebugPrint("\tPaTime: %g\n\n", result );
+#endif
+
+ }
+
+ return result;
+}
+
+
+double Pa_GetStreamCpuLoad( PaStream* stream )
+{
+ PaError error = ValidateStream( stream );
+ double result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamCpuLoad called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( error != paNoError )
+ {
+
+ result = 0.0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" );
+ PaUtil_DebugPrint("\tdouble: 0.0 [PaError error: %d ( %s )]\n\n", error, Pa_GetErrorText( error ) );
+#endif
+
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->GetCpuLoad( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" );
+ PaUtil_DebugPrint("\tdouble: %g\n\n", result );
+#endif
+
+ }
+
+ return result;
+}
+
+
+PaError Pa_ReadStream( PaStream* stream,
+ void *buffer,
+ unsigned long frames )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_ReadStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ /* @todo should return an error if buffer is zero or frames <= 0 */
+ if( frames > 0 && buffer != 0 )
+ result = PA_STREAM_INTERFACE(stream)->Read( stream, buffer, frames );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_ReadStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_WriteStream( PaStream* stream,
+ void *buffer,
+ unsigned long frames )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_WriteStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ /* @todo should return an error if buffer is zero or frames <= 0 */
+ if( frames > 0 && buffer != 0 )
+ result = PA_STREAM_INTERFACE(stream)->Write( stream, buffer, frames );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_WriteStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+signed long Pa_GetStreamReadAvailable( PaStream* stream )
+{
+ PaError error = ValidateStream( stream );
+ signed long result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamReadAvailable called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( error != paNoError )
+ {
+ result = 0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" );
+ PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) );
+#endif
+
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->GetReadAvailable( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ }
+
+ return result;
+}
+
+
+signed long Pa_GetStreamWriteAvailable( PaStream* stream )
+{
+ PaError error = ValidateStream( stream );
+ signed long result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamWriteAvailable called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( error != paNoError )
+ {
+ result = 0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" );
+ PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) );
+#endif
+
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->GetWriteAvailable( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ }
+
+ return result;
+}
+
+
+PaError Pa_GetSampleSize( PaSampleFormat format )
+{
+ int result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetSampleSize called:\n" );
+ PaUtil_DebugPrint("\tPaSampleFormat format: %d\n", format );
+#endif
+
+ switch( format & ~paNonInterleaved )
+ {
+
+ case paUInt8:
+ case paInt8:
+ result = 1;
+ break;
+
+ case paInt16:
+ result = 2;
+ break;
+
+ case paInt24:
+ result = 3;
+ break;
+
+ case paFloat32:
+ case paInt32:
+ result = 4;
+ break;
+
+ default:
+ result = paSampleFormatNotSupported;
+ break;
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetSampleSize returned:\n" );
+ if( result > 0 )
+ PaUtil_DebugPrint("\tint: %d\n\n", result );
+ else
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return (PaError) result;
+}
+
diff --git a/pd/portaudio/pa_common/pa_front.o b/pd/portaudio/pa_common/pa_front.o
new file mode 100644
index 00000000..0ce74a68
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_front.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_hostapi.h b/pd/portaudio/pa_common/pa_hostapi.h
new file mode 100644
index 00000000..f1f7a7ea
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_hostapi.h
@@ -0,0 +1,238 @@
+#ifndef PA_HOSTAPI_H
+#define PA_HOSTAPI_H
+/*
+ *
+ * Portable Audio I/O Library
+ * host api representation
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+/** @file
+ Virtualised host api mechanism used by pa_front.
+*/
+
+#include "portaudio.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+typedef struct PaUtilPrivatePaFrontHostApiInfo {
+/* **for the use of pa_front.c only**
+ don't use fields in this structure, they my change at any time
+ use functions defined in pa_util.h if you think you need functionality
+ which can be derived from here
+*/
+
+ unsigned long baseDeviceIndex;
+}PaUtilPrivatePaFrontHostApiInfo;
+
+
+/** The common header for all data structures whose pointers are passed through
+ the hostApiSpecificStreamInfo field of the PaStreamParameters structure.
+ Note that in order to keep the public PortAudio interface clean, this structure
+ is not used explicitly when declaring hostApiSpecificStreamInfo data structures
+ however some code in pa_front depends on the first 3 members being equivalent
+ with this structure.
+ @see PaStreamParameters
+*/
+typedef struct PaUtilHostApiSpecificStreamInfoHeader
+{
+ unsigned long size; /**< size of whole structure including this header */
+ PaHostApiTypeId hostApiType; /**< host API for which this data is intended */
+ unsigned long version; /**< structure version */
+} PaUtilHostApiSpecificStreamInfoHeader;
+
+
+
+/*
+ PaUtilHostApiRepresentation must be implemented by each host api implementation.
+
+*/
+
+typedef struct PaUtilHostApiRepresentation {
+ PaUtilPrivatePaFrontHostApiInfo privatePaFrontInfo;
+
+ /**
+ The host api implementation should populate the info field. In the
+ case of info.defaultInputDevice and info.defaultOutputDevice the
+ values stored should be 0 based indicies within the host api's own
+ device index range (0 to deviceCount). These values will be converted
+ to global device indicies after PaUtilHostApiInitializer() returns.
+ */
+ PaHostApiInfo info;
+
+ PaDeviceInfo** deviceInfos;
+
+ /**
+ (*Terminate)() is guaranteed to be called with a valid <hostApi>
+ parameter, which was previously returned from the same implementation's
+ initializer.
+ */
+ void (*Terminate)( struct PaUtilHostApiRepresentation *hostApi );
+
+ /**
+ The inputParameters and outputParameters pointers should not be saved
+ as they will not remain valid after OpenStream is called.
+
+
+ The following guarantees are made about parameters to (*OpenStream)():
+
+ [NOTE: the following list up to *END PA FRONT VALIDATIONS* should be
+ kept in sync with the one for ValidateOpenStreamParameters and
+ Pa_OpenStream in pa_front.c]
+
+ PaHostApiRepresentation *hostApi
+ - is valid for this implementation
+
+ PaStream** stream
+ - is non-null
+
+ - at least one of inputParameters & outputParmeters is valid (not NULL)
+
+ - if inputParameters & outputParmeters are both valid, that
+ inputParameters->device & outputParmeters->device both use the same host api
+
+ PaDeviceIndex inputParameters->device
+ - is within range (0 to Pa_CountDevices-1) Or:
+ - is paUseHostApiSpecificDeviceSpecification and
+ inputParameters->hostApiSpecificStreamInfo is non-NULL and refers
+ to a valid host api
+
+ int inputParameters->numChannels
+ - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, numInputChannels is > 0
+ - upper bound is NOT validated against device capabilities
+
+ PaSampleFormat inputParameters->sampleFormat
+ - is one of the sample formats defined in portaudio.h
+
+ void *inputParameters->hostApiSpecificStreamInfo
+ - if supplied its hostApi field matches the input device's host Api
+
+ PaDeviceIndex outputParmeters->device
+ - is within range (0 to Pa_CountDevices-1)
+
+ int outputParmeters->numChannels
+ - if inputDevice is valid, numInputChannels is > 0
+ - upper bound is NOT validated against device capabilities
+
+ PaSampleFormat outputParmeters->sampleFormat
+ - is one of the sample formats defined in portaudio.h
+
+ void *outputParmeters->hostApiSpecificStreamInfo
+ - if supplied its hostApi field matches the output device's host Api
+
+ double sampleRate
+ - is not an 'absurd' rate (less than 1000. or greater than 200000.)
+ - sampleRate is NOT validated against device capabilities
+
+ PaStreamFlags streamFlags
+ - unused platform neutral flags are zero
+
+ [*END PA FRONT VALIDATIONS*]
+
+
+ The following validations MUST be performed by (*OpenStream)():
+
+ - check that input device can support numInputChannels
+
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if inputStreamInfo is supplied, validate its contents,
+ or return an error if no inputStreamInfo is expected
+
+ - check that output device can support numOutputChannels
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if outputStreamInfo is supplied, validate its contents,
+ or return an error if no outputStreamInfo is expected
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+
+ - alter sampleRate to a close allowable rate if necessary
+
+ - validate inputLatency and outputLatency
+
+ - validate any platform specific flags, if flags are supplied they
+ must be valid.
+ */
+ PaError (*OpenStream)( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** stream,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerCallback,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData );
+
+
+ PaError (*IsFormatSupported)( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate );
+} PaUtilHostApiRepresentation;
+
+
+/**
+ every host api implementation must supply a host api initializer in the
+ following form.
+*/
+typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex );
+
+
+/**
+ paHostApiInitializers is a NULL-terminated array of host api initializers
+ for the host apis which will be initialized when Pa_Initialize() is called.
+ each platform has a file which defines paHostApiInitializers for that platform.
+ see pa_win_init.c for example.
+*/
+extern PaUtilHostApiInitializer *paHostApiInitializers[];
+
+
+/** index of the default host API in the paHostApiInitializers array. Each
+ platform has a file which defines paDefaultHostApiIndex for that platform.
+ see pa_win_init.c for example.
+*/
+extern int paDefaultHostApiIndex;
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_HOSTAPI_H */
diff --git a/pd/portaudio/pa_common/pa_process.c b/pd/portaudio/pa_common/pa_process.c
new file mode 100644
index 00000000..2fbeb277
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_process.c
@@ -0,0 +1,1355 @@
+/*
+ * $Id: pa_process.c,v 1.1.2.28 2002/10/26 05:33:29 rossbencina Exp $
+ * Portable Audio I/O Library
+ * streamCallback <-> host buffer processing adapter
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include <assert.h>
+#include <string.h> /* memset() */
+
+#include "pa_process.h"
+#include "pa_util.h"
+
+/** @file
+ The code in this file is not optimised yet. there may appear to be redundancies
+ that could be factored into common functions, but the redundanceis are left
+ intentionally as each appearance may have different optimisation possibilities.
+
+ The optimisations which are planned involve only converting data in-place
+ where possible, rather than copying to the temp buffer(s).
+
+ Note that in the extreme case of being able to convert in-place, and there
+ being no conversion necessary there should be some code which short-circuits
+ the operation.
+
+ Cache tilings for intereave<->deinterleave also need to be considered.
+
+ @todo The abort flag from the streamCallback is currently not honoured properly
+ in this file, see fixmes.
+
+ @todo see FIXMEs
+
+ @todo implement the streamFlags callback parameter, currently it is
+ always zero. It needs to be passed from the host layer somehow.
+*/
+
+#define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_ 1024
+
+
+/* greatest common divisor - PGCD in french */
+static unsigned long GCD( unsigned long a, unsigned long b )
+{
+ return (b==0) ? a : GCD( b, a%b);
+}
+
+/* least common multiple - PPCM in french */
+static unsigned long LCM( unsigned long a, unsigned long b )
+{
+ return (a*b) / GCD(a,b);
+}
+
+#define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b))
+
+static unsigned long CalculateFrameShift( unsigned long M, unsigned long N )
+{
+ unsigned long result = 0;
+ unsigned long i;
+ unsigned long lcm;
+ lcm = LCM( M, N );
+ for( i = M; i < lcm; i += M )
+ result = PA_MAX_( result, i % N );
+
+ return result;
+}
+
+
+PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
+ int inputChannelCount, PaSampleFormat userInputSampleFormat,
+ PaSampleFormat hostInputSampleFormat,
+ int outputChannelCount, PaSampleFormat userOutputSampleFormat,
+ PaSampleFormat hostOutputSampleFormat,
+ double sampleRate,
+ PaStreamFlags streamFlags,
+ unsigned long framesPerUserBuffer,
+ unsigned long framesPerHostBuffer,
+ PaUtilHostBufferSizeMode hostBufferSizeMode,
+ PaStreamCallback *streamCallback, void *userData )
+{
+ PaError result = paNoError;
+ PaError bytesPerSample;
+ unsigned long tempInputBufferSize, tempOutputBufferSize;
+
+ /* initialize buffer ptrs to zero so they can be freed if necessary in error */
+ bp->tempInputBuffer = 0;
+ bp->tempInputBufferPtrs = 0;
+ bp->tempOutputBuffer = 0;
+ bp->tempOutputBufferPtrs = 0;
+
+ bp->framesPerUserBuffer = framesPerUserBuffer;
+ bp->framesPerHostBuffer = framesPerHostBuffer;
+
+ bp->inputChannelCount = inputChannelCount;
+ bp->outputChannelCount = outputChannelCount;
+
+ bp->hostBufferSizeMode = hostBufferSizeMode;
+
+ bp->hostInputChannels[0] = 0;
+ bp->hostOutputChannels[0] = 0;
+
+ if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */
+ {
+ bp->useNonAdaptingProcess = 1;
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = 0;
+
+ if( hostBufferSizeMode == paUtilFixedHostBufferSize
+ || hostBufferSizeMode == paUtilBoundedHostBufferSize )
+ {
+ bp->framesPerTempBuffer = framesPerHostBuffer;
+ }
+ else /* unknown host buffer size */
+ {
+ bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_;
+ }
+ }
+ else
+ {
+ bp->framesPerTempBuffer = framesPerUserBuffer;
+
+ if( hostBufferSizeMode == paUtilFixedHostBufferSize
+ && framesPerHostBuffer % framesPerUserBuffer == 0 )
+ {
+ bp->useNonAdaptingProcess = 1;
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = 0;
+ }
+ else
+ {
+ bp->useNonAdaptingProcess = 0;
+
+ if( inputChannelCount > 0 && outputChannelCount > 0 )
+ {
+ /* full duplex */
+ if( hostBufferSizeMode == paUtilFixedHostBufferSize )
+ {
+ unsigned long frameShift =
+ CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer );
+
+ if( framesPerUserBuffer > framesPerHostBuffer )
+ {
+ bp->framesInTempInputBuffer = frameShift;
+ bp->framesInTempOutputBuffer = 0;
+ }
+ else
+ {
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = frameShift;
+ }
+ }
+ else /* variable host buffer size, add framesPerUserBuffer latency */
+ {
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = framesPerUserBuffer;
+ }
+ }
+ else
+ {
+ /* half duplex */
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = 0;
+ }
+ }
+ }
+
+
+
+ if( inputChannelCount > 0 )
+ {
+ bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat );
+ if( bytesPerSample > 0 )
+ {
+ bp->bytesPerHostInputSample = bytesPerSample;
+ }
+ else
+ {
+ result = bytesPerSample;
+ goto error;
+ }
+
+ bytesPerSample = Pa_GetSampleSize( userInputSampleFormat );
+ if( bytesPerSample > 0 )
+ {
+ bp->bytesPerUserInputSample = bytesPerSample;
+ }
+ else
+ {
+ result = bytesPerSample;
+ goto error;
+ }
+
+ bp->inputConverter =
+ PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, streamFlags );
+
+
+ bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
+
+
+ tempInputBufferSize =
+ bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
+
+ bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize );
+ if( bp->tempInputBuffer == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( bp->framesInTempInputBuffer > 0 )
+ memset( bp->tempInputBuffer, 0, tempInputBufferSize );
+
+ if( userInputSampleFormat & paNonInterleaved )
+ {
+ bp->tempInputBufferPtrs =
+ PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount );
+ if( bp->tempInputBufferPtrs == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ }
+
+ bp->hostInputChannels[0] = (PaUtilChannelDescriptor*)
+ PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2);
+ if( bp->hostInputChannels[0] == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount];
+ }
+
+ if( outputChannelCount > 0 )
+ {
+ bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat );
+ if( bytesPerSample > 0 )
+ {
+ bp->bytesPerHostOutputSample = bytesPerSample;
+ }
+ else
+ {
+ result = bytesPerSample;
+ goto error;
+ }
+
+ bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat );
+ if( bytesPerSample > 0 )
+ {
+ bp->bytesPerUserOutputSample = bytesPerSample;
+ }
+ else
+ {
+ result = bytesPerSample;
+ goto error;
+ }
+
+ bp->outputConverter =
+ PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags );
+
+
+ bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
+
+ tempOutputBufferSize =
+ bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
+
+ bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize );
+ if( bp->tempOutputBuffer == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( bp->framesInTempOutputBuffer > 0 )
+ memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
+
+ if( userOutputSampleFormat & paNonInterleaved )
+ {
+ bp->tempOutputBufferPtrs =
+ PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount );
+ if( bp->tempOutputBufferPtrs == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ }
+
+ bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*)
+ PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 );
+ if( bp->hostOutputChannels[0] == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount];
+ }
+
+ PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator );
+
+ bp->samplePeriod = 1. / sampleRate;
+
+ bp->streamCallback = streamCallback;
+ bp->userData = userData;
+
+ return result;
+
+error:
+ if( bp->tempInputBuffer )
+ PaUtil_FreeMemory( bp->tempInputBuffer );
+
+ if( bp->tempInputBufferPtrs )
+ PaUtil_FreeMemory( bp->tempInputBufferPtrs );
+
+ if( bp->hostInputChannels[0] )
+ PaUtil_FreeMemory( bp->hostInputChannels[0] );
+
+ if( bp->tempOutputBuffer )
+ PaUtil_FreeMemory( bp->tempOutputBuffer );
+
+ if( bp->tempOutputBufferPtrs )
+ PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
+
+ if( bp->hostOutputChannels[0] )
+ PaUtil_FreeMemory( bp->hostOutputChannels[0] );
+
+ return result;
+}
+
+
+void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp )
+{
+ if( bp->tempInputBuffer )
+ PaUtil_FreeMemory( bp->tempInputBuffer );
+
+ if( bp->tempInputBufferPtrs )
+ PaUtil_FreeMemory( bp->tempInputBufferPtrs );
+
+ if( bp->hostInputChannels[0] )
+ PaUtil_FreeMemory( bp->hostInputChannels[0] );
+
+ if( bp->tempOutputBuffer )
+ PaUtil_FreeMemory( bp->tempOutputBuffer );
+
+ if( bp->tempOutputBufferPtrs )
+ PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
+
+ if( bp->hostOutputChannels[0] )
+ PaUtil_FreeMemory( bp->hostOutputChannels[0] );
+}
+
+
+void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp, PaStreamCallbackTimeInfo* timeInfo )
+{
+ bp->timeInfo = timeInfo;
+
+ /* the first streamCallback will be called to process samples which are
+ currently in the input buffer before the ones starting at the timeInfo time */
+
+ bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod;
+
+ (void)bp->timeInfo->currentTime; /* FIXME: @todo time info currentTime not implemented */
+
+ /* the first streamCallback will be called to generate samples which will be
+ outputted after the frames currently in the output buffer have been
+ outputted. */
+ bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod;
+
+ bp->hostInputFrameCount[1] = 0;
+ bp->hostOutputFrameCount[1] = 0;
+}
+
+
+static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostInputChannels,
+ PaUtilChannelDescriptor *hostOutputChannels,
+ unsigned long frameCount );
+
+static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostInputChannels,
+ unsigned long frameCount );
+
+static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostOutputChannels,
+ unsigned long framesToProcess );
+
+static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult, int processPartialUserBuffers );
+
+#define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) )
+
+unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult )
+{
+ unsigned long framesToProcess, framesToGo;
+ unsigned long framesProcessed = 0;
+
+ if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
+ {
+ assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) ==
+ (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) );
+ }
+
+
+ if( bp->useNonAdaptingProcess )
+ {
+ if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
+ {
+ /* full duplex non-adapting process, splice buffers if they are
+ different lengths */
+
+ framesToGo = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]; /* relies on assert above for input/output equivalence */
+
+ do{
+ unsigned long *hostInputFrameCount;
+ PaUtilChannelDescriptor *hostInputChannels;
+ unsigned long *hostOutputFrameCount;
+ PaUtilChannelDescriptor *hostOutputChannels;
+ unsigned long framesProcessedThisIteration;
+
+ if( bp->hostInputFrameCount[0] != 0 )
+ {
+ hostInputFrameCount = &bp->hostInputFrameCount[0];
+ hostInputChannels = bp->hostInputChannels[0];
+ }
+ else
+ {
+ hostInputFrameCount = &bp->hostInputFrameCount[1];
+ hostInputChannels = bp->hostInputChannels[1];
+ }
+
+ if( bp->hostOutputFrameCount[0] != 0 )
+ {
+ hostOutputFrameCount = &bp->hostOutputFrameCount[0];
+ hostOutputChannels = bp->hostOutputChannels[0];
+ }
+ else
+ {
+ hostOutputFrameCount = &bp->hostOutputFrameCount[1];
+ hostOutputChannels = bp->hostOutputChannels[1];
+ }
+
+ framesToProcess = PA_MIN_( *hostInputFrameCount,
+ *hostOutputFrameCount );
+
+ assert( framesToProcess != 0 );
+
+ framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult,
+ hostInputChannels, hostOutputChannels,
+ framesToProcess );
+
+ *hostInputFrameCount -= framesProcessedThisIteration;
+ *hostOutputFrameCount -= framesProcessedThisIteration;
+
+ framesProcessed += framesProcessedThisIteration;
+ framesToGo -= framesProcessedThisIteration;
+
+ }while( framesToGo > 0 );
+ }
+ else
+ {
+ /* half duplex non-adapting process, just process 1st and 2nd buffer */
+ /* process first buffer */
+
+ framesToProcess = (bp->inputChannelCount != 0)
+ ? bp->hostInputFrameCount[0]
+ : bp->hostOutputFrameCount[0];
+
+ framesProcessed = NonAdaptingProcess( bp, streamCallbackResult,
+ bp->hostInputChannels[0], bp->hostOutputChannels[0],
+ framesToProcess );
+
+ /* process second buffer if provided */
+
+ framesToProcess = (bp->inputChannelCount != 0)
+ ? bp->hostInputFrameCount[1]
+ : bp->hostOutputFrameCount[1];
+ if( framesToProcess > 0 )
+ {
+ framesProcessed += NonAdaptingProcess( bp, streamCallbackResult,
+ bp->hostInputChannels[1], bp->hostOutputChannels[1],
+ framesToProcess );
+ }
+ }
+ }
+ else /* block adaption necessary*/
+ {
+
+ if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
+ {
+ /* full duplex */
+
+ if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed )
+ {
+ framesProcessed = AdaptingProcess( bp, streamCallbackResult,
+ 0 /* dont process partial user buffers */ );
+ }
+ else
+ {
+ framesProcessed = AdaptingProcess( bp, streamCallbackResult,
+ 1 /* process partial user buffers */ );
+ }
+ }
+ else if( bp->inputChannelCount != 0 )
+ {
+ /* input only */
+ framesToProcess = bp->hostInputFrameCount[0];
+
+ framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult,
+ bp->hostInputChannels[0], framesToProcess );
+
+ framesToProcess = bp->hostInputFrameCount[1];
+ if( framesToProcess > 0 )
+ {
+ framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult,
+ bp->hostInputChannels[1], framesToProcess );
+ }
+ }
+ else
+ {
+ /* output only */
+ framesToProcess = bp->hostOutputFrameCount[0];
+
+ framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult,
+ bp->hostOutputChannels[0], framesToProcess );
+
+ framesToProcess = bp->hostOutputFrameCount[1];
+ if( framesToProcess > 0 )
+ {
+ framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult,
+ bp->hostOutputChannels[1], framesToProcess );
+ }
+ }
+ }
+
+ return framesProcessed;
+}
+
+
+void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp,
+ unsigned long frameCount )
+{
+ if( frameCount == 0 )
+ bp->hostInputFrameCount[0] = bp->framesPerHostBuffer;
+ else
+ bp->hostInputFrameCount[0] = frameCount;
+}
+
+
+void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data, unsigned int stride )
+{
+ assert( channel < bp->inputChannelCount );
+
+ bp->hostInputChannels[0][channel].data = data;
+ bp->hostInputChannels[0][channel].stride = stride;
+}
+
+
+void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
+ unsigned int firstChannel, void *data, unsigned int channelCount )
+{
+ unsigned int i;
+ unsigned int channel = firstChannel;
+ unsigned char *p = (unsigned char*)data;
+
+ if( channelCount == 0 )
+ channelCount = bp->inputChannelCount;
+
+ assert( firstChannel < bp->inputChannelCount );
+ assert( firstChannel + channelCount <= bp->inputChannelCount );
+
+ for( i=0; i< channelCount; ++i )
+ {
+ bp->hostInputChannels[0][channel+i].data = p;
+ p += bp->bytesPerHostInputSample;
+ bp->hostInputChannels[0][channel+i].stride = channelCount;
+ }
+}
+
+
+void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data )
+{
+ assert( channel < bp->inputChannelCount );
+
+ bp->hostInputChannels[0][channel].data = data;
+ bp->hostInputChannels[0][channel].stride = 1;
+}
+
+
+void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp,
+ unsigned long frameCount )
+{
+ bp->hostInputFrameCount[1] = frameCount;
+}
+
+
+void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data, unsigned int stride )
+{
+ assert( channel < bp->inputChannelCount );
+
+ bp->hostInputChannels[1][channel].data = data;
+ bp->hostInputChannels[1][channel].stride = stride;
+}
+
+
+void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
+ unsigned int firstChannel, void *data, unsigned int channelCount )
+{
+ unsigned int i;
+ unsigned int channel = firstChannel;
+ unsigned char *p = (unsigned char*)data;
+
+ if( channelCount == 0 )
+ channelCount = bp->inputChannelCount;
+
+ assert( firstChannel < bp->inputChannelCount );
+ assert( firstChannel + channelCount <= bp->inputChannelCount );
+
+ for( i=0; i< channelCount; ++i )
+ {
+ bp->hostInputChannels[1][channel+i].data = p;
+ p += bp->bytesPerHostInputSample;
+ bp->hostInputChannels[1][channel+i].stride = channelCount;
+ }
+}
+
+
+void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data )
+{
+ assert( channel < bp->inputChannelCount );
+
+ bp->hostInputChannels[1][channel].data = data;
+ bp->hostInputChannels[1][channel].stride = 1;
+}
+
+
+void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp,
+ unsigned long frameCount )
+{
+ if( frameCount == 0 )
+ bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer;
+ else
+ bp->hostOutputFrameCount[0] = frameCount;
+}
+
+
+void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data, unsigned int stride )
+{
+ assert( channel < bp->outputChannelCount );
+
+ bp->hostOutputChannels[0][channel].data = data;
+ bp->hostOutputChannels[0][channel].stride = stride;
+}
+
+
+void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
+ unsigned int firstChannel, void *data, unsigned int channelCount )
+{
+ unsigned int i;
+ unsigned int channel = firstChannel;
+ unsigned char *p = (unsigned char*)data;
+
+ if( channelCount == 0 )
+ channelCount = bp->outputChannelCount;
+
+ assert( firstChannel < bp->outputChannelCount );
+ assert( firstChannel + channelCount <= bp->outputChannelCount );
+
+ for( i=0; i< channelCount; ++i )
+ {
+ bp->hostOutputChannels[0][channel+i].data = p;
+ p += bp->bytesPerHostOutputSample;
+ bp->hostOutputChannels[0][channel+i].stride = channelCount;
+ }
+}
+
+
+void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data )
+{
+ assert( channel < bp->outputChannelCount );
+
+ bp->hostOutputChannels[0][channel].data = data;
+ bp->hostOutputChannels[0][channel].stride = 1;
+}
+
+
+void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp,
+ unsigned long frameCount )
+{
+ bp->hostOutputFrameCount[1] = frameCount;
+}
+
+
+void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data, unsigned int stride )
+{
+ assert( channel < bp->outputChannelCount );
+
+ bp->hostOutputChannels[1][channel].data = data;
+ bp->hostOutputChannels[1][channel].stride = stride;
+}
+
+
+void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
+ unsigned int firstChannel, void *data, unsigned int channelCount )
+{
+ unsigned int i;
+ unsigned int channel = firstChannel;
+ unsigned char *p = (unsigned char*)data;
+
+ if( channelCount == 0 )
+ channelCount = bp->outputChannelCount;
+
+ assert( firstChannel < bp->outputChannelCount );
+ assert( firstChannel + channelCount <= bp->outputChannelCount );
+
+ for( i=0; i< channelCount; ++i )
+ {
+ bp->hostOutputChannels[1][channel+i].data = p;
+ p += bp->bytesPerHostOutputSample;
+ bp->hostOutputChannels[1][channel+i].stride = channelCount;
+ }
+}
+
+
+void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data )
+{
+ assert( channel < bp->outputChannelCount );
+
+ bp->hostOutputChannels[1][channel].data = data;
+ bp->hostOutputChannels[1][channel].stride = 1;
+}
+
+
+/*
+ NonAdaptingProcess() is a simple buffer copying adaptor that can handle
+ both full and half duplex copies. It processes framesToProcess frames,
+ broken into blocks bp->framesPerTempBuffer long.
+ This routine can be used when the streamCallback doesn't care what length the
+ buffers are, or when framesToProcess is an integer multiple of
+ bp->framesPerTempBuffer, in which case streamCallback will always be called
+ with bp->framesPerTempBuffer samples.
+*/
+static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostInputChannels,
+ PaUtilChannelDescriptor *hostOutputChannels,
+ unsigned long framesToProcess )
+{
+ void *userInput, *userOutput;
+ unsigned char *srcBytePtr, *destBytePtr;
+ unsigned int srcStride, srcBytePtrStride;
+ unsigned int destStride, destBytePtrStride;
+ unsigned int i;
+ unsigned long frameCount;
+ unsigned long framesToGo = framesToProcess;
+ unsigned long framesProcessed = 0;
+ unsigned long statusFlags = 0; // FIXME: implement this
+
+ do
+ {
+ frameCount = ( bp->framesPerTempBuffer < framesToGo )
+ ? bp->framesPerTempBuffer
+ : framesToGo;
+
+ /* configure user input buffer and convert input data (host -> user) */
+ if( bp->inputChannelCount == 0 )
+ {
+ /* no input */
+ userInput = 0;
+ }
+ else /* there are input channels */
+ {
+ /*
+ could use more elaborate logic here and sometimes process
+ buffers in-place.
+ */
+
+ destBytePtr = bp->tempInputBuffer;
+
+ if( bp->userInputIsInterleaved )
+ {
+ destStride = bp->inputChannelCount;
+ destBytePtrStride = bp->bytesPerUserInputSample;
+ userInput = bp->tempInputBuffer;
+ }
+ else /* user input is not interleaved */
+ {
+ destStride = 1;
+ destBytePtrStride = frameCount * bp->bytesPerUserInputSample;
+
+ /* setup non-interleaved ptrs */
+ for( i=0; i<bp->inputChannelCount; ++i )
+ {
+ bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
+ i * bp->bytesPerUserInputSample * frameCount;
+ }
+
+ userInput = bp->tempInputBufferPtrs;
+ }
+
+ for( i=0; i<bp->inputChannelCount; ++i )
+ {
+ bp->inputConverter( destBytePtr, destStride,
+ hostInputChannels[i].data,
+ hostInputChannels[i].stride,
+ frameCount, &bp->ditherGenerator );
+
+ destBytePtr += destBytePtrStride; /* skip to next destination channel */
+
+ /* advance src ptr for next iteration */
+ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
+ frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
+ }
+ }
+
+ /* configure user output buffer */
+ if( bp->outputChannelCount == 0 )
+ {
+ /* no output */
+ userOutput = 0;
+ }
+ else /* there are output channels */
+ {
+ if( bp->userOutputIsInterleaved )
+ {
+ userOutput = bp->tempOutputBuffer;
+ }
+ else /* user output is not interleaved */
+ {
+ for( i = 0; i < bp->outputChannelCount; ++i )
+ {
+ bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
+ i * bp->bytesPerUserOutputSample * frameCount;
+ }
+
+ userOutput = bp->tempOutputBufferPtrs;
+ }
+ }
+
+ *streamCallbackResult = bp->streamCallback( userInput, userOutput,
+ frameCount, bp->timeInfo,
+ statusFlags, bp->userData );
+
+ bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
+ bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod;
+
+
+ // FIXME: if streamCallback result is abort, then abort!
+
+ /* convert output data (user -> host) */
+ if( bp->outputChannelCount != 0 )
+ {
+ /*
+ could use more elaborate logic here and sometimes process
+ buffers in-place.
+ */
+
+ srcBytePtr = bp->tempOutputBuffer;
+
+ if( bp->userOutputIsInterleaved )
+ {
+ srcStride = bp->outputChannelCount;
+ srcBytePtrStride = bp->bytesPerUserOutputSample;
+ }
+ else /* user output is not interleaved */
+ {
+ srcStride = 1;
+ srcBytePtrStride = frameCount * bp->bytesPerUserOutputSample;
+ }
+
+ for( i=0; i<bp->outputChannelCount; ++i )
+ {
+ bp->outputConverter( hostOutputChannels[i].data,
+ hostOutputChannels[i].stride,
+ srcBytePtr, srcStride,
+ frameCount, &bp->ditherGenerator );
+
+ srcBytePtr += srcBytePtrStride; /* skip to next source channel */
+
+ /* advance dest ptr for next iteration */
+ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
+ frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
+ }
+ }
+
+ framesProcessed += frameCount;
+
+ framesToGo -= frameCount;
+ }
+ while( framesToGo > 0 );
+
+ return framesProcessed;
+}
+
+
+/*
+ AdaptingInputOnlyProcess() is a half duplex input buffer processor. It
+ converts data from the input buffers into the temporary input buffer,
+ when the temporary input buffer is full, it calls the streamCallback.
+*/
+static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostInputChannels,
+ unsigned long framesToProcess )
+{
+ void *userInput, *userOutput;
+ unsigned char *destBytePtr;
+ unsigned int destStride, destBytePtrStride;
+ unsigned int i;
+ unsigned long frameCount;
+ unsigned long framesToGo = framesToProcess;
+ unsigned long framesProcessed = 0;
+ unsigned long statusFlags = 0; // FIXME: implement this
+
+ userOutput = 0;
+
+ do
+ {
+ frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer )
+ ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer )
+ : framesToGo;
+
+ /* convert frameCount samples into temp buffer */
+
+ if( bp->userInputIsInterleaved )
+ {
+ destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
+ bp->bytesPerUserInputSample * bp->inputChannelCount *
+ bp->framesInTempInputBuffer;
+
+ destStride = bp->inputChannelCount;
+ destBytePtrStride = bp->bytesPerUserInputSample;
+
+ userInput = bp->tempInputBuffer;
+ }
+ else /* user input is not interleaved */
+ {
+ destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
+ bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
+
+ destStride = 1;
+ destBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
+
+ /* setup non-interleaved ptrs */
+ for( i=0; i<bp->inputChannelCount; ++i )
+ {
+ bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
+ i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer;
+ }
+
+ userInput = bp->tempInputBufferPtrs;
+ }
+
+ for( i=0; i<bp->inputChannelCount; ++i )
+ {
+ bp->inputConverter( destBytePtr, destStride,
+ hostInputChannels[i].data,
+ hostInputChannels[i].stride,
+ frameCount, &bp->ditherGenerator );
+
+ destBytePtr += destBytePtrStride; /* skip to next destination channel */
+
+ /* advance src ptr for next iteration */
+ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
+ frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
+ }
+
+ bp->framesInTempInputBuffer += frameCount;
+
+ if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer )
+ {
+ bp->timeInfo->outputBufferDacTime = 0;
+
+ *streamCallbackResult = bp->streamCallback( userInput, userOutput,
+ bp->framesPerUserBuffer, bp->timeInfo,
+ statusFlags, bp->userData );
+
+ bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
+
+ // FIXME: if streamCallback result is abort, then abort!
+
+ bp->framesInTempInputBuffer = 0;
+ }
+
+ framesProcessed += frameCount;
+
+ framesToGo -= frameCount;
+ }while( framesToGo > 0 );
+
+ return framesProcessed;
+}
+
+
+/*
+ AdaptingOutputOnlyProcess() is a half duplex output buffer processor.
+ It converts data from the temporary output buffer, to the output buffers,
+ when the temporary output buffer is empty, it calls the streamCallback.
+*/
+static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostOutputChannels,
+ unsigned long framesToProcess )
+{
+ void *userInput, *userOutput;
+ unsigned char *srcBytePtr;
+ unsigned int srcStride, srcBytePtrStride;
+ unsigned int i;
+ unsigned long frameCount;
+ unsigned long framesToGo = framesToProcess;
+ unsigned long framesProcessed = 0;
+ unsigned long statusFlags = 0; // FIXME: implement this
+
+ do
+ {
+ if( bp->framesInTempOutputBuffer == 0 )
+ {
+ userInput = 0;
+
+ /* setup userOutput */
+ if( bp->userOutputIsInterleaved )
+ {
+ userOutput = bp->tempOutputBuffer;
+ }
+ else /* user output is not interleaved */
+ {
+ for( i = 0; i < bp->outputChannelCount; ++i )
+ {
+ bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
+ i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
+ }
+
+ userOutput = bp->tempOutputBufferPtrs;
+ }
+
+ bp->timeInfo->inputBufferAdcTime = 0;
+
+ *streamCallbackResult = bp->streamCallback( userInput, userOutput,
+ bp->framesPerUserBuffer, bp->timeInfo,
+ statusFlags, bp->userData );
+
+ bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
+
+ // FIXME: if streamCallback result is abort, then abort!
+
+ bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
+ }
+
+ frameCount = ( bp->framesInTempOutputBuffer > framesToGo )
+ ? framesToGo
+ : bp->framesInTempOutputBuffer;
+
+ /* convert frameCount frames from user buffer to host buffer */
+
+ if( bp->userOutputIsInterleaved )
+ {
+ srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
+ bp->bytesPerUserOutputSample * bp->outputChannelCount *
+ (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
+
+ srcStride = bp->outputChannelCount;
+ srcBytePtrStride = bp->bytesPerUserOutputSample;
+ }
+ else /* user output is not interleaved */
+ {
+ srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
+ bp->bytesPerUserOutputSample *
+ (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
+
+ srcStride = 1;
+ srcBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
+ }
+
+ for( i=0; i<bp->outputChannelCount; ++i )
+ {
+ bp->outputConverter( hostOutputChannels[i].data,
+ hostOutputChannels[i].stride,
+ srcBytePtr, srcStride,
+ frameCount, &bp->ditherGenerator );
+
+ srcBytePtr += srcBytePtrStride; /* skip to next source channel */
+
+ /* advance dest ptr for next iteration */
+ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
+ frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
+ }
+
+ bp->framesInTempOutputBuffer -= frameCount;
+
+ framesProcessed += frameCount;
+
+ framesToGo -= frameCount;
+
+ }while( framesToGo > 0 );
+
+ return framesProcessed;
+}
+
+
+/*
+ AdaptingProcess is a full duplex adapting buffer processor. It converts
+ data from the temporary output buffer into the host output buffers, then
+ from the host input buffers into the temporary input buffers. Calling the
+ streamCallback when necessary.
+ When processPartialUserBuffers is 0, all available input data will be
+ consumed and all available output space will be filled. When
+ processPartialUserBuffers is non-zero, as many full user buffers
+ as possible will be processed, but partial buffers will not be consumed.
+*/
+static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult, int processPartialUserBuffers )
+{
+ void *userInput, *userOutput;
+ unsigned long framesProcessed = 0;
+ unsigned long framesAvailable;
+ unsigned long endProcessingMinFrameCount;
+ unsigned long maxFramesToCopy;
+ PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels;
+ unsigned int frameCount;
+ unsigned char *srcBytePtr, *destBytePtr;
+ unsigned int srcStride, srcBytePtrStride, destStride, destBytePtrStride;
+ unsigned int i;
+ unsigned long statusFlags = 0; // FIXME: implement this
+
+ framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffers frame count */
+
+ if( processPartialUserBuffers )
+ endProcessingMinFrameCount = 0;
+ else
+ endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1);
+
+ while( framesAvailable > endProcessingMinFrameCount )
+ {
+ /* copy frames from user to host output buffers */
+ while( bp->framesInTempOutputBuffer > 0 &&
+ ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) )
+ {
+ maxFramesToCopy = bp->framesInTempOutputBuffer;
+
+ /* select the output buffer set (1st or 2nd) */
+ if( bp->hostOutputFrameCount[0] > 0 )
+ {
+ hostOutputChannels = bp->hostOutputChannels[0];
+ frameCount = (bp->hostOutputFrameCount[0] < maxFramesToCopy)
+ ? bp->hostOutputFrameCount[0]
+ : maxFramesToCopy;
+ }
+ else
+ {
+ hostOutputChannels = bp->hostOutputChannels[1];
+ frameCount = (bp->hostOutputFrameCount[1] < maxFramesToCopy)
+ ? bp->hostOutputFrameCount[1]
+ : maxFramesToCopy;
+ }
+
+ if( bp->userOutputIsInterleaved )
+ {
+ srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
+ bp->bytesPerUserOutputSample * bp->outputChannelCount *
+ (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
+
+ srcStride = bp->outputChannelCount;
+ srcBytePtrStride = bp->bytesPerUserOutputSample;
+ }
+ else /* user output is not interleaved */
+ {
+ srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
+ bp->bytesPerUserOutputSample *
+ (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
+
+ srcStride = 1;
+ srcBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
+ }
+
+ for( i=0; i<bp->outputChannelCount; ++i )
+ {
+ bp->outputConverter( hostOutputChannels[i].data,
+ hostOutputChannels[i].stride,
+ srcBytePtr, srcStride,
+ frameCount, &bp->ditherGenerator );
+
+ srcBytePtr += srcBytePtrStride; /* skip to next source channel */
+
+ /* advance dest ptr for next iteration */
+ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
+ frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
+ }
+
+ if( bp->hostOutputFrameCount[0] > 0 )
+ bp->hostOutputFrameCount[0] -= frameCount;
+ else
+ bp->hostOutputFrameCount[1] -= frameCount;
+
+ bp->framesInTempOutputBuffer -= frameCount;
+ }
+
+
+ /* copy frames from host to user input buffers */
+ while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer &&
+ ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) )
+ {
+ maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer;
+
+ /* select the input buffer set (1st or 2nd) */
+ if( bp->hostInputFrameCount[0] > 0 )
+ {
+ hostInputChannels = bp->hostInputChannels[0];
+ frameCount = (bp->hostInputFrameCount[0] < maxFramesToCopy)
+ ? bp->hostInputFrameCount[0]
+ : maxFramesToCopy;
+ }
+ else
+ {
+ hostInputChannels = bp->hostInputChannels[1];
+ frameCount = (bp->hostInputFrameCount[1] < maxFramesToCopy)
+ ? bp->hostInputFrameCount[1]
+ : maxFramesToCopy;
+ }
+
+ /* configure conversion destination pointers */
+ if( bp->userInputIsInterleaved )
+ {
+ destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
+ bp->bytesPerUserInputSample * bp->inputChannelCount *
+ bp->framesInTempInputBuffer;
+
+ destStride = bp->inputChannelCount;
+ destBytePtrStride = bp->bytesPerUserInputSample;
+ }
+ else /* user input is not interleaved */
+ {
+ destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
+ bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
+
+ destStride = 1;
+ destBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
+ }
+
+ for( i=0; i<bp->inputChannelCount; ++i )
+ {
+ bp->inputConverter( destBytePtr, destStride,
+ hostInputChannels[i].data,
+ hostInputChannels[i].stride,
+ frameCount, &bp->ditherGenerator );
+
+ destBytePtr += destBytePtrStride; /* skip to next destination channel */
+
+ /* advance src ptr for next iteration */
+ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
+ frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
+ }
+
+ if( bp->hostInputFrameCount[0] > 0 )
+ bp->hostInputFrameCount[0] -= frameCount;
+ else
+ bp->hostInputFrameCount[1] -= frameCount;
+
+ bp->framesInTempInputBuffer += frameCount;
+
+ /* update framesAvailable and framesProcessed based on input consumed
+ unless something is very wrong this will also correspond to the
+ amount of output generated */
+ framesAvailable -= frameCount;
+ framesProcessed += frameCount;
+ }
+
+ /* call streamCallback */
+ if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer &&
+ bp->framesInTempOutputBuffer == 0 )
+ {
+ /* setup userInput */
+ if( bp->userInputIsInterleaved )
+ {
+ userInput = bp->tempInputBuffer;
+ }
+ else /* user input is not interleaved */
+ {
+ for( i = 0; i < bp->inputChannelCount; ++i )
+ {
+ bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
+ i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
+ }
+
+ userInput = bp->tempInputBufferPtrs;
+ }
+
+ /* setup userOutput */
+ if( bp->userOutputIsInterleaved )
+ {
+ userOutput = bp->tempOutputBuffer;
+ }
+ else /* user output is not interleaved */
+ {
+ for( i = 0; i < bp->outputChannelCount; ++i )
+ {
+ bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
+ i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
+ }
+
+ userOutput = bp->tempOutputBufferPtrs;
+ }
+
+ /* call streamCallback */
+
+ *streamCallbackResult = bp->streamCallback( userInput, userOutput,
+ bp->framesPerUserBuffer, bp->timeInfo,
+ statusFlags, bp->userData );
+
+ bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
+ bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
+
+
+ // FIXME: if streamCallback result is abort, then abort!
+
+
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
+ }
+ }
+
+ return framesProcessed;
+}
diff --git a/pd/portaudio/pa_common/pa_process.h b/pd/portaudio/pa_common/pa_process.h
new file mode 100644
index 00000000..47bc0d70
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_process.h
@@ -0,0 +1,203 @@
+#ifndef PA_PROCESS_H
+#define PA_PROCESS_H
+/*
+ * $Id: pa_process.h,v 1.1.2.16 2002/10/26 05:33:29 rossbencina Exp $
+ * Portable Audio I/O Library callback buffer processing adapters
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include "portaudio.h"
+#include "pa_converters.h"
+#include "pa_dither.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/** @file
+
+ @todo finish documentation for the buffer processor
+*/
+
+typedef enum {
+ paUtilFixedHostBufferSize,
+ paUtilBoundedHostBufferSize,
+ paUtilUnknownHostBufferSize,
+ paUtilVariableHostBufferSizePartialUsageAllowed, /**< the only mode where process() may not consume the whole buffer */
+}PaUtilHostBufferSizeMode;
+
+
+typedef struct PaUtilChannelDescriptor{
+ void *data;
+ unsigned int stride;
+}PaUtilChannelDescriptor;
+
+
+typedef struct {
+ unsigned long framesPerUserBuffer;
+ unsigned long framesPerHostBuffer;
+
+ PaUtilHostBufferSizeMode hostBufferSizeMode;
+ int useNonAdaptingProcess;
+ unsigned long framesPerTempBuffer;
+
+ unsigned int inputChannelCount;
+ unsigned int bytesPerHostInputSample;
+ unsigned int bytesPerUserInputSample;
+ int userInputIsInterleaved;
+ PaUtilConverter *inputConverter;
+
+ unsigned int outputChannelCount;
+ unsigned int bytesPerHostOutputSample;
+ unsigned int bytesPerUserOutputSample;
+ int userOutputIsInterleaved;
+ PaUtilConverter *outputConverter;
+
+ void *tempInputBuffer; /**< used for slips, block adaption, and conversion. */
+ void **tempInputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user input */
+ unsigned long framesInTempInputBuffer; /**< frames remaining in input buffer from previous adaption iteration */
+
+ void *tempOutputBuffer; /**< used for slips, block adaption, and conversion. */
+ void **tempOutputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user output */
+ unsigned long framesInTempOutputBuffer; /**< frames remaining in input buffer from previous adaption iteration */
+
+ PaStreamCallbackTimeInfo *timeInfo;
+
+ unsigned long hostInputFrameCount[2];
+ PaUtilChannelDescriptor *hostInputChannels[2];
+ unsigned long hostOutputFrameCount[2];
+ PaUtilChannelDescriptor *hostOutputChannels[2];
+
+ PaUtilTriangularDitherGenerator ditherGenerator;
+
+ double samplePeriod;
+
+ PaStreamCallback *streamCallback;
+ void *userData;
+} PaUtilBufferProcessor;
+
+
+/**
+ @param framesPerHostBuffer Specifies the number of frames per host buffer
+ for fixed the fixed buffer size mode, and the maximum number of frames
+ per host buffer for the bounded host buffer size mode. It is ignored for
+ the other modes.
+
+ @note The interleave flag is ignored for host buffer formats. Host interleave
+ is determined by the use of different SetInput and SetOutput functions.
+*/
+PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bufferProcessor,
+ int numInputChannels, PaSampleFormat userInputSampleFormat,
+ PaSampleFormat hostInputSampleFormat,
+ int numOutputChannels, PaSampleFormat userOutputSampleFormat,
+ PaSampleFormat hostOutputSampleFormat,
+ double sampleRate,
+ PaStreamFlags streamFlags,
+ unsigned long framesPerUserBuffer, /* 0 indicates don't care */
+ unsigned long framesPerHostBuffer,
+ PaUtilHostBufferSizeMode hostBufferSizeMode,
+ PaStreamCallback *streamCallback, void *userData );
+
+
+void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bufferProcessor );
+
+
+/**
+ @param timeInfo Timing information for the first sample of the buffer(s)
+ passed to the buffer processor. The buffer processor may adjust this
+ information as necessary.
+*/
+void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bufferProcessor,
+ PaStreamCallbackTimeInfo* timeInfo );
+
+/** returns the number of frames processed */
+unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bufferProcessor, int *callbackResult );
+
+
+/** a 0 frameCount indicates to use the framesPerHostBuffer value passed to init */
+void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bufferProcessor,
+ unsigned long frameCount );
+
+
+void PaUtil_SetInputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data, unsigned int stride );
+
+/** if channel count is zero use all channels as specified to initialize buffer processor */
+void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int firstChannel, void *data, unsigned int channelCount );
+
+void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data );
+
+
+void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bufferProcessor,
+ unsigned long frameCount );
+
+void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data, unsigned int stride );
+
+/** if channel count is zero use all channels as specified to initialize buffer processor */
+void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int firstChannel, void *data, unsigned int channelCount );
+
+void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data );
+
+/** a 0 frameCount indicates to use the framesPerHostBuffer value passed to init */
+void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,
+ unsigned long frameCount );
+
+void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data, unsigned int stride );
+
+/** if channel count is zero use all channels as specified to initialize buffer processor */
+void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int firstChannel, void *data, unsigned int channelCount );
+
+void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data );
+
+
+void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,
+ unsigned long frameCount );
+
+void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data, unsigned int stride );
+
+/** if channel count is zero use all channels as specified to initialize buffer processor */
+void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int firstChannel, void *data, unsigned int channelCount );
+
+void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_PROCESS_H */
diff --git a/pd/portaudio/pa_common/pa_process.o b/pd/portaudio/pa_common/pa_process.o
new file mode 100644
index 00000000..3429227b
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_process.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_skeleton.c b/pd/portaudio/pa_common/pa_skeleton.c
new file mode 100644
index 00000000..d9a90f4b
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_skeleton.c
@@ -0,0 +1,724 @@
+/*
+ * $Id: pa_skeleton.c,v 1.1.2.27 2002/12/03 06:30:40 rossbencina Exp $
+ * Portable Audio I/O Library skeleton implementation
+ * demonstrates how to use the common functions to implement support
+ * for a host API
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include <string.h> /* strlen() */
+
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
+
+/** @file
+ NOTE TO IMPLEMENTORS:
+
+ This file is provided as a starting point for implementing support for
+ a new host API. IMPLEMENT ME comments are used to indicate functionality
+ which much be customised for each implementation.
+*/
+
+
+/* prototypes for functions declared in this file */
+
+PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData );
+static PaError CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamInputLatency( PaStream *stream );
+static PaTime GetStreamOutputLatency( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+static signed long GetStreamReadAvailable( PaStream* stream );
+static signed long GetStreamWriteAvailable( PaStream* stream );
+
+
+/* IMPLEMENT ME: a macro like the following one should be used for reporting
+ host errors */
+#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
+ PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
+
+/* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */
+
+typedef struct
+{
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
+
+ PaUtilAllocationGroup *allocations;
+
+ /* implementation specific data goes here */
+}
+PaSkeletonHostApiRepresentation; /* IMPLEMENT ME: rename this */
+
+
+PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ int i, deviceCount;
+ PaSkeletonHostApiRepresentation *skeletonHostApi;
+ PaDeviceInfo *deviceInfoArray;
+
+ skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) );
+ if( !skeletonHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !skeletonHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ *hostApi = &skeletonHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paInDevelopment; /* IMPLEMENT ME: change to correct type id */
+ (*hostApi)->info.name = "skeleton implementation"; /* IMPLEMENT ME: change to correct name */
+
+ (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */
+ (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
+
+ (*hostApi)->info.deviceCount = 0;
+
+ deviceCount = 0; /* IMPLEMENT ME */
+
+ if( deviceCount > 0 )
+ {
+ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
+ if( !(*hostApi)->deviceInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* allocate all device info structs in a contiguous block */
+ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
+ if( !deviceInfoArray )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i=0; i < deviceCount; ++i )
+ {
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+ deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg:
+ deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 );
+ if( !deviceName )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ strcpy( deviceName, srcName );
+ deviceInfo->name = deviceName;
+ */
+
+ deviceInfo->maxInputChannels = 0; /* IMPLEMENT ME */
+ deviceInfo->maxOutputChannels = 0; /* IMPLEMENT ME */
+
+ deviceInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */
+ deviceInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */
+ deviceInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */
+ deviceInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */
+
+ deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */
+
+ (*hostApi)->deviceInfos[i] = deviceInfo;
+ ++(*hostApi)->info.deviceCount;
+ }
+ }
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+
+ return result;
+
+error:
+ if( skeletonHostApi )
+ {
+ if( skeletonHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( skeletonHostApi );
+ }
+ return result;
+}
+
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
+
+ /*
+ IMPLEMENT ME:
+ - clean up any resourced not handled by the allocation group
+ */
+
+ if( skeletonHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( skeletonHostApi );
+}
+
+
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
+{
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ /*
+ IMPLEMENT ME:
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+ */
+
+ return paFormatIsSupported;
+}
+
+/* PaSkeletonStream - a stream data structure specifically for this implementation */
+
+typedef struct PaSkeletonStream
+{ /* IMPLEMENT ME: rename this */
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ /* IMPLEMENT ME:
+ - implementation specific data goes here
+ */
+ unsigned long framesPerHostCallback; /* just an example */
+}
+PaSkeletonStream;
+
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
+ PaSkeletonStream *stream = 0;
+ unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat=0, outputSampleFormat=0;
+ PaSampleFormat hostInputSampleFormat=0, hostOutputSampleFormat=0;
+
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+
+ /* IMPLEMENT ME - establish which host formats are available */
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+
+ /* IMPLEMENT ME - establish which host formats are available */
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ /*
+ IMPLEMENT ME:
+
+ ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
+
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+
+ - alter sampleRate to a close allowable rate if possible / necessary
+
+ - validate suggestedInputLatency and suggestedOutputLatency parameters,
+ use default values where necessary
+ */
+
+
+
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
+
+
+ stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( streamCallback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &skeletonHostApi->callbackStreamInterface, streamCallback, userData );
+ }
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &skeletonHostApi->blockingStreamInterface, streamCallback, userData );
+ }
+
+ /*
+ IMPLEMENT ME: initialise the following fields with estimated or actual
+ values.
+ */
+ stream->streamRepresentation.streamInfo.inputLatency = 0.;
+ stream->streamRepresentation.streamInfo.outputLatency = 0.;
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+
+ /* we assume a fixed host buffer size in this example, but the buffer processor
+ can also support bounded and unknown host buffer sizes by passing
+ paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
+ paUtilFixedHostBufferSize below. */
+
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ inputChannelCount, inputSampleFormat, hostInputSampleFormat,
+ outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer,
+ framesPerHostBuffer, paUtilFixedHostBufferSize,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+
+ /*
+ IMPLEMENT ME:
+ - additional stream setup + opening
+ */
+
+ stream->framesPerHostCallback = framesPerHostBuffer;
+
+ *s = (PaStream*)stream;
+
+ return result;
+
+error:
+ if( stream )
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+/*
+ ExampleHostProcessingLoop() illustrates the kind of processing which may
+ occur in a host implementation.
+
+*/
+static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)userData;
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
+ int callbackResult;
+ unsigned long framesProcessed;
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ /*
+ IMPLEMENT ME:
+ - generate timing information
+ - handle buffer slips
+ */
+
+ /*
+ If you need to byte swap or shift inputBuffer to convert it into a
+ portaudio format, do it here.
+ */
+
+
+
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo );
+
+ /*
+ depending on whether the host buffers are interleaved, non-interleaved
+ or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
+ PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
+ */
+
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
+ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
+ 0, /* first channel of inputBuffer is channel 0 */
+ inputBuffer,
+ 0 ); /* 0 - use inputChannelCount passed to init buffer processor */
+
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
+ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
+ 0, /* first channel of outputBuffer is channel 0 */
+ outputBuffer,
+ 0 ); /* 0 - use outputChannelCount passed to init buffer processor */
+
+ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
+
+
+ /*
+ If you need to byte swap or shift outputBuffer to convert it to
+ host format, do it here.
+ */
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+
+
+ if( callbackResult == paContinue )
+ {
+ /* nothing special to do */
+ }
+ else if( callbackResult == paAbort )
+ {
+ /* IMPLEMENT ME - finish playback immediately */
+
+ /* once finished, call the finished callback */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+ }
+ else
+ {
+ /* User callback has asked us to stop with paComplete or other non-zero value */
+
+ /* IMPLEMENT ME - finish playback once currently queued audio has completed */
+
+ /* once finished, call the finished callback */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+ }
+}
+
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /*
+ IMPLEMENT ME:
+ - additional stream closing + cleanup
+ */
+
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior */
+
+ return result;
+}
+
+
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior */
+
+ return result;
+}
+
+
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior */
+
+ return result;
+}
+
+
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior */
+
+ return 0;
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior */
+
+ return 0;
+}
+
+
+static PaTime GetStreamTime( PaStream *s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
+/*
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
+
+static PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return paNoError;
+}
+
+
+static PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return paNoError;
+}
+
+
+static signed long GetStreamReadAvailable( PaStream* s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
+}
+
+
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
+}
+
+
+
diff --git a/pd/portaudio/pa_common/pa_skeleton.o b/pd/portaudio/pa_common/pa_skeleton.o
new file mode 100644
index 00000000..4641670a
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_skeleton.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_stream.c b/pd/portaudio/pa_common/pa_stream.c
new file mode 100644
index 00000000..b2eba53d
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_stream.c
@@ -0,0 +1,114 @@
+/*
+ * $Id: pa_stream.c,v 1.1.2.9 2002/12/03 06:30:40 rossbencina Exp $
+ * Portable Audio I/O Library
+ *
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 2002 Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include "pa_stream.h"
+
+void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface,
+ PaError (*Close)( PaStream* ),
+ PaError (*Start)( PaStream* ),
+ PaError (*Stop)( PaStream* ),
+ PaError (*Abort)( PaStream* ),
+ PaError (*IsStopped)( PaStream* ),
+ PaError (*IsActive)( PaStream* ),
+ PaTime (*GetTime)( PaStream* ),
+ double (*GetCpuLoad)( PaStream* ),
+ PaError (*Read)( PaStream*, void *, unsigned long ),
+ PaError (*Write)( PaStream*, void *, unsigned long ),
+ signed long (*GetReadAvailable)( PaStream* ),
+ signed long (*GetWriteAvailable)( PaStream* ) )
+{
+ streamInterface->Close = Close;
+ streamInterface->Start = Start;
+ streamInterface->Stop = Stop;
+ streamInterface->Abort = Abort;
+ streamInterface->IsStopped = IsStopped;
+ streamInterface->IsActive = IsActive;
+ streamInterface->GetTime = GetTime;
+ streamInterface->GetCpuLoad = GetCpuLoad;
+ streamInterface->Read = Read;
+ streamInterface->Write = Write;
+ streamInterface->GetReadAvailable = GetReadAvailable;
+ streamInterface->GetWriteAvailable = GetWriteAvailable;
+}
+
+
+void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation,
+ PaUtilStreamInterface *streamInterface,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ streamRepresentation->magic = PA_STREAM_MAGIC;
+ streamRepresentation->nextOpenStream = 0;
+ streamRepresentation->streamInterface = streamInterface;
+ streamRepresentation->streamCallback = streamCallback;
+ streamRepresentation->streamFinishedCallback = 0;
+
+ streamRepresentation->userData = userData;
+
+ streamRepresentation->streamInfo.inputLatency = 0.;
+ streamRepresentation->streamInfo.outputLatency = 0.;
+ streamRepresentation->streamInfo.sampleRate = 0.;
+}
+
+
+void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation )
+{
+ streamRepresentation->magic = 0;
+}
+
+
+PaError PaUtil_DummyReadWrite( PaStream* stream,
+ void *buffer,
+ unsigned long frames )
+{
+ (void)stream; /* unused parameter */
+ (void)buffer; /* unused parameter */
+ (void)frames; /* unused parameter */
+
+ return paNoError; /* @todo FIXME: need new error code paCantReadWriteToCallbackStream or something */
+}
+
+
+signed long PaUtil_DummyGetAvailable( PaStream* stream )
+{
+ (void)stream; /* unused parameter */
+
+ return 0;
+}
+
+
+double PaUtil_DummyGetCpuLoad( PaStream* stream )
+{
+ (void)stream; /* unused parameter */
+
+ return 0.0;
+}
diff --git a/pd/portaudio/pa_common/pa_stream.h b/pd/portaudio/pa_common/pa_stream.h
new file mode 100644
index 00000000..5e66c097
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_stream.h
@@ -0,0 +1,128 @@
+#ifndef PA_STREAM_H
+#define PA_STREAM_H
+/*
+ * $Id: pa_stream.h,v 1.1.2.9 2002/12/03 06:30:40 rossbencina Exp $
+ * Portable Audio I/O Library
+ * stream interface
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+/** @file
+ Interface used by pa_front to virtualise stream calls.
+*/
+
+#include "portaudio.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+#define PA_STREAM_MAGIC (0x18273645)
+
+typedef struct {
+ /*
+ all PaStreamInterface functions are guaranteed to be called with a
+ non-null, valid <stream> parameter
+ */
+ PaError (*Close)( PaStream* stream );
+ PaError (*Start)( PaStream *stream );
+ PaError (*Stop)( PaStream *stream );
+ PaError (*Abort)( PaStream *stream );
+ PaError (*IsStopped)( PaStream *stream );
+ PaError (*IsActive)( PaStream *stream );
+ PaTime (*GetTime)( PaStream *stream );
+ double (*GetCpuLoad)( PaStream* stream );
+ PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames );
+ PaError (*Write)( PaStream* stream, void *buffer, unsigned long frames );
+ signed long (*GetReadAvailable)( PaStream* stream );
+ signed long (*GetWriteAvailable)( PaStream* stream );
+} PaUtilStreamInterface;
+
+
+void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface,
+ PaError (*Close)( PaStream* ),
+ PaError (*Start)( PaStream* ),
+ PaError (*Stop)( PaStream* ),
+ PaError (*Abort)( PaStream* ),
+ PaError (*IsStopped)( PaStream* ),
+ PaError (*IsActive)( PaStream* ),
+ PaTime (*GetTime)( PaStream* ),
+ double (*GetCpuLoad)( PaStream* ),
+ PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ),
+ PaError (*Write)( PaStream* stream, void *buffer, unsigned long frames ),
+ signed long (*GetReadAvailable)( PaStream* stream ),
+ signed long (*GetWriteAvailable)( PaStream* stream ) );
+
+
+/** Use PaUtil_DummyReadWrite and PaUtil_DummyGetAvailable for
+ callback based streams.
+*/
+PaError PaUtil_DummyReadWrite( PaStream* stream,
+ void *buffer,
+ unsigned long frames );
+
+
+signed long PaUtil_DummyGetAvailable( PaStream* stream );
+
+/** Use PaUtil_DummyGetCpuLoad for read/write streams
+*/
+double PaUtil_DummyGetCpuLoad( PaStream* stream );
+
+
+typedef struct PaUtilStreamRepresentation {
+ unsigned long magic; /* set to PA_STREAM_MAGIC */
+ struct PaUtilStreamRepresentation *nextOpenStream; /* field used by multi-api code */
+ PaUtilStreamInterface *streamInterface;
+ PaStreamCallback *streamCallback;
+ PaStreamFinishedCallback *streamFinishedCallback;
+ void *userData;
+ PaStreamInfo streamInfo;
+} PaUtilStreamRepresentation;
+
+
+void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation,
+ PaUtilStreamInterface *streamInterface,
+ PaStreamCallback *streamCallback,
+ void *userData );
+
+void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation );
+
+
+#define PA_STREAM_REP( streamRepPtr )\
+ ((PaUtilStreamRepresentation*) streamRepPtr )
+
+#define PA_STREAM_INTERFACE( streamRepPtr )\
+ PA_STREAM_REP( streamRepPtr )->streamInterface
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_STREAM_H */
diff --git a/pd/portaudio/pa_common/pa_stream.o b/pd/portaudio/pa_common/pa_stream.o
new file mode 100644
index 00000000..c75789bb
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_stream.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_trace.c b/pd/portaudio/pa_common/pa_trace.c
index d55a6d37..74e8bb2f 100644
--- a/pd/portaudio/pa_common/pa_trace.c
+++ b/pd/portaudio/pa_common/pa_trace.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_trace.c,v 1.1.1.1 2002/01/22 00:52:11 phil Exp $
+ * $Id: pa_trace.c,v 1.1.1.1.2.2 2002/10/26 05:34:03 rossbencina Exp $
* Portable Audio I/O Library Trace Facility
* Store trace information in real-time for later printing.
*
@@ -35,7 +35,7 @@
#include <string.h>
#include "pa_trace.h"
-#if TRACE_REALTIME_EVENTS
+#if PA_TRACE_REALTIME_EVENTS
static char *traceTextArray[MAX_TRACE_RECORDS];
static int traceIntArray[MAX_TRACE_RECORDS];
@@ -43,19 +43,19 @@ static int traceIndex = 0;
static int traceBlock = 0;
/*********************************************************************/
-void ResetTraceMessages()
+void PaUtil_ResetTraceMessages()
{
traceIndex = 0;
}
/*********************************************************************/
-void DumpTraceMessages()
+void PaUtil_DumpTraceMessages()
{
int i;
- int numDump = (traceIndex < MAX_TRACE_RECORDS) ? traceIndex : MAX_TRACE_RECORDS;
+ int messageCount = (traceIndex < PA_MAX_TRACE_RECORDS) ? traceIndex : PA_MAX_TRACE_RECORDS;
printf("DumpTraceMessages: traceIndex = %d\n", traceIndex );
- for( i=0; i<numDump; i++ )
+ for( i=0; i<messageCount; i++ )
{
printf("%3d: %s = 0x%08X\n",
i, traceTextArray[i], traceIntArray[i] );
@@ -65,14 +65,14 @@ void DumpTraceMessages()
}
/*********************************************************************/
-void AddTraceMessage( char *msg, int data )
+void PaUtil_AddTraceMessage( const char *msg, int data )
{
- if( (traceIndex == MAX_TRACE_RECORDS) && (traceBlock == 0) )
+ if( (traceIndex == PA_MAX_TRACE_RECORDS) && (traceBlock == 0) )
{
traceBlock = 1;
- /* DumpTraceMessages(); */
+ /* PaUtil_DumpTraceMessages(); */
}
- else if( traceIndex < MAX_TRACE_RECORDS )
+ else if( traceIndex < PA_MAX_TRACE_RECORDS )
{
traceTextArray[traceIndex] = msg;
traceIntArray[traceIndex] = data;
@@ -80,4 +80,4 @@ void AddTraceMessage( char *msg, int data )
}
}
-#endif
+#endif /* TRACE_REALTIME_EVENTS */
diff --git a/pd/portaudio/pa_common/pa_trace.h b/pd/portaudio/pa_common/pa_trace.h
index d0fc904c..069d006d 100644
--- a/pd/portaudio/pa_common/pa_trace.h
+++ b/pd/portaudio/pa_common/pa_trace.h
@@ -1,7 +1,7 @@
#ifndef PA_TRACE_H
#define PA_TRACE_H
/*
- * $Id: pa_trace.h,v 1.1.1.1 2002/01/22 00:52:11 phil Exp $
+ * $Id: pa_trace.h,v 1.1.1.1.2.2 2002/10/22 08:58:16 rossbencina Exp $
* Portable Audio I/O Library Trace Facility
* Store trace information in real-time for later printing.
*
@@ -32,9 +32,13 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+/** @file
+ Event trace mechanism for debugging. Allows data to be written to the buffer
+ at interrupt time and dumped later.
+*/
-#define TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */
-#define MAX_TRACE_RECORDS (2048)
+#define PA_TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */
+#define PA_MAX_TRACE_RECORDS (2048)
#ifdef __cplusplus
extern "C"
@@ -42,24 +46,21 @@ extern "C"
#endif /* __cplusplus */
- /************************************************************************************/
- /****************** Prototypes ******************************************************/
- /************************************************************************************/
-
-#if TRACE_REALTIME_EVENTS
-
- void DumpTraceMessages();
- void ResetTraceMessages();
- void AddTraceMessage( char *msg, int data );
+#if PA_TRACE_REALTIME_EVENTS
+void PaUtil_ResetTraceMessages();
+void PaUtil_AddTraceMessage( const char *msg, int data );
+void PaUtil_DumpTraceMessages();
+
#else
-#define AddTraceMessage(msg,data) /* noop */
-#define ResetTraceMessages() /* noop */
-#define DumpTraceMessages() /* noop */
+#define PaUtil_ResetTraceMessages() /* noop */
+#define PaUtil_AddTraceMessage(msg,data) /* noop */
+#define PaUtil_DumpTraceMessages() /* noop */
#endif
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/pd/portaudio/pa_common/pa_trace.o b/pd/portaudio/pa_common/pa_trace.o
new file mode 100644
index 00000000..0c160bea
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_trace.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_util.h b/pd/portaudio/pa_common/pa_util.h
new file mode 100644
index 00000000..c87d71ca
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_util.h
@@ -0,0 +1,143 @@
+#ifndef PA_UTIL_H
+#define PA_UTIL_H
+/*
+ * Id:
+ * Portable Audio I/O Library implementation utilities header
+ * common implementation utilities and interfaces
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include "portaudio.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+struct PaUtilHostApiRepresentation;
+
+
+/** Retrieve a specific host API representation. This function can be used
+ by implementations to retrieve a pointer to their representation in
+ host api specific extension functions which aren't passed a rep pointer
+ by pa_front.c.
+
+ @param hostApi A pointer to a host API represenation pointer. Apon success
+ this will receive the requested representation pointer.
+
+ @param type A valid host API type identifier.
+
+ @returns An error code. If the result is PaNoError then a pointer to the
+ requested host API representation will be stored in *hostApi.
+*/
+PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,
+ PaHostApiTypeId type );
+
+
+/** Convert a PortAudio device index into a host API specific device index.
+ @param hostApiDevice Pointer to a device index, on success this will recieve the
+ converted device index value.
+ @param device The PortAudio device index to convert.
+ @param hostApi The host api which the index should be converted for.
+
+ @returns On success returns PaNoError and places the converted index in the
+ hostApiDevice parameter.
+*/
+PaError PaUtil_DeviceIndexToHostApiDeviceIndex(
+ PaDeviceIndex *hostApiDevice, PaDeviceIndex device,
+ struct PaUtilHostApiRepresentation *hostApi );
+
+
+/** Set the host error information returned by Pa_GetLastHostErrorInfo. This
+ function and the paUnanticipatedHostError error code should be used as a
+ last resort. Implementors should use existing PA error codes where possible,
+ or nominate new ones. Note that at it is always better to use
+ PaUtil_SetLastHostErrorInfo() and paUnanticipatedHostError than to return an
+ ambiguous or inaccurate PaError code.
+
+ @param hostApiType The host API which encountered the error (ie of the caller)
+
+ @param errorCode The error code returned by the native API function.
+
+ @param errorText A string describing the error. PaUtil_SetLastHostErrorInfo
+ makes a copy of the string, so it is not necessary for the pointer to remain
+ valid after the call to PaUtil_SetLastHostErrorInfo() returns.
+
+*/
+void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
+ const char *errorText );
+
+
+
+/**
+PA_DEBUG() provides a simple debug message printing facility. The macro
+passes it's argument to a printf-like function called PaUtil_DebugPrint()
+which prints to stderr and always flushes the stream after printing.
+Because preprocessor macros cannot directly accept variable length argument
+lists, calls to the macro must include an additional set of parenthesis, eg:
+PA_DEBUG(("errorno: %d", 1001 ));
+*/
+
+void PaUtil_DebugPrint( const char *format, ... );
+
+#if (0) /* set to 1 to print debug messages */
+#define PA_DEBUG(x) PaUtil_DebugPrint x ;
+#else
+#define PA_DEBUG(x)
+#endif
+
+
+/* the following functions are implemented in a per-platform .c file */
+
+void *PaUtil_AllocateMemory( long size );
+/**< Allocate size bytes, guaranteed to be aligned to a FIXME byte boundary */
+
+void PaUtil_FreeMemory( void *block );
+/**< Realease block if non-NULL. block may be NULL */
+
+int PaUtil_CountCurrentlyAllocatedBlocks( void );
+/**<
+ Return the number of currently allocated blocks. This function can be
+ used for detecting memory leaks.
+
+ @note Allocations will only be tracked if PA_TRACK_MEMORY is #defined. If
+ it isn't, this function will always return 0.
+*/
+
+
+void PaUtil_InitializeClock( void );
+double PaUtil_GetTime( void ); /* system time in seconds, used to implement CPU load functions */
+
+/* void Pa_Sleep( long msec ); must also be implemented in per-platform .c file */
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_UTIL_H */
diff --git a/pd/portaudio/pa_common/portaudio.h b/pd/portaudio/pa_common/portaudio.h
index 06f7079b..68303e1c 100644
--- a/pd/portaudio/pa_common/portaudio.h
+++ b/pd/portaudio/pa_common/portaudio.h
@@ -1,5 +1,5 @@
-#ifndef PORT_AUDIO_H
-#define PORT_AUDIO_H
+#ifndef PORTAUDIO_H
+#define PORTAUDIO_H
#ifdef __cplusplus
extern "C"
@@ -7,12 +7,12 @@ extern "C"
#endif /* __cplusplus */
/*
- * $Id: portaudio.h,v 1.5 2002/03/26 18:04:22 philburk Exp $
+ * $Id: portaudio.h,v 1.5.2.34 2002/12/03 07:02:54 rossbencina Exp $
* PortAudio Portable Real-Time Audio Library
* PortAudio API Header File
- * Latest version available at: http://www.audiomulch.com/portaudio/
+ * Latest version available at: http://www.portaudio.com/
*
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ * Copyright (c) 1999-2002 Ross Bencina and Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -39,14 +39,31 @@ extern "C"
*
*/
+
+/** Retrieve the release number of the currently running PortAudio build,
+ eg 1900.
+*/
+int Pa_GetVersion( void );
+
+
+/** Retrieve a textual description of the current PortAudio build,
+ eg "PortAudio V19-devel 13 October 2002".
+*/
+const char* Pa_GetVersionText( void );
+
+
+/** Error codes returned by PortAudio functions. */
+
typedef int PaError;
-typedef enum {
+typedef enum PaErrorCode
+{
paNoError = 0,
- paHostError = -10000,
+ paNotInitialized = -10000,
+ paUnanticipatedHostError,
paInvalidChannelCount,
paInvalidSampleRate,
- paInvalidDeviceId,
+ paInvalidDevice,
paInvalidFlag,
paSampleFormatNotSupported,
paBadIODeviceCombination,
@@ -57,407 +74,999 @@ typedef enum {
paBadStreamPtr,
paTimedOut,
paInternalError,
- paDeviceUnavailable
-} PaErrorNum;
+ paDeviceUnavailable,
+ paIncompatibleHostApiSpecificStreamInfo,
+ paStreamIsStopped,
+ paStreamIsNotStopped,
+ paInputOverflowed,
+ paOutputUnderflowed
+} PaErrorCode;
-/*
- Pa_Initialize() is the library initialisation function - call this before
- using the library.
+/** Translate the supplied PortAudio error number into a human readable
+ message.
*/
+const char *Pa_GetErrorText( PaError errorNumber );
-PaError Pa_Initialize( void );
-/*
- Pa_Terminate() is the library termination function - call this after
- using the library.
+/** Library initialization function - call this before using PortAudio.
+ This function initialises internal data structures and prepares underlying
+ host APIs for use. This function MUST be called before using any other
+ PortAudio API functions.
+
+ If Pa_Initialize() is called multiple times, each call must be matched with
+ a corresponding call to Pa_Terminate(). Pairs of calls to
+ Pa_Initialize()/Pa_Terminate() may overlap, and are not requireed to be fully
+ nested.
+ @return paNoError if successful, otherwise an error code indicating the cause
+ of failure.
+
+ @see Pa_Terminate
*/
+PaError Pa_Initialize( void );
+
+
+/** Library termination function - call this when finished using PortAudio.
+ This function deallocates all resources allocated by PortAudio since it was
+ initializied by a call to Pa_Initialize(). In cases where Pa_Initialise() has
+ been called multiple times, each call must be matched with a corresponding call
+ to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically
+ close any PortAudio streams that are still open.
+ Pa_Terminate() MUST be called before exiting a program which uses PortAudio.
+ Failure to do so may result in serious resource leaks, such as audio devices
+ not being available until the next reboot.
+
+ @return paNoError if successful, otherwise an error code indicating the cause
+ of failure.
+
+ @see Pa_Initialize
+*/
PaError Pa_Terminate( void );
-/*
- Pa_GetHostError() returns a host specific error code.
- This can be called after receiving a PortAudio error code of paHostError.
+
+/** The type used to refer to audio devices. Values of this type usually
+ range from 0 to (Pa_DeviceCount-1), and may also take on the PaNoDevice
+ and paUseHostApiSpecificDeviceSpecification values.
+
+ @see Pa_DeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification
*/
+typedef int PaDeviceIndex;
-long Pa_GetHostError( void );
-/*
- Pa_GetErrorText() translates the supplied PortAudio error number
- into a human readable message.
-
+/** A special PaDeviceIndex value indicating that no device is available,
+ or should be used.
+
+ @see PaDeviceIndex
*/
+#define paNoDevice ((PaDeviceIndex)-1)
-const char *Pa_GetErrorText( PaError errnum );
-/*
- Sample formats
-
- These are formats used to pass sound data between the callback and the
- stream. Each device has a "native" format which may be used when optimum
- efficiency or control over conversion is required.
-
- Formats marked "always available" are supported (emulated) by all
- PortAudio implementations.
-
- The floating point representation (paFloat32) uses +1.0 and -1.0 as the
- maximum and minimum respectively.
+/** A special PaDeviceIndex value indicating that the device(s) to be used
+ are specified in the host api specific stream info structure.
- paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
+ @see PaDeviceIndex
+*/
+#define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2)
+
+/* Host API enumeration mechanism */
+
+/** The type used to enumerate to host APIs at runtime. Values of this type
+ range from 0 to (Pa_CountHostApis()-1).
+
+ @see Pa_CountHostApis
*/
+typedef int PaHostApiIndex;
-typedef unsigned long PaSampleFormat;
-#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
-#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
-#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
-#define paInt24 ((PaSampleFormat) (1<<3))
-#define paPackedInt24 ((PaSampleFormat) (1<<4))
-#define paInt8 ((PaSampleFormat) (1<<5))
-#define paUInt8 ((PaSampleFormat) (1<<6))
-#define paCustomFormat ((PaSampleFormat) (1<<16))
-/*
- Device enumeration mechanism.
-
- Device ids range from 0 to Pa_CountDevices()-1.
-
- Devices may support input, output or both.
+/** Retrieve the number of available host APIs. Even if a host API is
+ available it may have no devices available.
+ @return A non-negative value indicating the number of available host APIs.
+ Returns a negative PaErrorCode if PortAudio is not initialized or an error
+ is encountered.
+
+ @see PaHostApiIndex
*/
+PaHostApiIndex Pa_CountHostApis( void );
-typedef int PaDeviceID;
-#define paNoDevice -1
-int Pa_CountDevices( void );
+/** Retrieve the index of the default host API. The default host API will be
+ the lowest common denominator host API on the current platform and is
+ unlikely to provide the best performance.
-typedef struct
+ @return A non-negative value indicating the default host API index. Returns a
+ negative PaErrorCode if PortAudio is not initialized or an error is encountered.
+*/
+PaHostApiIndex Pa_GetDefaultHostApi( void );
+
+
+/** Unchanging unique identifiers for each supported host API. This type
+ is used in the PaHostApiInfo structure. The values are guaranteed to be
+ unique and to never change, thus allowing code to be written that
+ conditionally uses host API specific extensions.
+
+ New type ids will be allocated when support for a host API reaches
+ "public alpha" status, prior to that developers should use the
+ paInDevelopment type id.
+
+ @see PaHostApiInfo
+*/
+typedef enum PaHostApiTypeId
+{
+ paInDevelopment=0, /* use while developing support for a new host API */
+ paDirectSound=1,
+ paMME=2,
+ paASIO=3,
+ paSoundManager=4,
+ paCoreAudio=5,
+ paOSS=7,
+ paALSA=8,
+ paAL=9,
+ paBeOS=10
+} PaHostApiTypeId;
+
+
+/** A structure containing information about a particular host API. */
+
+typedef struct PaHostApiInfo
{
+ /** this is struct version 1 */
int structVersion;
+ /** The well known unique identifier of this host API @see PaHostApiTypeId */
+ PaHostApiTypeId type;
+ /** A textual description of the host API for display on user interfaces. */
const char *name;
- int maxInputChannels;
- int maxOutputChannels;
- /* Number of discrete rates, or -1 if range supported. */
- int numSampleRates;
- /* Array of supported sample rates, or {min,max} if range supported. */
- const double *sampleRates;
- PaSampleFormat nativeSampleFormats;
-}
-PaDeviceInfo;
-/*
- Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() return the
- default device ids for input and output respectively, or paNoDevice if
- no device is available.
- The result can be passed to Pa_OpenStream().
-
+ /** The number of devices belonging to this host API. This field may be
+ used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate
+ all devices for this host API.
+ @see Pa_HostApiDeviceIndexToDeviceIndex
+ */
+ int deviceCount;
+
+ /** The the default input device for this host API. The value will be a
+ device index ranging from 0 to (Pa_CountDevices()-1), or paNoDevice
+ if no default input device is available.
+ */
+ PaDeviceIndex defaultInputDevice;
+
+ /** The the default output device for this host API. The value will be a
+ device index ranging from 0 to (Pa_CountDevices()-1), or paNoDevice
+ if no default output device is available.
+ */
+ PaDeviceIndex defaultOutputDevice;
+
+} PaHostApiInfo;
+
+
+/** Retrieve a pointer to a structure containing information about a specific
+ host Api.
+
+ @param hostApi A valid host API index ranging from 0 to (Pa_CountHostApis()-1)
+
+ @return A pointer to an immutable PaHostApiInfo structure describing
+ a specific host API. If the hostApi parameter is out of range or an error
+ is encountered, the function returns NULL.
+
+ The returned structure is owned by the PortAudio implementation and must not
+ be manipulated or freed. The pointer is only guaranteed to be valid between
+ calls to Pa_Initialize() and Pa_Terminate().
+*/
+const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi );
+
+
+/** Convert a static host API unique identifier, into a runtime
+ host API index.
+
+ @param type A unique host API identifier belonging to the PaHostApiTypeId
+ enumeration.
+
+ @return A valid PaHostApiIndex ranging from 0 to (Pa_CountHostApis()-1), or
+ -1 if the host API specified by the type parameter is not available.
+
+ @see PaHostApiTypeId
+*/
+PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type );
+
+
+/** Convert a host-API-specific device index to standard PortAudio device index.
+ This function may be used in conjunction with the deviceCount field of
+ PaHostApiInfo to enumerate all devices for the specified host API.
+
+ @param hostApi A valid host API index ranging from 0 to (Pa_CountHostApis()-1)
+
+ @param hostApiDeviceIndex A valid per-host device index in the range
+ 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1)
+
+ @see PaHostApiInfo
+*/
+PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi,
+ int hostApiDeviceIndex );
+
+
+
+/** Structure used to return information about a host error condition.
+*/
+typedef struct PaHostErrorInfo{
+ PaHostApiTypeId hostApiType; /**< the host API which returned the error code */
+ long errorCode; /**< the error code returned */
+ const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */
+}PaHostErrorInfo;
+
+
+/** Return information about the last host error encountered. The error
+ information returned by Pa_GetLastHostErrorInfo() will never be modified
+ asyncronously by errors occurring in other PortAudio owned threads
+ (such as the thread that manages the stream callback.)
+
+ This function is provided as a last resort, primarily to enhance debugging
+ by providing clients with access to all available error information.
+
+ @return A pointer to an immutable structure constaining information about
+ the host error. The values in this structure will only be valid if a
+ PortAudio function has previously returned the paUnanticipatedHostError
+ error code.
+*/
+const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void );
+
+
+
+/* Device enumeration and capabilities */
+
+/** Retrieve the number of available devices.
+ @return The number of available devices. May return 0 if PortAudio is
+ not initialized or an error has occured.
+*/
+PaDeviceIndex Pa_CountDevices( void );
+
+
+/** Retrieve the index of the default input device. The result can be
+ used in the inputDevice parameter to Pa_OpenStream().
+
+ @return The default input device index for the defualt host API, or paNoDevice
+ if no default input device is available or an error was encountered.
+*/
+PaDeviceIndex Pa_GetDefaultInputDevice( void );
+
+
+/** Retrieve the index of the default output device. The result can be
+ used in the outputDevice parameter to Pa_OpenStream().
+
+ @return The default output device index for the defualt host API, or paNoDevice
+ if no default output device is available or an error was encountered.
+
+ @note
On the PC, the user can specify a default device by
setting an environment variable. For example, to use device #1.
-
- set PA_RECOMMENDED_OUTPUT_DEVICE=1
-
+<pre>
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+</pre>
The user should first determine the available device ids by using
the supplied application "pa_devs".
+*/
+PaDeviceIndex Pa_GetDefaultOutputDevice( void );
+
+/** The type used to represent monotonic time in seconds that can be used
+ for syncronisation. The type is used for the outTime argument to the
+ PaStreamCallback and as the result of Pa_GetStreamTime().
+
+ @see PaStreamCallback, Pa_GetStreamTime
*/
+typedef double PaTime;
-PaDeviceID Pa_GetDefaultInputDeviceID( void );
-PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+/** A type used to specify one or more sample formats. They indicate
+ the formats used to pass sound data between the stream callback and the
+ stream. Each device has one or more "native" formats which may be used when
+ optimum efficiency or control over conversion is required.
+ Formats marked "always available" are supported (emulated) by all
+ PortAudio implementations.
-/*
- Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
- for the device specified.
- If the device parameter is out of range the function returns NULL.
+ The floating point representation (paFloat32) uses +1.0 and -1.0 as the
+ maximum and minimum respectively.
- PortAudio manages the memory referenced by the returned pointer, the client
- must not manipulate or free the memory. The pointer is only guaranteed to be
- valid between calls to Pa_Initialize() and Pa_Terminate().
+ paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
+
+ The paNonInterleaved flag indicates that a multichannel buffer is passed
+ as a set of non-interleaved pointers.
+ @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo
+ @see paFloat32, paInt16, paInt32, paInt24, paInt8
+ @see paUInt8, paCustomFormat, paNonInterleaved
*/
+typedef unsigned long PaSampleFormat;
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID device );
-/*
- PaTimestamp is used to represent a continuous sample clock with arbitrary
- start time that can be used for syncronization. The type is used for the
- outTime argument to the PortAudioCallback and as the result of Pa_StreamTime()
+#define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */
+#define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */
+#define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */
+#define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */
+#define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */
+#define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */
+#define paCustomFormat ((PaSampleFormat) 0x00010000)/**< @see PaSampleFormat */
+
+#define paNonInterleaved ((PaSampleFormat) 0x80000000)
+/** A structure providing information and capabilities of PortAudio devices.
+ Devices may support input, output or both input and output.
*/
+typedef struct PaDeviceInfo
+{
+ int structVersion; /* this is struct version 2 */
+ const char *name;
+ PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/
+
+ int maxInputChannels;
+ int maxOutputChannels;
-typedef double PaTimestamp;
+ /* Default latency values for interactive performance. */
+ PaTime defaultLowInputLatency;
+ PaTime defaultLowOutputLatency;
+ /* Default latency values for robust non-interactive applications (eg. playing sound files). */
+ PaTime defaultHighInputLatency;
+ PaTime defaultHighOutputLatency;
-/*
- PortAudioCallback is implemented by PortAudio clients.
-
- inputBuffer and outputBuffer are arrays of interleaved samples,
- the format, packing and number of channels used by the buffers are
- determined by parameters to Pa_OpenStream() (see below).
-
- framesPerBuffer is the number of sample frames to be processed by the callback.
-
- outTime is the time in samples when the buffer(s) processed by
- this callback will begin being played at the audio output.
- See also Pa_StreamTime()
-
- userData is the value of a user supplied pointer passed to Pa_OpenStream()
- intended for storing synthesis data etc.
-
- return value:
- The callback can return a non-zero value to stop the stream. This may be
- useful in applications such as soundfile players where a specific duration
- of output is required. However, it is not necessary to utilise this mechanism
- as StopStream() will also terminate the stream. A callback returning a
- non-zero value must fill the entire outputBuffer.
-
- NOTE: None of the other stream functions may be called from within the
- callback function except for Pa_GetCPULoad().
+ double defaultSampleRate;
+} PaDeviceInfo;
+
+
+/** Retrieve a pointer to a PaDeviceInfo structure containing information
+ about the specified device.
+ @return A pointer to an immutable PaDeviceInfo structure. If the device
+ parameter is out of range the function returns NULL.
+
+ @param device A valid device index in the range 0 to (Pa_CountDevices()-1)
+ @note PortAudio manages the memory referenced by the returned pointer,
+ the client must not manipulate or free the memory. The pointer is only
+ guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate().
+
+ @see PaDeviceInfo, PaDeviceIndex
*/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device );
-typedef int (PortAudioCallback)(
- void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- PaTimestamp outTime, void *userData );
+/** Parameters for one direction (input or output) of a stream.
+*/
+typedef struct PaStreamParameters
+{
+ /** A valid device index in the range 0 to (Pa_CountDevices()-1)
+ specifying the device to be used or the special constant
+ paUseHostApiSpecificDeviceSpecification which indicates that the actual
+ device(s) to use are specified in hostApiSpecificStreamInfo.
+ This field must not be set to paNoDevice.
+ */
+ PaDeviceIndex device;
+
+ /** The number of channels of sound to be delivered to the
+ stream callback or accessed by Pa_ReadStream() or Pa_WriteStream().
+ It can range from 1 to the value of maxInputChannels in the
+ PaDeviceInfo record for the device specified by the device parameter.
+ */
+ int channelCount;
+
+ /** The sample format of the buffer provided to the stream callback,
+ a_ReadStream() or Pa_WriteStream(). It may be any of the formats described
+ by the PaSampleFormat enumeration.
+ FIXME: wrt below, what are we guaranteeing these days, if anything?
+ PortAudio guarantees support for
+ the device's native formats (nativeSampleFormats in the device info record)
+ and additionally 16 and 32 bit integer and 32 bit floating point formats.
+ Support for other formats is implementation defined.
+ */
+ PaSampleFormat sampleFormat;
+
+ /** The desired latency in seconds. Where practical, implementations should
+ configure their latency based on these parameters, otherwise they may
+ choose the closest viable latency instead. Unless the suggested latency
+ is greater than the absolute upper limit for the device implementations
+ shouldround the suggestedLatency up to the next practial value - ie to
+ provide an equal or higher latency than suggestedLatency whereever possibe.
+ Actual latency values for an open stream may be retrieved using the
+ inputLatency and outputLatency fields of the PaStreamInfo structure
+ returned by Pa_GetStreamInfo().
+ @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo
+ */
+ PaTime suggestedLatency;
+
+ /** An optional pointer to a host api specific data structure
+ containing additional information for device setup and/or stream processing.
+ hostApiSpecificStreamInfo is never required for correct operation.
+ If not used it should be set to paNullHostApiSpecificStreamInfo (aka NULL)
+ FIXME: redocument this based on new changes:
+ If hostApiSpecificStreamInfo is supplied, it's
+ size and hostApi fields must be compatible with the input devices host api.
+ */
+ void *hostApiSpecificStreamInfo;
+
+} PaStreamParameters;
+
+
+/** Return code for Pa_IsFormatSupported indicating success. */
+#define paFormatIsSupported (0)
+
+/** Determine whether it would be possible to open a stream with the specified
+ parameters.
+
+ @param inputParameters A structure that describes the input parameters used to
+ open a stream. The suggestedLatency field is ignored. See PaStreamParameters
+ for a description of these parameters. inputParameters must be NULL for
+ output-only streams.
+
+ @param outputParameters A structure that describes the output parameters used
+ to open a stream. The suggestedLatency field is ignored. See PaStreamParameters
+ for a description of these parameters. outputParameters must be NULL for
+ input-only streams.
+
+ @param sampleRate The required sampleRate. For full-duplex streams it is the
+ sample rate for both input and output
-/*
- Stream flags
-
- These flags may be supplied (ored together) in the streamFlags argument to
- the Pa_OpenStream() function.
+ @return Returns 0 if the format is supported, and an error code indicating why
+ the format is not supported otherwise. The constant paFormatIsSupported is
+ provided to compare with the return value for success.
+ @see paFormatIsSupported, PaStreamParameters
*/
+PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate );
-#define paNoFlag (0)
-#define paClipOff (1<<0) /* disable default clipping of out of range samples */
-#define paDitherOff (1<<1) /* disable default dithering */
-#define paPlatformSpecificFlags (0x00010000)
-typedef unsigned long PaStreamFlags;
-/*
- A single PortAudioStream provides multiple channels of real-time
- input and output audio streaming to a client application.
- Pointers to PortAudioStream objects are passed between PortAudio functions.
+
+/* Streaming types and functions */
+
+
+/**
+ A single PaStream can provide multiple channels of real-time
+ streaming audio input and output to a client application. A stream
+ provides access to audio hardware represented by one or more
+ PaDevices. Depending on the underlying Host API, it may be possible
+ to open multiple streams using the same device, however this behavior
+ is implementation defined. Portable applications should assume that
+ a PaDevice may be simultaneously used by at most one PaStream.
+
+ Pointers to PaStream objects are passed between PortAudio functions that
+ operate on streams.
+
+ @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream,
+ Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive,
+ Pa_GetStreamTime, Pa_GetStreamCpuLoad
+
*/
+typedef void PaStream;
-typedef void PortAudioStream;
-#define PaStream PortAudioStream
-/*
- Pa_OpenStream() opens a stream for either input, output or both.
-
- stream is the address of a PortAudioStream pointer which will receive
+/** Can be passed as the framesPerBuffer parameter to Pa_OpenStream()
+ or Pa_OpenDefaultStream() to indicate that the stream callback will
+ accept buffers of any size.
+*/
+#define paFramesPerBufferUnspecified (0)
+
+
+/** Flags used to control the behavior of a stream. They are passed as
+ parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be
+ ORed together.
+
+ @see Pa_OpenStream, Pa_OpenDefaultStream
+ @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput,
+ paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags
+*/
+typedef unsigned long PaStreamFlags;
+
+/** @see PaStreamFlags */
+#define paNoFlag ((PaStreamFlags) 0)
+
+/** Disable default clipping of out of range samples.
+ @see PaStreamFlags
+*/
+#define paClipOff ((PaStreamFlags) 0x00000001)
+
+/** Disable default dithering.
+ @see PaStreamFlags
+*/
+#define paDitherOff ((PaStreamFlags) 0x00000002)
+
+/** A full duplex stream will not discard overflowed input samples without
+ calling the stream callback, this flag is ignored for blocking read/write
+ streams.
+ @see PaStreamFlags
+*/
+#define paNeverDropInput ((PaStreamFlags) 0x00000004)
+
+/** Call the stream callback to fill initial output buffers, rather than the
+ default behavior of priming the buffers with zeros (silence). This flag has
+ no effect for input-only and blocking read/write streams.
+ @see PaStreamFlags
+*/
+#define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008)
+
+/** A mask specifying the platform specific bits.
+ @see PaStreamFlags
+*/
+#define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000)
+
+/**
+ Timing information for the buffers passed to the stream callback.
+*/
+typedef struct PaStreamCallbackTimeInfo{
+ PaTime inputBufferAdcTime;
+ PaTime currentTime;
+ PaTime outputBufferDacTime;
+} PaStreamCallbackTimeInfo;
+
+
+/**
+ Flag bit constants for the statusFlags to PaStreamCallback.
+
+ @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow,
+ paPrimingOutput
+*/
+typedef unsigned long PaStreamCallbackFlags;
+
+/** Input data is all zeros because no real data is available.
+ @see PaStreamCallbackFlags
+*/
+#define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001)
+
+/** Input data was discarded by PortAudio
+ @see PaStreamCallbackFlags
+*/
+#define paInputOverflow ((PaStreamCallbackFlags) 0x00000002)
+
+/** Output data was inserted by PortAudio because the stream callback is using
+ too much CPU
+ @see PaStreamCallbackFlags
+*/
+#define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004)
+
+/** Output data will be discarded because no room is available.
+ @see PaStreamCallbackFlags
+*/
+#define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008)
+
+/** Some of all of the output data will be used to prime the stream, input
+ data may be zero.
+ @see PaStreamCallbackFlags
+*/
+#define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010)
+
+/**
+ Allowable return values for the PaStreamCallback.
+ @see PaStreamCallback
+*/
+typedef enum PaStreamCallbackResult
+{
+ paContinue=0,
+ paComplete=1,
+ paAbort=2
+} PaStreamCallbackResult;
+
+
+/**
+ Functions of type PaStreamCallback are implemented by PortAudio clients.
+ They consume, process or generate audio in response to requests from an
+ active PortAudio stream.
+
+ @param input and @param output are arrays of interleaved samples,
+ the format, packing and number of channels used by the buffers are
+ determined by parameters to Pa_OpenStream().
+
+ @param frameCount The number of sample frames to be processed by
+ the stream callback.
+
+ @param timeInfo The time in seconds when the first sample of the input
+ buffer was received at the audio input, the time in seconds when the first
+ sample of the output buffer will begin being played at the audio output, and
+ the time in seconds when the stream callback was called.
+ See also Pa_GetStreamTime()
+
+ @param statusFlags Flags indicating whether input and/or output buffers
+ have been inserted or will be dropped to overcome underflow or overflow
+ conditions.
+
+ @param userData The value of a user supplied pointer passed to
+ Pa_OpenStream() intended for storing synthesis data etc.
+
+ @return
+ The stream callback should return one of the values in the
+ PaStreamCallbackResult enumeration. To ensure that the callback is continues
+ to be called, it should return paContinue (0). Either paComplete or paAbort
+ can be returned to finish stream processing, after either of these values is
+ returned the callback will not be called again. If paAbort is returned the
+ stream will finish as soon as possible. If paComplete is returned, the stream
+ will continue until all buffers generated by the callback have been played.
+ This may be useful in applications such as soundfile players where a specific
+ duration of output is required. However, it is not necessary to utilise this
+ mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also
+ be used to stop the stream. The callback must always fill the entire output
+ buffer irrespective of its return value.
+
+ @see Pa_OpenStream, Pa_OpenDefaultStream
+
+ @note With the exception of Pa_GetStreamCpuLoad() it is not permissable to call
+ PortAudio API functions from within the stream callback.
+*/
+typedef int PaStreamCallback(
+ void *input, void *output,
+ unsigned long frameCount,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData );
+
+
+/** Opens a stream for either input, output or both.
+
+ @param stream The address of a PaStream pointer which will receive
a pointer to the newly opened stream.
+
+ @param inputParameters A structure that describes the input parameters used by
+ the opened stream. See PaStreamParameters for a description of these parameters.
+ inputParameters must be NULL for output-only streams.
+
+ @param outputParameters A structure that describes the output parameters used by
+ the opened stream. See PaStreamParameters for a description of these parameters.
+ outputParameters must be NULL for input-only streams.
- inputDevice is the id of the device used for input (see PaDeviceID above.)
- inputDevice may be paNoDevice to indicate that an input device is not required.
-
- numInputChannels is the number of channels of sound to be delivered to the
- callback. It can range from 1 to the value of maxInputChannels in the
- PaDeviceInfo record for the device specified by the inputDevice parameter.
- If inputDevice is paNoDevice numInputChannels is ignored.
-
- inputSampleFormat is the sample format of inputBuffer provided to the callback
- function. inputSampleFormat may be any of the formats described by the
- PaSampleFormat enumeration (see above). PortAudio guarantees support for
- the device's native formats (nativeSampleFormats in the device info record)
- and additionally 16 and 32 bit integer and 32 bit floating point formats.
- Support for other formats is implementation defined.
-
- inputDriverInfo is a pointer to an optional driver specific data structure
- containing additional information for device setup or stream processing.
- inputDriverInfo is never required for correct operation. If not used
- inputDriverInfo should be NULL.
-
- outputDevice is the id of the device used for output (see PaDeviceID above.)
- outputDevice may be paNoDevice to indicate that an output device is not required.
-
- numOutputChannels is the number of channels of sound to be supplied by the
- callback. See the definition of numInputChannels above for more details.
-
- outputSampleFormat is the sample format of the outputBuffer filled by the
- callback function. See the definition of inputSampleFormat above for more
- details.
-
- outputDriverInfo is a pointer to an optional driver specific data structure
- containing additional information for device setup or stream processing.
- outputDriverInfo is never required for correct operation. If not used
- outputDriverInfo should be NULL.
-
- sampleRate is the desired sampleRate. For full-duplex streams it is the
+ @param sampleRate The desired sampleRate. For full-duplex streams it is the
sample rate for both input and output
+
+ @param framesPerBuffer The number of frames passed to the stream callback
+ function, or the preferred block granularity for a blocking read/write stream.
+ The special value paFramesPerBufferUnspecified (0) may be used to request that
+ the stream callback will recieve an optimal (and possibly varying) number of
+ frames based on host requirements and the requested latency settings.
+ Note: With some host APIs, the use of non-zero framesPerBuffer for a callback
+ stream may introduce an additional layer of buffering which could introduce
+ additional latency. PortAudio guarantees that the additional latency
+ will be kept to the theoretical minimum however, it is strongly recommended
+ that a non-zero framesPerBuffer value only be used when your algorithm
+ requires a fixed number of frames per stream callback.
- framesPerBuffer is the length in sample frames of all internal sample buffers
- used for communication with platform specific audio routines. Wherever
- possible this corresponds to the framesPerBuffer parameter passed to the
- callback function.
-
- numberOfBuffers is the number of buffers used for multibuffered communication
- with the platform specific audio routines. If you pass zero, then an optimum
- value will be chosen for you internally. This parameter is provided only
- as a guide - and does not imply that an implementation must use multibuffered
- i/o when reliable double buffering is available (such as SndPlayDoubleBuffer()
- on the Macintosh.)
-
- streamFlags may contain a combination of flags ORed together.
- These flags modify the behaviour of the streaming process. Some flags may only
- be relevant to certain buffer formats.
-
- callback is a pointer to a client supplied function that is responsible
- for processing and filling input and output buffers (see above for details.)
-
- userData is a client supplied pointer which is passed to the callback
+ @param streamFlags Flags which modify the behaviour of the streaming process.
+ This parameter may contain a combination of flags ORed together. Some flags may
+ only be relevant to certain buffer formats.
+
+ @param streamCallback A pointer to a client supplied function that is responsible
+ for processing and filling input and output buffers. If this parameter is NULL
+ the stream will be opened in 'blocking read/write' mode. In blocking mode,
+ the client can receive sample data using Pa_ReadStream and write sample data
+ using Pa_WriteStream, the number of samples that may be read or written
+ without blocking is returned by Pa_GetStreamReadAvailable and
+ Pa_GetStreamWriteAvailable respectively.
+
+ @param userData A client supplied pointer which is passed to the stream callback
function. It could for example, contain a pointer to instance data necessary
for processing the audio buffers.
-
- return value:
- Upon success Pa_OpenStream() returns PaNoError and places a pointer to a
- valid PortAudioStream in the stream argument. The stream is inactive (stopped).
- If a call to Pa_OpenStream() fails a non-zero error code is returned (see
- PaError above) and the value of stream is invalid.
-
+
+ @return
+ Upon success Pa_OpenStream() returns paNoError and places a pointer to a
+ valid PaStream in the stream argument. The stream is inactive (stopped).
+ If a call to Pa_OpenStream() fails, a non-zero error code is returned (see
+ PaError for possible error codes) and the value of stream is invalid.
+
+ @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream,
+ Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable
*/
-
-PaError Pa_OpenStream( PortAudioStream** stream,
- PaDeviceID inputDevice,
- int numInputChannels,
- PaSampleFormat inputSampleFormat,
- void *inputDriverInfo,
- PaDeviceID outputDevice,
- int numOutputChannels,
- PaSampleFormat outputSampleFormat,
- void *outputDriverInfo,
+PaError Pa_OpenStream( PaStream** stream,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
double sampleRate,
unsigned long framesPerBuffer,
- unsigned long numberOfBuffers,
PaStreamFlags streamFlags,
- PortAudioCallback *callback,
+ PaStreamCallback *streamCallback,
void *userData );
-/*
- Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that opens
- the default input and/or output devices. Most parameters have identical meaning
- to their Pa_OpenStream() counterparts, with the following exceptions:
+/** A simplified version of Pa_OpenStream() that opens the default input
+ and/or output devices.
+
+ @param stream The address of a PaStream pointer which will receive
+ a pointer to the newly opened stream.
- If either numInputChannels or numOutputChannels is 0 the respective device
- is not opened. This has the same effect as passing paNoDevice in the device
- arguments to Pa_OpenStream().
+ @param numInputChannels The number of channels of sound that will be supplied
+ to the stream callback or returned by Pa_ReadStream. It can range from 1 to
+ the value of maxInputChannels in the PaDeviceInfo record for the default input
+ device. If 0 the stream is opened as an output-only stream.
+
+ @param numOutputChannels The number of channels of sound to be delivered to the
+ stream callback or passed to Pa_WriteStream. It can range from 1 to the value
+ of maxOutputChannels in the PaDeviceInfo record for the default output dvice.
+ If 0 the stream is opened as an output-only stream.
+
+ @param sampleFormat The sample format of both the input and output buffers
+ provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream.
+ sampleFormat may be any of the formats described by the PaSampleFormat enumeration
+ (see above).
+ FIXME: the following may need to be rewritten - PortAudio guarantees support for
+ the device's native formats (nativeSampleFormats in the device info record)
+ and additionally 16 and 32 bit integer and 32 bit float
- sampleFormat applies to both the input and output buffers.
+ @param sampleRate Same as Pa_OpenStream parameter of the same name.
+ @param framesPerBuffer Same as Pa_OpenStream parameter of the same name.
+ @param streamCallback Same as Pa_OpenStream parameter of the same name.
+ @param userData Same as Pa_OpenStream parameter of the same name.
-*/
+ @return As for Pa_OpenStream
-PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ @see Pa_OpenStream, PaStreamCallback
+*/
+PaError Pa_OpenDefaultStream( PaStream** stream,
int numInputChannels,
int numOutputChannels,
PaSampleFormat sampleFormat,
double sampleRate,
unsigned long framesPerBuffer,
- unsigned long numberOfBuffers,
- PortAudioCallback *callback,
+ PaStreamCallback *streamCallback,
void *userData );
-/*
- Pa_CloseStream() closes an audio stream, flushing any pending buffers.
+/** Closes an audio stream. If the audio stream is active it
+ discards any pending buffers as if Pa_AbortStream() had been called.
+*/
+PaError Pa_CloseStream( PaStream *stream );
+
+
+/** Functions of type PaStreamFinishedCallback are implemented by PortAudio
+ clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback
+ function. Once registered they are called when the stream becomes inactive
+ (ie once a call to Pa_StopStream() will not block).
+ A stream will become inactive after the stream callback returns non-zero,
+ or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio
+ output, if the stream callback returns paComplete, or Pa_StopStream is called,
+ the stream finished callback will not be called until all generated sample data
+ has been played.
+
+ @param userData The userData parameter supplied to Pa_OpenStream()
+
+ @see Pa_SetStreamFinishedCallback
*/
+typedef void PaStreamFinishedCallback( void *userData );
-PaError Pa_CloseStream( PortAudioStream* );
-/*
- Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
- Pa_StopStream() waits until all pending audio buffers have been played.
- Pa_AbortStream() stops playing immediately without waiting for pending
+/** Register a stream finished callback function which will be called when the
+ stream becomes inactive. See the description of PaStreamFinishedCallback for
+ further details about when the callback will be called.
+
+ @param stream a pointer to a PaStream that is in the stopped state - if the
+ stream is not stopped, the stream's finished callback will remain unchanged
+ and an error code will be returned.
+
+ @param streamFinishedCallback a pointer to a function with the same signature
+ as PaStreamFinishedCallback, that will be called when the stream becomes
+ inactive. Passing NULL for this parameter will un-register a previously
+ registered stream finished callback function.
+
+ @return on success returns paNoError, otherwise an error code indicating the cause
+ of the error.
+
+ @see PaStreamFinishedCallback
+*/
+PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback );
+
+
+/** Commences audio processing.
+*/
+PaError Pa_StartStream( PaStream *stream );
+
+
+/** Terminates audio processing. It waits until all pending
+ audio buffers have been played before it returns.
+*/
+PaError Pa_StopStream( PaStream *stream );
+
+
+/** Terminates audio processing immediately without waiting for pending
buffers to complete.
-
*/
+PaError Pa_AbortStream( PaStream *stream );
-PaError Pa_StartStream( PortAudioStream *stream );
-PaError Pa_StopStream( PortAudioStream *stream );
+/** @return Returns one (1) when the stream is stopped, zero (0) when
+ the stream is running, or a negative error number if the stream
+ is invalid. A stream is considered to be stopped prior to a successful
+ call to Pa_StartStream and after a successful call to Pa_StopStream
+ or Pa_AbortStream. If a stream callback returns a value other than
+ paContinue the stream is NOT considered to be stopped.
+*/
+PaError Pa_IsStreamStopped( PaStream *stream );
-PaError Pa_AbortStream( PortAudioStream *stream );
-/*
- Pa_StreamActive() returns one (1) when the stream is active (ie playing
+/** @return Returns one (1) when the stream is active (ie playing
or recording audio), zero (0) when not playing, or a negative error number
if the stream is invalid.
- The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
- but may also become inactive if the callback returns a non-zero value.
- In the latter case, the stream is considered inactive after the last
- buffer has finished playing.
-
+
+ A stream is active after a successful call to Pa_StartStream(), until it
+ becomes inactive either as a result of a call to Pa_StopStream() or
+ Pa_AbortStream(), or as a result of a return value other than paContinue from
+ the stream callback. In the latter case, the stream is considered inactive after
+ the last buffer has finished playing.
+
+ @see Pa_StopStream, Pa_AbortStream
*/
+PaError Pa_IsStreamActive( PaStream *stream );
-PaError Pa_StreamActive( PortAudioStream *stream );
-/*
- Pa_StreamTime() returns the current output time in samples for the stream.
- This time may be used as a time reference (for example synchronizing audio to
- MIDI).
-
+
+/** A structure containing unchanging information about an open stream.
+ @see Pa_GetStreamInfo
*/
-PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+typedef struct PaStreamInfo
+{
+ /** this is struct version 1 */
+ int structVersion;
-/*
- Pa_GetCPULoad() returns the CPU Load for the stream.
- The "CPU Load" is a fraction of total CPU time consumed by the stream's
+ /** The input latency of the stream in seconds. This value provides the most
+ accurate estimate of input latency available to the implementation. It may
+ differ significantly from the suggestedLatency value passed to Pa_OpenStream().
+ The value of this field will be zero (0.) for output-only streams.
+ @see PaTime
+ */
+ PaTime inputLatency;
+
+ /** The output latency of the stream in seconds. This value provides the most
+ accurate estimate of output latency available to the implementation. It may
+ differ significantly from the suggestedLatency value passed to Pa_OpenStream().
+ The value of this field will be zero (0.) for input-only streams.
+ @see PaTime
+ */
+ PaTime outputLatency;
+
+ /** The sample rate of the stream in Hertz (samples per second). In cases
+ where the hardware sample rate is inaccurate and PortAudio is aware of it,
+ the value of this field may be different from the sampleRate parameter
+ passed to Pa_OpenStream(). If information about the actual hardware sample
+ rate is not available, this field will have the same value as the sampleRate
+ parameter passed to Pa_OpenStream().
+ */
+ double sampleRate;
+
+} PaStreamInfo;
+
+
+/** Retrieve a pointer to a PaStreamInfo structure containing information
+ about the specified stream.
+ @return A pointer to an immutable PaStreamInfo structure. If the stream
+ parameter invalid, or an error is encountered, the function returns NULL.
+
+ @param stream A pointer to an open stream previously created with Pa_OpenStream.
+
+ @note PortAudio manages the memory referenced by the returned pointer,
+ the client must not manipulate or free the memory. The pointer is only
+ guaranteed to be valid until the specified stream is closed.
+
+ @see PaStreamInfo
+*/
+const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream );
+
+
+/**
+ @return The current time (in seconds) according to the same clock used to
+ generate buffer timestamps for stream.
+ This time may be used for syncronising other events to the audio stream,
+ for example synchronizing audio to MIDI.
+
+ @see PaTime, PaStreamCallback
+*/
+PaTime Pa_GetStreamTime( PaStream *stream );
+
+
+/** Retrieve CPU usage information for the specified stream.
+ The "CPU Load" is a fraction of total CPU time consumed by a callback stream's
audio processing routines including, but not limited to the client supplied
- callback.
- A value of 0.5 would imply that PortAudio and the sound generating
- callback was consuming roughly 50% of the available CPU time.
- This function may be called from the callback function or the application.
-
+ stream callback. This function does not work with blocking read/write streams.
+
+ This function may be called from the stream callback function or the
+ application.
+
+ @return
+ A floating point value, typically between 0.0 and 1.0, where 1.0 indicates
+ that the stream callback is consuming the maximum number of CPU cycles possible
+ to maintain real-time operation. A value of 0.5 would imply that PortAudio and
+ the stream callback was consuming roughly 50% of the available CPU time. The
+ return value may exceed 1.0. A value of 0.0 will always be returned for a
+ blocking read/write stream.
*/
+double Pa_GetStreamCpuLoad( PaStream* stream );
-double Pa_GetCPULoad( PortAudioStream* stream );
-/*
- Pa_GetMinNumBuffers() returns the minimum number of buffers required by
- the current host based on minimum latency.
- On the PC, for the DirectSound implementation, latency can be optionally set
- by user by setting an environment variable.
- For example, to set latency to 200 msec, put:
-
- set PA_MIN_LATENCY_MSEC=200
-
- in the AUTOEXEC.BAT file and reboot.
- If the environment variable is not set, then the latency will be determined
- based on the OS. Windows NT has higher latency than Win95.
-
+/** Read samples from an input stream. The function doesn't return until
+ the entire buffer has been filled - this may involve waiting for the operating
+ system to supply the data.
+
+ @param buffer A pointer to a buffer of sample frames. The buffer contains
+ samples in the format specified by the inputParameters->sampleFormat field
+ used to open the stream, and the number of channels specified by
+ inputParameters->numChannels. If non-interleaved samples were requested,
+ buffer is a pointer to the first element of an array of non-interleaved
+ buffer pointers, one for each channel.
+
+ @param frames The number of frames to be read into buffer. This parameter
+ is not constrained to a specific range, however high performance applications
+ will want to match this parameter to the framesPerBuffer parameter used
+ when opening the stream.
+
+ @return On success PaNoError will be returned, or PaInputOverflowed if input
+ data was discarded by PortAudio after the previous call and before this call.
*/
+PaError Pa_ReadStream( PaStream* stream,
+ void *buffer,
+ unsigned long frames );
+
+
+/** Write samples to an output stream. This function doesn't return until the
+ entire buffer has been consumed - this may involve waiting for the operating
+ system to consume the data.
+
+ @param buffer A pointer to a buffer of sample frames. The buffer contains
+ samples in the format specified by the outputParameters->sampleFormat field
+ used to open the stream, and the number of channels specified by
+ outputParameters->numChannels. If non-interleaved samples were requested,
+ buffer is a pointer to the first element of an array of non-interleaved
+ buffer pointers, one for each channel.
+
+ @param frames The number of frames to be written from buffer. This parameter
+ is not constrained to a specific range, however high performance applications
+ will want to match this parameter to the framesPerBuffer parameter used
+ when opening the stream.
+
+ @return On success PaNoError will be returned, or paOutputUnderflowed if
+ additional output data was inserted after the previous call and before this
+ call.
+*/
+PaError Pa_WriteStream( PaStream* stream,
+ void *buffer,
+ unsigned long frames );
-int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
-/*
- Pa_Sleep() puts the caller to sleep for at least 'msec' milliseconds.
- You may sleep longer than the requested time so don't rely on this for
- accurate musical timing.
-
- Pa_Sleep() is provided as a convenience for authors of portable code (such as
- the tests and examples in the PortAudio distribution.)
-
+/** Retrieve the number of frames that can be read from the stream without
+ waiting.
+
+ @return If non-negative, the return value is the maximum number of frames
+ that can be read from the stream without blocking or busy waiting. A
+ negative value is a PaErrorCode.
*/
+signed long Pa_GetStreamReadAvailable( PaStream* stream );
-void Pa_Sleep( long msec );
-/*
- Pa_GetSampleSize() returns the size in bytes of a single sample in the
- supplied PaSampleFormat, or paSampleFormatNotSupported if the format is
- no supported.
-
+/** Retrieve the number of frames that can be written to the stream without
+ waiting.
+
+ @return If non-negative, the return value is the maximum number of frames
+ that can be written to the stream without blocking or busy waiting. A
+ negative value is a PaErrorCode.
*/
+signed long Pa_GetStreamWriteAvailable( PaStream* stream );
+
+
+/* Miscellaneous utilities */
+
+/**
+ @return The size in bytes of a single sample in the specified format,
+ or paSampleFormatNotSupported if the format is not supported.
+*/
PaError Pa_GetSampleSize( PaSampleFormat format );
+/** Puts the caller to sleep for at least 'msec' milliseconds.
+ It may sleep longer than requested so don't rely on this for accurate
+ musical timing.
+
+ This function is provided only as a convenience for authors of portable code
+ (such as the tests and examples in the PortAudio distribution.)
+*/
+void Pa_Sleep( long msec );
+
+
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
-#endif /* PORT_AUDIO_H */
+#endif /* PORTAUDIO_H */
diff --git a/pd/portaudio/pa_dll_switch/PaDllEntry.h b/pd/portaudio/pa_dll_switch/PaDllEntry.h
new file mode 100644
index 00000000..e070054b
--- /dev/null
+++ b/pd/portaudio/pa_dll_switch/PaDllEntry.h
@@ -0,0 +1,184 @@
+
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio DLL Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+// changed by zplane.developement in order to generate a DLL
+
+#ifndef __PADLLENTRY_HEADER_INCLUDED__
+
+#define __PADLLENTRY_HEADER_INCLUDED__
+
+typedef int PaError;
+typedef enum {
+ paNoError = 0,
+
+ paHostError = -10000,
+ paInvalidChannelCount,
+ paInvalidSampleRate,
+ paInvalidDeviceId,
+ paInvalidFlag,
+ paSampleFormatNotSupported,
+ paBadIODeviceCombination,
+ paInsufficientMemory,
+ paBufferTooBig,
+ paBufferTooSmall,
+ paNullCallback,
+ paBadStreamPtr,
+ paTimedOut,
+ paInternalError
+} PaErrorNum;
+
+typedef unsigned long PaSampleFormat;
+#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
+#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
+#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
+#define paInt24 ((PaSampleFormat) (1<<3))
+#define paPackedInt24 ((PaSampleFormat) (1<<4))
+#define paInt8 ((PaSampleFormat) (1<<5))
+#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */
+#define paCustomFormat ((PaSampleFormat) (1<<16))
+
+
+typedef int PaDeviceID;
+#define paNoDevice -1
+
+typedef struct
+{
+ int structVersion;
+ const char *name;
+ int maxInputChannels;
+ int maxOutputChannels;
+ /* Number of discrete rates, or -1 if range supported. */
+ int numSampleRates;
+ /* Array of supported sample rates, or {min,max} if range supported. */
+ const double *sampleRates;
+ PaSampleFormat nativeSampleFormats;
+}
+PaDeviceInfo;
+
+
+typedef double PaTimestamp;
+
+
+typedef int (PortAudioCallback)(
+ void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+
+#define paNoFlag (0)
+#define paClipOff (1<<0) /* disable default clipping of out of range samples */
+#define paDitherOff (1<<1) /* disable default dithering */
+#define paPlatformSpecificFlags (0x00010000)
+typedef unsigned long PaStreamFlags;
+
+typedef void PortAudioStream;
+#define PaStream PortAudioStream
+
+extern PaError (__cdecl* Pa_Initialize)( void );
+
+
+
+extern PaError (__cdecl* Pa_Terminate)( void );
+
+
+extern long (__cdecl* Pa_GetHostError)( void );
+
+
+extern const char* (__cdecl* Pa_GetErrorText)( PaError );
+
+
+
+extern int (__cdecl* Pa_CountDevices)(void);
+
+extern PaDeviceID (__cdecl* Pa_GetDefaultInputDeviceID)( void );
+
+extern PaDeviceID (__cdecl* Pa_GetDefaultOutputDeviceID)( void );
+
+
+extern const PaDeviceInfo* (__cdecl* Pa_GetDeviceInfo)( PaDeviceID);
+
+
+
+extern PaError (__cdecl* Pa_OpenStream)(
+ PortAudioStream ** ,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ double ,
+ unsigned long ,
+ unsigned long ,
+ unsigned long ,
+ PortAudioCallback *,
+ void * );
+
+
+
+extern PaError (__cdecl* Pa_OpenDefaultStream)( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+extern PaError (__cdecl* Pa_CloseStream)( PortAudioStream* );
+
+
+extern PaError (__cdecl* Pa_StartStream)( PortAudioStream *stream );
+
+extern PaError (__cdecl* Pa_StopStream)( PortAudioStream *stream );
+
+extern PaError (__cdecl* Pa_AbortStream)( PortAudioStream *stream );
+
+extern PaError (__cdecl* Pa_StreamActive)( PortAudioStream *stream );
+
+extern PaTimestamp (__cdecl* Pa_StreamTime)( PortAudioStream *stream );
+
+extern double (__cdecl* Pa_GetCPULoad)( PortAudioStream* stream );
+
+extern int (__cdecl* Pa_GetMinNumBuffers)( int framesPerBuffer, double sampleRate );
+
+extern void (__cdecl* Pa_Sleep)( long msec );
+
+extern PaError (__cdecl* Pa_GetSampleSize)( PaSampleFormat format );
+
+#endif // __PADLLENTRY_HEADER_INCLUDED__
+
diff --git a/pd/portaudio/pa_dll_switch/letter_from_tim_010817.txt b/pd/portaudio/pa_dll_switch/letter_from_tim_010817.txt
new file mode 100644
index 00000000..a535cd1d
--- /dev/null
+++ b/pd/portaudio/pa_dll_switch/letter_from_tim_010817.txt
Binary files differ
diff --git a/pd/portaudio/pa_dll_switch/loadPA_DLL.cpp b/pd/portaudio/pa_dll_switch/loadPA_DLL.cpp
new file mode 100644
index 00000000..043eda87
--- /dev/null
+++ b/pd/portaudio/pa_dll_switch/loadPA_DLL.cpp
@@ -0,0 +1,203 @@
+//////////////////////////////////////////////////////////////////////////
+
+
+HINSTANCE pPaDll;
+
+/*
+ the function pointers to the PortAudio DLLs
+*/
+
+PaError (__cdecl* Pa_Initialize)( void );
+
+
+
+PaError (__cdecl* Pa_Terminate)( void );
+
+
+long (__cdecl* Pa_GetHostError)( void );
+
+
+const char* (__cdecl* Pa_GetErrorText)( PaError );
+
+
+int (__cdecl* Pa_CountDevices)(void);
+
+PaDeviceID (__cdecl* Pa_GetDefaultInputDeviceID)( void );
+
+PaDeviceID (__cdecl* Pa_GetDefaultOutputDeviceID)( void );
+
+
+const PaDeviceInfo* (__cdecl* Pa_GetDeviceInfo)( PaDeviceID);
+
+
+
+PaError (__cdecl* Pa_OpenStream)(
+ PortAudioStream ** ,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ double ,
+ unsigned long ,
+ unsigned long ,
+ unsigned long ,
+ PortAudioCallback *,
+ void * );
+
+
+
+PaError (__cdecl* Pa_OpenDefaultStream)( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+PaError (__cdecl* Pa_CloseStream)( PortAudioStream* );
+
+
+PaError (__cdecl* Pa_StartStream)( PortAudioStream *stream );
+
+PaError (__cdecl* Pa_StopStream)( PortAudioStream *stream );
+
+PaError (__cdecl* Pa_AbortStream)( PortAudioStream *stream );
+
+PaError (__cdecl* Pa_StreamActive)( PortAudioStream *stream );
+
+PaTimestamp (__cdecl* Pa_StreamTime)( PortAudioStream *stream );
+
+double (__cdecl* Pa_GetCPULoad)( PortAudioStream* stream );
+
+int (__cdecl* Pa_GetMinNumBuffers)( int framesPerBuffer, double sampleRate );
+
+void (__cdecl* Pa_Sleep)( long msec );
+
+PaError (__cdecl* Pa_GetSampleSize)( PaSampleFormat format );
+
+
+//////////////////////////////////////////////////////////////////////////
+
+...
+
+ZERROR AudioEngine::DirectXSupport(ZBOOL bSupDX)
+{
+ if (bSupDX)
+ if (CheckForDirectXSupport())
+ bSupportDirectX = _TRUE;
+ else
+ return _NO_SOUND;
+ else
+ bSupportDirectX = _FALSE;
+ return _NO_ERROR;
+}
+
+
+
+ZBOOL AudioEngine::CheckForDirectXSupport()
+{
+ HMODULE pTestDXLib;
+ FARPROC pFunctionality;
+
+ pTestDXLib=LoadLibrary("DSOUND");
+ if (pTestDXLib!=NULL) // check if there is a DirectSound
+ {
+ pFunctionality = GetProcAddress(pTestDXLib, (char*) 7);
+ if (pFunctionality!=NULL)
+ {
+ FreeLibrary(pTestDXLib);
+ return _TRUE;
+ }
+ else
+ {
+ FreeLibrary(pTestDXLib);
+ return _FALSE;
+ }
+ }
+ else
+ return _FALSE;
+}
+
+
+ZERROR AudioEngine::LoadPALib()
+{
+#ifdef _DEBUG
+ if (bSupportDirectX)
+ pPaDll = LoadLibrary("PA_DXD");
+ else
+ pPaDll = LoadLibrary("PA_MMED");
+#else
+ if (bSupportDirectX)
+ pPaDll = LoadLibrary("PA_DX");
+ else
+ pPaDll = LoadLibrary("PA_MME");
+#endif
+ if (pPaDll!=NULL)
+ {
+
+ Pa_Initialize = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_Initialize");
+ Pa_Terminate = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_Terminate");
+ Pa_GetHostError = (long (__cdecl* )( void )) GetProcAddress(pPaDll,"Pa_GetHostError");
+ Pa_GetErrorText = (const char* (__cdecl* )( PaError )) GetProcAddress(pPaDll,"Pa_GetErrorText");
+ Pa_CountDevices = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_CountDevices");
+ Pa_GetDefaultInputDeviceID = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_GetDefaultInputDeviceID");
+ Pa_GetDefaultOutputDeviceID = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_GetDefaultOutputDeviceID");
+ Pa_GetDeviceInfo = (const PaDeviceInfo* (__cdecl* )( PaDeviceID)) GetProcAddress(pPaDll,"Pa_GetDeviceInfo");
+ Pa_OpenStream = ( PaError (__cdecl* )(
+ PortAudioStream ** ,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ double ,
+ unsigned long ,
+ unsigned long ,
+ unsigned long ,
+ PortAudioCallback *,
+ void * )) GetProcAddress(pPaDll,"Pa_OpenStream");
+
+ Pa_OpenDefaultStream = (PaError (__cdecl* )( PortAudioStream** ,
+ int ,
+ int ,
+ PaSampleFormat ,
+ double ,
+ unsigned long ,
+ unsigned long ,
+ PortAudioCallback *,
+ void * )) GetProcAddress(pPaDll,"Pa_OpenDefaultStream");
+ Pa_CloseStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_CloseStream");
+ Pa_StartStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_StartStream");
+ Pa_StopStream = (PaError (__cdecl* )( PortAudioStream* ))GetProcAddress(pPaDll,"Pa_StopStream");
+ Pa_AbortStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_AbortStream");
+ Pa_StreamActive = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_StreamActive");
+ Pa_StreamTime = (PaTimestamp (__cdecl* )( PortAudioStream *))GetProcAddress(pPaDll,"Pa_StreamTime");
+ Pa_GetCPULoad = (double (__cdecl* )( PortAudioStream* ))GetProcAddress(pPaDll,"Pa_GetCPULoad");
+ Pa_GetMinNumBuffers = (int (__cdecl* )( int , double )) GetProcAddress(pPaDll,"Pa_GetMinNumBuffers");
+ Pa_Sleep = (void (__cdecl* )( long )) GetProcAddress(pPaDll,"Pa_Sleep");
+ Pa_GetSampleSize = (PaError (__cdecl* )( PaSampleFormat )) GetProcAddress(pPaDll,"Pa_GetSampleSize");
+
+ return _NO_ERROR;
+ }
+ else
+ return _DLL_NOT_FOUND;
+}
+
+ZERROR AudioEngine::UnLoadPALib()
+{
+ if (pPaDll!=NULL)
+ FreeLibrary(pPaDll);
+ return _NO_ERROR;
+}
+
+...
diff --git a/pd/portaudio/pa_dll_switch/pa_lib.c b/pd/portaudio/pa_dll_switch/pa_lib.c
new file mode 100644
index 00000000..86601592
--- /dev/null
+++ b/pd/portaudio/pa_dll_switch/pa_lib.c
@@ -0,0 +1,827 @@
+/*
+ * Portable Audio I/O Library
+ * Host Independant Layer
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+/* Modification History:
+ PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
+#ifdef _WIN32
+#ifndef __MWERKS__
+#include <memory.h>
+#endif /* __MWERKS__ */
+#else /* !_WIN32 */
+#include <memory.h>
+#endif /* _WIN32 */
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+/* The reason we might NOT want to validate the rate before opening the stream
+ * is because many DirectSound drivers lie about the rates they actually support.
+ */
+#define PA_VALIDATE_RATE (0) /* If true validate sample rate against driver info. */
+
+/*
+O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for conversion
+*/
+
+#ifndef FALSE
+ #define FALSE (0)
+ #define TRUE (!FALSE)
+#endif
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */
+
+static PaError Pa_KillStream( PortAudioStream *stream, int abort );
+
+/***********************************************************************/
+int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, int numRates, double frameRate )
+{
+ double err, minErr = allowableError;
+ int i, bestFit = -1;
+
+ for( i=0; i<numRates; i++ )
+ {
+ err = fabs( frameRate - rateTable[i] );
+ if( err < minErr )
+ {
+ minErr = err;
+ bestFit = i;
+ }
+ }
+ return bestFit;
+}
+
+/**************************************************************************
+** Make sure sample rate is legal and also convert to enumeration for driver.
+*/
+PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
+ double *closestFrameRatePtr )
+{
+ long bestRateIndex;
+ const PaDeviceInfo *pdi;
+ pdi = Pa_GetDeviceInfo( id );
+ if( pdi == NULL ) return paInvalidDeviceId;
+
+ if( pdi->numSampleRates == -1 )
+ {
+ /* Is it out of range? */
+ if( (requestedFrameRate < pdi->sampleRates[0]) ||
+ (requestedFrameRate > pdi->sampleRates[1]) )
+ {
+ return paInvalidSampleRate;
+ }
+
+ *closestFrameRatePtr = requestedFrameRate;
+ }
+ else
+ {
+ bestRateIndex = PaHost_FindClosestTableEntry( 1.0, pdi->sampleRates, pdi->numSampleRates, requestedFrameRate );
+ if( bestRateIndex < 0 ) return paInvalidSampleRate;
+ *closestFrameRatePtr = pdi->sampleRates[bestRateIndex];
+ }
+ return paNoError;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_OpenStream(
+ PortAudioStream** streamPtrPtr,
+ PaDeviceID inputDeviceID,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDeviceID,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ unsigned long streamFlags,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ internalPortAudioStream *past = NULL;
+ PaError result = paNoError;
+ int bitsPerInputSample;
+ int bitsPerOutputSample;
+ /* Print passed parameters. */
+ DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n",
+ streamPtrPtr, inputDeviceID, numInputChannels,
+ inputSampleFormat, inputDriverInfo ));
+ DBUG((" %d, %d, %d, %p, /* output */\n",
+ outputDeviceID, numOutputChannels,
+ outputSampleFormat, outputDriverInfo ));
+ DBUG((" %g, %d, %d, 0x%x, , %p )\n",
+ sampleRate, framesPerBuffer, numberOfBuffers,
+ streamFlags, userData ));
+
+ /* Check for parameter errors. */
+ if( (streamFlags & ~(paClipOff | paDitherOff)) != 0 ) return paInvalidFlag;
+ if( streamPtrPtr == NULL ) return paBadStreamPtr;
+ if( inputDriverInfo != NULL ) return paHostError; /* REVIEW */
+ if( outputDriverInfo != NULL ) return paHostError; /* REVIEW */
+ if( (inputDeviceID < 0) && ( outputDeviceID < 0) ) return paInvalidDeviceId;
+ if( (outputDeviceID >= Pa_CountDevices()) || (inputDeviceID >= Pa_CountDevices()) ) return paInvalidDeviceId;
+ if( (numInputChannels <= 0) && ( numOutputChannels <= 0) ) return paInvalidChannelCount;
+
+#if SUPPORT_AUDIO_CAPTURE
+ if( inputDeviceID >= 0 )
+ {
+ PaError size = Pa_GetSampleSize( inputSampleFormat );
+ if( size < 0 ) return size;
+ bitsPerInputSample = 8 * size;
+ if( (numInputChannels <= 0) ) return paInvalidChannelCount;
+ }
+#else
+ if( inputDeviceID >= 0 )
+ {
+ return paInvalidChannelCount;
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ else
+ {
+ if( numInputChannels > 0 ) return paInvalidChannelCount;
+ bitsPerInputSample = 0;
+ }
+
+ if( outputDeviceID >= 0 )
+ {
+ PaError size = Pa_GetSampleSize( outputSampleFormat );
+ if( size < 0 ) return size;
+ bitsPerOutputSample = 8 * size;
+ if( (numOutputChannels <= 0) ) return paInvalidChannelCount;
+ }
+ else
+ {
+ if( numOutputChannels > 0 ) return paInvalidChannelCount;
+ bitsPerOutputSample = 0;
+ }
+
+ if( callback == NULL ) return paNullCallback;
+
+ /* Allocate and clear stream structure. */
+ past = (internalPortAudioStream *) PaHost_AllocateFastMemory( sizeof(internalPortAudioStream) );
+ if( past == NULL ) return paInsufficientMemory;
+ memset( past, 0, sizeof(internalPortAudioStream) );
+ AddTraceMessage("Pa_OpenStream: past", (long) past );
+
+ past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */
+ past->past_FramesPerUserBuffer = framesPerBuffer;
+ past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() NMUST CHECK FOR ZERO! */
+ past->past_Callback = callback;
+ past->past_UserData = userData;
+ past->past_OutputSampleFormat = outputSampleFormat;
+ past->past_InputSampleFormat = inputSampleFormat;
+ past->past_OutputDeviceID = outputDeviceID;
+ past->past_InputDeviceID = inputDeviceID;
+ past->past_NumInputChannels = numInputChannels;
+ past->past_NumOutputChannels = numOutputChannels;
+ past->past_Flags = streamFlags;
+
+ /* Check for absurd sample rates. */
+ if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
+ {
+ result = paInvalidSampleRate;
+ goto cleanup;
+ }
+
+ /* Allocate buffers that may be used for format conversion from user to native buffers. */
+ if( numInputChannels > 0 )
+ {
+
+#if PA_VALIDATE_RATE
+ result = PaHost_ValidateSampleRate( inputDeviceID, sampleRate, &past->past_SampleRate );
+ if( result < 0 )
+ {
+ goto cleanup;
+ }
+#else
+ past->past_SampleRate = sampleRate;
+#endif
+ /* Allocate single Input buffer. */
+ past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8);
+ past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize);
+ if( past->past_InputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ past->past_InputBuffer = NULL;
+ }
+
+ /* Allocate single Output buffer. */
+ if( numOutputChannels > 0 )
+ {
+#if PA_VALIDATE_RATE
+ result = PaHost_ValidateSampleRate( outputDeviceID, sampleRate, &past->past_SampleRate );
+ if( result < 0 )
+ {
+ goto cleanup;
+ }
+#else
+ past->past_SampleRate = sampleRate;
+#endif
+ past->past_OutputBufferSize = framesPerBuffer * numOutputChannels * ((bitsPerOutputSample+7) / 8);
+ past->past_OutputBuffer = PaHost_AllocateFastMemory(past->past_OutputBufferSize);
+ if( past->past_OutputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ past->past_OutputBuffer = NULL;
+ }
+
+ result = PaHost_OpenStream( past );
+ if( result < 0 ) goto cleanup;
+
+ *streamPtrPtr = (void *) past;
+
+ return result;
+
+cleanup:
+ if( past != NULL ) Pa_CloseStream( past );
+ *streamPtrPtr = NULL;
+ return result;
+}
+
+
+/*************************************************************************/
+DLL_API PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ return Pa_OpenStream(
+ stream,
+ ((numInputChannels > 0) ? Pa_GetDefaultInputDeviceID() : paNoDevice),
+ numInputChannels, sampleFormat, NULL,
+ ((numOutputChannels > 0) ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
+ numOutputChannels, sampleFormat, NULL,
+ sampleRate, framesPerBuffer, numberOfBuffers, paNoFlag, callback, userData );
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_CloseStream( PortAudioStream* stream)
+{
+ PaError result;
+ internalPortAudioStream *past;
+
+ DBUG(("Pa_CloseStream()\n"));
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ Pa_AbortStream( past );
+ result = PaHost_CloseStream( past );
+
+ if( past->past_InputBuffer ) PaHost_FreeFastMemory( past->past_InputBuffer, past->past_InputBufferSize );
+ if( past->past_OutputBuffer ) PaHost_FreeFastMemory( past->past_OutputBuffer, past->past_OutputBufferSize );
+ PaHost_FreeFastMemory( past, sizeof(internalPortAudioStream) );
+
+ return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_StartStream( PortAudioStream *stream )
+{
+ PaError result = paHostError;
+ internalPortAudioStream *past;
+
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ past->past_FrameCount = 0.0;
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ result = PaHost_StartInput( past );
+ DBUG(("Pa_StartStream: PaHost_StartInput returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ result = PaHost_StartOutput( past );
+ DBUG(("Pa_StartStream: PaHost_StartOutput returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ result = PaHost_StartEngine( past );
+ DBUG(("Pa_StartStream: PaHost_StartEngine returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+
+ return paNoError;
+
+error:
+ return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_StopStream( PortAudioStream *stream )
+{
+ return Pa_KillStream( stream, 0 );
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_AbortStream( PortAudioStream *stream )
+{
+ return Pa_KillStream( stream, 1 );
+}
+
+/*************************************************************************/
+static PaError Pa_KillStream( PortAudioStream *stream, int abort )
+{
+ PaError result = paNoError;
+ internalPortAudioStream *past;
+
+ DBUG(("Pa_StopStream().\n"));
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ if( (past->past_NumInputChannels > 0) || (past->past_NumOutputChannels > 0) )
+ {
+ result = PaHost_StopEngine( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopEngine returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ result = PaHost_StopInput( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopInput returned = 0x%X.\n", result));
+ if( result != paNoError ) goto error;
+ }
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ result = PaHost_StopOutput( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopOutput returned = 0x%X.\n", result));
+ if( result != paNoError ) goto error;
+ }
+
+error:
+ past->past_Usage = 0;
+ past->past_IfLastExitValid = 0;
+
+ return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_StreamActive( PortAudioStream *stream )
+{
+ internalPortAudioStream *past;
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+ return PaHost_StreamActive( past );
+}
+
+/*************************************************************************/
+DLL_API const char *Pa_GetErrorText( PaError errnum )
+{
+ const char *msg;
+
+ switch(errnum)
+ {
+ case paNoError: msg = "Success"; break;
+ case paHostError: msg = "Host error."; break;
+ case paInvalidChannelCount: msg = "Invalid number of channels."; break;
+ case paInvalidSampleRate: msg = "Invalid sample rate."; break;
+ case paInvalidDeviceId: msg = "Invalid device ID."; break;
+ case paInvalidFlag: msg = "Invalid flag."; break;
+ case paSampleFormatNotSupported: msg = "Sample format not supported"; break;
+ case paBadIODeviceCombination: msg = "Illegal combination of I/O devices."; break;
+ case paInsufficientMemory: msg = "Insufficient memory."; break;
+ case paBufferTooBig: msg = "Buffer too big."; break;
+ case paBufferTooSmall: msg = "Buffer too small."; break;
+ case paNullCallback: msg = "No callback routine specified."; break;
+ case paBadStreamPtr: msg = "Invalid stream pointer."; break;
+ case paTimedOut : msg = "Wait Timed Out."; break;
+ case paInternalError: msg = "Internal PortAudio Error."; break;
+ default: msg = "Illegal error number."; break;
+ }
+ return msg;
+}
+
+/*
+ Get CPU Load as a fraction of total CPU time.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ The amount may vary depending on CPU load.
+ This function may be called from the callback function.
+*/
+DLL_API double Pa_GetCPULoad( PortAudioStream* stream)
+{
+ internalPortAudioStream *past;
+ if( stream == NULL ) return (double) paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+ return past->past_Usage;
+}
+
+/*************************************************************
+** Calculate 2 LSB dither signal with a triangular distribution.
+** Ranged properly for adding to a 32 bit integer prior to >>15.
+*/
+#define DITHER_BITS (15)
+#define DITHER_SCALE (1.0f / ((1<<DITHER_BITS)-1))
+static long Pa_TriangularDither( void )
+{
+ static unsigned long previous = 0;
+ static unsigned long randSeed1 = 22222;
+ static unsigned long randSeed2 = 5555555;
+ long current, highPass;
+ /* Generate two random numbers. */
+ randSeed1 = (randSeed1 * 196314165) + 907633515;
+ randSeed2 = (randSeed2 * 196314165) + 907633515;
+ /* Generate triangular distribution about 0. */
+ current = (((long)randSeed1)>>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS));
+ /* High pass filter to reduce audibility. */
+ highPass = current - previous;
+ previous = current;
+ return highPass;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from Int16, call user code, then convert output
+** to Int16 format for native use.
+** Assumes host native format is paInt16.
+** Returns result from user callback.
+*/
+long Pa_CallConvertInt16( internalPortAudioStream *past,
+ short *nativeInputBuffer,
+ short *nativeOutputBuffer )
+{
+ long temp;
+ long bytesEmpty = 0;
+ long bytesFilled = 0;
+ int userResult;
+ unsigned int i;
+ void *inputBuffer = NULL;
+ void *outputBuffer = NULL;
+
+#if SUPPORT_AUDIO_CAPTURE
+ /* Get native data from DirectSound. */
+ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+ {
+ /* Convert from native format to PA format. */
+ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels;
+ switch(past->past_InputSampleFormat)
+ {
+
+ case paFloat32:
+ {
+ float *inBufPtr = (float *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = nativeInputBuffer[i] * (1.0f / 32767.0f);
+ }
+ break;
+ }
+
+ case paInt32:
+ {
+ /* Convert 16 bit data to 32 bit integers */
+ int *inBufPtr = (int *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = nativeInputBuffer[i] << 16;
+ }
+ break;
+ }
+
+ case paInt16:
+ {
+ /* Already in correct format so don't copy. */
+ inputBuffer = nativeInputBuffer;
+ break;
+ }
+
+ case paInt8:
+ {
+ /* Convert 16 bit data to 8 bit chars */
+ char *inBufPtr = (char *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = (char)(nativeInputBuffer[i] >> 8);
+ }
+ }
+ else
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = nativeInputBuffer[i];
+ temp += Pa_TriangularDither() >> 7;
+ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ inBufPtr[i] = (char)(temp >> 8);
+ }
+ }
+ break;
+ }
+
+ case paUInt8:
+ {
+ /* Convert 16 bit data to 8 bit unsigned chars */
+ unsigned char *inBufPtr = (unsigned char *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = ((unsigned char)(nativeInputBuffer[i] >> 8)) + 0x80;
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = nativeInputBuffer[i];
+ temp += Pa_TriangularDither() >> 7;
+ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ inBufPtr[i] = (unsigned char)(temp + 0x80);
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+
+ /* Are we doing output time? */
+ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+ {
+ /* May already be in native format so just write directly to native buffer. */
+ outputBuffer = (past->past_OutputSampleFormat == paInt16) ?
+ nativeOutputBuffer : past->past_OutputBuffer;
+ }
+ /*
+ AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+ AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+ */
+ /* Call user callback routine. */
+ userResult = past->past_Callback(
+ inputBuffer,
+ outputBuffer,
+ past->past_FramesPerUserBuffer,
+ past->past_FrameCount,
+ past->past_UserData );
+
+ past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
+
+ /* Convert to native format if necessary. */
+ if( outputBuffer != NULL )
+ {
+ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
+ switch(past->past_OutputSampleFormat)
+ {
+ case paFloat32:
+ {
+ float *outBufPtr = (float *) past->past_OutputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ if( past->past_Flags & paClipOff ) /* NOTHING */
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (outBufPtr[i] * (32767.0f));
+ }
+ }
+ else /* CLIP */
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = (long)(outBufPtr[i] * 32767.0f);
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ float dither = Pa_TriangularDither()*DITHER_SCALE;
+ float dithered = (outBufPtr[i] * (32767.0f)) + dither;
+ temp = (long) (dithered);
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ break;
+ }
+
+ case paInt32:
+ {
+ int *outBufPtr = (int *) past->past_OutputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (outBufPtr[i] >> 16 );
+ }
+ }
+ else
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ /* Shift one bit down before dithering so that we have room for overflow from add. */
+ temp = (outBufPtr[i] >> 1) + Pa_TriangularDither();
+ temp = temp >> 15;
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ break;
+ }
+
+ case paInt8:
+ {
+ char *outBufPtr = (char *) past->past_OutputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = ((short)outBufPtr[i]) << 8;
+ }
+ break;
+ }
+
+ case paUInt8:
+ {
+ unsigned char *outBufPtr = (unsigned char *) past->past_OutputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = ((short)(outBufPtr[i] - 0x80)) << 8;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+
+ return userResult;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from Float32, call user code, then convert output
+** to Float32 format for native use.
+** Assumes host native format is Float32.
+** Returns result from user callback.
+** FIXME - Unimplemented for formats other than paFloat32!!!!
+*/
+long Pa_CallConvertFloat32( internalPortAudioStream *past,
+ float *nativeInputBuffer,
+ float *nativeOutputBuffer )
+{
+ long bytesEmpty = 0;
+ long bytesFilled = 0;
+ int userResult;
+ void *inputBuffer = NULL;
+ void *outputBuffer = NULL;
+
+ /* Get native data from DirectSound. */
+ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+ {
+ inputBuffer = nativeInputBuffer; // FIXME
+ }
+
+ /* Are we doing output time? */
+ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+ {
+ /* May already be in native format so just write directly to native buffer. */
+ outputBuffer = (past->past_OutputSampleFormat == paFloat32) ?
+ nativeOutputBuffer : past->past_OutputBuffer;
+ }
+ /*
+ AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+ AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+ */
+ /* Call user callback routine. */
+ userResult = past->past_Callback(
+ inputBuffer,
+ outputBuffer,
+ past->past_FramesPerUserBuffer,
+ past->past_FrameCount,
+ past->past_UserData );
+
+ past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
+
+ /* Convert to native format if necessary. */ // FIXME
+ return userResult;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_Initialize( void )
+{
+ if( gInitCount++ > 0 ) return paNoError;
+ ResetTraceMessages();
+ return PaHost_Init();
+}
+
+DLL_API PaError Pa_Terminate( void )
+{
+ PaError result = paNoError;
+
+ if( gInitCount == 0 ) return paNoError;
+ else if( --gInitCount == 0 )
+ {
+ result = PaHost_Term();
+ DumpTraceMessages();
+ }
+ return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_GetSampleSize( PaSampleFormat format )
+{
+ int size;
+ switch(format )
+ {
+
+ case paUInt8:
+ case paInt8:
+ size = 1;
+ break;
+
+ case paInt16:
+ size = 2;
+ break;
+
+ case paPackedInt24:
+ size = 3;
+ break;
+
+ case paFloat32:
+ case paInt32:
+ case paInt24:
+ size = 4;
+ break;
+
+ default:
+ size = paSampleFormatNotSupported;
+ break;
+ }
+ return (PaError) size;
+}
+
+
diff --git a/pd/portaudio/pa_dll_switch/portaudio.h b/pd/portaudio/pa_dll_switch/portaudio.h
new file mode 100644
index 00000000..9632521e
--- /dev/null
+++ b/pd/portaudio/pa_dll_switch/portaudio.h
@@ -0,0 +1,439 @@
+#ifndef PORT_AUDIO_H
+#define PORT_AUDIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio API Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+// added by zplane.developement in order to generate a DLL
+
+#if defined(PA_MME_EXPORTS) || defined(PA_DX_EXPORTS)
+#define DLL_API __declspec( dllexport )
+#elif defined(_LIB) || defined(_STATIC_LINK) || defined(_STATIC_APP)
+#define DLL_API
+#else
+#define DLL_API __declspec(dllexport)
+#endif
+
+
+typedef int PaError;
+typedef enum {
+ paNoError = 0,
+
+ paHostError = -10000,
+ paInvalidChannelCount,
+ paInvalidSampleRate,
+ paInvalidDeviceId,
+ paInvalidFlag,
+ paSampleFormatNotSupported,
+ paBadIODeviceCombination,
+ paInsufficientMemory,
+ paBufferTooBig,
+ paBufferTooSmall,
+ paNullCallback,
+ paBadStreamPtr,
+ paTimedOut,
+ paInternalError
+} PaErrorNum;
+
+/*
+ Pa_Initialize() is the library initialisation function - call this before
+ using the library.
+*/
+
+DLL_API PaError Pa_Initialize( void );
+
+/*
+ Pa_Terminate() is the library termination function - call this after
+ using the library.
+*/
+
+DLL_API PaError Pa_Terminate( void );
+
+/*
+ Return host specific error.
+ This can be called after receiving a paHostError.
+*/
+DLL_API long Pa_GetHostError( void );
+
+/*
+ Translate the error number into a human readable message.
+*/
+DLL_API const char *Pa_GetErrorText( PaError errnum );
+
+/*
+ Sample formats
+
+ These are formats used to pass sound data between the callback and the
+ stream. Each device has a "native" format which may be used when optimum
+ efficiency or control over conversion is required.
+
+ Formats marked "always available" are supported (emulated) by all devices.
+
+ The floating point representation uses +1.0 and -1.0 as the respective
+ maximum and minimum.
+
+*/
+
+typedef unsigned long PaSampleFormat;
+#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
+#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
+#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
+#define paInt24 ((PaSampleFormat) (1<<3))
+#define paPackedInt24 ((PaSampleFormat) (1<<4))
+#define paInt8 ((PaSampleFormat) (1<<5))
+#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */
+#define paCustomFormat ((PaSampleFormat) (1<<16))
+
+/*
+ Device enumeration mechanism.
+
+ Device ids range from 0 to Pa_CountDevices()-1.
+
+ Devices may support input, output or both. Device 0 is always the "default"
+ device and should support at least stereo in and out if that is available
+ on the taget platform _even_ if this involves kludging an input/output
+ device on platforms that usually separate input from output. Other platform
+ specific devices are specified by positive device ids.
+*/
+
+typedef int PaDeviceID;
+#define paNoDevice -1
+
+typedef struct
+{
+ int structVersion;
+ const char *name;
+ int maxInputChannels;
+ int maxOutputChannels;
+ /* Number of discrete rates, or -1 if range supported. */
+ int numSampleRates;
+ /* Array of supported sample rates, or {min,max} if range supported. */
+ const double *sampleRates;
+ PaSampleFormat nativeSampleFormats;
+}
+PaDeviceInfo;
+
+
+DLL_API int Pa_CountDevices();
+/*
+ Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID()
+
+ Return the default device ID or paNoDevice if there is no devices.
+ The result can be passed to Pa_OpenStream().
+
+ On the PC, the user can specify a default device by
+ setting an environment variable. For example, to use device #1.
+
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ID by using
+ the supplied application "pa_devs".
+*/
+DLL_API PaDeviceID Pa_GetDefaultInputDeviceID( void );
+DLL_API PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+
+/*
+ PaTimestamp is used to represent a continuous sample clock with arbitrary
+ start time useful for syncronisation. The type is used in the outTime
+ argument to the callback function and the result of Pa_StreamTime()
+*/
+
+typedef double PaTimestamp;
+
+/*
+ Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
+ referring to the device specified by id.
+ If id is out of range the function returns NULL.
+
+ The returned structure is owned by the PortAudio implementation and must
+ not be manipulated or freed. The pointer is guaranteed to be valid until
+ between calls to Pa_Initialize() and Pa_Terminate().
+*/
+
+DLL_API const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id );
+
+/*
+ PortAudioCallback is implemented by clients of the portable audio api.
+
+ inputBuffer and outputBuffer are arrays of interleaved samples,
+ the format, packing and number of channels used by the buffers are
+ determined by parameters to Pa_OpenStream() (see below).
+
+ framesPerBuffer is the number of sample frames to be processed by the callback.
+
+ outTime is the time in samples when the buffer(s) processed by
+ this callback will begin being played at the audio output.
+ See also Pa_StreamTime()
+
+ userData is the value of a user supplied pointer passed to Pa_OpenStream()
+ intended for storing synthesis data etc.
+
+ return value:
+ The callback can return a nonzero value to stop the stream. This may be
+ useful in applications such as soundfile players where a specific duration
+ of output is required. However, it is not necessary to utilise this mechanism
+ as StopStream() will also terminate the stream. A callback returning a
+ nonzero value must fill the entire outputBuffer.
+
+ NOTE: None of the other stream functions may be called from within the
+ callback function except for Pa_GetCPULoad().
+
+*/
+
+typedef int (PortAudioCallback)(
+ void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+
+/*
+ Stream flags
+
+ These flags may be supplied (ored together) in the streamFlags argument to
+ the Pa_OpenStream() function.
+
+ [ suggestions? ]
+*/
+
+#define paNoFlag (0)
+#define paClipOff (1<<0) /* disable defult clipping of out of range samples */
+#define paDitherOff (1<<1) /* disable default dithering */
+#define paPlatformSpecificFlags (0x00010000)
+typedef unsigned long PaStreamFlags;
+
+/*
+ A single PortAudioStream provides multiple channels of real-time
+ input and output audio streaming to a client application.
+ Pointers to PortAudioStream objects are passed between PortAudio functions.
+*/
+
+typedef void PortAudioStream;
+#define PaStream PortAudioStream
+
+/*
+ Pa_OpenStream() opens a stream for either input, output or both.
+
+ stream is the address of a PortAudioStream pointer which will receive
+ a pointer to the newly opened stream.
+
+ inputDevice is the id of the device used for input (see PaDeviceID above.)
+ inputDevice may be paNoDevice to indicate that an input device is not required.
+
+ numInputChannels is the number of channels of sound to be delivered to the
+ callback. It can range from 1 to the value of maxInputChannels in the
+ device input record for the device specified in the inputDevice parameter.
+ If inputDevice is paNoDevice numInputChannels is ignored.
+
+ inputSampleFormat is the format of inputBuffer provided to the callback
+ function. inputSampleFormat may be any of the formats described by the
+ PaSampleFormat enumeration (see above). PortAudio guarantees support for
+ the sound devices native formats (nativeSampleFormats in the device info
+ record) and additionally 16 and 32 bit integer and 32 bit floating point
+ formats. Support for other formats is implementation defined.
+
+ inputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ inputDriverInfo is never required for correct operation. If not used
+ inputDriverInfo should be NULL.
+
+ outputDevice is the id of the device used for output (see PaDeviceID above.)
+ outputDevice may be paNoDevice to indicate that an output device is not required.
+
+ numOutputChannels is the number of channels of sound to be supplied by the
+ callback. See the definition of numInputChannels above for more details.
+
+ outputSampleFormat is the sample format of the outputBuffer filled by the
+ callback function. See the definition of inputSampleFormat above for more
+ details.
+
+ outputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ outputDriverInfo is never required for correct operation. If not used
+ outputDriverInfo should be NULL.
+
+ sampleRate is the desired sampleRate for input and output
+
+ framesPerBuffer is the length in sample frames of all internal sample buffers
+ used for communication with platform specific audio routines. Wherever
+ possible this corresponds to the framesPerBuffer parameter passed to the
+ callback function.
+
+ numberOfBuffers is the number of buffers used for multibuffered
+ communication with the platform specific audio routines. This parameter is
+ provided only as a guide - and does not imply that an implementation must
+ use multibuffered i/o when reliable double buffering is available (such as
+ SndPlayDoubleBuffer() on the Macintosh.)
+
+ streamFlags may contain a combination of flags ORed together.
+ These flags modify the behavior of the
+ streaming process. Some flags may only be relevant to certain buffer formats.
+
+ callback is a pointer to a client supplied function that is responsible
+ for processing and filling input and output buffers (see above for details.)
+
+ userData is a client supplied pointer which is passed to the callback
+ function. It could for example, contain a pointer to instance data necessary
+ for processing the audio buffers.
+
+ return value:
+ Apon success Pa_OpenStream() returns PaNoError and places a pointer to a
+ valid PortAudioStream in the stream argument. The stream is inactive (stopped).
+ If a call to Pa_OpenStream() fails a nonzero error code is returned (see
+ PAError above) and the value of stream is invalid.
+
+*/
+
+DLL_API PaError Pa_OpenStream( PortAudioStream** stream,
+ PaDeviceID inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+/*
+ Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that
+ opens the default input and/or ouput devices. Most parameters have
+ identical meaning to their Pa_OpenStream() counterparts, with the following
+ exceptions:
+
+ If either numInputChannels or numOutputChannels is 0 the respective device
+ is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() )
+
+ sampleFormat applies to both the input and output buffers.
+*/
+
+DLL_API PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+/*
+ Pa_CloseStream() closes an audio stream, flushing any pending buffers.
+*/
+
+DLL_API PaError Pa_CloseStream( PortAudioStream* );
+
+/*
+ Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
+ When Pa_StopStream() returns, all pending audio buffers have been played.
+ Pa_AbortStream() stops playing immediately without waiting for pending
+ buffers to complete.
+*/
+
+DLL_API PaError Pa_StartStream( PortAudioStream *stream );
+
+DLL_API PaError Pa_StopStream( PortAudioStream *stream );
+
+DLL_API PaError Pa_AbortStream( PortAudioStream *stream );
+
+/*
+ Pa_StreamActive() returns one when the stream is playing audio,
+ zero when not playing, or a negative error number if the
+ stream is invalid.
+ The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
+ but may also become inactive if the callback returns a non-zero value.
+ In the latter case, the stream is considered inactive after the last
+ buffer has finished playing.
+*/
+
+DLL_API PaError Pa_StreamActive( PortAudioStream *stream );
+
+/*
+ Pa_StreamTime() returns the current output time for the stream in samples.
+ This time may be used as a time reference (for example syncronising audio to
+ MIDI).
+*/
+
+DLL_API PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+
+/*
+ The "CPU Load" is a fraction of total CPU time consumed by the
+ stream's audio processing.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ This function may be called from the callback function or the application.
+*/
+DLL_API double Pa_GetCPULoad( PortAudioStream* stream );
+
+/*
+ Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for
+ the current host based on minimum latency.
+ On the PC, for the DirectSound implementation, latency can be optionally set
+ by user by setting an environment variable.
+ For example, to set latency to 200 msec, put:
+
+ set PA_MIN_LATENCY_MSEC=200
+
+ in the AUTOEXEC.BAT file and reboot.
+ If the environment variable is not set, then the latency will be determined
+ based on the OS. Windows NT has higher latency than Win95.
+*/
+
+DLL_API int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
+
+/*
+ Sleep for at least 'msec' milliseconds.
+ You may sleep longer than the requested time so don't rely
+ on this for accurate musical timing.
+*/
+DLL_API void Pa_Sleep( long msec );
+
+/*
+ Return size in bytes of a single sample in a given PaSampleFormat
+ or paSampleFormatNotSupported.
+*/
+DLL_API PaError Pa_GetSampleSize( PaSampleFormat format );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PORT_AUDIO_H */
diff --git a/pd/portaudio/pa_jack/pa_jack.c b/pd/portaudio/pa_jack/pa_jack.c
new file mode 100644
index 00000000..4efeff81
--- /dev/null
+++ b/pd/portaudio/pa_jack/pa_jack.c
@@ -0,0 +1,864 @@
+/*
+ * $Id: pa_jack.c,v 1.1.2.1 2002/07/31 04:22:56 joshua Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * JACK Implementation by Joshua Haberman
+ *
+ * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include <string.h>
+#include <regex.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <jack/types.h>
+#include <jack/jack.h>
+
+#include "pa_util.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_process.h"
+#include "pa_allocation.h"
+#include "pa_cpuload.h"
+
+PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi,
+ PaHostApiIndex hostApiIndex );
+
+/*
+ * Functions that directly map to the PortAudio stream interface
+ */
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ PaDeviceIndex inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ unsigned long inputLatency,
+ PaHostApiSpecificStreamInfo *inputStreamInfo,
+ PaDeviceIndex outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ unsigned long outputLatency,
+ PaHostApiSpecificStreamInfo *outputStreamInfo,
+ double sampleRate,
+ unsigned long framesPerCallback,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ void *userData );
+static PaError CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTimestamp GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+
+/*
+ * Data specific to this API
+ */
+
+typedef struct
+{
+ PaUtilHostApiRepresentation commonHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+
+ PaUtilAllocationGroup *deviceInfoMemory;
+
+ jack_client_t *jack_client;
+ PaHostApiIndex hostApiIndex;
+}
+PaJackHostApiRepresentation;
+
+#define MAX_CLIENTS 100
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * Functions specific to this API
+ */
+
+static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi );
+static int JackCallback( jack_nframes_t frames, void *userData );
+
+
+
+/*
+ *
+ * Implementation
+ *
+ */
+
+
+/* BuildDeviceList():
+ *
+ * The process of determining a list of PortAudio "devices" from
+ * JACK's client/port system is fairly involved, so it is separated
+ * into its own routine.
+ */
+
+static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
+{
+ /* Utility macros for the repetitive process of allocating memory */
+
+ /* ... MALLOC: allocate memory as part of the device list
+ * allocation group */
+#define MALLOC(size) \
+ (PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, (size) ))
+
+ /* ... MEMVERIFY: make sure we didn't get NULL */
+#define MEMVERIFY(ptr) \
+ if( (ptr) == NULL ) return paInsufficientMemory;
+
+ /* JACK has no concept of a device. To JACK, there are clients
+ * which have an arbitrary number of ports. To make this
+ * intelligible to PortAudio clients, we will group each JACK client
+ * into a device, and make each port of that client a channel */
+
+ PaUtilHostApiRepresentation *commonApi = &jackApi->commonHostApiRep;
+
+ const char **jack_ports;
+ char *client_names[MAX_CLIENTS];
+ int num_clients = 0;
+ int port_index, client_index, i;
+ double *globalSampleRate;
+ regex_t port_regex;
+
+ /* since we are rebuilding the list of devices, free all memory
+ * associated with the previous list */
+ PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory );
+
+ /* We can only retrieve the list of clients indirectly, by first
+ * asking for a list of all ports, then parsing the port names
+ * according to the client_name:port_name convention (which is
+ * enforced by jackd) */
+ jack_ports = jack_get_ports( jackApi->jack_client, "", "", 0 );
+
+ if( jack_ports == NULL )
+ return paHostError;
+
+ /* Parse the list of ports, using a regex to grab the client names */
+ regcomp( &port_regex, "^[^:]*", REG_EXTENDED );
+
+ /* Build a list of clients from the list of ports */
+ for( port_index = 0; jack_ports[port_index] != NULL; port_index++ )
+ {
+ int client_seen;
+ regmatch_t match_info;
+ char tmp_client_name[100];
+
+ /* extract the client name from the port name, using a regex
+ * that parses the clientname:portname syntax */
+ regexec( &port_regex, jack_ports[port_index], 1, &match_info, 0 );
+ memcpy( tmp_client_name, &jack_ports[port_index][match_info.rm_so],
+ match_info.rm_eo - match_info.rm_so );
+ tmp_client_name[ match_info.rm_eo - match_info.rm_so ] = '\0';
+
+ /* do we know about this port's client yet? */
+ client_seen = FALSE;
+
+ for( i = 0; i < num_clients; i++ )
+ if( strcmp( tmp_client_name, client_names[i] ) == 0 )
+ client_seen = TRUE;
+
+ if( client_seen == FALSE )
+ {
+ client_names[num_clients] = (char*)MALLOC(strlen(tmp_client_name) + 1);
+ MEMVERIFY( client_names[num_clients] );
+
+ /* The alsa_pcm client should go in spot 0. If this
+ * is the alsa_pcm client AND we are NOT about to put
+ * it in spot 0 put it in spot 0 and move whatever
+ * was already in spot 0 to the end. */
+ if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && num_clients > 0 )
+ {
+ /* alsa_pcm goes in spot 0 */
+ strcpy( client_names[ num_clients ], client_names[0] );
+ strcpy( client_names[0], "alsa_pcm" );
+ num_clients++;
+ }
+ else
+ {
+ /* put the new client at the end of the client list */
+ strcpy( client_names[ num_clients ], tmp_client_name );
+ num_clients++;
+ }
+ }
+ }
+ free( jack_ports );
+
+ /* Now we have a list of clients, which will become the list of
+ * PortAudio devices. */
+
+ commonApi->deviceCount = num_clients;
+ commonApi->defaultInputDeviceIndex = 0;
+ commonApi->defaultOutputDeviceIndex = 0;
+
+ /* there is one global sample rate all clients must conform to */
+
+ globalSampleRate = (double*)MALLOC( sizeof(double) );
+ MEMVERIFY( globalSampleRate );
+ *globalSampleRate = jack_get_sample_rate( jackApi->jack_client );
+
+ commonApi->deviceInfos = (PaDeviceInfo**)MALLOC( sizeof(PaDeviceInfo*) *
+ num_clients );
+ MEMVERIFY(commonApi->deviceInfos);
+
+ /* Create a PaDeviceInfo structure for every client */
+ for( client_index = 0; client_index < num_clients; client_index++ )
+ {
+ char regex_pattern[100];
+ PaDeviceInfo *curDevInfo;
+
+ curDevInfo = (PaDeviceInfo*)MALLOC( sizeof(PaDeviceInfo) );
+ MEMVERIFY( curDevInfo );
+
+ curDevInfo->name = (char*)MALLOC( strlen(client_names[client_index]) + 1 );
+ MEMVERIFY( curDevInfo->name );
+ strcpy( (char*)curDevInfo->name, client_names[client_index] );
+
+ curDevInfo->structVersion = 2;
+ curDevInfo->hostApi = jackApi->hostApiIndex;
+
+ /* JACK is very inflexible: there is one sample rate the whole
+ * system must run at, and all clients must speak IEEE float. */
+ curDevInfo->numSampleRates = 1;
+ curDevInfo->sampleRates = globalSampleRate;
+ curDevInfo->nativeSampleFormats = paFloat32|paNonInterleaved;
+
+ /* To determine how many input and output channels are available,
+ * we re-query jackd with more specific parameters. */
+
+ sprintf( regex_pattern, "%s:.*", client_names[client_index] );
+
+ /* ... what are your output ports (that we could input to)? */
+ jack_ports = jack_get_ports( jackApi->jack_client, regex_pattern,
+ NULL, JackPortIsOutput);
+ curDevInfo->maxInputChannels = 0;
+ for( i = 0; jack_ports[i] != NULL ; i++)
+ {
+ /* The number of ports returned is the number of output channels.
+ * We don't care what they are, we just care how many */
+ curDevInfo->maxInputChannels++;
+ }
+ free(jack_ports);
+
+ /* ... what are your input ports (that we could output to)? */
+ jack_ports = jack_get_ports( jackApi->jack_client, regex_pattern,
+ NULL, JackPortIsInput);
+ curDevInfo->maxOutputChannels = 0;
+ for( i = 0; jack_ports[i] != NULL ; i++)
+ {
+ /* The number of ports returned is the number of input channels.
+ * We don't care what they are, we just care how many */
+ curDevInfo->maxOutputChannels++;
+ }
+ free(jack_ports);
+
+ /* Add this client to the list of devices */
+ commonApi->deviceInfos[client_index] = curDevInfo;
+ }
+
+#undef MALLOC
+#undef MEMVERIFY
+ return paNoError;
+}
+
+PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi,
+ PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ PaJackHostApiRepresentation *jackHostApi;
+
+ jackHostApi = (PaJackHostApiRepresentation*)
+ PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) );
+ if( !jackHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* Try to become a client of the JACK server. If we cannot do
+ * this, than this API cannot be used. */
+
+ jackHostApi->jack_client = jack_client_new( "PortAudio client" );
+ if( jackHostApi->jack_client == 0 )
+ {
+ /* the V19 development docs say that if an implementation
+ * detects that it cannot be used, it should return a NULL
+ * interface and paNoError */
+ result = paNoError;
+ *hostApi = NULL;
+ goto error;
+ }
+
+ jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup();
+ if( !jackHostApi->deviceInfoMemory )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ jackHostApi->hostApiIndex = hostApiIndex;
+
+ *hostApi = &jackHostApi->commonHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paInDevelopment;
+ (*hostApi)->info.name = "JACK Audio Connection Kit";
+
+ /* Build a device list by querying the JACK server */
+
+ result = BuildDeviceList( jackHostApi );
+ if( result != paNoError )
+ goto error;
+
+ /* Register functions */
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+
+ PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface,
+ CloseStream, StartStream,
+ StopStream, AbortStream,
+ IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite,
+ PaUtil_DummyGetAvailable,
+ PaUtil_DummyGetAvailable );
+
+ return result;
+
+error:
+ if( jackHostApi )
+ {
+ if( jackHostApi->deviceInfoMemory )
+ {
+ PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory );
+ PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory );
+ }
+
+ PaUtil_FreeMemory( jackHostApi );
+ }
+ return result;
+}
+
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
+
+ jack_client_close( jackHostApi->jack_client );
+
+ if( jackHostApi->deviceInfoMemory )
+ {
+ PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory );
+ PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory );
+ }
+
+ PaUtil_FreeMemory( jackHostApi );
+}
+
+
+/* PaJackStream - a stream data structure specifically for this implementation */
+
+typedef struct PaJackStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilBufferProcessor bufferProcessor;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+
+ /* our input and output ports */
+ jack_port_t **local_input_ports;
+ jack_port_t **local_output_ports;
+
+ /* the input and output ports of the client we are connecting to */
+ jack_port_t **remote_input_ports;
+ jack_port_t **remote_output_ports;
+
+ int num_incoming_connections;
+ int num_outgoing_connections;
+
+ jack_client_t *jack_client;
+
+ /* The stream is running if it's still producing samples.
+ * The stream is active if samples it produced are still being heard.
+ */
+ int is_running;
+ int is_active;
+
+ jack_nframes_t t0;
+ unsigned long total_frames_sent;
+
+ PaUtilAllocationGroup *stream_memory;
+}
+PaJackStream;
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ PaDeviceIndex inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ unsigned long inputLatency,
+ PaHostApiSpecificStreamInfo *inputStreamInfo,
+ PaDeviceIndex outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ unsigned long outputLatency,
+ PaHostApiSpecificStreamInfo *outputStreamInfo,
+ double sampleRate,
+ unsigned long framesPerCallback,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
+ PaJackStream *stream = 0;
+ char port_string[100];
+ char regex_pattern[100];
+ const char **jack_ports;
+ int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client );
+ int i;
+
+ /* the client has no say over the frames per callback */
+
+ (void)framesPerCallback;
+
+ /* Preliminary checks */
+
+ /* ... check that input device can support numInputChannels */
+
+ if( inputDevice != paNoDevice &&
+ numInputChannels > hostApi->deviceInfos[ inputDevice ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* ... check that output device can support numOutputChannels */
+
+ if( outputDevice != paNoDevice &&
+ numOutputChannels > hostApi->deviceInfos[ outputDevice ]->maxOutputChannels)
+ return paInvalidChannelCount;
+
+ /* ... check that the sample rate exactly matches the ONE acceptable rate */
+
+#define ABS(x) ( (x) > 0 ? (x) : -(x) )
+ if( ABS(sampleRate - hostApi->deviceInfos[0]->sampleRates[0]) > 1 )
+ return paInvalidSampleRate;
+#undef ABS
+
+ /* ... this implementation doesn't use custom stream info */
+
+ if( inputStreamInfo )
+ return paIncompatibleStreamInfo;
+
+ /* ... this implementation doesn't use custom stream info */
+
+ if( outputStreamInfo )
+ return paIncompatibleStreamInfo;
+
+ /* ... this implementation doesn't use platform-specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag;
+
+ /* Allocate memory for structuures */
+
+#define MALLOC(size) \
+ (PaUtil_GroupAllocateMemory( stream->stream_memory, (size) ))
+
+#define MEMVERIFY(ptr) \
+ if( (ptr) == NULL ) \
+ { \
+ result = paInsufficientMemory; \
+ goto error; \
+ }
+
+ stream = (PaJackStream*)PaUtil_AllocateMemory( sizeof(PaJackStream) );
+ MEMVERIFY( stream );
+
+ stream->stream_memory = PaUtil_CreateAllocationGroup();
+ stream->jack_client = jackHostApi->jack_client;
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+ stream->local_input_ports =
+ (jack_port_t**) MALLOC(sizeof(jack_port_t*) * numInputChannels );
+ stream->local_output_ports =
+ (jack_port_t**) MALLOC( sizeof(jack_port_t*) * numOutputChannels );
+ stream->remote_output_ports =
+ (jack_port_t**) MALLOC( sizeof(jack_port_t*) * numInputChannels );
+ stream->remote_input_ports =
+ (jack_port_t**) MALLOC( sizeof(jack_port_t*) * numOutputChannels );
+
+ MEMVERIFY( stream->local_input_ports );
+ MEMVERIFY( stream->local_output_ports );
+ MEMVERIFY( stream->remote_input_ports );
+ MEMVERIFY( stream->remote_output_ports );
+
+ stream->num_incoming_connections = numInputChannels;
+ stream->num_outgoing_connections = numOutputChannels;
+
+ if( callback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &jackHostApi->callbackStreamInterface, callback, userData );
+ }
+ else
+ {
+ /* we do not support blocking I/O */
+ return paBadIODeviceCombination;
+ }
+
+ /* create the JACK ports. We cannot connect them until audio
+ * processing begins */
+
+ for( i = 0; i < numInputChannels; i++ )
+ {
+ sprintf( port_string, "in_%d", i );
+ stream->local_input_ports[i] = jack_port_register(
+ jackHostApi->jack_client, port_string,
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
+ }
+
+ for( i = 0; i < numOutputChannels; i++ )
+ {
+ sprintf( port_string, "out_%d", i );
+ stream->local_output_ports[i] = jack_port_register(
+ jackHostApi->jack_client, port_string,
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
+ }
+
+ /* look up the jack_port_t's for the remote ports. We could do
+ * this at stream start time, but doing it here ensures the
+ * name lookup only happens once. */
+
+ if( numInputChannels > 0 )
+ {
+ /* ... remote output ports (that we input from) */
+ sprintf( regex_pattern, "%s:.*", hostApi->deviceInfos[ inputDevice ]->name );
+ jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
+ NULL, JackPortIsOutput);
+ for( i = 0; i < numInputChannels && jack_ports[i]; i++ )
+ {
+ stream->remote_output_ports[i] = jack_port_by_name(
+ jackHostApi->jack_client, jack_ports[i] );
+ }
+ if( i < numInputChannels )
+ {
+ /* we found fewer ports than we expected */
+ return paInternalError;
+ }
+ free( jack_ports ); // XXX: this doesn't happen if we exit prematurely
+ }
+
+
+ if( numOutputChannels > 0 )
+ {
+ /* ... remote input ports (that we output to) */
+ sprintf( regex_pattern, "%s:.*", hostApi->deviceInfos[ outputDevice ]->name );
+ jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
+ NULL, JackPortIsInput);
+ for( i = 0; i < numOutputChannels && jack_ports[i]; i++ )
+ {
+ stream->remote_input_ports[i] = jack_port_by_name(
+ jackHostApi->jack_client, jack_ports[i] );
+ }
+ if( i < numOutputChannels )
+ {
+ /* we found fewer ports than we expected */
+ return paInternalError;
+ }
+ free( jack_ports ); // XXX: this doesn't happen if we exit prematurely
+ }
+
+ result = PaUtil_InitializeBufferProcessor(
+ &stream->bufferProcessor,
+ numInputChannels,
+ inputSampleFormat,
+ paFloat32, /* hostInputSampleFormat */
+ numOutputChannels,
+ outputSampleFormat,
+ paFloat32, /* hostOutputSampleFormat */
+ sampleRate,
+ streamFlags,
+ framesPerCallback,
+ jack_max_buffer_size,
+ paUtilFixedHostBufferSize,
+ callback,
+ userData );
+
+ if( result != paNoError )
+ goto error;
+
+ stream->is_running = FALSE;
+ stream->t0 = -1;/* set the first time through the callback*/
+ stream->total_frames_sent = 0;
+
+ jack_set_process_callback( jackHostApi->jack_client, JackCallback, stream );
+
+ *s = (PaStream*)stream;
+
+ return result;
+
+error:
+ if( stream )
+ {
+ if( stream->stream_memory )
+ {
+ PaUtil_FreeAllAllocations( stream->stream_memory );
+ PaUtil_DestroyAllocationGroup( stream->stream_memory );
+ }
+
+ PaUtil_FreeMemory( stream );
+ }
+
+ return result;
+
+#undef MALLOC
+#undef MEMVERIFY
+}
+
+
+static int JackCallback( jack_nframes_t frames, void *userData )
+{
+ PaJackStream *stream = (PaJackStream*)userData;
+ PaTimestamp outTime = 0; /* IMPLEMENT ME */
+ int callbackResult;
+ int chn;
+ int framesProcessed;
+
+ if( stream->t0 == -1 )
+ {
+ if( stream->num_outgoing_connections == 0 )
+ {
+ /* TODO: how to handle stream time for capture-only operation? */
+ }
+ else
+ {
+ /* the beginning time needs to be initialized */
+ stream->t0 = jack_frame_time( stream->jack_client ) -
+ jack_frames_since_cycle_start( stream->jack_client) +
+ jack_port_get_total_latency( stream->jack_client,
+ stream->local_output_ports[0] );
+ }
+ }
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, outTime );
+
+ for( chn = 0; chn < stream->num_incoming_connections; chn++ )
+ {
+ jack_default_audio_sample_t *channel_buf;
+ channel_buf = (jack_default_audio_sample_t*)
+ jack_port_get_buffer( stream->local_input_ports[chn],
+ frames );
+
+ PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor,
+ chn,
+ channel_buf );
+ }
+
+ for( chn = 0; chn < stream->num_outgoing_connections; chn++ )
+ {
+ jack_default_audio_sample_t *channel_buf;
+ channel_buf = (jack_default_audio_sample_t*)
+ jack_port_get_buffer( stream->local_output_ports[chn],
+ frames );
+
+ PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor,
+ chn,
+ channel_buf );
+ }
+
+ if( stream->num_incoming_connections > 0 )
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames );
+
+ if( stream->num_outgoing_connections > 0 )
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames );
+
+ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
+ &callbackResult );
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+ stream->total_frames_sent += frames;
+
+
+ if( callbackResult == paContinue )
+ {
+ /* nothing special */
+ }
+ else if( callbackResult == paAbort )
+ {
+ /* finish playback immediately */
+
+ /* TODO: memset 0 the outgoing samples to "cancel" them */
+
+ stream->is_active = FALSE;
+
+ /* return nonzero so we get deactivated (and the callback won't
+ * get called again) */
+ return 1;
+ }
+ else
+ {
+ /* User callback has asked us to stop with paComplete or other non-zero value. */
+
+ stream->is_active = FALSE;
+
+ /* return nonzero so we get deactivated (and the callback won't
+ * get called again) */
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaJackStream *stream = (PaJackStream*)s;
+
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaJackStream *stream = (PaJackStream*)s;
+ int i;
+
+ /* start the audio thread */
+
+ jack_activate( stream->jack_client );
+
+ /* connect the ports */
+
+ /* NOTE: I would rather use jack_port_connect which uses jack_port_t's
+ * instead of port names, but it is not implemented yet. */
+ if( stream->num_incoming_connections > 0 )
+ {
+ for( i = 0; i < stream->num_incoming_connections; i++ )
+ jack_connect( stream->jack_client,
+ jack_port_name(stream->remote_output_ports[i]),
+ jack_port_name(stream->local_input_ports[i] ) );
+ }
+
+ if( stream->num_outgoing_connections > 0 )
+ {
+ for( i = 0; i < stream->num_outgoing_connections; i++ )
+ jack_connect( stream->jack_client,
+ jack_port_name(stream->local_output_ports[i]),
+ jack_port_name(stream->remote_input_ports[i]) );
+ }
+
+ stream->is_running = TRUE;
+
+ return result;
+}
+
+
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaJackStream *stream = (PaJackStream*)s;
+
+ /* note: this automatically disconnects all ports, since a deactivated
+ * client is not allowed to have any ports connected */
+ jack_deactivate( stream->jack_client );
+
+ stream->is_running = FALSE;
+
+ /* TODO: block until playback complete */
+
+ stream->is_active = FALSE;
+
+ return result;
+}
+
+
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaJackStream *stream = (PaJackStream*)s;
+
+ /* There's no way to cancel samples already submitted, but we can
+ * return immediately */
+
+ /* note: this automatically disconnects all ports, since a deactivated
+ * client is not allowed to have any ports connected */
+ jack_deactivate( stream->jack_client );
+
+ stream->is_running = FALSE;
+ stream->is_active = FALSE;
+
+ return result;
+}
+
+
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaJackStream *stream = (PaJackStream*)s;
+
+ return stream->is_running == FALSE;
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+ PaJackStream *stream = (PaJackStream*)s;
+
+ return stream->is_active == TRUE;
+}
+
+
+static PaTimestamp GetStreamTime( PaStream *s )
+{
+ PaJackStream *stream = (PaJackStream*)s;
+
+ /* TODO: what if we're recording-only? */
+ return jack_frame_time( stream->jack_client ) - stream->t0;
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaJackStream *stream = (PaJackStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
diff --git a/pd/portaudio/pa_linux_alsa/blocking_calls.c b/pd/portaudio/pa_linux_alsa/blocking_calls.c
new file mode 100644
index 00000000..6304b117
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/blocking_calls.c
@@ -0,0 +1,61 @@
+
+#include "pa_stream.h"
+
+#include "pa_linux_alsa.h"
+
+PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ /* TODO: handle failure, xruns */
+
+ if( stream->capture_interleaved )
+ {
+ snd_pcm_mmap_readi( stream->pcm_capture, buffer, frames );
+ }
+ else
+ {
+ snd_pcm_mmap_readn( stream->pcm_capture, (void**)buffer, frames );
+ }
+
+ return paNoError;
+}
+
+
+PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ if( stream->playback_interleaved )
+ {
+ snd_pcm_mmap_writei( stream->pcm_playback, buffer, frames );
+ }
+ else
+ {
+ snd_pcm_mmap_writen( stream->pcm_playback, (void**)buffer, frames );
+ }
+
+ return paNoError;
+}
+
+
+unsigned long GetStreamReadAvailable( PaStream* s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ return snd_pcm_avail_update( stream->pcm_capture );
+}
+
+
+unsigned long GetStreamWriteAvailable( PaStream* s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ return snd_pcm_avail_update( stream->pcm_playback );
+}
+
+
diff --git a/pd/portaudio/pa_linux_alsa/blocking_calls.o b/pd/portaudio/pa_linux_alsa/blocking_calls.o
new file mode 100644
index 00000000..d4bc2108
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/blocking_calls.o
Binary files differ
diff --git a/pd/portaudio/pa_linux_alsa/callback_thread.c b/pd/portaudio/pa_linux_alsa/callback_thread.c
new file mode 100644
index 00000000..483557b6
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/callback_thread.c
@@ -0,0 +1,374 @@
+
+#include <sys/poll.h>
+#include <limits.h>
+#include <math.h> /* abs() */
+
+#include <alsa/asoundlib.h>
+
+#include "pa_linux_alsa.h"
+
+#define MIN(x,y) ( (x) < (y) ? (x) : (y) )
+
+static int wait( PaAlsaStream *stream )
+{
+ int need_capture;
+ int need_playback;
+ int capture_avail = INT_MAX;
+ int playback_avail = INT_MAX;
+ int common_avail;
+
+ if( stream->pcm_capture )
+ need_capture = 1;
+ else
+ need_capture = 0;
+
+ if( stream->pcm_playback )
+ need_playback = 1;
+ else
+ need_playback = 0;
+
+ while( need_capture || need_playback )
+ {
+ int playback_pfd_offset=0;
+ int total_fds = 0;
+
+ /* if the main thread has requested that we stop, do so now */
+ pthread_testcancel();
+
+ /*printf("still polling...\n");
+ if( need_capture )
+ printf("need capture.\n");
+ if( need_playback )
+ printf("need playback.\n"); */
+
+ /* get the fds, packing all applicable fds into a single array,
+ * so we can check them all with a single poll() call */
+
+ if( need_capture )
+ {
+ snd_pcm_poll_descriptors( stream->pcm_capture, stream->pfds,
+ stream->capture_nfds );
+ total_fds += stream->capture_nfds;
+ }
+
+ if( need_playback )
+ {
+ playback_pfd_offset = total_fds;
+ snd_pcm_poll_descriptors( stream->pcm_playback,
+ stream->pfds + playback_pfd_offset,
+ stream->playback_nfds );
+ total_fds += stream->playback_nfds;
+ }
+
+ /* now poll on the combination of playback and capture fds.
+ * TODO: handle interrupt and/or failure */
+ poll( stream->pfds, total_fds, 1000 );
+
+ /* check the return status of our pfds */
+ if( need_capture )
+ {
+ short revents;
+ snd_pcm_poll_descriptors_revents( stream->pcm_capture, stream->pfds,
+ stream->capture_nfds, &revents );
+ if( revents == POLLIN )
+ need_capture = 0;
+ }
+
+ if( need_playback )
+ {
+ short revents;
+ snd_pcm_poll_descriptors_revents( stream->pcm_playback,
+ stream->pfds + playback_pfd_offset,
+ stream->playback_nfds, &revents );
+ //if( revents & POLLOUT )
+ //if( revents & POLLERR )
+ // printf("polling error!");
+ if( revents == POLLOUT )
+ need_playback = 0;
+ }
+ }
+
+ /* we have now established that there are buffers ready to be
+ * operated on. Now determine how many frames are available. */
+ if( stream->pcm_capture )
+ capture_avail = snd_pcm_avail_update( stream->pcm_capture );
+
+ if( stream->pcm_playback )
+ playback_avail = snd_pcm_avail_update( stream->pcm_playback );
+
+ common_avail = MIN(capture_avail, playback_avail);
+ common_avail -= common_avail % stream->frames_per_period;
+
+ return common_avail;
+}
+
+static int setup_buffers( PaAlsaStream *stream, int frames_avail )
+{
+ int i;
+ int capture_frames_avail = INT_MAX;
+ int playback_frames_avail = INT_MAX;
+ int common_frames_avail;
+
+ if( stream->pcm_capture )
+ {
+ const snd_pcm_channel_area_t *capture_areas;
+ const snd_pcm_channel_area_t *area;
+ snd_pcm_uframes_t frames = frames_avail;
+
+ /* I do not understand this code fragment yet, it is copied out of the
+ * alsa-devel archives... */
+ snd_pcm_mmap_begin( stream->pcm_capture, &capture_areas,
+ &stream->capture_offset, &frames);
+
+ if( stream->capture_interleaved )
+ {
+ void *interleaved_capture_buffer;
+ area = &capture_areas[0];
+ interleaved_capture_buffer = area->addr +
+ (area->first + area->step * stream->capture_offset) / 8;
+ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
+ 0, /* starting at channel 0 */
+ interleaved_capture_buffer,
+ 0 /* default numInputChannels */
+ );
+ }
+ else
+ {
+ /* noninterleaved */
+ void *noninterleaved_capture_buffers[1000];
+ for( i = 0; i < stream->capture_channels; i++ )
+ {
+ area = &capture_areas[i];
+ noninterleaved_capture_buffers[i] = area->addr +
+ (area->first + area->step * stream->capture_offset) / 8;
+ PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor,
+ i,
+ noninterleaved_capture_buffers[i]);
+ }
+ }
+
+ capture_frames_avail = frames;
+ }
+
+ if( stream->pcm_playback )
+ {
+ const snd_pcm_channel_area_t *playback_areas;
+ const snd_pcm_channel_area_t *area;
+ snd_pcm_uframes_t frames = frames_avail;
+
+ /* I do not understand this code fragment yet, it is copied out of the
+ * alsa-devel archives... */
+ snd_pcm_mmap_begin( stream->pcm_playback, &playback_areas,
+ &stream->playback_offset, &frames);
+
+ if( stream->playback_interleaved )
+ {
+ void *interleaved_playback_buffer;
+ area = &playback_areas[0];
+ interleaved_playback_buffer = area->addr +
+ (area->first + area->step * stream->playback_offset) / 8;
+ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
+ 0, /* starting at channel 0 */
+ interleaved_playback_buffer,
+ 0 /* default numInputChannels */
+ );
+ }
+ else
+ {
+ /* noninterleaved */
+ void *noninterleaved_playback_buffers[1000];
+ for( i = 0; i < stream->playback_channels; i++ )
+ {
+ area = &playback_areas[i];
+ noninterleaved_playback_buffers[i] = area->addr +
+ (area->first + area->step * stream->playback_offset) / 8;
+ PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor,
+ i,
+ noninterleaved_playback_buffers[i]);
+ }
+ }
+
+ playback_frames_avail = frames;
+ }
+
+
+ common_frames_avail = MIN(capture_frames_avail, playback_frames_avail);
+ common_frames_avail -= common_frames_avail % stream->frames_per_period;
+ //printf( "%d capture frames available\n", capture_frames_avail );
+ //printf( "%d frames playback available\n", playback_frames_avail );
+ //printf( "%d frames available\n", common_frames_avail );
+
+ if( stream->pcm_capture )
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, common_frames_avail );
+
+ if( stream->pcm_playback )
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, common_frames_avail );
+
+ return common_frames_avail;
+}
+
+void *CallbackThread( void *userData )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)userData;
+
+ if( stream->pcm_capture )
+ snd_pcm_start( stream->pcm_capture );
+ if( stream->pcm_playback )
+ snd_pcm_start( stream->pcm_playback );
+
+ while(1)
+ {
+ int frames_avail;
+ int frames_got;
+
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
+ int callbackResult;
+ int framesProcessed;
+
+ pthread_testcancel();
+ {
+ /* calculate time info */
+ snd_timestamp_t capture_timestamp;
+ snd_timestamp_t playback_timestamp;
+ snd_pcm_status_t *capture_status;
+ snd_pcm_status_t *playback_status;
+ snd_pcm_status_alloca( &capture_status );
+ snd_pcm_status_alloca( &playback_status );
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_status( stream->pcm_capture, capture_status );
+ snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );
+ }
+ if( stream->pcm_playback )
+ {
+ snd_pcm_status( stream->pcm_playback, playback_status );
+ snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );
+ }
+
+ /* Hmm, we potentially have both a playback and a capture timestamp.
+ * Hopefully they are the same... */
+ if( stream->pcm_capture && stream->pcm_playback )
+ {
+ float capture_time = capture_timestamp.tv_sec +
+ ((float)capture_timestamp.tv_usec/1000000);
+ float playback_time= playback_timestamp.tv_sec +
+ ((float)playback_timestamp.tv_usec/1000000);
+ if( fabsf(capture_time-playback_time) > 0.01 )
+ printf("Capture time and playback time differ by %f\n", fabsf(capture_time-playback_time));
+ timeInfo.currentTime = capture_time;
+ }
+ else if( stream->pcm_playback )
+ {
+ timeInfo.currentTime = playback_timestamp.tv_sec +
+ ((float)playback_timestamp.tv_usec/1000000);
+ }
+ else
+ {
+ timeInfo.currentTime = capture_timestamp.tv_sec +
+ ((float)capture_timestamp.tv_usec/1000000);
+ }
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_sframes_t capture_delay = snd_pcm_status_get_delay( capture_status );
+ timeInfo.inputBufferAdcTime = timeInfo.currentTime -
+ (float)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_sframes_t playback_delay = snd_pcm_status_get_delay( playback_status );
+ timeInfo.outputBufferDacTime = timeInfo.currentTime +
+ (float)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;
+ }
+ }
+
+
+ /*
+ IMPLEMENT ME:
+ - handle buffer slips
+ */
+
+ /*
+ depending on whether the host buffers are interleaved, non-interleaved
+ or a mixture, you will want to call PaUtil_ProcessInterleavedBuffers(),
+ PaUtil_ProcessNonInterleavedBuffers() or PaUtil_ProcessBuffers() here.
+ */
+
+ frames_avail = wait( stream );
+ //printf( "%d frames available\n", frames_avail );
+
+ /* Now we know the soundcard is ready to produce/receive at least
+ * one period. We just need to get the buffers for the client
+ * to read/write. */
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo );
+
+ frames_got = setup_buffers( stream, frames_avail );
+
+ if( frames_avail == frames_got )
+ ;//printf("good, they were both %d\n", frames_avail );
+ else
+ printf("damn, they were different: avail: %d, got: %d\n", frames_avail, frames_got );
+
+ /* this calls the callback */
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
+ &callbackResult );
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+
+ /* inform ALSA how many frames we wrote */
+
+ if( stream->pcm_capture )
+ snd_pcm_mmap_commit( stream->pcm_capture, stream->capture_offset, frames_avail );
+
+ if( stream->pcm_playback )
+ snd_pcm_mmap_commit( stream->pcm_playback, stream->playback_offset, frames_avail );
+
+
+ /*
+ If you need to byte swap outputBuffer, you can do it here using
+ routines in pa_byteswappers.h
+ */
+
+ if( callbackResult == paContinue )
+ {
+ /* nothing special to do */
+ }
+ else if( callbackResult == paAbort )
+ {
+ stream->callback_finished = 1;
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_drop( stream->pcm_capture );
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_drop( stream->pcm_playback );
+ }
+ pthread_exit(NULL);
+ }
+ else
+ {
+ stream->callback_finished = 1;
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_drain( stream->pcm_capture );
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_drain( stream->pcm_playback );
+ }
+ pthread_exit(NULL);
+ }
+
+ }
+}
+
diff --git a/pd/portaudio/pa_linux_alsa/callback_thread.o b/pd/portaudio/pa_linux_alsa/callback_thread.o
new file mode 100644
index 00000000..a242d490
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/callback_thread.o
Binary files differ
diff --git a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c
new file mode 100644
index 00000000..9582b5b8
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c
@@ -0,0 +1,989 @@
+/*
+ * $Id: pa_linux_alsa.c,v 1.1.2.3 2003/02/01 21:55:03 joshua Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * ALSA implementation by Joshua Haberman
+ *
+ * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include <sys/poll.h>
+#include <pthread.h>
+
+#include <string.h> /* strlen() */
+#include <limits.h>
+
+#include <alsa/asoundlib.h>
+
+#include "portaudio.h"
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
+
+#include "pa_linux_alsa.h"
+
+/* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */
+
+typedef struct
+{
+ PaUtilHostApiRepresentation commonHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
+
+ PaUtilAllocationGroup *allocations;
+
+ PaHostApiIndex hostApiIndex;
+}
+PaAlsaHostApiRepresentation;
+
+
+/* prototypes for functions declared in this file */
+
+PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *callback,
+ void *userData );
+static PaError CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi );
+
+/* blocking calls are in blocking_calls.c */
+extern PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+extern PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+extern signed long GetStreamReadAvailable( PaStream* stream );
+extern signed long GetStreamWriteAvailable( PaStream* stream );
+
+/* all callback-related functions are in callback_thread.c */
+extern void *CallbackThread( void *userData );
+
+
+PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ int i, deviceCount;
+ PaAlsaHostApiRepresentation *skeletonHostApi;
+
+ skeletonHostApi = (PaAlsaHostApiRepresentation*)
+ PaUtil_AllocateMemory( sizeof(PaAlsaHostApiRepresentation) );
+ if( !skeletonHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !skeletonHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ skeletonHostApi->hostApiIndex = hostApiIndex;
+ *hostApi = (PaUtilHostApiRepresentation*)skeletonHostApi;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paALSA;
+ (*hostApi)->info.name = "ALSA implementation";
+
+ BuildDeviceList( skeletonHostApi );
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+
+ PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface,
+ CloseStream, StartStream,
+ StopStream, AbortStream,
+ IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite,
+ PaUtil_DummyGetAvailable,
+ PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface,
+ CloseStream, StartStream,
+ StopStream, AbortStream,
+ IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream,
+ GetStreamReadAvailable,
+ GetStreamWriteAvailable );
+
+ return result;
+
+error:
+ if( skeletonHostApi )
+ {
+ if( skeletonHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( skeletonHostApi );
+ }
+ return result;
+}
+
+static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
+{
+ PaUtilHostApiRepresentation *commonApi = &alsaApi->commonHostApiRep;
+ PaDeviceInfo *deviceInfoArray;
+ int deviceCount = 0;
+ int card_idx;
+ int device_idx;
+ snd_ctl_t *ctl;
+ snd_ctl_card_info_t *card_info;
+
+ /* count the devices by enumerating all the card numbers */
+
+ /* snd_card_next() modifies the integer passed to it to be:
+ * the index of the first card if the parameter is -1
+ * the index of the next card if the parameter is the index of a card
+ * -1 if there are no more cards
+ *
+ * The function itself returns 0 if it succeeded. */
+ card_idx = -1;
+ while( snd_card_next( &card_idx ) == 0 && card_idx >= 0 )
+ {
+ deviceCount++;
+ }
+
+ /* allocate deviceInfo memory based on the number of devices */
+
+ commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ alsaApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
+ if( !commonApi->deviceInfos )
+ {
+ return paInsufficientMemory;
+ }
+
+ /* allocate all device info structs in a contiguous block */
+ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ alsaApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
+ if( !deviceInfoArray )
+ {
+ return paInsufficientMemory;
+ }
+
+ /* now loop over the list of devices again, filling in the deviceInfo for each */
+ card_idx = -1;
+ device_idx = 0;
+ while( snd_card_next( &card_idx ) == 0 && card_idx >= 0 )
+ {
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[device_idx];
+ char *deviceName;
+ char alsaDeviceName[50];
+ const char *cardName;
+
+ commonApi->deviceInfos[device_idx++] = deviceInfo;
+
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = alsaApi->hostApiIndex;
+
+ sprintf( alsaDeviceName, "hw:%d", card_idx );
+ snd_ctl_open( &ctl, alsaDeviceName, 0 );
+ snd_ctl_card_info_malloc( &card_info );
+ snd_ctl_card_info( ctl, card_info );
+ cardName = snd_ctl_card_info_get_id( card_info );
+
+ deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
+ strlen(cardName) + 1 );
+ if( !deviceName )
+ {
+ return paInsufficientMemory;
+ }
+ strcpy( deviceName, cardName );
+ deviceInfo->name = deviceName;
+
+ snd_ctl_card_info_free( card_info );
+
+ /* to determine max. channels, we must open the device and query the
+ * hardware parameter configuration space */
+ {
+ snd_pcm_t *pcm_handle;
+ snd_pcm_hw_params_t *hw_params;
+ int dir;
+
+ snd_pcm_hw_params_malloc( &hw_params );
+
+ /* get max channels for capture */
+
+ if( snd_pcm_open( &pcm_handle, alsaDeviceName, SND_PCM_STREAM_CAPTURE, 0 ) < 0 )
+ {
+ deviceInfo->maxInputChannels = 0;
+ }
+ else
+ {
+ snd_pcm_hw_params_any( pcm_handle, hw_params );
+ deviceInfo->maxInputChannels = snd_pcm_hw_params_get_channels_max( hw_params );
+ /* TODO: I'm not really sure what to do here */
+ //deviceInfo->defaultLowInputLatency = snd_pcm_hw_params_get_period_size_min( hw_params, &dir );
+ //deviceInfo->defaultHighInputLatency = snd_pcm_hw_params_get_period_size_max( hw_params, &dir );
+ deviceInfo->defaultLowInputLatency = 128. / 44100;
+ deviceInfo->defaultHighInputLatency = 16384. / 44100;
+ snd_pcm_close( pcm_handle );
+ }
+
+ /* get max channels for playback */
+ if( snd_pcm_open( &pcm_handle, alsaDeviceName, SND_PCM_STREAM_PLAYBACK, 0 ) < 0 )
+ {
+ deviceInfo->maxOutputChannels = 0;
+ }
+ else
+ {
+ snd_pcm_hw_params_any( pcm_handle, hw_params );
+ deviceInfo->maxOutputChannels = snd_pcm_hw_params_get_channels_max( hw_params );
+ /* TODO: I'm not really sure what to do here */
+ //deviceInfo->defaultLowOutputLatency = snd_pcm_hw_params_get_period_size_min( hw_params, &dir );
+ //deviceInfo->defaultHighOutputLatency = snd_pcm_hw_params_get_period_size_max( hw_params, &dir );
+ deviceInfo->defaultLowOutputLatency = 128. / 44100;
+ deviceInfo->defaultHighOutputLatency = 16384. / 44100;
+ snd_pcm_close( pcm_handle );
+ }
+
+ snd_pcm_hw_params_free( hw_params );
+ }
+
+ deviceInfo->defaultSampleRate = 44100.; /* IMPLEMENT ME */
+ }
+
+ commonApi->info.deviceCount = deviceCount;
+ commonApi->info.defaultInputDevice = 0;
+ commonApi->info.defaultOutputDevice = 0;
+
+ return paNoError;
+}
+
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaAlsaHostApiRepresentation *skeletonHostApi;
+ skeletonHostApi = (PaAlsaHostApiRepresentation*)hostApi;
+
+ /*
+ IMPLEMENT ME:
+ - clean up any resourced not handled by the allocation group
+ */
+
+ if( skeletonHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( skeletonHostApi );
+}
+
+
+/* Given an open stream, what sample formats are available? */
+
+static PaSampleFormat GetAvailableFormats( snd_pcm_t *stream )
+{
+ PaSampleFormat available = 0;
+ snd_pcm_hw_params_t *hw_params;
+ snd_pcm_hw_params_alloca( &hw_params );
+
+ snd_pcm_hw_params_any( stream, hw_params );
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_FLOAT ) == 0)
+ available |= paFloat32;
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S16 ) == 0)
+ available |= paInt16;
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S24 ) == 0)
+ available |= paInt24;
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S32 ) == 0)
+ available |= paInt32;
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S8 ) == 0)
+ available |= paInt8;
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_U8 ) == 0)
+ available |= paUInt8;
+
+ return available;
+}
+
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
+
+static PaError ConfigureStream( snd_pcm_t *stream, int channels,
+ int interleaved, unsigned long rate,
+ PaSampleFormat pa_format, int framesPerBuffer )
+{
+#define ENSURE(functioncall) \
+ if( (functioncall) < 0 ) { \
+ printf("Error executing ALSA call, line %d\n", __LINE__); \
+ return 1; \
+ } \
+ else { \
+ printf("ALSA call at line %d succeeded\n", __LINE__ ); \
+ }
+
+ snd_pcm_access_t access_mode;
+ snd_pcm_format_t alsa_format;
+
+ /* configuration consists of setting all of ALSA's parameters.
+ * These parameters come in two flavors: hardware parameters
+ * and software paramters. Hardware parameters will affect
+ * the way the device is initialized, software parameters
+ * affect the way ALSA interacts with me, the user-level client. */
+
+ snd_pcm_hw_params_t *hw_params;
+ snd_pcm_sw_params_t *sw_params;
+
+ snd_pcm_hw_params_alloca( &hw_params );
+
+ /* ... fill up the configuration space with all possibile
+ * combinations of parameters this device will accept */
+ ENSURE( snd_pcm_hw_params_any( stream, hw_params ) );
+
+ if( interleaved )
+ access_mode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else
+ access_mode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+
+ ENSURE( snd_pcm_hw_params_set_access( stream, hw_params, access_mode ) );
+
+ /* set the format based on what the user selected */
+ switch( pa_format )
+ {
+ case paFloat32:
+ alsa_format = SND_PCM_FORMAT_FLOAT;
+ break;
+
+ case paInt16:
+ alsa_format = SND_PCM_FORMAT_S16;
+ break;
+
+ case paInt24:
+ alsa_format = SND_PCM_FORMAT_S24;
+ break;
+
+ case paInt32:
+ alsa_format = SND_PCM_FORMAT_S32;
+ break;
+
+ case paInt8:
+ alsa_format = SND_PCM_FORMAT_S8;
+ break;
+
+ case paUInt8:
+ alsa_format = SND_PCM_FORMAT_U8;
+ break;
+
+ default:
+ printf("Unknown PortAudio format %d\n", (int)pa_format );
+ return 1;
+ }
+ //printf("PortAudio format: %d\n", pa_format);
+ printf("ALSA format: %d\n", alsa_format);
+ ENSURE( snd_pcm_hw_params_set_format( stream, hw_params, alsa_format ) );
+
+ /* ... set the sample rate */
+ ENSURE( snd_pcm_hw_params_set_rate( stream, hw_params, rate, 0 ) );
+
+ /* ... set the number of channels */
+ ENSURE( snd_pcm_hw_params_set_channels( stream, hw_params, channels ) );
+
+ /* ... set the number of periods to 2, which is essentially double buffering.
+ * this makes the latency the number of samples per buffer, which is the best
+ * it can be */
+ ENSURE( snd_pcm_hw_params_set_periods ( stream, hw_params, 2, 0 ) );
+
+ /* ... set the period size, which is essentially the hardware buffer size */
+ if( framesPerBuffer != 0 )
+ {
+ ENSURE( snd_pcm_hw_params_set_period_size( stream, hw_params,
+ framesPerBuffer, 0 ) );
+ }
+ else
+ {
+ ENSURE( snd_pcm_hw_params_set_period_size( stream, hw_params,
+ 2048, 0 ) );
+ }
+
+
+ /* Set the parameters! */
+ ENSURE( snd_pcm_hw_params( stream, hw_params ) );
+
+ return 0;
+#undef ENSURE
+}
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *callback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaAlsaHostApiRepresentation *skeletonHostApi =
+ (PaAlsaHostApiRepresentation*)hostApi;
+ PaAlsaStream *stream = 0;
+ PaSampleFormat hostInputSampleFormat=0, hostOutputSampleFormat=0;
+ int numInputChannels, numOutputChannels;
+ PaSampleFormat inputSampleFormat=0, outputSampleFormat=0;
+ unsigned long framesPerHostBuffer = framesPerBuffer;
+
+ if( framesPerHostBuffer == paFramesPerBufferUnspecified )
+ {
+ // TODO: have some reason
+ framesPerHostBuffer = 2048;
+ }
+
+ if( inputParameters )
+ {
+ numInputChannels = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification.
+ [JH] this could be supported in the future, to allow ALSA device strings
+ like hw:0 */
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support numInputChannels */
+ if( numInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numInputChannels = 0;
+ }
+
+ if( outputParameters )
+ {
+ numOutputChannels = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification
+ [JH] this could be supported in the future, to allow ALSA device strings
+ like hw:0 */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support numInputChannels */
+ if( numOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numOutputChannels = 0;
+ }
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
+
+ /* allocate and do basic initialization of the stream structure */
+
+ stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) );
+ if( !stream )
+ {
+ printf("memory point 2\n");
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ stream->pcm_capture = NULL;
+ stream->pcm_playback = NULL;
+ stream->callback_mode = (callback != 0);
+ stream->callback_finished = 0;
+
+ if( callback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &skeletonHostApi->callbackStreamInterface,
+ callback, userData );
+ }
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &skeletonHostApi->blockingStreamInterface,
+ callback, userData );
+ }
+
+
+ stream->streamRepresentation.streamInfo.inputLatency = framesPerHostBuffer;
+ stream->streamRepresentation.streamInfo.outputLatency = framesPerHostBuffer;
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+ /* open the devices now, so we can obtain info about the available formats */
+
+ if( numInputChannels > 0 )
+ {
+ char inputDeviceName[50];
+
+ sprintf( inputDeviceName, "hw:CARD=%s", hostApi->deviceInfos[inputParameters->device]->name );
+ if( snd_pcm_open( &stream->pcm_capture, inputDeviceName, SND_PCM_STREAM_CAPTURE, 0 ) < 0 )
+ {
+ result = paBadIODeviceCombination;
+ goto error;
+ }
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( GetAvailableFormats(stream->pcm_capture),
+ inputSampleFormat );
+ }
+
+ if( numOutputChannels > 0 )
+ {
+ char outputDeviceName[50];
+
+ sprintf( outputDeviceName, "hw:CARD=%s", hostApi->deviceInfos[outputParameters->device]->name );
+ if( snd_pcm_open( &stream->pcm_playback, outputDeviceName, SND_PCM_STREAM_PLAYBACK, 0 ) < 0 )
+ {
+ result = paBadIODeviceCombination;
+ goto error;
+ }
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( GetAvailableFormats(stream->pcm_playback),
+ outputSampleFormat );
+ stream->playback_hostsampleformat = hostOutputSampleFormat;
+ }
+
+
+
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ numInputChannels, inputSampleFormat, hostInputSampleFormat,
+ numOutputChannels, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer, framesPerHostBuffer,
+ paUtilFixedHostBufferSize, callback, userData );
+ if( result != paNoError )
+ goto error;
+
+ /* configure the streams */
+
+ if( numInputChannels > 0 )
+ {
+ int interleaved;
+ PaSampleFormat plain_format = hostInputSampleFormat & ~paNonInterleaved;
+
+ if( inputSampleFormat & paNonInterleaved )
+ interleaved = 0;
+ else
+ interleaved = 1;
+
+ if( ConfigureStream( stream->pcm_capture, numInputChannels, interleaved,
+ sampleRate, plain_format, framesPerHostBuffer ) != 0 )
+ {
+ result = paBadIODeviceCombination;
+ goto error;
+ }
+
+ stream->capture_interleaved = interleaved;
+ }
+
+ if( numOutputChannels > 0 )
+ {
+ int interleaved;
+ PaSampleFormat plain_format = hostOutputSampleFormat & ~paNonInterleaved;
+
+ if( outputSampleFormat & paNonInterleaved )
+ interleaved = 0;
+ else
+ interleaved = 1;
+
+ if( ConfigureStream( stream->pcm_playback, numOutputChannels, interleaved,
+ sampleRate, plain_format, framesPerHostBuffer ) != 0 )
+ {
+ result = paBadIODeviceCombination;
+ goto error;
+ }
+
+ stream->playback_interleaved = interleaved;
+ }
+
+ stream->capture_nfds = 0;
+ stream->playback_nfds = 0;
+
+ if( stream->pcm_capture )
+ stream->capture_nfds = snd_pcm_poll_descriptors_count( stream->pcm_capture );
+
+ if( stream->pcm_playback )
+ stream->playback_nfds = snd_pcm_poll_descriptors_count( stream->pcm_playback );
+
+ /* TODO: free this properly */
+ printf("trying to allocate %d bytes of memory\n", (stream->capture_nfds + stream->playback_nfds + 1) * sizeof(struct pollfd) );
+ stream->pfds = (struct pollfd*)PaUtil_AllocateMemory( (stream->capture_nfds +
+ stream->playback_nfds + 1) *
+ sizeof(struct pollfd) );
+ if( !stream->pfds )
+ {
+ printf("bad memory point 1\n");
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ stream->frames_per_period = framesPerHostBuffer;
+ stream->capture_channels = numInputChannels;
+ stream->playback_channels = numOutputChannels;
+
+ *s = (PaStream*)stream;
+
+ return result;
+
+error:
+ if( stream )
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_close( stream->pcm_capture );
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_close( stream->pcm_playback );
+ }
+
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ /* TODO: support errorText */
+#define ENSURE(x) \
+ { \
+ int error_ret; \
+ error_ret = (x); \
+ if( error_ret != 0 ) { \
+ PaHostErrorInfo err; \
+ err.errorCode = error_ret; \
+ err.hostApiType = paALSA; \
+ printf("call at %d failed\n", __LINE__); \
+ return paUnanticipatedHostError; \
+ } \
+ else \
+ printf("call at line %d succeeded\n", __LINE__); \
+ }
+
+ if( stream->pcm_capture )
+ {
+ ENSURE( snd_pcm_prepare( stream->pcm_capture ) );
+ }
+
+ if( stream->pcm_playback )
+ {
+ const snd_pcm_channel_area_t *playback_areas, *area;
+ snd_pcm_uframes_t offset, frames;
+ int sample_size = Pa_GetSampleSize( stream->playback_hostsampleformat );
+ printf("Sample size: %d\n", sample_size );
+ ENSURE( snd_pcm_prepare( stream->pcm_playback ) );
+ frames = snd_pcm_avail_update( stream->pcm_playback );
+ printf("frames: %d\n", (int)frames );
+ printf("channels: %d\n", stream->playback_channels );
+
+ snd_pcm_mmap_begin( stream->pcm_playback, &playback_areas, &offset, &frames );
+
+ /* Insert silence */
+ if( stream->playback_interleaved )
+ {
+ void *playback_buffer;
+ area = &playback_areas[0];
+ playback_buffer = area->addr + (area->first + area->step * offset) / 8;
+ memset( playback_buffer, 0,
+ frames * stream->playback_channels * sample_size );
+ }
+ else
+ {
+ int i;
+ for( i = 0; i < stream->playback_channels; i++ )
+ {
+ void *channel_buffer;
+ area = &playback_areas[i];
+ channel_buffer = area->addr + (area->first + area->step * offset) / 8;
+ memset( channel_buffer, 0, frames * sample_size );
+ }
+ }
+
+ snd_pcm_mmap_commit( stream->pcm_playback, offset, frames );
+ }
+
+ if( stream->callback_mode )
+ {
+ ENSURE( pthread_create( &stream->callback_thread, NULL, &CallbackThread, stream ) );
+
+ /* we'll do the snd_pcm_start() in the callback thread */
+ }
+ else
+ {
+ if( stream->pcm_capture )
+ snd_pcm_start( stream->pcm_capture );
+ if( stream->pcm_playback )
+ snd_pcm_start( stream->pcm_playback );
+ }
+
+ /* On my machine, the pcm stream will not transition to the RUNNING
+ * state for a while after snd_pcm_start is called. The PortAudio
+ * client needs to be able to depend on Pa_IsStreamActive() returning
+ * true the second after this function returns. So I sleep briefly here.
+ *
+ * I don't like this one bit.
+ */
+ Pa_Sleep( 100 );
+
+ stream->callback_finished = 0;
+
+ return result;
+}
+
+
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ /* First deal with the callback thread, cancelling and/or joining
+ * it if necessary
+ */
+
+ if( stream->callback_mode && stream->callback_finished )
+ {
+ /* We are running in callback mode but the callback thread has
+ * already been cancelled by the return value from the user's
+ * callback function. Therefore we don't need to cancel the
+ * thread, but we do want to wait for it. */
+ pthread_join( stream->callback_thread, NULL );
+ }
+ else if( stream->callback_mode )
+ {
+ /* We are running in callback mode, and the callback thread
+ * is still running. Cancel it and wait for it to be done. */
+ pthread_cancel( stream->callback_thread );
+ pthread_join( stream->callback_thread, NULL );
+ }
+
+ /* Stop the ALSA streams if necessary */
+
+ if( stream->callback_mode && stream->callback_finished )
+ {
+ /* If we are in the callback_finished state the callback thread
+ * already stopped the streams. So there is nothing to do here.
+ */
+ }
+ else
+ {
+ if( stream->pcm_capture )
+ {
+ snd_pcm_drain( stream->pcm_capture );
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_drain( stream->pcm_playback );
+ }
+ }
+
+ stream->callback_finished = 0;
+
+ return result;
+}
+
+
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ /* First deal with the callback thread, cancelling and/or joining
+ * it if necessary
+ */
+
+ if( stream->callback_mode && stream->callback_finished )
+ {
+ /* We are running in callback mode but the callback thread has
+ * already been cancelled by the return value from the user's
+ * callback function. Therefore we don't need to cancel the
+ * thread, but we do want to wait for it. */
+ pthread_join( stream->callback_thread, NULL );
+ }
+ else if( stream->callback_mode )
+ {
+ /* We are running in callback mode, and the callback thread
+ * is still running. Cancel it and wait for it to be done. */
+ pthread_cancel( stream->callback_thread );
+ pthread_join( stream->callback_thread, NULL );
+ }
+
+ /* Stop the ALSA streams if necessary */
+
+ if( stream->callback_mode && stream->callback_finished )
+ {
+ /* If we are in the callback_finished state the callback thread
+ * already stopped the streams. So there is nothing to do here.
+ */
+ }
+ else
+ {
+ if( stream->pcm_capture )
+ {
+ snd_pcm_drop( stream->pcm_capture );
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_drop( stream->pcm_playback );
+ }
+ }
+
+ stream->callback_finished = 0;
+
+ return result;
+}
+
+
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ if( IsStreamActive(s) || stream->callback_finished )
+ return 0;
+ else
+ return 1;
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_state_t capture_state = snd_pcm_state( stream->pcm_capture );
+
+ if( capture_state == SND_PCM_STATE_RUNNING /*||
+ capture_state == SND_PCM_STATE_PREPARED*/ )
+ return 1;
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_state_t playback_state = snd_pcm_state( stream->pcm_playback );
+
+ if( playback_state == SND_PCM_STATE_RUNNING /*||
+ playback_state == SND_PCM_STATE_PREPARED*/ )
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static PaTime GetStreamTime( PaStream *s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ snd_output_t *output;
+ snd_timestamp_t timestamp;
+ snd_pcm_status_t *status;
+ snd_pcm_status_alloca( &status );
+
+ /* TODO: what if we have both? does it really matter? */
+
+ /* TODO: if running in callback mode, this will mean
+ * libasound routines are being called form multiple threads.
+ * need to verify that libasound is thread-safe. */
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_status( stream->pcm_capture, status );
+ }
+ else if( stream->pcm_playback )
+ {
+ snd_pcm_status( stream->pcm_playback, status );
+ }
+
+ snd_pcm_status_get_tstamp( status, &timestamp );
+
+ return timestamp.tv_sec + ((float)timestamp.tv_usec/1000000);
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
diff --git a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.h b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.h
new file mode 100644
index 00000000..62c9512c
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.h
@@ -0,0 +1,45 @@
+
+#include <alsa/asoundlib.h>
+
+#include <pthread.h>
+
+#include "pa_util.h"
+#include "pa_process.h"
+#include "pa_cpuload.h"
+#include "pa_stream.h"
+
+typedef struct PaAlsaStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ snd_pcm_t *pcm_capture;
+ snd_pcm_t *pcm_playback;
+
+ int callback_finished; /* bool: are we in the "callback finished" state? */
+
+ int frames_per_period;
+ int playback_hostsampleformat;
+
+ int capture_channels;
+ int playback_channels;
+
+ int capture_interleaved; /* bool: is capture interleaved? */
+ int playback_interleaved; /* bool: is playback interleaved? */
+
+ int callback_mode; /* bool: are we running in callback mode? */
+ pthread_t callback_thread;
+
+ /* the callback thread uses these to poll the sound device, waiting
+ * for data to be ready/available */
+ unsigned int capture_nfds;
+ unsigned int playback_nfds;
+ struct pollfd *pfds;
+
+ /* these aren't really stream state, the callback uses them */
+ snd_pcm_uframes_t capture_offset;
+ snd_pcm_uframes_t playback_offset;
+}
+PaAlsaStream;
+
diff --git a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.o b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.o
new file mode 100644
index 00000000..f79af61d
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.o
Binary files differ
diff --git a/pd/portaudio/pa_mac_core/notes.txt b/pd/portaudio/pa_mac_core/notes.txt
index 3b557d9a..c79b90e6 100644
--- a/pd/portaudio/pa_mac_core/notes.txt
+++ b/pd/portaudio/pa_mac_core/notes.txt
@@ -2,25 +2,25 @@ Notes on Core Audio Implementation of PortAudio
by Phil Burk and Darren Gibbs
-Document last updated October 18, 2002
+Document last updated March 20, 2002
WHAT WORKS
Output with very low latency, <10 msec.
Half duplex input or output.
-Full duplex
+Full duplex on the same CoreAudio device.
The paFLoat32, paInt16, paInt8, paUInt8 sample formats.
Pa_GetCPULoad()
Pa_StreamTime()
KNOWN BUGS OR LIMITATIONS
-The iMic supports multiple sample rates.
-But there is a bug when changing sample rates:
- Run patest_record.c at rate A - it works.
- Then run patest_record.c at rate B - it FAIL!
- Then run patest_record.c again at rate B - it works!
+We do not yet support simultaneous input and output on different
+devices. Note that some CoreAudio devices like the Roland UH30 look
+like one device but are actually two different CoreAudio devices. The
+BuiltIn audio is typically one CoreAudio device.
+Mono doesn't work.
DEVICE MAPPING
diff --git a/pd/portaudio/pa_mac_core/pa_mac_core.c b/pd/portaudio/pa_mac_core/pa_mac_core.c
index de781d09..9a4b1488 100644
--- a/pd/portaudio/pa_mac_core/pa_mac_core.c
+++ b/pd/portaudio/pa_mac_core/pa_mac_core.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_mac_core.c,v 1.8.4.3 2002/10/18 01:29:06 philburk Exp $
+ * $Id: pa_mac_core.c,v 1.8 2002/04/12 18:07:20 philburk Exp $
* pa_mac_core.c
* Implementation of PortAudio for Mac OS X Core Audio
*
@@ -7,18 +7,7 @@
* Latest Version at: http://www.portaudio.com
*
* Authors: Ross Bencina and Phil Burk
- * Copyright (c) 1999-2002 Ross Bencina and Phil Burk
- *
- * Theory of Operation
- *
- * This code uses the HAL (Hardware Access Layer) of the Apple CoreAudio library.
- * This is the layer closes to the hardware.
- * The HAL layer only supports the native HW supported sample rates.
- * So if the chip only supports 44100 Hz, then the HAL only supports 44100.
- * To provide other rates we use the handy Apple AUConverter which provides
- * sample rate conversion, mono-to-stereo conversion, and buffer size adaptation.
- *
- * License
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -54,28 +43,18 @@
audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices).
2.22.2002 - Stephane Letz - Explicit cast needed for compilation with Code Warrior 7
3.19.2002 - Phil Burk - Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file.
- Return error if opened in mono mode cuz not supported. [Supported 10.12.2002]
+ Return error if opened in mono mode cuz not supported.
Add support for Pa_GetCPULoad();
Fixed timestamp in callback and Pa_StreamTime() (Thanks n++k for the advice!)
Check for invalid sample rates and return an error.
- Check for getenv("PA_MIN_LATENCY_MSEC") to set latency externally.
+ Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally.
Better error checking for invalid channel counts and invalid devices.
3.29.2002 - Phil Burk - Fixed Pa_GetCPULoad() for small buffers.
3.31.2002 - Phil Burk - Use getrusage() instead of gettimeofday() for CPU Load calculation.
- 10.12.2002 - Phil Burk - Use AudioConverter to allow wide range of sample rates, and mono.
- Use FIFO (from pablio/rinbuffer.h) so that we can pull data through converter.
- Added PaOSX_FixVolumeScalar() to make iMic audible.
- 10.17.2002 - Phil Burk - Support full duplex between two different devices.
- Name internal functions PaOSX_*
- Dumped useless PA_MIN_LATENCY_MSEC environment variable.
- Use kAudioDevicePropertyStreamFormatMatch to determine max channels.
TODO:
-O- debug problem when changing sample rates on iMic
-O- add support for paInt32 format
-O- Why does iMic have grunge for the first second or two then clears up?
-O- request notification when formats change or device unplugged
-O- Why does patest_wire.c on iMic chop up sound when SR=34567Hz?
+O- how do mono output?
+O- FIFO between input and output callbacks if different devices, like in pa_mac.c
*/
#include <CoreServices/CoreServices.h>
@@ -83,14 +62,10 @@ O- Why does patest_wire.c on iMic chop up sound when SR=34567Hz?
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
-#include <AudioUnit/AudioUnit.h>
-#include <AudioToolbox/DefaultAudioOutput.h>
-#include <AudioToolbox/AudioConverter.h>
#include "portaudio.h"
#include "pa_host.h"
#include "pa_trace.h"
-#include "ringbuffer.h"
/************************************************* Constants ********/
@@ -98,45 +73,37 @@ O- Why does patest_wire.c on iMic chop up sound when SR=34567Hz?
#define PA_TRACE_RUN (0)
#define PA_TRACE_START_STOP (1)
-#define PA_MIN_LATENCY_MSEC (1)
+#define PA_MIN_LATENCY_MSEC (8)
#define MIN_TIMEOUT_MSEC (1000)
#define PRINT(x) { printf x; fflush(stdout); }
-#define PRINT_ERR( msg, err ) PRINT(( msg ": error = 0x%0lX = '%s'\n", (err), ErrorToString(err)) )
-#define DBUG(x) /* PRINT(x) */
-#define DBUGBACK(x) /* if( sMaxBackgroundErrorMessages-- > 0 ) PRINT(x) */
-#define DBUGX(x)
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) /**/
+#define DBUGX(x) /* PRINT(x) /**/
// define value of isInput passed to CoreAudio routines
#define IS_INPUT (true)
#define IS_OUTPUT (false)
-typedef struct PaHostInOut
-{
- AudioDeviceID audioDeviceID; // CoreAudio specific ID
- int bytesPerUserNativeBuffer; /* User buffer size in native host format. Depends on numChannels. */
- AudioConverterRef converter;
- void *converterBuffer;
-} PaHostInOut;
-
/**************************************************************
* Structure for internal host specific stream data.
* This is allocated on a per stream basis.
*/
typedef struct PaHostSoundControl
{
- PaHostInOut input;
- PaHostInOut output;
- AudioDeviceID primaryDeviceID;
- Boolean usingSecondDevice;
- int framesPerHostBuffer;
- /* For sample rate, format conversion, or when using two devices. */
- RingBuffer ringBuffer;
- char *ringBufferData;
+ AudioDeviceID pahsc_AudioDeviceID; // Must be the same for input and output for now.
+ /* Input -------------- */
+ int pahsc_BytesPerUserNativeInputBuffer; /* native buffer size in bytes per user chunk */
+ /* Output -------------- */
+ int pahsc_BytesPerUserNativeOutputBuffer; /* native buffer size in bytes per user chunk */
+ /* Init Time -------------- */
+ int pahsc_FramesPerHostBuffer;
+ int pahsc_UserBuffersPerHostBuffer;
/* For measuring CPU utilization. */
- struct rusage entryRusage;
- double inverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
-} PaHostSoundControl;
+ struct rusage pahsc_EntryRusage;
+ double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
+}
+PaHostSoundControl;
/**************************************************************
* Structure for internal extended device info.
@@ -158,18 +125,14 @@ static int sNumOutputDevices = 0;
static PaHostDeviceInfo *sDeviceInfos = NULL;
static int sDefaultInputDeviceID = paNoDevice;
static int sDefaultOutputDeviceID = paNoDevice;
-static int sSavedHostError = 0;
+static int sPaHostError = 0;
+
static int sNumCoreDevices = 0;
static AudioDeviceID *sCoreDeviceIDs; // Array of Core AudioDeviceIDs
-static const double supportedSampleRateRange[] = { 8000.0, 96000.0 };
static const char sMapperSuffixInput[] = " - Input";
static const char sMapperSuffixOutput[] = " - Output";
-/* Debug support. */
-//static int sMaxBackgroundErrorMessages = 100;
-//static int sCoverageCounter = 1; // used to check code coverage during validation
-
/* We index the input devices first, then the output devices. */
#define LOWEST_INPUT_DEVID (0)
#define HIGHEST_INPUT_DEVID (sNumInputDevices - 1)
@@ -180,64 +143,15 @@ static const char sMapperSuffixOutput[] = " - Output";
/************************************************* Prototypes **********/
-static PaError PaOSX_QueryDevices( void );
-static int PaOSX_ScanDevices( Boolean isInput );
-static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput );
-static PaDeviceID PaOSX_QueryDefaultInputDevice( void );
-static PaDeviceID PaOSX_QueryDefaultOutputDevice( void );
-static void PaOSX_CalcHostBufferSize( internalPortAudioStream *past );
-
-/**********************************************************************/
-/* OS X errors are 4 character ID that can be printed.
- * Note that uses a static pad so result must be printed immediately.
- */
-static OSStatus statusText[2] = { 0, 0 };
-static const char *ErrorToString( OSStatus err )
-{
- const char *str;
-
- switch (err)
- {
- case kAudioHardwareUnspecifiedError:
- str = "kAudioHardwareUnspecifiedError";
- break;
- case kAudioHardwareNotRunningError:
- str = "kAudioHardwareNotRunningError";
- break;
- case kAudioHardwareUnknownPropertyError:
- str = "kAudioHardwareUnknownPropertyError";
- break;
- case kAudioDeviceUnsupportedFormatError:
- str = "kAudioDeviceUnsupportedFormatError";
- break;
- case kAudioHardwareBadPropertySizeError:
- str = "kAudioHardwareBadPropertySizeError";
- break;
- case kAudioHardwareIllegalOperationError:
- str = "kAudioHardwareIllegalOperationError";
- break;
- default:
- str = "Unknown CoreAudio Error!";
- statusText[0] = err;
- str = (const char *)statusText;
- break;
- }
+static PaError Pa_QueryDevices( void );
+PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past );
- return str;
-}
+static int PaHost_ScanDevices( Boolean isInput );
+static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput );
-/**********************************************************************/
-static unsigned long RoundUpToNextPowerOf2( unsigned long n )
-{
- long numBits = 0;
- if( ((n-1) & n) == 0) return n; /* Already Power of two. */
- while( n > 0 )
- {
- n= n>>1;
- numBits++;
- }
- return (1<<numBits);
-}
+static PaDeviceID Pa_QueryDefaultInputDevice( void );
+static PaDeviceID Pa_QueryDefaultOutputDevice( void );
+static void PaHost_CalcHostBufferSize( internalPortAudioStream *past );
/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
static void Pa_StartUsageCalculation( internalPortAudioStream *past )
@@ -245,7 +159,7 @@ static void Pa_StartUsageCalculation( internalPortAudioStream *past )
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return;
/* Query user CPU timer for usage analysis and to prevent overuse of CPU. */
- getrusage( RUSAGE_SELF, &pahsc->entryRusage );
+ getrusage( RUSAGE_SELF, &pahsc->pahsc_EntryRusage );
}
static long SubtractTime_AminusB( struct timeval *timeA, struct timeval *timeB )
@@ -274,10 +188,10 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past )
if( getrusage( RUSAGE_SELF, &currentRusage ) == 0 )
{
- usecsElapsed = SubtractTime_AminusB( &currentRusage.ru_utime, &pahsc->entryRusage.ru_utime );
+ usecsElapsed = SubtractTime_AminusB( &currentRusage.ru_utime, &pahsc->pahsc_EntryRusage.ru_utime );
/* Use inverse because it is faster than the divide. */
- newUsage = usecsElapsed * pahsc->inverseMicrosPerHostBuffer;
+ newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer;
past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
(LOWPASS_COEFFICIENT_1 * newUsage);
@@ -286,104 +200,92 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past )
/****************************************** END CPU UTILIZATION *******/
/************************************************************************/
-static PaDeviceID PaOSX_QueryDefaultInputDevice( void )
+static PaDeviceID Pa_QueryDefaultInputDevice( void )
{
- OSStatus err = noErr;
- UInt32 count;
- int i;
+ OSStatus err = noErr;
+ UInt32 count;
+ int i;
AudioDeviceID tempDeviceID = kAudioDeviceUnknown;
- PaDeviceID defaultDeviceID = paNoDevice;
+ PaDeviceID defaultDeviceID = paNoDevice;
// get the default output device for the HAL
// it is required to pass the size of the data to be returned
count = sizeof(tempDeviceID);
err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice, &count, (void *) &tempDeviceID);
- if (err != noErr) goto error;
+ if (err != noErr) goto Bail;
// scan input devices to see which one matches this device
defaultDeviceID = paNoDevice;
for( i=LOWEST_INPUT_DEVID; i<=HIGHEST_INPUT_DEVID; i++ )
{
- DBUG(("PaOSX_QueryDefaultInputDevice: i = %d, aDevId = %ld\n", i, sDeviceInfos[i].audioDeviceID ));
+ DBUG(("Pa_QueryDefaultInputDevice: i = %d, aDevId = %d\n", i, sDeviceInfos[i].audioDeviceID ));
if( sDeviceInfos[i].audioDeviceID == tempDeviceID )
{
defaultDeviceID = i;
break;
}
}
-error:
+Bail:
return defaultDeviceID;
}
/************************************************************************/
-static PaDeviceID PaOSX_QueryDefaultOutputDevice( void )
+static PaDeviceID Pa_QueryDefaultOutputDevice( void )
{
- OSStatus err = noErr;
- UInt32 count;
- int i;
+ OSStatus err = noErr;
+ UInt32 count;
+ int i;
AudioDeviceID tempDeviceID = kAudioDeviceUnknown;
- PaDeviceID defaultDeviceID = paNoDevice;
+ PaDeviceID defaultDeviceID = paNoDevice;
// get the default output device for the HAL
// it is required to pass the size of the data to be returned
count = sizeof(tempDeviceID);
err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &tempDeviceID);
- if (err != noErr) goto error;
+ if (err != noErr) goto Bail;
// scan output devices to see which one matches this device
defaultDeviceID = paNoDevice;
for( i=LOWEST_OUTPUT_DEVID; i<=HIGHEST_OUTPUT_DEVID; i++ )
{
- DBUG(("PaOSX_QueryDefaultOutputDevice: i = %d, aDevId = %ld\n", i, sDeviceInfos[i].audioDeviceID ));
+ DBUG(("Pa_QueryDefaultOutputDevice: i = %d, aDevId = %d\n", i, sDeviceInfos[i].audioDeviceID ));
if( sDeviceInfos[i].audioDeviceID == tempDeviceID )
{
defaultDeviceID = i;
break;
}
}
-error:
+Bail:
return defaultDeviceID;
}
/******************************************************************/
-static PaError PaOSX_QueryDevices( void )
+static PaError Pa_QueryDevices( void )
{
OSStatus err = noErr;
UInt32 outSize;
Boolean outWritable;
- int numBytes;
+ int numBytes;
// find out how many Core Audio devices there are, if any
- outSize = sizeof(outWritable);
err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &outSize, &outWritable);
if (err != noErr)
- {
- PRINT_ERR("Couldn't get info about list of audio devices", err);
- sSavedHostError = err;
- return paHostError;
- }
-
+ ERR_RPT(("Couldn't get info about list of audio devices\n"));
+
// calculate the number of device available
sNumCoreDevices = outSize / sizeof(AudioDeviceID);
// Bail if there aren't any devices
if (sNumCoreDevices < 1)
- {
- PRINT(("No Devices Available"));
- return paHostError;
- }
-
+ ERR_RPT(("No Devices Available\n"));
+
// make space for the devices we are about to get
sCoreDeviceIDs = (AudioDeviceID *)malloc(outSize);
// get an array of AudioDeviceIDs
err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &outSize, (void *)sCoreDeviceIDs);
if (err != noErr)
- {
- PRINT_ERR("Couldn't get list of audio device IDs", err);
- sSavedHostError = err;
- return paHostError;
- }
+ ERR_RPT(("Couldn't get list of audio device IDs\n"));
// Allocate structures to hold device info pointers.
// There will be a maximum of two Pa devices per Core Audio device, input and/or output.
@@ -393,22 +295,35 @@ static PaError PaOSX_QueryDevices( void )
// Scan all the Core Audio devices to see which support input and allocate a
// PaHostDeviceInfo structure for each one.
- PaOSX_ScanDevices( IS_INPUT );
+ PaHost_ScanDevices( IS_INPUT );
sNumInputDevices = sNumPaDevices;
// Now scan all the output devices.
- PaOSX_ScanDevices( IS_OUTPUT );
+ PaHost_ScanDevices( IS_OUTPUT );
sNumOutputDevices = sNumPaDevices - sNumInputDevices;
// Figure out which of the devices that we scanned is the default device.
- sDefaultInputDeviceID = PaOSX_QueryDefaultInputDevice();
- sDefaultOutputDeviceID = PaOSX_QueryDefaultOutputDevice();
+ sDefaultInputDeviceID = Pa_QueryDefaultInputDevice();
+ sDefaultOutputDeviceID = Pa_QueryDefaultOutputDevice();
return paNoError;
}
+/************************************************************************************/
+long Pa_GetHostError()
+{
+ return sPaHostError;
+}
+
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ if( sNumPaDevices <= 0 ) Pa_Initialize();
+ return sNumPaDevices;
+}
+
/*************************************************************************/
/* Allocate a string containing the device name. */
-static char *PaOSX_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput )
+static char *PaHost_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput )
{
OSStatus err = noErr;
UInt32 outSize;
@@ -424,18 +339,87 @@ static char *PaOSX_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput )
{
err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, deviceName);
if (err != noErr)
- PRINT_ERR("Couldn't get audio device name", err);
+ ERR_RPT(("Couldn't get audio device name.\n"));
}
}
return deviceName;
}
+/*************************************************************************/
+// An AudioStreamBasicDescription is passed in to query whether or not
+// the format is supported. A kAudioDeviceUnsupportedFormatError will
+// be returned if the format is not supported and kAudioHardwareNoError
+// will be returned if it is supported. AudioStreamBasicDescription
+// fields set to 0 will be ignored in the query, but otherwise values
+// must match exactly.
+
+Boolean deviceDoesSupportFormat(AudioDeviceID deviceID, AudioStreamBasicDescription *desc, Boolean isInput )
+{
+ OSStatus err = noErr;
+ UInt32 outSize;
+
+ outSize = sizeof(*desc);
+ err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &outSize, desc);
+
+ if (err == kAudioHardwareNoError)
+ return true;
+ else
+ return false;
+}
+
+/*************************************************************************/
+// return an error string
+char* coreAudioErrorString (int errCode )
+{
+ char *str;
+
+ switch (errCode)
+ {
+ case kAudioHardwareUnspecifiedError:
+ str = "kAudioHardwareUnspecifiedError";
+ break;
+ case kAudioHardwareNotRunningError:
+ str = "kAudioHardwareNotRunningError";
+ break;
+ case kAudioHardwareUnknownPropertyError:
+ str = "kAudioHardwareUnknownPropertyError";
+ break;
+ case kAudioDeviceUnsupportedFormatError:
+ str = "kAudioDeviceUnsupportedFormatError";
+ break;
+ case kAudioHardwareBadPropertySizeError:
+ str = "kAudioHardwareBadPropertySizeError";
+ break;
+ case kAudioHardwareIllegalOperationError:
+ str = "kAudioHardwareIllegalOperationError";
+ break;
+ default:
+ str = "Unknown CoreAudio Error!";
+ break;
+ }
+
+ return str;
+}
+
+/*************************************************************************
+** PaDeviceInfo structures have already been created
+** so just return the pointer.
+**
+*/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ if( id < 0 || id >= sNumPaDevices )
+ return NULL;
+
+ return &sDeviceInfos[id].paInfo;
+}
+
/*************************************************************************
** Scan all of the Core Audio devices to see which support input or output.
** Changes sNumDevices, and fills in sDeviceInfos.
*/
-static int PaOSX_ScanDevices( Boolean isInput )
+static int PaHost_ScanDevices( Boolean isInput )
{
int coreDeviceIndex;
int result;
@@ -446,8 +430,8 @@ static int PaOSX_ScanDevices( Boolean isInput )
{
// try to fill in next PaHostDeviceInfo
hostDeviceInfo = &sDeviceInfos[sNumPaDevices];
- result = PaOSX_QueryDeviceInfo( hostDeviceInfo, coreDeviceIndex, isInput );
- DBUGX(("PaOSX_ScanDevices: paDevId = %d, coreDevId = %d\n", sNumPaDevices, coreDeviceIndex ));
+ result = PaHost_QueryDeviceInfo( hostDeviceInfo, coreDeviceIndex, isInput );
+ DBUG(("PaHost_ScanDevices: paDevId = %d, coreDevId = %d\n", sNumPaDevices, hostDeviceInfo->audioDeviceID ));
if( result > 0 )
{
sNumPaDevices += 1; // bump global counter if we got one
@@ -458,7 +442,6 @@ static int PaOSX_ScanDevices( Boolean isInput )
return numAdded;
}
-
/*************************************************************************
** Try to fill in the device info for this device.
** Return 1 if a good device that PA can use.
@@ -466,55 +449,59 @@ static int PaOSX_ScanDevices( Boolean isInput )
** or return negative error.
**
*/
-static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput )
+static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput )
{
- OSStatus err;
- UInt32 outSize;
+ OSErr err;
+ int index;
+ UInt32 outSize;
AudioStreamBasicDescription formatDesc;
+ Boolean result;
AudioDeviceID devID;
- PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo;
+ double *sampleRates = NULL; /* non-const ptr */
+
+ PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo;
+ double possibleSampleRates[] = {8000.0, 11025.0, 22050.0, 44100.0, 48000.0, 88200.0, 96000.0};
+ int maxNumSampleRates = sizeof( possibleSampleRates ) / sizeof( double );
deviceInfo->structVersion = 1;
deviceInfo->maxInputChannels = 0;
deviceInfo->maxOutputChannels = 0;
-
- deviceInfo->sampleRates = supportedSampleRateRange; // because we use sample rate converter to get continuous rates
deviceInfo->numSampleRates = -1;
devID = sCoreDeviceIDs[ coreDeviceIndex ];
hostDeviceInfo->audioDeviceID = devID;
- DBUG(("PaOSX_QueryDeviceInfo: coreDeviceIndex = %d, devID = %d, isInput = %d\n",
- coreDeviceIndex, devID, isInput ));
- // Get data format info from the device.
- outSize = sizeof(formatDesc);
- err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc);
- // This just may not be an appropriate device for input or output so leave quietly.
- if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error;
- // Right now the Core Audio headers only define one formatID: LinearPCM
- // Apparently LinearPCM must be Float32 for now.
- if( (formatDesc.mFormatID == kAudioFormatLinearPCM) &&
- (formatDesc.mFormatFlags & kLinearPCMFormatFlagIsFloat) )
- {
- deviceInfo->nativeSampleFormats = paFloat32;
- }
- else
+ // Figure out supported sample rates
+ // Make room in case device supports all rates.
+ sampleRates = (double*)PaHost_AllocateFastMemory( maxNumSampleRates * sizeof(double) );
+ if( sampleRates == NULL ) return paInsufficientMemory;
+
+ deviceInfo->sampleRates = sampleRates;
+ deviceInfo->numSampleRates = 0;
+
+ // Loop through the possible sampling rates and check each to see if the device supports it.
+ for (index = 0; index < maxNumSampleRates; index ++)
{
- return paSampleFormatNotSupported;
+ memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
+ formatDesc.mSampleRate = possibleSampleRates[index];
+ result = deviceDoesSupportFormat( devID, &formatDesc, isInput );
+
+ if (result == true)
+ {
+ deviceInfo->numSampleRates += 1;
+ *sampleRates = possibleSampleRates[index];
+ sampleRates++;
+ }
}
+ // If no sample rates supported, then not a very good device.
+ if( deviceInfo->numSampleRates == 0 ) goto error;
- // Determine maximum number of channels supported.
- memset( &formatDesc, 0, sizeof(formatDesc));
- formatDesc.mChannelsPerFrame = 256; // FIXME - what about device with > 256 channels
+ // Get data format info from the device.
outSize = sizeof(formatDesc);
- err = AudioDeviceGetProperty( devID, 0,
- isInput, kAudioDevicePropertyStreamFormatMatch, &outSize, &formatDesc);
- if( err != noErr )
- {
- PRINT_ERR("PaOSX_QueryDeviceInfo: Could not get device format match", err);
- sSavedHostError = err;
- return paHostError;
- }
+ err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc);
+
+ // If no channels supported, then not a very good device.
+ if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error;
if( isInput )
{
@@ -525,268 +512,205 @@ static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDevi
deviceInfo->maxOutputChannels = formatDesc.mChannelsPerFrame;
}
+ // FIXME - where to put current sample rate?: formatDesc.mSampleRate
+
+ // Right now the Core Audio headers only define one formatID: LinearPCM
+ // Apparently LinearPCM must be Float32 for now.
+ switch (formatDesc.mFormatID)
+ {
+ case kAudioFormatLinearPCM:
+ deviceInfo->nativeSampleFormats = paFloat32;
+
+ // FIXME - details about the format are in these flags.
+ // formatDesc.mFormatFlags
+
+ // here are the possibilities
+ // kLinearPCMFormatFlagIsFloat // set for floating point, clear for integer
+ // kLinearPCMFormatFlagIsBigEndian // set for big endian, clear for little
+ // kLinearPCMFormatFlagIsSignedInteger // set for signed integer, clear for unsigned integer,
+ // only valid if kLinearPCMFormatFlagIsFloat is clear
+ // kLinearPCMFormatFlagIsPacked // set if the sample bits are packed as closely together as possible,
+ // clear if they are high or low aligned within the channel
+ // kLinearPCMFormatFlagIsAlignedHigh // set if the sample bits are placed
+ break;
+
+ default:
+ deviceInfo->nativeSampleFormats = paFloat32; // FIXME
+ break;
+ }
+
// Get the device name
- deviceInfo->name = PaOSX_DeviceNameFromID( devID, isInput );
+ deviceInfo->name = PaHost_DeviceNameFromID( devID, isInput );
return 1;
error:
+ if( sampleRates != NULL ) free( sampleRates );
return 0;
}
-/**********************************************************************/
-static PaError PaOSX_MaybeQueryDevices( void )
+/*************************************************************************
+** Returns recommended device ID.
+** On the PC, the recommended device can be specified by the user by
+** setting an environment variable. For example, to use device #1.
+**
+** set PA_RECOMMENDED_OUTPUT_DEVICE=1
+**
+** The user should first determine the available device ID by using
+** the supplied application "pa_devs".
+*/
+#define PA_ENV_BUF_SIZE (32)
+#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE")
+#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE")
+
+static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName )
+{
+#if 0
+ UInt32 hresult;
+ char envbuf[PA_ENV_BUF_SIZE];
+ PaDeviceID recommendedID = paNoDevice;
+
+ /* Let user determine default device by setting environment variable. */
+ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE );
+ if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
+ {
+ recommendedID = atoi( envbuf );
+ }
+
+ return recommendedID;
+#endif
+ return paNoDevice;
+}
+
+static PaError Pa_MaybeQueryDevices( void )
{
if( sNumPaDevices == 0 )
{
- return PaOSX_QueryDevices();
+ return Pa_QueryDevices();
}
return 0;
}
-static char zeroPad[256] = { 0 };
-
/**********************************************************************
-** This is the proc that supplies the data to the AudioConverterFillBuffer call.
-** We can pass back arbitrarily sized blocks so if the FIFO region is split
-** just pass back the first half.
+** Check for environment variable, else query devices and use result.
*/
-static OSStatus PaOSX_InputConverterCallbackProc (AudioConverterRef inAudioConverter,
- UInt32* outDataSize,
- void** outData,
- void* inUserData)
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
{
- internalPortAudioStream *past = (internalPortAudioStream *) inUserData;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- void *dataPtr1;
- long size1;
- void *dataPtr2;
- long size2;
-
- /* Pass contiguous region from FIFO directly to converter. */
- RingBuffer_GetReadRegions( &pahsc->ringBuffer, *outDataSize,
- &dataPtr1, &size1, &dataPtr2, &size2 );
-
- if( size1 > 0 )
+ PaError result;
+ result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME );
+ if( result < 0 )
{
- *outData = dataPtr1;
- *outDataSize = size1;
- RingBuffer_AdvanceReadIndex( &pahsc->ringBuffer, size1 );
- DBUGX(("PaOSX_InputConverterCallbackProc: read %ld bytes from FIFO.\n", size1 ));
+ result = Pa_MaybeQueryDevices();
+ if( result < 0 ) return result;
+ result = sDefaultInputDeviceID;
}
- else
- {
- DBUGBACK(("PaOSX_InputConverterCallbackProc: got no data!\n"));
- *outData = zeroPad; // Give it zero data to keep it happy.
- *outDataSize = sizeof(zeroPad);
- }
- return noErr;
+ return result;
}
-/*****************************************************************************
-** Get audio input, if any, from passed in buffer, or from converter or from FIFO
-** and run PA callback.
-*/
-static OSStatus PaOSX_LoadAndProcess( internalPortAudioStream *past,
- void *inputBuffer, void *outputBuffer )
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
{
- OSStatus err = noErr;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
-
- if( past->past_StopSoon )
- {
- if( outputBuffer )
- {
- /* Clear remainder of audio buffer if we are waiting for stop. */
- AddTraceMessage("PaOSX_HandleInputOutput: zero rest of wave buffer ", i );
- memset( outputBuffer, 0, pahsc->output.bytesPerUserNativeBuffer );
- }
- }
- else
+ PaError result;
+ result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME );
+ if( result < 0 )
{
- /* Do we need data from the converted input? */
- if( pahsc->input.converter != NULL )
- {
- UInt32 size = pahsc->input.bytesPerUserNativeBuffer;
- err = AudioConverterFillBuffer(
- pahsc->input.converter,
- PaOSX_InputConverterCallbackProc,
- past,
- &size,
- pahsc->input.converterBuffer);
- if( err != noErr ) return err;
- inputBuffer = pahsc->input.converterBuffer;
- }
- /* Or should just get the data directly from the FIFO? */
- else if( pahsc->ringBufferData != NULL )
- {
- if( RingBuffer_GetReadAvailable( &pahsc->ringBuffer ) >= pahsc->input.bytesPerUserNativeBuffer)
- {
- RingBuffer_Read( &pahsc->ringBuffer, pahsc->input.converterBuffer, pahsc->input.bytesPerUserNativeBuffer );
- inputBuffer = pahsc->input.converterBuffer;
- }
- }
-
- /* Fill part of audio converter buffer by converting input to user format,
- * calling user callback, then converting output to native format. */
- if( PaConvert_Process( past, inputBuffer, outputBuffer ))
- {
- past->past_StopSoon = 1;
- }
+ result = Pa_MaybeQueryDevices();
+ if( result < 0 ) return result;
+ result = sDefaultOutputDeviceID;
}
- return err;
+ return result;
}
-/*****************************************************************************
-** This is the proc that supplies the data to the AudioConverterFillBuffer call
+/**********************************************************************
+** Initialize Host dependant part of API.
*/
-static OSStatus PaOSX_OutputConverterCallbackProc (AudioConverterRef inAudioConverter,
- UInt32* outDataSize,
- void** outData,
- void* inUserData)
+
+PaError PaHost_Init( void )
{
- internalPortAudioStream *past = (internalPortAudioStream *) inUserData;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
-
- *outData = pahsc->output.converterBuffer;
- *outDataSize = pahsc->output.bytesPerUserNativeBuffer;
-
- return PaOSX_LoadAndProcess ( past, pahsc->input.converterBuffer, pahsc->output.converterBuffer );
+ return Pa_MaybeQueryDevices();
}
/**********************************************************************
** Fill any available output buffers and use any available
** input buffers by calling user callback.
-** Will set past->past_StopSoon if user callback indicates that it is finished.
*/
-static OSStatus PaOSX_HandleInputOutput( internalPortAudioStream *past,
- const AudioBufferList* inInputData,
- AudioBufferList* outOutputData )
+static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferList* inInputData,
+ AudioBufferList* outOutputData )
{
- OSStatus err = noErr;
- char *inputNativeBufferfPtr = NULL;
- char *outputNativeBufferfPtr = NULL;
- int i;
+ PaError result = 0;
+ char *inputNativeBufferfPtr = NULL;
+ char *outputNativeBufferfPtr = NULL;
+ int i;
+ int buffersProcessed = 0;
+ int done = 0;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+
+ past->past_NumCallbacks += 1;
+
+#if PA_TRACE_RUN
+ AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks );
+#endif
+
+ Pa_StartUsageCalculation( past );
/* If we are using output, then we need an empty output buffer. */
- if( outOutputData->mNumberBuffers > 0 )
+ if( past->past_NumOutputChannels > 0 )
{
outputNativeBufferfPtr = (char*)outOutputData->mBuffers[0].mData;
}
- if( inInputData->mNumberBuffers > 0 )
+ /* If we are using input, then we need a full input buffer. */
+ if( past->past_NumInputChannels > 0 )
{
inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData;
-
- /* If there is a FIFO for input then write to it. */
- if( (pahsc->ringBufferData != NULL) && !pahsc->usingSecondDevice )
- {
- long writeRoom = RingBuffer_GetWriteAvailable( &pahsc->ringBuffer );
- long numBytes = inInputData->mBuffers[0].mDataByteSize;
- if( numBytes <= writeRoom )
- {
- RingBuffer_Write( &pahsc->ringBuffer, inputNativeBufferfPtr, numBytes );
- DBUGBACK(("PaOSX_HandleInputOutput: wrote %ld bytes to FIFO.\n", inInputData->mBuffers[0].mDataByteSize));
- } // FIXME else ???
- }
- }
-
- if( pahsc->output.converter != NULL )
- {
- /* Using output and input converter. */
- UInt32 size = outOutputData->mBuffers[0].mDataByteSize;
- err = AudioConverterFillBuffer(
- pahsc->output.converter,
- PaOSX_OutputConverterCallbackProc,
- past,
- &size,
- outputNativeBufferfPtr);
- if( err != noErr )
- {
- PRINT_ERR("PaOSX_HandleInputOutput: AudioConverterFillBuffer failed", err);
- goto error;
- }
- }
- else if( (pahsc->input.converter != NULL) && !pahsc->usingSecondDevice)
- {
- /* Using just an input converter. */
- /* Generate user buffers as long as we have a half full input FIFO. */
- long gotHalf = pahsc->ringBuffer.bufferSize / 2;
- while( (RingBuffer_GetReadAvailable( &pahsc->ringBuffer ) >= gotHalf) &&
- (past->past_StopSoon == 0) )
- {
- err = PaOSX_LoadAndProcess ( past, NULL, outputNativeBufferfPtr );
- if( err != noErr ) goto error;
- if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->output.bytesPerUserNativeBuffer;
- }
}
- else
- {
- /* No AUConverters used. */
- /* Each host buffer contains multiple user buffers so do them all now. */
- for( i=0; i<past->past_NumUserBuffers; i++ )
- {
- err = PaOSX_LoadAndProcess ( past, inputNativeBufferfPtr, outputNativeBufferfPtr );
- if( err != noErr ) goto error;
- if( inputNativeBufferfPtr ) inputNativeBufferfPtr += pahsc->input.bytesPerUserNativeBuffer;
- if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->output.bytesPerUserNativeBuffer;
- }
- }
-
-error:
- return err;
-}
-/******************************************************************
- * This callback is used when two separate devices are used for input and output.
- * This often happens when using USB devices which present as two devices: input and output.
- * It just writes its data to a FIFO so that it can be read by the main callback
- * proc PaOSX_CoreAudioIOCallback().
- */
-static OSStatus PaOSX_CoreAudioInputCallback (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime,
- void* contextPtr)
-{
- internalPortAudioStream *past = (internalPortAudioStream *) contextPtr;
- PaHostSoundControl *pahsc;
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
-
- /* If there is a FIFO for input then write to it. */
- if( pahsc->ringBufferData != NULL )
+ buffersProcessed += 1;
+
+ /* Each host buffer contains multiple user buffers so do them all now. */
+ for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
{
- long writeRoom = RingBuffer_GetWriteAvailable( &pahsc->ringBuffer );
- long numBytes = inInputData->mBuffers[0].mDataByteSize;
- if( numBytes <= writeRoom )
+ if( done )
{
- RingBuffer_Write( &pahsc->ringBuffer, inInputData->mBuffers[0].mData, inInputData->mBuffers[0].mDataByteSize );
+ if( outputNativeBufferfPtr )
+ {
+ /* Clear remainder of wave buffer if we are waiting for stop. */
+ AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i );
+ memset( outputNativeBufferfPtr, 0, pahsc->pahsc_BytesPerUserNativeOutputBuffer );
+ }
}
else
{
- DBUGBACK(("PaOSX_CoreAudioInputCallback: FIFO too full to write!\n"));
- }
+ /* Convert 32 bit native data to user data and call user routine. */
+ result = PaConvert_Process( past, inputNativeBufferfPtr, outputNativeBufferfPtr );
+ if( result != 0) done = 1;
+ }
+ if( inputNativeBufferfPtr ) inputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeInputBuffer;
+ if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeOutputBuffer;
}
-
- return noErr;
+
+ Pa_EndUsageCalculation( past );
+
+#if PA_TRACE_RUN
+ AddTraceMessage("Pa_TimeSlice: buffersProcessed ", buffersProcessed );
+#endif
+
+ return (result != 0) ? result : done;
}
-/******************************************************************
- * This is the primary callback for CoreAudio.
- * It can handle input and/or output for a single device.
- * It takes input from CoreAudio, converts it and passes it to the
- * PortAudio callback. Then takes the PA results and passes it back to CoreAudio.
- */
-static OSStatus PaOSX_CoreAudioIOCallback (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
+OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime,
AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime,
void* contextPtr)
{
- OSStatus err = noErr;
+
+ PaError result = 0;
internalPortAudioStream *past;
PaHostSoundControl *pahsc;
past = (internalPortAudioStream *) contextPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
+// printf("Num input Buffers: %d; Num output Buffers: %d.\n", inInputData->mNumberBuffers, outOutputData->mNumberBuffers);
+
/* Has someone asked us to abort by calling Pa_AbortStream()? */
if( past->past_StopNow )
{
@@ -797,7 +721,7 @@ static OSStatus PaOSX_CoreAudioIOCallback (AudioDeviceID inDevice, const AudioT
*/
else if( past->past_StopSoon )
{
- // FIXME - Pretend all done. Should wait for audio to play out but CoreAudio latency very low.
+ // FIXME - pretend all done
past->past_IsActive = 0; /* Will cause thread to return. */
}
else
@@ -808,220 +732,63 @@ static OSStatus PaOSX_CoreAudioIOCallback (AudioDeviceID inDevice, const AudioT
past->past_FrameCount = inOutputTime->mSampleTime;
}
- /* Measure CPU load. */
- Pa_StartUsageCalculation( past );
- past->past_NumCallbacks += 1;
-
/* Process full input buffer and fill up empty output buffers. */
- err = PaOSX_HandleInputOutput( past, inInputData, outOutputData );
-
- Pa_EndUsageCalculation( past );
+ if( (result = Pa_TimeSlice( past, inInputData, outOutputData )) != 0)
+ {
+ /* User callback has asked us to stop. */
+#if PA_TRACE_START_STOP
+ AddTraceMessage( "Pa_OutputThreadProc: TimeSlice() returned ", result );
+#endif
+ past->past_StopSoon = 1; /* Request that audio play out then stop. */
+ result = paNoError;
+ }
}
- // FIXME PaOSX_UpdateStreamTime( pahsc );
- if( err != 0 ) DBUG(("PaOSX_CoreAudioIOCallback: returns %ld.\n", err ));
+ // FIXME PaHost_UpdateStreamTime( pahsc );
+
+ return result;
+}
- return err;
+#if 0
+static int PaHost_CalcTimeOut( internalPortAudioStream *past )
+{
+ /* Calculate timeOut longer than longest time it could take to play all buffers. */
+ int timeOut = (UInt32) (1500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate);
+ if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC;
+ return timeOut;
}
+#endif
+
/*******************************************************************/
/* Attempt to set device sample rate. */
-static PaError PaOSX_SetSampleRate( AudioDeviceID devID, Boolean isInput, double sampleRate )
+static PaError PaHost_SetSampleRate( AudioDeviceID devID, Boolean isInput, double sampleRate )
{
AudioStreamBasicDescription formatDesc;
- PaError result = paNoError;
OSStatus err;
- UInt32 dataSize;
-
- // try to set to desired rate
memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
formatDesc.mSampleRate = sampleRate;
err = AudioDeviceSetProperty( devID, 0, 0,
isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
- if (err != noErr)
- {
- result = paInvalidSampleRate;
-
- /* Could not set to desired rate so query for closest match. */
- DBUG(("PaOSX_SetSampleRate: couldn't set to %f. Try to find match.\n", sampleRate ));
- dataSize = sizeof(formatDesc);
- AudioDeviceGetProperty( devID, 0,
- isInput, kAudioDevicePropertyStreamFormatMatch, &dataSize, &formatDesc);
- formatDesc.mSampleRate = sampleRate;
- err = AudioDeviceGetProperty( devID, 0,
- isInput, kAudioDevicePropertyStreamFormatMatch, &dataSize, &formatDesc);
- if (err == noErr)
- {
- /* Set to that matching rate. */
- sampleRate = formatDesc.mSampleRate;
- DBUG(("PaOSX_SetSampleRate: match succeeded, set to %f instead\n", sampleRate ));
- memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
- formatDesc.mSampleRate = sampleRate;
- AudioDeviceSetProperty( devID, 0, 0,
- isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
- }
- }
- return result;
-}
-
-/*******************************************************************
- * Check volume level of device. If below threshold, then set to newLevel.
- * Using volume instead of decibels because decibel range varies by device.
- */
-static void PaOSX_FixVolumeScalars( AudioDeviceID devID, Boolean isInput,
- int numChannels, double threshold, double newLevel )
-{
- OSStatus err = noErr;
- UInt32 dataSize;
- int iChannel;
-
-/* The master channel is 0. Left and right are channels 1 and 2. */
-/* Fix volume. */
- for( iChannel = 0; iChannel<=numChannels; iChannel++ )
- {
- Float32 fdata32;
- dataSize = sizeof( fdata32 );
- err = AudioDeviceGetProperty( devID, iChannel, isInput,
- kAudioDevicePropertyVolumeScalar, &dataSize, &fdata32 );
- if( err == noErr )
- {
- DBUG(("kAudioDevicePropertyVolumeScalar for channel %d = %f\n", iChannel, fdata32));
- if( fdata32 <= (Float32) threshold )
- {
- dataSize = sizeof( fdata32 );
- fdata32 = (Float32) newLevel;
- err = AudioDeviceSetProperty( devID, 0, iChannel, isInput,
- kAudioDevicePropertyVolumeScalar, dataSize, &fdata32 );
- if( err != noErr )
- {
- PRINT(("Warning: audio volume is very low and could not be turned up.\n"));
- }
- else
- {
- PRINT(("Volume for audio channel %d was <= %4.2f so set to %4.2f by PortAudio!\n",
- iChannel, threshold, newLevel ));
- }
- }
- }
- }
-/* Unmute if muted. */
- for( iChannel = 0; iChannel<=numChannels; iChannel++ )
- {
- UInt32 uidata32;
- dataSize = sizeof( uidata32 );
- err = AudioDeviceGetProperty( devID, iChannel, isInput,
- kAudioDevicePropertyMute, &dataSize, &uidata32 );
- if( err == noErr )
- {
- DBUG(("uidata32 for channel %d = %ld\n", iChannel, uidata32));
- if( uidata32 == 1 ) // muted?
- {
- dataSize = sizeof( uidata32 );
- uidata32 = 0; // unmute
- err = AudioDeviceSetProperty( devID, 0, iChannel, isInput,
- kAudioDevicePropertyMute, dataSize, &uidata32 );
- if( err != noErr )
- {
- PRINT(("Warning: audio is muted and could not be unmuted!\n"));
- }
- else
- {
- PRINT(("Audio channel %d was unmuted by PortAudio!\n", iChannel ));
- }
- }
- }
- }
+ if (err != kAudioHardwareNoError) return paInvalidSampleRate;
+ else return paNoError;
}
-#if 0
-static void PaOSX_DumpDeviceInfo( AudioDeviceID devID, Boolean isInput )
-{
- OSStatus err = noErr;
- UInt32 dataSize;
- UInt32 uidata32;
- Float32 fdata32;
- AudioValueRange audioRange;
-
- dataSize = sizeof( uidata32 );
- err = AudioDeviceGetProperty( devID, 0, isInput,
- kAudioDevicePropertyLatency, &dataSize, &uidata32 );
- if( err != noErr )
- {
- PRINT_ERR("Error reading kAudioDevicePropertyLatency", err);
- return;
- }
- PRINT(("kAudioDevicePropertyLatency = %d\n", (int)uidata32 ));
-
- dataSize = sizeof( fdata32 );
- err = AudioDeviceGetProperty( devID, 1, isInput,
- kAudioDevicePropertyVolumeScalar, &dataSize, &fdata32 );
- if( err != noErr )
- {
- PRINT_ERR("Error reading kAudioDevicePropertyVolumeScalar", err);
- return;
- }
- PRINT(("kAudioDevicePropertyVolumeScalar = %f\n", fdata32 ));
-
- dataSize = sizeof( uidata32 );
- err = AudioDeviceGetProperty( devID, 0, isInput,
- kAudioDevicePropertyBufferSize, &dataSize, &uidata32 );
- if( err != noErr )
- {
- PRINT_ERR("Error reading buffer size", err);
- return;
- }
- PRINT(("kAudioDevicePropertyBufferSize = %d bytes\n", (int)uidata32 ));
-
- dataSize = sizeof( audioRange );
- err = AudioDeviceGetProperty( devID, 0, isInput,
- kAudioDevicePropertyBufferSizeRange, &dataSize, &audioRange );
- if( err != noErr )
- {
- PRINT_ERR("Error reading buffer size range", err);
- return;
- }
- PRINT(("kAudioDevicePropertyBufferSizeRange = %g to %g bytes\n", audioRange.mMinimum, audioRange.mMaximum ));
-
- dataSize = sizeof( uidata32 );
- err = AudioDeviceGetProperty( devID, 0, isInput,
- kAudioDevicePropertyBufferFrameSize, &dataSize, &uidata32 );
- if( err != noErr )
- {
- PRINT_ERR("Error reading buffer size", err);
- return;
- }
- PRINT(("kAudioDevicePropertyBufferFrameSize = %d frames\n", (int)uidata32 ));
-
- dataSize = sizeof( audioRange );
- err = AudioDeviceGetProperty( devID, 0, isInput,
- kAudioDevicePropertyBufferFrameSizeRange, &dataSize, &audioRange );
- if( err != noErr )
- {
- PRINT_ERR("Error reading buffer size range", err);
- return;
- }
- PRINT(("kAudioDevicePropertyBufferFrameSizeRange = %g to %g frames\n", audioRange.mMinimum, audioRange.mMaximum ));
-
- return;
-}
-#endif
-
/*******************************************************************/
-static PaError PaOSX_OpenInputDevice( internalPortAudioStream *past )
+PaError PaHost_OpenInputStream( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc;
const PaHostDeviceInfo *hostDeviceInfo;
PaError result = paNoError;
+ UInt32 bytesPerHostBuffer;
UInt32 dataSize;
OSStatus err = noErr;
- int needConverter = 0;
- double deviceRate = past->past_SampleRate;
-
- DBUG(("PaOSX_OpenInputDevice: -------------\n"));
+ int bytesPerInputFrame;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID));
if( (past->past_InputDeviceID < LOWEST_INPUT_DEVID) ||
(past->past_InputDeviceID > HIGHEST_INPUT_DEVID) )
{
@@ -1029,134 +796,68 @@ static PaError PaOSX_OpenInputDevice( internalPortAudioStream *past )
}
hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID];
- PaOSX_FixVolumeScalars( pahsc->input.audioDeviceID, IS_INPUT,
- hostDeviceInfo->paInfo.maxInputChannels, 0.1, 0.9 );
-
/* Try to set sample rate. */
- result = PaOSX_SetSampleRate( pahsc->input.audioDeviceID, IS_INPUT, past->past_SampleRate );
- if( result != paNoError )
- {
- DBUG(("PaOSX_OpenInputDevice: Need converter for sample rate = %f\n", past->past_SampleRate ));
- needConverter = 1;
- result = paNoError;
- }
- else
- {
- DBUG(("PaOSX_OpenInputDevice: successfully set sample rate to %f\n", past->past_SampleRate ));
- }
+ result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_INPUT, past->past_SampleRate );
+ if( result != paNoError ) return result;
- /* Try to set number of channels. */
- if( past->past_NumInputChannels > hostDeviceInfo->paInfo.maxInputChannels )
- {
- return paInvalidChannelCount; /* Too many channels! */
- }
- else if( past->past_NumInputChannels < hostDeviceInfo->paInfo.maxInputChannels )
+ if( past->past_NumInputChannels != hostDeviceInfo->paInfo.maxInputChannels )
{
-
+#if 1
+ return paInvalidChannelCount; // FIXME - how support mono?
+#else
+FIXME - should this be set on a stream basis? Is it possible to change?
+ /* Attempt to set number of channels. */
AudioStreamBasicDescription formatDesc;
OSStatus err;
memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
formatDesc.mChannelsPerFrame = past->past_NumInputChannels;
- err = AudioDeviceSetProperty( pahsc->input.audioDeviceID, 0, 0,
+
+ err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0,
IS_INPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
- if (err != noErr)
+ if (err != kAudioHardwareNoError)
{
- needConverter = 1;
+ result = paInvalidChannelCount;
+ goto error;
}
+#endif
}
- /* Try to set the I/O bufferSize of the device. */
- dataSize = sizeof(pahsc->framesPerHostBuffer);
- err = AudioDeviceSetProperty( pahsc->input.audioDeviceID, 0, 0, IS_INPUT,
- kAudioDevicePropertyBufferFrameSize, dataSize,
- &pahsc->framesPerHostBuffer);
+ // calculate native buffer sizes in bytes
+ bytesPerInputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels;
+ pahsc->pahsc_BytesPerUserNativeInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame;
+ bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerInputFrame;
+
+ // Change the bufferSize of the device! Is this per device or just for our stream?
+ dataSize = sizeof(UInt32);
+ err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_INPUT,
+ kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer);
if( err != noErr )
{
- DBUG(("PaOSX_OpenInputDevice: Need converter for buffer size = %d\n", pahsc->framesPerHostBuffer));
- needConverter = 1;
+ ERR_RPT(("Could not force buffer size!"));
+ result = paHostError;
+ goto error;
}
-
- // setup PA conversion procedure
+
+ // setup conversion procedure
result = PaConvert_SetupInput( past, paFloat32 );
-
- if( needConverter )
- {
- AudioStreamBasicDescription sourceStreamFormat, destStreamFormat;
-
- /* Get source device format */
- dataSize = sizeof(sourceStreamFormat);
- err = AudioDeviceGetProperty(pahsc->input.audioDeviceID, 0, IS_INPUT,
- kAudioDevicePropertyStreamFormat, &dataSize, &sourceStreamFormat);
- if( err != noErr )
- {
- PRINT_ERR("PaOSX_OpenInputDevice: Could not get input device format", err);
- sSavedHostError = err;
- return paHostError;
- }
- deviceRate = sourceStreamFormat.mSampleRate;
- DBUG(("PaOSX_OpenInputDevice: current device sample rate = %f\n", deviceRate ));
-
- /* Set target user format. */
- destStreamFormat = sourceStreamFormat;
- destStreamFormat.mSampleRate = past->past_SampleRate; // sample rate of the user synthesis code
- destStreamFormat.mChannelsPerFrame = past->past_NumInputChannels; // the number of channels in each frame
-
- err = AudioConverterNew (
- &sourceStreamFormat,
- &destStreamFormat,
- &pahsc->input.converter);
- if( err != noErr )
- {
- PRINT_ERR("Could not create input format converter", err);
- sSavedHostError = err;
- return paHostError;
- }
- }
-
- /* Allocate FIFO between Device callback and Converter callback so that device can push data
- * and converter can pull data.
- */
- if( needConverter || pahsc->usingSecondDevice )
- {
- double sampleRateRatio;
- long minSize, numBytes;
-
- /* Allocate an input buffer because we need it between the user callback and the converter. */
- pahsc->input.converterBuffer = PaHost_AllocateFastMemory( pahsc->input.bytesPerUserNativeBuffer );
- if( pahsc->input.converterBuffer == NULL )
- {
- return paInsufficientMemory;
- }
- sampleRateRatio = deviceRate / past->past_SampleRate;
- minSize = pahsc->input.bytesPerUserNativeBuffer * 4 * sampleRateRatio;
- numBytes = RoundUpToNextPowerOf2( minSize );
- DBUG(("PaOSX_OpenInputDevice: FIFO numBytes = %ld\n", numBytes));
- pahsc->ringBufferData = PaHost_AllocateFastMemory( numBytes );
- if( pahsc->ringBufferData == NULL )
- {
- return paInsufficientMemory;
- }
- RingBuffer_Init( &pahsc->ringBuffer, numBytes, pahsc->ringBufferData );
- // make it look full at beginning
- RingBuffer_AdvanceWriteIndex( &pahsc->ringBuffer, numBytes );
- }
-
+ return result;
+
+error:
return result;
}
/*******************************************************************/
-static PaError PaOSX_OpenOutputDevice( internalPortAudioStream *past )
+PaError PaHost_OpenOutputStream( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc;
const PaHostDeviceInfo *hostDeviceInfo;
PaError result = paNoError;
+ UInt32 bytesPerHostBuffer;
UInt32 dataSize;
OSStatus err = noErr;
- int needConverter = 0;
+ int bytesPerOutputFrame;
- DBUG(("PaOSX_OpenOutputDevice: -------------\n"));
-
pahsc = (PaHostSoundControl *) past->past_DeviceData;
DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID));
@@ -1165,141 +866,101 @@ static PaError PaOSX_OpenOutputDevice( internalPortAudioStream *past )
{
return paInvalidDeviceId;
}
-
hostDeviceInfo = &sDeviceInfos[past->past_OutputDeviceID];
-
- //PaOSX_DumpDeviceInfo( pahsc->output.audioDeviceID, IS_OUTPUT );
- PaOSX_FixVolumeScalars( pahsc->output.audioDeviceID, IS_OUTPUT,
- hostDeviceInfo->paInfo.maxOutputChannels, 0.1, 0.9 );
-
/* Try to set sample rate. */
- result = PaOSX_SetSampleRate( pahsc->output.audioDeviceID, IS_OUTPUT, past->past_SampleRate );
- if( result != paNoError )
- {
- DBUG(("PaOSX_OpenOutputDevice: Need converter for sample rate = %f\n", past->past_SampleRate ));
- needConverter = 1;
- result = paNoError;
- }
- else
- {
- DBUG(("PaOSX_OpenOutputDevice: successfully set sample rate to %f\n", past->past_SampleRate ));
- }
+ result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_OUTPUT, past->past_SampleRate );
+ if( result != paNoError ) return result;
- if( past->past_NumOutputChannels > hostDeviceInfo->paInfo.maxOutputChannels )
- {
- return paInvalidChannelCount; /* Too many channels! */
- }
- else
+ if( past->past_NumOutputChannels != hostDeviceInfo->paInfo.maxOutputChannels )
{
+#if 1
+ return paInvalidChannelCount; // FIXME - how support mono?
+#else
/* Attempt to set number of channels. */
AudioStreamBasicDescription formatDesc;
OSStatus err;
memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
formatDesc.mChannelsPerFrame = past->past_NumOutputChannels;
- err = AudioDeviceSetProperty( pahsc->output.audioDeviceID, 0, 0,
+ err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0,
IS_OUTPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
+
if (err != kAudioHardwareNoError)
{
- DBUG(("PaOSX_OpenOutputDevice: Need converter for num channels.\n"));
- needConverter = 1;
+ result = paInvalidChannelCount;
+ goto error;
}
+#endif
}
- /* Change the I/O bufferSize of the device. */
- dataSize = sizeof(pahsc->framesPerHostBuffer);
- err = AudioDeviceSetProperty( pahsc->output.audioDeviceID, 0, 0, IS_OUTPUT,
- kAudioDevicePropertyBufferFrameSize, dataSize,
- &pahsc->framesPerHostBuffer);
+ // calculate buffer sizes in bytes
+ bytesPerOutputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels;
+ pahsc->pahsc_BytesPerUserNativeOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame;
+ bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerOutputFrame;
+
+ // Change the bufferSize of the device! Is this per device or just for our stream?
+ dataSize = sizeof(bytesPerHostBuffer);
+ err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_OUTPUT,
+ kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer);
if( err != noErr )
{
- DBUG(("PaOSX_OpenOutputDevice: Need converter for buffer size = %d\n", pahsc->framesPerHostBuffer));
- needConverter = 1;
+ ERR_RPT(("Could not force buffer size!"));
+ result = paHostError;
+ goto error;
}
-
+
// setup conversion procedure
result = PaConvert_SetupOutput( past, paFloat32 );
- if( needConverter )
- {
- AudioStreamBasicDescription sourceStreamFormat, destStreamFormat;
- DBUG(("PaOSX_OpenOutputDevice: using AUConverter!\n"));
- /* Get target device format */
- dataSize = sizeof(destStreamFormat);
- err = AudioDeviceGetProperty(pahsc->output.audioDeviceID, 0, IS_OUTPUT,
- kAudioDevicePropertyStreamFormat, &dataSize, &destStreamFormat);
- if( err != noErr )
- {
- PRINT_ERR("PaOSX_OpenOutputDevice: Could not get output device format", err);
- sSavedHostError = err;
- return paHostError;
- }
+ return result;
- /* Set source user format. */
- sourceStreamFormat = destStreamFormat;
- sourceStreamFormat.mSampleRate = past->past_SampleRate; // sample rate of the user synthesis code
- sourceStreamFormat.mChannelsPerFrame = past->past_NumOutputChannels; // the number of channels in each frame
-
- /* Allocate an output buffer because we need it between the user callback and the converter. */
- pahsc->output.converterBuffer = PaHost_AllocateFastMemory( pahsc->output.bytesPerUserNativeBuffer );
- err = AudioConverterNew (
- &sourceStreamFormat,
- &destStreamFormat,
- &pahsc->output.converter);
- if( err != noErr )
- {
- PRINT_ERR("Could not create output format converter", err);
- sSavedHostError = err;
- return paHostError;
- }
- }
-
+error:
return result;
}
+/*******************************************************************/
+PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ return pahsc->pahsc_FramesPerHostBuffer;
+}
+
+
/*******************************************************************
* Determine how many User Buffers we can put into our CoreAudio stream buffer.
* Uses:
* past->past_FramesPerUserBuffer, etc.
* Sets:
* past->past_NumUserBuffers
-* pahsc->framesPerHostBuffer
-* pahsc->input.bytesPerUserNativeBuffer
-* pahsc->output.bytesPerUserNativeBuffer
+* pahsc->pahsc_UserBuffersPerHostBuffer
+* pahsc->pahsc_FramesPerHostBuffer
*/
-static void PaOSX_CalcHostBufferSize( internalPortAudioStream *past )
+static void PaHost_CalcHostBufferSize( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = ( PaHostSoundControl *)past->past_DeviceData;
+ unsigned int minNumUserBuffers;
- // Determine number of user buffers based strictly on minimum reasonable buffer size.
- // We ignore the Pa_OpenStream numBuffer parameter because CoreAudio has a big
- // mix buffer and handles latency automatically.
- past->past_NumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
+ // Determine number of user buffers based on minimum latency.
+ minNumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
+ // Compare to user requested number in user wants more than the minimum.
+ past->past_NumUserBuffers = ( minNumUserBuffers > past->past_NumUserBuffers ) ?
+ minNumUserBuffers : past->past_NumUserBuffers;
+ DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
+ // For CoreAudio, we only have one Host buffer, so...
+ pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers;
// Calculate size of CoreAudio buffer.
- pahsc->framesPerHostBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers;
+ pahsc->pahsc_FramesPerHostBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers;
- // calculate buffer sizes in bytes
- pahsc->input.bytesPerUserNativeBuffer = past->past_FramesPerUserBuffer *
- Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels;
- pahsc->output.bytesPerUserNativeBuffer = past->past_FramesPerUserBuffer *
- Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels;
-
- DBUG(("PaOSX_CalcNumHostBuffers: past_NumUserBuffers = %ld\n", past->past_NumUserBuffers ));
- DBUG(("PaOSX_CalcNumHostBuffers: framesPerHostBuffer = %d\n", pahsc->framesPerHostBuffer ));
- DBUG(("PaOSX_CalcNumHostBuffers: input.bytesPerUserNativeBuffer = %d\n", pahsc->input.bytesPerUserNativeBuffer ));
- DBUG(("PaOSX_CalcNumHostBuffers: output.bytesPerUserNativeBuffer = %d\n", pahsc->output.bytesPerUserNativeBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));
}
-/*****************************************************************************/
-/************** Internal Host API ********************************************/
-/*****************************************************************************/
+/*******************************************************************/
PaError PaHost_OpenStream( internalPortAudioStream *past )
{
PaError result = paNoError;
PaHostSoundControl *pahsc;
- Boolean useInput;
- Boolean useOutput;
/* Allocate and initialize host data. */
pahsc = (PaHostSoundControl *) malloc(sizeof(PaHostSoundControl));
@@ -1310,53 +971,43 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
}
memset( pahsc, 0, sizeof(PaHostSoundControl) );
past->past_DeviceData = (void *) pahsc;
- pahsc->primaryDeviceID = kAudioDeviceUnknown;
- pahsc->input.audioDeviceID = kAudioDeviceUnknown;
- pahsc->output.audioDeviceID = kAudioDeviceUnknown;
-
- PaOSX_CalcHostBufferSize( past );
-
- /* Setup constants for CPU load measurement. */
- pahsc->inverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->framesPerHostBuffer);
- useOutput = (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0);
- useInput = (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0);
-
- // Set device IDs
- if( useOutput )
+ // If we are using both input and out, then they must be on the same CoreAudio device,
+ // until we implement a FIFO between two devices.
+ if( (past->past_OutputDeviceID != paNoDevice) && (past->past_InputDeviceID != paNoDevice) )
{
- pahsc->output.audioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID;
- pahsc->primaryDeviceID = pahsc->output.audioDeviceID;
- if( useInput )
+ AudioDeviceID inputID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
+ AudioDeviceID outputID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID;
+ if( inputID != outputID )
{
- pahsc->input.audioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
- if( pahsc->input.audioDeviceID != pahsc->primaryDeviceID )
- {
- pahsc->usingSecondDevice = TRUE; // Use two separate devices!
- }
+ ERR_RPT(("PortAudio: input and output must use same CoreAudio device!\n"));
+ return paInvalidDeviceId;
}
}
- else
+
+ PaHost_CalcHostBufferSize( past );
+
{
- /* Just input, not output. */
- pahsc->input.audioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
- pahsc->primaryDeviceID = pahsc->input.audioDeviceID;
+ int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate);
+ PRINT(("PortAudio on OS X - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency ));
}
- DBUG(("outputDeviceID = %ld\n", pahsc->output.audioDeviceID ));
- DBUG(("inputDeviceID = %ld\n", pahsc->input.audioDeviceID ));
- DBUG(("primaryDeviceID = %ld\n", pahsc->primaryDeviceID ));
+ /* Setup constants for CPU load measurement. */
+ pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer);
+
/* ------------------ OUTPUT */
- if( useOutput )
+ if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) )
{
- result = PaOSX_OpenOutputDevice( past );
+ pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID;
+ result = PaHost_OpenOutputStream( past );
if( result < 0 ) goto error;
}
/* ------------------ INPUT */
- if( useInput )
+ if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) )
{
- result = PaOSX_OpenInputDevice( past );
+ pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
+ result = PaHost_OpenInputStream( past );
if( result < 0 ) goto error;
}
@@ -1390,49 +1041,21 @@ PaError PaHost_StartEngine( internalPortAudioStream *past )
past->past_StopNow = 0;
past->past_IsActive = 1;
-/* If full duplex and using two separate devices then start input device. */
- if( pahsc->usingSecondDevice )
- {
- // Associate an IO proc with the device and pass a pointer to the audio data context
- err = AudioDeviceAddIOProc(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback, past);
- if (err != noErr)
- {
- PRINT_ERR("PaHost_StartEngine: AudioDeviceAddIOProc secondary failed", err );
- goto error;
- }
-
- // start playing sound through the device
- err = AudioDeviceStart(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback);
- if (err != noErr)
- {
- PRINT_ERR("PaHost_StartEngine: AudioDeviceStart secondary failed", err );
- PRINT(("The program may succeed if you run it again!\n"));
- goto error;
- }
- }
-
// Associate an IO proc with the device and pass a pointer to the audio data context
- err = AudioDeviceAddIOProc(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback, past);
- if (err != noErr)
- {
- PRINT_ERR("PaHost_StartEngine: AudioDeviceAddIOProc primary failed", err );
- goto error;
- }
+ err = AudioDeviceAddIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc, past);
+ if (err != noErr) goto error;
// start playing sound through the device
- err = AudioDeviceStart(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback);
- if (err != noErr)
- {
- PRINT_ERR("PaHost_StartEngine: AudioDeviceStart primary failed", err );
- PRINT(("The program may succeed if you run it again!\n"));
- goto error;
- }
-
+ err = AudioDeviceStart(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc);
+ if (err != noErr) goto error;
return result;
+#if PA_TRACE_START_STOP
+ AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result );
+#endif
+
error:
- sSavedHostError = err;
- return paHostError;
+ return paHostError; // FIXME - save host error
}
/*************************************************************************/
@@ -1454,29 +1077,16 @@ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
#endif
// FIXME - we should ask proc to stop instead of stopping abruptly
- err = AudioDeviceStop(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback);
- if (err != noErr)
- {
- goto error;
- }
+ err = AudioDeviceStop(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc);
+ if (err != noErr) goto Bail;
- err = AudioDeviceRemoveIOProc(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback);
- if (err != noErr) goto error;
-
-/* If full duplex and using two separate devices then start input device. */
- if( pahsc->usingSecondDevice )
- {
- err = AudioDeviceStop(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback);
- if (err != noErr) goto error;
- err = AudioDeviceRemoveIOProc(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback);
- if (err != noErr) goto error;
- }
+ err = AudioDeviceRemoveIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc);
+ if (err != noErr) goto Bail;
return paNoError;
-error:
- sSavedHostError = err;
- return paHostError;
+Bail:
+ return paHostError; // FIXME - save err
}
/*************************************************************************/
@@ -1499,47 +1109,70 @@ PaError PaHost_CloseStream( internalPortAudioStream *past )
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
-
- //PaOSX_DumpDeviceInfo( sDeviceInfos[past->past_OutputDeviceID].audioDeviceID, IS_OUTPUT );
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
#endif
- if( pahsc->output.converterBuffer != NULL )
- {
- PaHost_FreeFastMemory( pahsc->output.converterBuffer, pahsc->output.bytesPerUserNativeBuffer );
- }
- if( pahsc->input.converterBuffer != NULL )
- {
- PaHost_FreeFastMemory( pahsc->input.converterBuffer, pahsc->input.bytesPerUserNativeBuffer );
- }
- if( pahsc->ringBufferData != NULL )
- {
- PaHost_FreeFastMemory( pahsc->ringBufferData, pahsc->ringBuffer.bufferSize );
- }
- if( pahsc->output.converter != NULL )
- {
- verify_noerr(AudioConverterDispose (pahsc->output.converter));
- }
- if( pahsc->input.converter != NULL )
- {
- verify_noerr(AudioConverterDispose (pahsc->input.converter));
- }
-
free( pahsc );
past->past_DeviceData = NULL;
return paNoError;
}
-/**********************************************************************
-** Initialize Host dependant part of API.
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+**
+** set PA_MIN_LATENCY_MSEC=200
+**
+** in the cshrc file.
*/
-PaError PaHost_Init( void )
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+
+#if 1
+int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond )
+{
+ int minBuffers;
+ int denominator;
+ int minLatencyMsec = PA_MIN_LATENCY_MSEC;
+ char *minLatencyText = getenv(PA_LATENCY_ENV_NAME);
+ if( minLatencyText != NULL )
+ {
+ PRINT(("PA_MIN_LATENCY_MSEC = %s\n", minLatencyText ));
+ minLatencyMsec = atoi( minLatencyText );
+ if( minLatencyMsec < 1 ) minLatencyMsec = 1;
+ else if( minLatencyMsec > 5000 ) minLatencyMsec = 5000;
+ }
+
+ denominator = 1000.0 * framesPerBuffer;
+ minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator );
+ if( minBuffers < 1 ) minBuffers = 1;
+ return minBuffers;
+}
+#else
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency.
+*/
+int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate )
{
- return PaOSX_MaybeQueryDevices();
+ int minUserBuffers;
+ int minFramesPerHostBuffer;
+
+ // Calculate minimum and maximum sizes based on timing and sample rate.
+ minFramesPerHostBuffer = (int) (PA_MIN_LATENCY_MSEC * sampleRate / 1000.0);
+ // round up to nearest multiple of 8
+ minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
+ DBUG(("Pa_GetMinNumBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
+
+ minUserBuffers = (minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer;
+ if( minUserBuffers < 1 ) minUserBuffers = 1;
+
+ return minUserBuffers;
}
+#endif
/*************************************************************************
** Cleanup device info.
@@ -1552,10 +1185,8 @@ PaError PaHost_Term( void )
{
for( i=0; i<sNumPaDevices; i++ )
{
- if( sDeviceInfos[i].paInfo.name != NULL )
- {
- free( (char*)sDeviceInfos[i].paInfo.name );
- }
+ if( sDeviceInfos[i].paInfo.name != NULL ) free( (char*)sDeviceInfos[i].paInfo.name );
+ if( sDeviceInfos[i].paInfo.sampleRates != NULL ) free( (void*)sDeviceInfos[i].paInfo.sampleRates );
}
free( sDeviceInfos );
sDeviceInfos = NULL;
@@ -1565,6 +1196,19 @@ PaError PaHost_Term( void )
return paNoError;
}
+/*************************************************************************/
+void Pa_Sleep( long msec )
+{
+#if 0
+ struct timeval timeout;
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+ select( 0, NULL, NULL, NULL, &timeout );
+#else
+ usleep( msec * 1000 );
+#endif
+}
+
/*************************************************************************
* Allocate memory that can be accessed in real-time.
* This may need to be held in physical memory so that it is not
@@ -1573,7 +1217,7 @@ PaError PaHost_Term( void )
*/
void *PaHost_AllocateFastMemory( long numBytes )
{
- void *addr = malloc( numBytes ); /* FIXME - do we need physical memory, not virtual memory? */
+ void *addr = malloc( numBytes ); /* FIXME - do we need physical memory? */
if( addr != NULL ) memset( addr, 0, numBytes );
return addr;
}
@@ -1598,57 +1242,6 @@ PaError PaHost_StreamActive( internalPortAudioStream *past )
return (PaError) past->past_IsActive;
}
-/*******************************************************************/
-PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- return pahsc->framesPerHostBuffer;
-}
-
-/*****************************************************************************/
-/************** External User API ********************************************/
-/*****************************************************************************/
-
-/**********************************************************************
-** Query devices and use result.
-*/
-PaDeviceID Pa_GetDefaultInputDeviceID( void )
-{
- PaError result = PaOSX_MaybeQueryDevices();
- if( result < 0 ) return result;
- return sDefaultInputDeviceID;
-}
-
-PaDeviceID Pa_GetDefaultOutputDeviceID( void )
-{
- PaError result = PaOSX_MaybeQueryDevices();
- if( result < 0 ) return result;
- return sDefaultOutputDeviceID;
-}
-
-
-/*************************************************************************
-** Determine minimum number of buffers required for this host based
-** on minimum latency. Because CoreAudio manages latency, this just sets
-** a reasonable small buffer size.
-*/
-int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond )
-{
- int minBuffers;
- double denominator;
- int minLatencyMsec = PA_MIN_LATENCY_MSEC;
- denominator = 1000.0 * framesPerBuffer;
- minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator );
- if( minBuffers < 1 ) minBuffers = 1;
- return minBuffers;
-}
-
-/*************************************************************************/
-void Pa_Sleep( long msec )
-{
- usleep( msec * 1000 );
-}
-
/*************************************************************************/
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{
@@ -1659,37 +1252,10 @@ PaTimestamp Pa_StreamTime( PortAudioStream *stream )
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
- AudioDeviceGetCurrentTime(pahsc->primaryDeviceID, &timeStamp);
+ AudioDeviceGetCurrentTime(pahsc->pahsc_AudioDeviceID, &timeStamp);
streamTime = ( timeStamp.mFlags & kAudioTimeStampSampleTimeValid) ?
timeStamp.mSampleTime : past->past_FrameCount;
return streamTime;
}
-
-/************************************************************************************/
-long Pa_GetHostError()
-{
- return sSavedHostError;
-}
-
-/*************************************************************************/
-int Pa_CountDevices()
-{
- if( sNumPaDevices <= 0 ) Pa_Initialize();
- return sNumPaDevices;
-}
-
-/*************************************************************************
-** PaDeviceInfo structures have already been created
-** so just return the pointer.
-**
-*/
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
-{
- if( id < 0 || id >= sNumPaDevices )
- return NULL;
-
- return &sDeviceInfos[id].paInfo;
-}
-
diff --git a/pd/portaudio/pa_mac_sm/pa_mac_sm.c b/pd/portaudio/pa_mac_sm/pa_mac_sm.c
new file mode 100644
index 00000000..59457ded
--- /dev/null
+++ b/pd/portaudio/pa_mac_sm/pa_mac_sm.c
@@ -0,0 +1,1656 @@
+/*
+ * $Id: pa_mac_sm.c,v 1.1.2.1 2002/06/07 21:20:48 rossb Exp $
+ * Portable Audio I/O Library for Macintosh
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Special thanks to Chris Rolfe for his many helpful suggestions, bug fixes,
+ * and code contributions.
+ * Thanks also to Tue Haste Andersen, Alberto Ricci, Nico Wald,
+ * Roelf Toxopeus and Tom Erbe for testing the code and making
+ * numerous suggestions.
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+/* Modification History
+ PLB20010415 - ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID
+ PLB20010415 - Device Scan was crashing for anything other than siBadSoundInDevice, but some Macs may return other errors!
+ PLB20010420 - Fix TIMEOUT in record mode.
+ PLB20010420 - Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON
+ PLB20010907 - Pass unused event to WaitNextEvent to prevent Mac OSX crash. Thanks Dominic Mazzoni.
+ PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni.
+ PLB20011009 - Use NewSndCallBackUPP() for CARBON
+ PLB20020417 - I used to call Pa_GetMinNumBuffers() which doesn't take into account the
+ variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will
+ give lower latency when virtual memory is turned off.
+ Thanks Kristoffer Jensen and Georgios Marentakis for spotting this bug.
+ PLB20020423 - Use new method to calculate CPU load similar to other ports. Based on num frames calculated.
+ Fixed Pa_StreamTime(). Now estimates how many frames have played based on MicroSecond timer.
+ Added PA_MAX_USAGE_ALLOWED to prevent Mac form hanging when CPU load approaches 100%.
+ PLB20020424 - Fixed return value in Pa_StreamTime
+*/
+
+/*
+COMPATIBILITY
+This Macintosh implementation is designed for use with Mac OS 7, 8 and
+9 on PowerMacs, and OS X if compiled with CARBON
+
+OUTPUT
+A circular array of CmpSoundHeaders is used as a queue. For low latency situations
+there will only be two small buffers used. For higher latency, more and larger buffers
+may be used.
+To play the sound we use SndDoCommand() with bufferCmd. Each buffer is followed
+by a callbackCmd which informs us when the buffer has been processsed.
+
+INPUT
+The SndInput Manager SPBRecord call is used for sound input. If only
+input is used, then the PA user callback is called from the Input completion proc.
+For full-duplex, or output only operation, the PA callback is called from the
+HostBuffer output completion proc. In that case, input sound is passed to the
+callback by a simple FIFO.
+
+TODO:
+O- Add support for native sample data formats other than int16.
+O- Review buffer sizing. Should it be based on result of siDeviceBufferInfo query?
+O- Determine default devices somehow.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <math.h>
+
+/* Mac specific includes */
+#include "OSUtils.h"
+#include <MacTypes.h>
+#include <Math64.h>
+#include <Errors.h>
+#include <Sound.h>
+#include <SoundInput.h>
+#include <SoundComponents.h>
+#include <Devices.h>
+#include <DateTimeUtils.h>
+#include <Timer.h>
+#include <Gestalt.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+#ifndef FALSE
+ #define FALSE (0)
+ #define TRUE (!FALSE)
+#endif
+
+/* #define TARGET_API_MAC_CARBON (1) */
+
+/*
+ * Define maximum CPU load that will be allowed. User callback will
+ * be skipped if load exceeds this limit. This is to prevent the Mac
+ * from hanging when the CPU is hogged by the sound thread.
+ * On my PowerBook G3, the mac hung when I used 94% of CPU ( usage = 0.94 ).
+ */
+#define PA_MAX_USAGE_ALLOWED (0.92)
+
+/* Debugging output macros. */
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) /**/
+#define DBUGX(x) /* PRINT(x) /**/
+
+#define MAC_PHYSICAL_FRAMES_PER_BUFFER (512) /* Minimum number of stereo frames per SoundManager double buffer. */
+#define MAC_VIRTUAL_FRAMES_PER_BUFFER (4096) /* Need this many when using Virtual Memory for recording. */
+#define PA_MIN_NUM_HOST_BUFFERS (2)
+#define PA_MAX_NUM_HOST_BUFFERS (16) /* Do not exceed!! */
+#define PA_MAX_DEVICE_INFO (32)
+
+/* Conversions for 16.16 fixed point code. */
+#define DoubleToUnsignedFixed(x) ((UnsignedFixed) ((x) * 65536.0))
+#define UnsignedFixedToDouble(fx) (((double)(fx)) * (1.0/(1<<16)))
+
+/************************************************************************************/
+/****************** Structures ******************************************************/
+/************************************************************************************/
+/* Use for passing buffers from input callback to output callback for processing. */
+typedef struct MultiBuffer
+{
+ char *buffers[PA_MAX_NUM_HOST_BUFFERS];
+ int numBuffers;
+ int nextWrite;
+ int nextRead;
+}
+MultiBuffer;
+
+/* Define structure to contain all Macintosh specific data. */
+typedef struct PaHostSoundControl
+{
+ UInt64 pahsc_EntryCount;
+ double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
+
+ /* Use char instead of Boolean for atomic operation. */
+ volatile char pahsc_IsRecording; /* Recording in progress. Set by foreground. Cleared by background. */
+ volatile char pahsc_StopRecording; /* Signal sent to background. */
+ volatile char pahsc_IfInsideCallback;
+ /* Input */
+ SPB pahsc_InputParams;
+ SICompletionUPP pahsc_InputCompletionProc;
+ MultiBuffer pahsc_InputMultiBuffer;
+ int32 pahsc_BytesPerInputHostBuffer;
+ int32 pahsc_InputRefNum;
+ /* Output */
+ CmpSoundHeader pahsc_SoundHeaders[PA_MAX_NUM_HOST_BUFFERS];
+ int32 pahsc_BytesPerOutputHostBuffer;
+ SndChannelPtr pahsc_Channel;
+ SndCallBackUPP pahsc_OutputCompletionProc;
+ int32 pahsc_NumOutsQueued;
+ int32 pahsc_NumOutsPlayed;
+ PaTimestamp pahsc_NumFramesDone;
+ UInt64 pahsc_WhenFramesDoneIncremented;
+ /* Init Time -------------- */
+ int32 pahsc_NumHostBuffers;
+ int32 pahsc_FramesPerHostBuffer;
+ int32 pahsc_UserBuffersPerHostBuffer;
+ int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */
+}
+PaHostSoundControl;
+
+/* Mac specific device information. */
+typedef struct internalPortAudioDevice
+{
+ long pad_DeviceRefNum;
+ long pad_DeviceBufferSize;
+ Component pad_Identifier;
+ PaDeviceInfo pad_Info;
+}
+internalPortAudioDevice;
+
+/************************************************************************************/
+/****************** Data ************************************************************/
+/************************************************************************************/
+static int sNumDevices = 0;
+static internalPortAudioDevice sDevices[PA_MAX_DEVICE_INFO] = { 0 };
+static int32 sPaHostError = 0;
+static int sDefaultOutputDeviceID;
+static int sDefaultInputDeviceID;
+
+/************************************************************************************/
+/****************** Prototypes ******************************************************/
+/************************************************************************************/
+static PaError PaMac_TimeSlice( internalPortAudioStream *past, int16 *macOutputBufPtr );
+static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr );
+static PaError PaMac_RecordNext( internalPortAudioStream *past );
+static void PaMac_StartLoadCalculation( internalPortAudioStream *past );
+static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerBuffer, double sampleRate );
+static double *PaMac_GetSampleRatesFromHandle ( int numRates, Handle h );
+static PaError PaMac_ScanInputDevices( void );
+static PaError PaMac_ScanOutputDevices( void );
+static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad );
+static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad );
+static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader );
+static void PaMac_EndLoadCalculation( internalPortAudioStream *past );
+static void PaMac_PlayNext ( internalPortAudioStream *past, int index );
+static long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index );
+static pascal void PaMac_InputCompletionProc(SPBPtr recParams);
+static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCmd);
+static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index );
+long PaHost_GetTotalBufferFrames( internalPortAudioStream *past );
+static int Mac_IsVirtualMemoryOn( void );
+static void PToCString(unsigned char* inString, char* outString);
+char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf );
+char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf );
+int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf );
+int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf );
+int MultiBuffer_IsWriteable( MultiBuffer *mbuf );
+int MultiBuffer_IsReadable( MultiBuffer *mbuf );
+void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf );
+void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf );
+
+/*************************************************************************
+** Simple FIFO index control for multiple buffers.
+** Read and Write indices range from 0 to 2N-1.
+** This allows us to distinguish between full and empty.
+*/
+char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf )
+{
+ return mbuf->buffers[mbuf->nextWrite % mbuf->numBuffers];
+}
+char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf )
+{
+ return mbuf->buffers[mbuf->nextRead % mbuf->numBuffers];
+}
+int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf )
+{
+ return mbuf->nextRead % mbuf->numBuffers;
+}
+int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf )
+{
+ return mbuf->nextWrite % mbuf->numBuffers;
+}
+
+int MultiBuffer_IsWriteable( MultiBuffer *mbuf )
+{
+ int bufsFull = mbuf->nextWrite - mbuf->nextRead;
+ if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers);
+ return (bufsFull < mbuf->numBuffers);
+}
+int MultiBuffer_IsReadable( MultiBuffer *mbuf )
+{
+ int bufsFull = mbuf->nextWrite - mbuf->nextRead;
+ if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers);
+ return (bufsFull > 0);
+}
+void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf )
+{
+ int temp = mbuf->nextRead + 1;
+ mbuf->nextRead = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp;
+}
+void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf )
+{
+ int temp = mbuf->nextWrite + 1;
+ mbuf->nextWrite = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp;
+}
+
+/*************************************************************************
+** String Utility by Chris Rolfe
+*/
+static void PToCString(unsigned char* inString, char* outString)
+{
+ long i;
+ for(i=0; i<inString[0]; i++) /* convert Pascal to C string */
+ outString[i] = inString[i+1];
+ outString[i]=0;
+}
+
+/*************************************************************************/
+PaError PaHost_Term( void )
+{
+ int i;
+ PaDeviceInfo *dev;
+ double *rates;
+ /* Free any allocated sample rate arrays. */
+ for( i=0; i<sNumDevices; i++ )
+ {
+ dev = &sDevices[i].pad_Info;
+ rates = (double *) dev->sampleRates;
+ if( (rates != NULL) ) free( rates ); /* MEM_011 */
+ dev->sampleRates = NULL;
+ if( dev->name != NULL ) free( (void *) dev->name ); /* MEM_010 */
+ dev->name = NULL;
+ }
+ sNumDevices = 0;
+ return paNoError;
+}
+
+/*************************************************************************
+ PaHost_Init() is the library initialization function - call this before
+ using the library.
+*/
+PaError PaHost_Init( void )
+{
+ PaError err;
+ NumVersionVariant version;
+
+ version.parts = SndSoundManagerVersion();
+ DBUG(("SndSoundManagerVersion = 0x%x\n", version.whole));
+
+ /* Have we already initialized the device info? */
+ err = (PaError) Pa_CountDevices();
+ if( err < 0 ) return err;
+ else return paNoError;
+}
+
+/*************************************************************************
+ PaMac_ScanOutputDevices() queries the properties of all output devices.
+*/
+static PaError PaMac_ScanOutputDevices( void )
+{
+ PaError err;
+ Component identifier=0;
+ ComponentDescription criteria = { kSoundOutputDeviceType, 0, 0, 0, 0 };
+ long numComponents, i;
+
+ /* Search the system linked list for output components */
+ numComponents = CountComponents (&criteria);
+ identifier = 0;
+ sDefaultOutputDeviceID = sNumDevices; /* FIXME - query somehow */
+ for (i = 0; i < numComponents; i++)
+ {
+ /* passing nil returns first matching component. */
+ identifier = FindNextComponent( identifier, &criteria);
+ sDevices[sNumDevices].pad_Identifier = identifier;
+
+ /* Set up for default OUTPUT devices. */
+ err = PaMac_QueryOutputDeviceInfo( identifier, &sDevices[sNumDevices] );
+ if( err < 0 ) return err;
+ else sNumDevices++;
+
+ }
+
+ return paNoError;
+}
+
+/*************************************************************************
+ PaMac_ScanInputDevices() queries the properties of all input devices.
+*/
+static PaError PaMac_ScanInputDevices( void )
+{
+ Str255 deviceName;
+ int count;
+ Handle iconHandle;
+ PaError err;
+ OSErr oserr;
+ count = 1;
+ sDefaultInputDeviceID = sNumDevices; /* FIXME - query somehow */ /* PLB20010415 - was setting sDefaultOutputDeviceID */
+ while(true)
+ {
+ /* Thanks Chris Rolfe and Alberto Ricci for this trick. */
+ oserr = SPBGetIndexedDevice(count++, deviceName, &iconHandle);
+ DBUG(("PaMac_ScanInputDevices: SPBGetIndexedDevice returned %d\n", oserr ));
+#if 1
+ /* PLB20010415 - was giving error for anything other than siBadSoundInDevice, but some Macs may return other errors! */
+ if(oserr != noErr) break; /* Some type of error is expected when count > devices */
+#else
+ if(oserr == siBadSoundInDevice)
+ { /* it's expected when count > devices */
+ oserr = noErr;
+ break;
+ }
+ if(oserr != noErr)
+ {
+ ERR_RPT(("ERROR: SPBGetIndexedDevice(%d,,) returned %d\n", count-1, oserr ));
+ sPaHostError = oserr;
+ return paHostError;
+ }
+#endif
+ DisposeHandle(iconHandle); /* Don't need the icon */
+
+ err = PaMac_QueryInputDeviceInfo( deviceName, &sDevices[sNumDevices] );
+ DBUG(("PaMac_ScanInputDevices: PaMac_QueryInputDeviceInfo returned %d\n", err ));
+ if( err < 0 ) return err;
+ else if( err == 1 ) sNumDevices++;
+ }
+
+ return paNoError;
+}
+
+/* Sample rate info returned by using siSampleRateAvailable selector in SPBGetDeviceInfo() */
+/* Thanks to Chris Rolfe for help with this query. */
+#pragma options align=mac68k
+typedef struct
+{
+ int16 numRates;
+ UnsignedFixed (**rates)[]; /* Handle created by SPBGetDeviceInfo */
+}
+SRateInfo;
+#pragma options align=reset
+
+/*************************************************************************
+** PaMac_QueryOutputDeviceInfo()
+** Query information about a named output device.
+** Clears contents of ipad and writes info based on queries.
+** Return one if OK,
+** zero if device cannot be used,
+** or negative error.
+*/
+static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad )
+{
+ int len;
+ OSErr err;
+ PaDeviceInfo *dev = &ipad->pad_Info;
+ SRateInfo srinfo = {0};
+ int numRates;
+ ComponentDescription tempD;
+ Handle nameH=nil, infoH=nil, iconH=nil;
+
+ memset( ipad, 0, sizeof(internalPortAudioDevice) );
+
+ dev->structVersion = 1;
+ dev->maxInputChannels = 0;
+ dev->maxOutputChannels = 2;
+ dev->nativeSampleFormats = paInt16; /* FIXME - query to see if 24 or 32 bit data can be handled. */
+
+ /* Get sample rates supported. */
+ err = GetSoundOutputInfo(identifier, siSampleRateAvailable, (Ptr) &srinfo);
+ if(err != noErr)
+ {
+ ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetSoundOutputInfo siSampleRateAvailable returned %d\n", err ));
+ goto error;
+ }
+ numRates = srinfo.numRates;
+ DBUG(("PaMac_QueryOutputDeviceInfo: srinfo.numRates = 0x%x\n", srinfo.numRates ));
+ if( numRates == 0 )
+ {
+ dev->numSampleRates = -1;
+ numRates = 2;
+ }
+ else
+ {
+ dev->numSampleRates = numRates;
+ }
+ dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates );
+ /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */
+ DisposeHandle((Handle) srinfo.rates);
+
+ /* Device name */
+ /* we pass an existing handle for the component name;
+ we don't care about the info (type, subtype, etc.) or icon, so set them to nil */
+ infoH = nil;
+ iconH = nil;
+ nameH = NewHandle(0);
+ if(nameH == nil) return paInsufficientMemory;
+ err = GetComponentInfo(identifier, &tempD, nameH, infoH, iconH);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetComponentInfo returned %d\n", err ));
+ goto error;
+ }
+ len = (*nameH)[0] + 1;
+ dev->name = (char *) malloc(len); /* MEM_010 */
+ if( dev->name == NULL )
+ {
+ DisposeHandle(nameH);
+ return paInsufficientMemory;
+ }
+ else
+ {
+ PToCString((unsigned char *)(*nameH), (char *) dev->name);
+ DisposeHandle(nameH);
+ }
+
+ DBUG(("PaMac_QueryOutputDeviceInfo: dev->name = %s\n", dev->name ));
+ return paNoError;
+
+error:
+ sPaHostError = err;
+ return paHostError;
+
+}
+
+/*************************************************************************
+** PaMac_QueryInputDeviceInfo()
+** Query information about a named input device.
+** Clears contents of ipad and writes info based on queries.
+** Return one if OK,
+** zero if device cannot be used,
+** or negative error.
+*/
+static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad )
+{
+ PaError result = paNoError;
+ int len;
+ OSErr err;
+ long mRefNum = 0;
+ long tempL;
+ int16 tempS;
+ Fixed tempF;
+ PaDeviceInfo *dev = &ipad->pad_Info;
+ SRateInfo srinfo = {0};
+ int numRates;
+
+ memset( ipad, 0, sizeof(internalPortAudioDevice) );
+ dev->maxOutputChannels = 0;
+
+ /* Open device based on name. If device is in use, it may not be able to open in write mode. */
+ err = SPBOpenDevice( deviceName, siWritePermission, &mRefNum);
+ if (err)
+ {
+ /* If device is in use, it may not be able to open in write mode so try read mode. */
+ err = SPBOpenDevice( deviceName, siReadPermission, &mRefNum);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBOpenDevice returned %d\n", err ));
+ sPaHostError = err;
+ return paHostError;
+ }
+ }
+
+ /* Define macros for printing out device info. */
+#define PrintDeviceInfo(selector,var) \
+ err = SPBGetDeviceInfo(mRefNum, selector, (Ptr) &var); \
+ if (err) { \
+ DBUG(("query %s failed\n", #selector )); \
+ }\
+ else { \
+ DBUG(("query %s = 0x%x\n", #selector, var )); \
+ }
+
+ PrintDeviceInfo( siContinuous, tempS );
+ PrintDeviceInfo( siAsync, tempS );
+ PrintDeviceInfo( siNumberChannels, tempS );
+ PrintDeviceInfo( siSampleSize, tempS );
+ PrintDeviceInfo( siSampleRate, tempF );
+ PrintDeviceInfo( siChannelAvailable, tempS );
+ PrintDeviceInfo( siActiveChannels, tempL );
+ PrintDeviceInfo( siDeviceBufferInfo, tempL );
+
+ err = SPBGetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL);
+ if (err == 0) DBUG(("%s = 0x%x\n", "siActiveChannels", tempL ));
+ /* Can we use this device? */
+ err = SPBGetDeviceInfo(mRefNum, siAsync, (Ptr) &tempS);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siAsync returned %d\n", err ));
+ goto error;
+ }
+ if( tempS == 0 ) goto useless; /* Does not support async recording so forget about it. */
+
+ err = SPBGetDeviceInfo(mRefNum, siChannelAvailable, (Ptr) &tempS);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siChannelAvailable returned %d\n", err ));
+ goto error;
+ }
+ dev->maxInputChannels = tempS;
+
+ /* Get sample rates supported. */
+ err = SPBGetDeviceInfo(mRefNum, siSampleRateAvailable, (Ptr) &srinfo);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleRateAvailable returned %d\n", err ));
+ goto error;
+ }
+
+ numRates = srinfo.numRates;
+ DBUG(("numRates = 0x%x\n", numRates ));
+ if( numRates == 0 )
+ {
+ dev->numSampleRates = -1;
+ numRates = 2;
+ }
+ else
+ {
+ dev->numSampleRates = numRates;
+ }
+ dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates );
+ /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */
+ DisposeHandle((Handle) srinfo.rates);
+
+ /* Get size of device buffer. */
+ err = SPBGetDeviceInfo(mRefNum, siDeviceBufferInfo, (Ptr) &tempL);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siDeviceBufferInfo returned %d\n", err ));
+ goto error;
+ }
+ ipad->pad_DeviceBufferSize = tempL;
+ DBUG(("siDeviceBufferInfo = %d\n", tempL ));
+
+ /* Set format based on sample size. */
+ err = SPBGetDeviceInfo(mRefNum, siSampleSize, (Ptr) &tempS);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleSize returned %d\n", err ));
+ goto error;
+ }
+ switch( tempS )
+ {
+ case 0x0020:
+ dev->nativeSampleFormats = paInt32; /* FIXME - warning, code probably won't support this! */
+ break;
+ case 0x0010:
+ default: /* FIXME - What about other formats? */
+ dev->nativeSampleFormats = paInt16;
+ break;
+ }
+ DBUG(("nativeSampleFormats = %d\n", dev->nativeSampleFormats ));
+
+ /* Device name */
+ len = deviceName[0] + 1; /* Get length of Pascal string */
+ dev->name = (char *) malloc(len); /* MEM_010 */
+ if( dev->name == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ PToCString(deviceName, (char *) dev->name);
+ DBUG(("deviceName = %s\n", dev->name ));
+ result = (PaError) 1;
+ /* All done so close up device. */
+cleanup:
+ if( mRefNum ) SPBCloseDevice(mRefNum);
+ return result;
+
+error:
+ if( mRefNum ) SPBCloseDevice(mRefNum);
+ sPaHostError = err;
+ return paHostError;
+
+useless:
+ if( mRefNum ) SPBCloseDevice(mRefNum);
+ return (PaError) 0;
+}
+
+/*************************************************************************
+** Allocate a double array and fill it with listed sample rates.
+*/
+static double * PaMac_GetSampleRatesFromHandle ( int numRates, Handle h )
+{
+ OSErr err = noErr;
+ SInt8 hState;
+ int i;
+ UnsignedFixed *fixedRates;
+ double *rates = (double *) malloc( numRates * sizeof(double) ); /* MEM_011 */
+ if( rates == NULL ) return NULL;
+ /* Save and restore handle state as suggested by TechNote at:
+ http://developer.apple.com/technotes/tn/tn1122.html
+ */
+ hState = HGetState (h);
+ if (!(err = MemError ()))
+ {
+ HLock (h);
+ if (!(err = MemError ( )))
+ {
+ fixedRates = (UInt32 *) *h;
+ for( i=0; i<numRates; i++ )
+ {
+ rates[i] = UnsignedFixedToDouble(fixedRates[i]);
+ }
+
+ HSetState (h,hState);
+ err = MemError ( );
+ }
+ }
+ if( err )
+ {
+ free( rates );
+ ERR_RPT(("Error in PaMac_GetSampleRatesFromHandle = %d\n", err ));
+ }
+ return rates;
+}
+
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ PaError err;
+ DBUG(("Pa_CountDevices()\n"));
+ /* If no devices, go find some. */
+ if( sNumDevices <= 0 )
+ {
+ err = PaMac_ScanOutputDevices();
+ if( err != paNoError ) goto error;
+ err = PaMac_ScanInputDevices();
+ if( err != paNoError ) goto error;
+ }
+ return sNumDevices;
+
+error:
+ PaHost_Term();
+ DBUG(("Pa_CountDevices: returns %d\n", err ));
+ return err;
+
+}
+
+/*************************************************************************/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
+ return &sDevices[id].pad_Info;
+}
+/*************************************************************************/
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
+{
+ return sDefaultInputDeviceID;
+}
+
+/*************************************************************************/
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
+{
+ return sDefaultOutputDeviceID;
+}
+
+/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
+static void PaMac_StartLoadCalculation( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ UnsignedWide widePad;
+ if( pahsc == NULL ) return;
+ /* Query system timer for usage analysis and to prevent overuse of CPU. */
+ Microseconds( &widePad );
+ pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad );
+}
+
+/******************************************************************************
+** Measure fractional CPU load based on real-time it took to calculate
+** buffers worth of output.
+*/
+/**************************************************************************/
+static void PaMac_EndLoadCalculation( internalPortAudioStream *past )
+{
+ UnsignedWide widePad;
+ UInt64 currentCount;
+ long usecsElapsed;
+ double newUsage;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+
+ /* Measure CPU utilization during this callback. Note that this calculation
+ ** assumes that we had the processor the whole time.
+ */
+#define LOWPASS_COEFFICIENT_0 (0.95)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+ Microseconds( &widePad );
+ currentCount = UnsignedWideToUInt64( widePad );
+
+ usecsElapsed = (long) U64Subtract(currentCount, pahsc->pahsc_EntryCount);
+
+ /* Use inverse because it is faster than the divide. */
+ newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer;
+
+ past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
+ (LOWPASS_COEFFICIENT_1 * newUsage);
+
+}
+
+/***********************************************************************
+** Called by Pa_StartStream()
+*/
+PaError PaHost_StartInput( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ pahsc->pahsc_IsRecording = 0;
+ pahsc->pahsc_StopRecording = 0;
+ pahsc->pahsc_InputMultiBuffer.nextWrite = 0;
+ pahsc->pahsc_InputMultiBuffer.nextRead = 0;
+ return PaMac_RecordNext( past );
+}
+
+/***********************************************************************
+** Called by Pa_StopStream().
+** May be called during error recovery or cleanup code
+** so protect against NULL pointers.
+*/
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
+{
+ int32 timeOutMsec;
+ PaError result = paNoError;
+ OSErr err = 0;
+ long mRefNum;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+
+ (void) abort;
+
+ mRefNum = pahsc->pahsc_InputRefNum;
+
+ DBUG(("PaHost_StopInput: mRefNum = %d\n", mRefNum ));
+ if( mRefNum )
+ {
+ DBUG(("PaHost_StopInput: pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording ));
+ if( pahsc->pahsc_IsRecording )
+ {
+ /* PLB20010420 - Fix TIMEOUT in record mode. */
+ pahsc->pahsc_StopRecording = 1; /* Request that we stop recording. */
+ err = SPBStopRecording(mRefNum);
+ DBUG(("PaHost_StopInput: then pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording ));
+
+ /* Calculate timeOut longer than longest time it could take to play one buffer. */
+ timeOutMsec = (int32) ((1500.0 * pahsc->pahsc_FramesPerHostBuffer) / past->past_SampleRate);
+ /* Keep querying sound channel until it is no longer busy playing. */
+ while( !err && pahsc->pahsc_IsRecording && (timeOutMsec > 0))
+ {
+ Pa_Sleep(20);
+ timeOutMsec -= 20;
+ }
+ if( timeOutMsec <= 0 )
+ {
+ ERR_RPT(("PaHost_StopInput: timed out!\n"));
+ return paTimedOut;
+ }
+ }
+ }
+ if( err )
+ {
+ sPaHostError = err;
+ result = paHostError;
+ }
+
+ DBUG(("PaHost_StopInput: finished.\n", mRefNum ));
+ return result;
+}
+
+/***********************************************************************/
+static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader )
+{
+ sndHeader->numChannels = past->past_NumOutputChannels;
+ sndHeader->sampleRate = DoubleToUnsignedFixed(past->past_SampleRate);
+ sndHeader->loopStart = 0;
+ sndHeader->loopEnd = 0;
+ sndHeader->encode = cmpSH;
+ sndHeader->baseFrequency = kMiddleC;
+ sndHeader->markerChunk = nil;
+ sndHeader->futureUse2 = nil;
+ sndHeader->stateVars = nil;
+ sndHeader->leftOverSamples = nil;
+ sndHeader->compressionID = 0;
+ sndHeader->packetSize = 0;
+ sndHeader->snthID = 0;
+ sndHeader->sampleSize = 8 * sizeof(int16); // FIXME - might be 24 or 32 bits some day;
+ sndHeader->sampleArea[0] = 0;
+ sndHeader->format = kSoundNotCompressed;
+}
+
+static void SetFramesDone( PaHostSoundControl *pahsc, PaTimestamp framesDone )
+{
+ UnsignedWide now;
+ Microseconds( &now );
+ pahsc->pahsc_NumFramesDone = framesDone;
+ pahsc->pahsc_WhenFramesDoneIncremented = UnsignedWideToUInt64( now );
+}
+
+/***********************************************************************/
+PaError PaHost_StartOutput( internalPortAudioStream *past )
+{
+ SndCommand pauseCommand;
+ SndCommand resumeCommand;
+ int i;
+ OSErr error;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+ if( pahsc->pahsc_Channel == NULL ) return paInternalError;
+
+ past->past_StopSoon = 0;
+ past->past_IsActive = 1;
+ pahsc->pahsc_NumOutsQueued = 0;
+ pahsc->pahsc_NumOutsPlayed = 0;
+
+ SetFramesDone( pahsc, 0.0 );
+
+ /* Pause channel so it does not do back ground processing while we are still filling the queue. */
+ pauseCommand.cmd = pauseCmd;
+ pauseCommand.param1 = pauseCommand.param2 = 0;
+ error = SndDoCommand (pahsc->pahsc_Channel, &pauseCommand, true);
+ if (noErr != error) goto exit;
+
+ /* Queue all of the buffers so we start off full. */
+ for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
+ {
+ PaMac_PlayNext( past, i );
+ }
+
+ /* Resume channel now that the queue is full. */
+ resumeCommand.cmd = resumeCmd;
+ resumeCommand.param1 = resumeCommand.param2 = 0;
+ error = SndDoImmediate( pahsc->pahsc_Channel, &resumeCommand );
+ if (noErr != error) goto exit;
+
+ return paNoError;
+exit:
+ past->past_IsActive = 0;
+ sPaHostError = error;
+ ERR_RPT(("Error in PaHost_StartOutput: SndDoCommand returned %d\n", error ));
+ return paHostError;
+}
+
+/*******************************************************************/
+long PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ return (long) (pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer);
+}
+
+/***********************************************************************
+** Called by Pa_StopStream().
+** May be called during error recovery or cleanup code
+** so protect against NULL pointers.
+*/
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+{
+ int32 timeOutMsec;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ if( pahsc->pahsc_Channel == NULL ) return paNoError;
+
+ DBUG(("PaHost_StopOutput()\n"));
+ if( past->past_IsActive == 0 ) return paNoError;
+
+ /* Set flags for callback function to see. */
+ if( abort ) past->past_StopNow = 1;
+ past->past_StopSoon = 1;
+ /* Calculate timeOut longer than longest time it could take to play all buffers. */
+ timeOutMsec = (int32) ((1500.0 * PaHost_GetTotalBufferFrames( past )) / past->past_SampleRate);
+ /* Keep querying sound channel until it is no longer busy playing. */
+ while( past->past_IsActive && (timeOutMsec > 0))
+ {
+ Pa_Sleep(20);
+ timeOutMsec -= 20;
+ }
+ if( timeOutMsec <= 0 )
+ {
+ ERR_RPT(("PaHost_StopOutput: timed out!\n"));
+ return paTimedOut;
+ }
+ else return paNoError;
+}
+
+/***********************************************************************/
+PaError PaHost_StartEngine( internalPortAudioStream *past )
+{
+ (void) past; /* Prevent unused variable warnings. */
+ return paNoError;
+}
+
+/***********************************************************************/
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+{
+ (void) past; /* Prevent unused variable warnings. */
+ (void) abort; /* Prevent unused variable warnings. */
+ return paNoError;
+}
+/***********************************************************************/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ return (PaError) ( past->past_IsActive + pahsc->pahsc_IsRecording );
+}
+int Mac_IsVirtualMemoryOn( void )
+{
+ long attr;
+ OSErr result = Gestalt( gestaltVMAttr, &attr );
+ DBUG(("gestaltVMAttr : 0x%x\n", attr ));
+ return ((attr >> gestaltVMHasPagingControl ) & 1);
+}
+
+/*******************************************************************
+* Determine number of host Buffers
+* and how many User Buffers we can put into each host buffer.
+*/
+static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ int32 minNumBuffers;
+ int32 minFramesPerHostBuffer;
+ int32 minTotalFrames;
+ int32 userBuffersPerHostBuffer;
+ int32 framesPerHostBuffer;
+ int32 numHostBuffers;
+
+ minFramesPerHostBuffer = pahsc->pahsc_MinFramesPerHostBuffer;
+ minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
+ DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
+
+ /* Determine number of user buffers based on minimum latency. */
+ /* PLB20020417 I used to call Pa_GetMinNumBuffers() which doesn't take into account the
+ ** variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will
+ ** gove lower latency when virtual memory is turned off. */
+ /* minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); WRONG */
+ minNumBuffers = PaMac_GetMinNumBuffers( minFramesPerHostBuffer, past->past_FramesPerUserBuffer, past->past_SampleRate );
+
+ past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers;
+ DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
+ minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer;
+
+ /* We cannot make the buffers too small because they may not get serviced quickly enough. */
+ if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer )
+ {
+ userBuffersPerHostBuffer =
+ (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) /
+ past->past_FramesPerUserBuffer;
+ }
+ else
+ {
+ userBuffersPerHostBuffer = 1;
+ }
+ framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
+
+ /* Calculate number of host buffers needed. Round up to cover minTotalFrames. */
+ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
+ /* Make sure we have enough host buffers. */
+ if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS)
+ {
+ numHostBuffers = PA_MIN_NUM_HOST_BUFFERS;
+ }
+ else
+ {
+ /* If we have too many host buffers, try to put more user buffers in a host buffer. */
+ while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS)
+ {
+ userBuffersPerHostBuffer += 1;
+ framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
+ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
+ }
+ }
+
+ pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer;
+ pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer;
+ pahsc->pahsc_NumHostBuffers = numHostBuffers;
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
+}
+
+/*******************************************************************/
+PaError PaHost_OpenStream( internalPortAudioStream *past )
+{
+ OSErr err;
+ PaError result = paHostError;
+ PaHostSoundControl *pahsc;
+ int i;
+ /* Allocate and initialize host data. */
+ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
+ if( pahsc == NULL )
+ {
+ return paInsufficientMemory;
+ }
+ past->past_DeviceData = (void *) pahsc;
+
+ /* If recording, and virtual memory is turned on, then use bigger buffers to prevent glitches. */
+ if( (past->past_NumInputChannels > 0) && Mac_IsVirtualMemoryOn() )
+ {
+ pahsc->pahsc_MinFramesPerHostBuffer = MAC_VIRTUAL_FRAMES_PER_BUFFER;
+ }
+ else
+ {
+ pahsc->pahsc_MinFramesPerHostBuffer = MAC_PHYSICAL_FRAMES_PER_BUFFER;
+ }
+
+ PaHost_CalcNumHostBuffers( past );
+
+ /* Setup constants for CPU load measurement. */
+ pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer);
+
+ /* ------------------ OUTPUT */
+ if( past->past_NumOutputChannels > 0 )
+ {
+ /* Create sound channel to which we can send commands. */
+ pahsc->pahsc_Channel = 0L;
+ err = SndNewChannel(&pahsc->pahsc_Channel, sampledSynth, 0, nil); /* FIXME - use kUseOptionalOutputDevice if not default. */
+ if(err != 0)
+ {
+ ERR_RPT(("Error in PaHost_OpenStream: SndNewChannel returned 0x%x\n", err ));
+ goto error;
+ }
+
+ /* Install our callback function pointer straight into the sound channel structure */
+ /* Use new CARBON name for callback procedure. */
+#if TARGET_API_MAC_CARBON
+ pahsc->pahsc_OutputCompletionProc = NewSndCallBackUPP(PaMac_OutputCompletionProc);
+#else
+ pahsc->pahsc_OutputCompletionProc = NewSndCallBackProc(PaMac_OutputCompletionProc);
+#endif
+
+ pahsc->pahsc_Channel->callBack = pahsc->pahsc_OutputCompletionProc;
+
+ pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumOutputChannels * sizeof(int16);
+ for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
+ {
+ char *buf = (char *)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer);
+ if (buf == NULL)
+ {
+ ERR_RPT(("Error in PaHost_OpenStream: could not allocate output buffer. Size = \n", pahsc->pahsc_BytesPerOutputHostBuffer ));
+ goto memerror;
+ }
+
+ PaMac_InitSoundHeader( past, &pahsc->pahsc_SoundHeaders[i] );
+ pahsc->pahsc_SoundHeaders[i].samplePtr = buf;
+ pahsc->pahsc_SoundHeaders[i].numFrames = (unsigned long) pahsc->pahsc_FramesPerHostBuffer;
+
+ }
+ }
+#ifdef SUPPORT_AUDIO_CAPTURE
+ /* ------------------ INPUT */
+ /* Use double buffer scheme that matches output. */
+ if( past->past_NumInputChannels > 0 )
+ {
+ int16 tempS;
+ long tempL;
+ Fixed tempF;
+ long mRefNum;
+ unsigned char noname = 0; /* FIXME - use real device names. */
+#if TARGET_API_MAC_CARBON
+ pahsc->pahsc_InputCompletionProc = NewSICompletionUPP((SICompletionProcPtr)PaMac_InputCompletionProc);
+#else
+ pahsc->pahsc_InputCompletionProc = NewSICompletionProc((ProcPtr)PaMac_InputCompletionProc);
+#endif
+ pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumInputChannels * sizeof(int16);
+ for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
+ {
+ char *buf = (char *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer);
+ if ( buf == NULL )
+ {
+ ERR_RPT(("PaHost_OpenStream: could not allocate input buffer. Size = \n", pahsc->pahsc_BytesPerInputHostBuffer ));
+ goto memerror;
+ }
+ pahsc->pahsc_InputMultiBuffer.buffers[i] = buf;
+ }
+ pahsc->pahsc_InputMultiBuffer.numBuffers = pahsc->pahsc_NumHostBuffers;
+
+ err = SPBOpenDevice( (const unsigned char *) &noname, siWritePermission, &mRefNum); /* FIXME - use name so we get selected device */
+ // FIXME err = SPBOpenDevice( (const unsigned char *) sDevices[past->past_InputDeviceID].pad_Info.name, siWritePermission, &mRefNum);
+ if (err) goto error;
+ pahsc->pahsc_InputRefNum = mRefNum;
+ DBUG(("PaHost_OpenStream: mRefNum = %d\n", mRefNum ));
+
+ /* Set input device characteristics. */
+ tempS = 1;
+ err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS);
+ if (err)
+ {
+ ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siContinuous returned %d\n", err ));
+ goto error;
+ }
+
+ tempL = 0x03;
+ err = SPBSetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL);
+ if (err)
+ {
+ DBUG(("PaHost_OpenStream: setting siActiveChannels returned 0x%x. Error ignored.\n", err ));
+ }
+
+ /* PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. */
+ tempS = past->past_NumInputChannels;
+ err = SPBSetDeviceInfo(mRefNum, siNumberChannels, (Ptr) &tempS);
+ if (err)
+ {
+ ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siNumberChannels returned %d\n", err ));
+ goto error;
+ }
+
+ tempF = ((unsigned long)past->past_SampleRate) << 16;
+ err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF);
+ if (err)
+ {
+ ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siSampleRate returned %d\n", err ));
+ goto error;
+ }
+
+ /* Setup record-parameter block */
+ pahsc->pahsc_InputParams.inRefNum = mRefNum;
+ pahsc->pahsc_InputParams.milliseconds = 0; // not used
+ pahsc->pahsc_InputParams.completionRoutine = pahsc->pahsc_InputCompletionProc;
+ pahsc->pahsc_InputParams.interruptRoutine = 0;
+ pahsc->pahsc_InputParams.userLong = (long) past;
+ pahsc->pahsc_InputParams.unused1 = 0;
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ DBUG(("PaHost_OpenStream: complete.\n"));
+ return paNoError;
+
+error:
+ PaHost_CloseStream( past );
+ ERR_RPT(("PaHost_OpenStream: sPaHostError = 0x%x.\n", err ));
+ sPaHostError = err;
+ return paHostError;
+
+memerror:
+ PaHost_CloseStream( past );
+ return paInsufficientMemory;
+}
+
+/***********************************************************************
+** Called by Pa_CloseStream().
+** May be called during error recovery or cleanup code
+** so protect against NULL pointers.
+*/
+PaError PaHost_CloseStream( internalPortAudioStream *past )
+{
+ PaError result = paNoError;
+ OSErr err = 0;
+ int i;
+ PaHostSoundControl *pahsc;
+
+ DBUG(("PaHost_CloseStream( 0x%x )\n", past ));
+
+ if( past == NULL ) return paBadStreamPtr;
+
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ /* TRUE means flush now instead of waiting for quietCmd to be processed. */
+ if( pahsc->pahsc_Channel != NULL ) SndDisposeChannel(pahsc->pahsc_Channel, TRUE);
+ {
+ for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
+ {
+ Ptr p = (Ptr) pahsc->pahsc_SoundHeaders[i].samplePtr;
+ if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerOutputHostBuffer );
+ }
+ }
+ }
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ if( pahsc->pahsc_InputRefNum )
+ {
+ err = SPBCloseDevice(pahsc->pahsc_InputRefNum);
+ pahsc->pahsc_InputRefNum = 0;
+ if( err )
+ {
+ sPaHostError = err;
+ result = paHostError;
+ }
+ }
+ {
+ for (i = 0; i<pahsc->pahsc_InputMultiBuffer.numBuffers; i++)
+ {
+ Ptr p = (Ptr) pahsc->pahsc_InputMultiBuffer.buffers[i];
+ if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerInputHostBuffer );
+ }
+ }
+ }
+
+ past->past_DeviceData = NULL;
+ PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) );
+
+ DBUG(("PaHost_CloseStream: complete.\n", past ));
+ return result;
+}
+/*************************************************************************/
+int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate )
+{
+/* We use the MAC_VIRTUAL_FRAMES_PER_BUFFER because we might be recording.
+** This routine doesn't have enough information to determine the best value
+** and is being depracated. */
+ return PaMac_GetMinNumBuffers( MAC_VIRTUAL_FRAMES_PER_BUFFER, framesPerUserBuffer, sampleRate );
+}
+/*************************************************************************/
+static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerUserBuffer, double sampleRate )
+{
+ int minUserPerHost = ( minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer;
+ int numBufs = PA_MIN_NUM_HOST_BUFFERS * minUserPerHost;
+ if( numBufs < PA_MIN_NUM_HOST_BUFFERS ) numBufs = PA_MIN_NUM_HOST_BUFFERS;
+ (void) sampleRate;
+ return numBufs;
+}
+
+/*************************************************************************/
+void Pa_Sleep( int32 msec )
+{
+ EventRecord event;
+ int32 sleepTime, endTime;
+ /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */
+ sleepTime = ((msec * 60) + 999) / 1000;
+ if( sleepTime < 1 ) sleepTime = 1;
+ endTime = TickCount() + sleepTime;
+ do
+ {
+ DBUGX(("Sleep for %d ticks.\n", sleepTime ));
+ /* Use WaitNextEvent() to sleep without getting events. */
+ /* PLB20010907 - Pass unused event to WaitNextEvent instead of NULL to prevent
+ * Mac OSX crash. Thanks Dominic Mazzoni. */
+ WaitNextEvent( 0, &event, sleepTime, NULL );
+ sleepTime = endTime - TickCount();
+ }
+ while( sleepTime > 0 );
+}
+/*************************************************************************/
+int32 Pa_GetHostError( void )
+{
+ int32 err = sPaHostError;
+ sPaHostError = 0;
+ return err;
+}
+
+/*************************************************************************
+ * Allocate memory that can be accessed in real-time.
+ * This may need to be held in physical memory so that it is not
+ * paged to virtual memory.
+ * This call MUST be balanced with a call to PaHost_FreeFastMemory().
+ */
+void *PaHost_AllocateFastMemory( long numBytes )
+{
+ void *addr = NewPtrClear( numBytes );
+ if( (addr == NULL) || (MemError () != 0) ) return NULL;
+
+#if (TARGET_API_MAC_CARBON == 0)
+ if( HoldMemory( addr, numBytes ) != noErr )
+ {
+ DisposePtr( (Ptr) addr );
+ return NULL;
+ }
+#endif
+ return addr;
+}
+
+/*************************************************************************
+ * Free memory that could be accessed in real-time.
+ * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
+ */
+void PaHost_FreeFastMemory( void *addr, long numBytes )
+{
+ if( addr == NULL ) return;
+#if TARGET_API_MAC_CARBON
+ (void) numBytes;
+#else
+ UnholdMemory( addr, numBytes );
+#endif
+ DisposePtr( (Ptr) addr );
+}
+
+/*************************************************************************/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ PaTimestamp framesDone1;
+ PaTimestamp framesDone2;
+ UInt64 whenIncremented;
+ UnsignedWide now;
+ UInt64 now64;
+ long microsElapsed;
+ long framesElapsed;
+
+ PaHostSoundControl *pahsc;
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+/* Capture information from audio thread.
+ * We have to be careful that we don't get interrupted in the middle.
+ * So we grab the pahsc_NumFramesDone twice and make sure it didn't change.
+ */
+ do
+ {
+ framesDone1 = pahsc->pahsc_NumFramesDone;
+ whenIncremented = pahsc->pahsc_WhenFramesDoneIncremented;
+ framesDone2 = pahsc->pahsc_NumFramesDone;
+ } while( framesDone1 != framesDone2 );
+
+ /* Calculate how many microseconds have elapsed and convert to frames. */
+ Microseconds( &now );
+ now64 = UnsignedWideToUInt64( now );
+ microsElapsed = U64Subtract( now64, whenIncremented );
+ framesElapsed = microsElapsed * past->past_SampleRate * 0.000001;
+
+ return framesDone1 + framesElapsed;
+}
+
+/**************************************************************************
+** Callback for Input, SPBRecord()
+*/
+int gRecordCounter = 0;
+int gPlayCounter = 0;
+pascal void PaMac_InputCompletionProc(SPBPtr recParams)
+{
+ PaError result = paNoError;
+ int finished = 1;
+ internalPortAudioStream *past;
+ PaHostSoundControl *pahsc;
+
+ gRecordCounter += 1; /* debug hack to see if engine running */
+
+ /* Get our PA data from Mac structure. */
+ past = (internalPortAudioStream *) recParams->userLong;
+ if( past == NULL ) return;
+
+ if( past->past_Magic != PA_MAGIC )
+ {
+ AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, past", (long) past );
+ AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, magic", (long) past->past_Magic );
+ goto error;
+ }
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ past->past_NumCallbacks += 1;
+
+ /* Have we been asked to stop recording? */
+ if( (recParams->error == abortErr) || pahsc->pahsc_StopRecording ) goto error;
+
+ /* If there are no output channels, then we need to call the user callback function from here.
+ * Otherwise we will call the user code during the output completion routine.
+ */
+ if(past->past_NumOutputChannels == 0)
+ {
+ SetFramesDone( pahsc,
+ pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
+ result = PaMac_CallUserLoop( past, NULL );
+ }
+
+ /* Did user code ask us to stop? If not, issue another recording request. */
+ if( (result == paNoError) && (pahsc->pahsc_StopRecording == 0) )
+ {
+ result = PaMac_RecordNext( past );
+ if( result != paNoError ) pahsc->pahsc_IsRecording = 0;
+ }
+ else goto error;
+
+ return;
+
+error:
+ pahsc->pahsc_IsRecording = 0;
+ pahsc->pahsc_StopRecording = 0;
+ return;
+}
+
+/***********************************************************************
+** Called by either input or output completion proc.
+** Grabs input data if any present, and calls PA conversion code,
+** that in turn calls user code.
+*/
+static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr )
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ int16 *inPtr = NULL;
+ int i;
+
+
+ /* Advance read index for sound input FIFO here, independantly of record/write process. */
+ if(past->past_NumInputChannels > 0)
+ {
+ if( MultiBuffer_IsReadable( &pahsc->pahsc_InputMultiBuffer ) )
+ {
+ inPtr = (int16 *) MultiBuffer_GetNextReadBuffer( &pahsc->pahsc_InputMultiBuffer );
+ MultiBuffer_AdvanceReadIndex( &pahsc->pahsc_InputMultiBuffer );
+ }
+ }
+
+ /* Call user code enough times to fill buffer. */
+ if( (inPtr != NULL) || (outPtr != NULL) )
+ {
+ PaMac_StartLoadCalculation( past ); /* CPU usage */
+
+#ifdef PA_MAX_USAGE_ALLOWED
+ /* If CPU usage exceeds limit, skip user callback to prevent hanging CPU. */
+ if( past->past_Usage > PA_MAX_USAGE_ALLOWED )
+ {
+ past->past_FrameCount += (PaTimestamp) pahsc->pahsc_FramesPerHostBuffer;
+ }
+ else
+#endif
+ {
+
+ for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
+ {
+ result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr );
+ if( result != 0)
+ {
+ /* Recording might be in another process, so tell it to stop with a flag. */
+ pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording;
+ break;
+ }
+ /* Advance sample pointers. */
+ if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels;
+ if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
+ }
+ }
+
+ PaMac_EndLoadCalculation( past );
+ }
+ return result;
+}
+
+/***********************************************************************
+** Setup next recording buffer in FIFO and issue recording request to Snd Input Manager.
+*/
+static PaError PaMac_RecordNext( internalPortAudioStream *past )
+{
+ PaError result = paNoError;
+ OSErr err;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ /* Get pointer to next buffer to record into. */
+ pahsc->pahsc_InputParams.bufferPtr = MultiBuffer_GetNextWriteBuffer( &pahsc->pahsc_InputMultiBuffer );
+
+ /* Advance write index if there is room. Otherwise keep writing same buffer. */
+ if( MultiBuffer_IsWriteable( &pahsc->pahsc_InputMultiBuffer ) )
+ {
+ MultiBuffer_AdvanceWriteIndex( &pahsc->pahsc_InputMultiBuffer );
+ }
+
+ AddTraceMessage("PaMac_RecordNext: bufferPtr", (long) pahsc->pahsc_InputParams.bufferPtr );
+ AddTraceMessage("PaMac_RecordNext: nextWrite", pahsc->pahsc_InputMultiBuffer.nextWrite );
+
+ /* Setup parameters and issue an asynchronous recording request. */
+ pahsc->pahsc_InputParams.bufferLength = pahsc->pahsc_BytesPerInputHostBuffer;
+ pahsc->pahsc_InputParams.count = pahsc->pahsc_BytesPerInputHostBuffer;
+ err = SPBRecord(&pahsc->pahsc_InputParams, true);
+ if( err )
+ {
+ AddTraceMessage("PaMac_RecordNext: SPBRecord error ", err );
+ sPaHostError = err;
+ result = paHostError;
+ }
+ else
+ {
+ pahsc->pahsc_IsRecording = 1;
+ }
+ return result;
+}
+
+/**************************************************************************
+** Callback for Output Playback()
+** Return negative error, 0 to continue, 1 to stop.
+*/
+long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index )
+{
+ PaHostSoundControl *pahsc;
+ long result = 0;
+ int finished = 1;
+ char *outPtr;
+
+ gPlayCounter += 1; /* debug hack */
+
+ past->past_NumCallbacks += 1;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return -1;
+ /* Are we nested?! */
+ if( pahsc->pahsc_IfInsideCallback ) return 0;
+ pahsc->pahsc_IfInsideCallback = 1;
+ /* Get pointer to buffer to fill. */
+ outPtr = pahsc->pahsc_SoundHeaders[index].samplePtr;
+ /* Combine with any sound input, and call user callback. */
+ result = PaMac_CallUserLoop( past, (int16 *) outPtr );
+
+ pahsc->pahsc_IfInsideCallback = 0;
+ return result;
+}
+
+/*************************************************************************************
+** Called by SoundManager when ready for another buffer.
+*/
+static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd)
+{
+ internalPortAudioStream *past;
+ PaHostSoundControl *pahsc;
+ (void) theChannel;
+ (void) theCallBackCmd;
+
+ /* Get our data from Mac structure. */
+ past = (internalPortAudioStream *) theCallBackCmd->param2;
+ if( past == NULL ) return;
+
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ pahsc->pahsc_NumOutsPlayed += 1;
+
+ SetFramesDone( pahsc,
+ pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
+
+ PaMac_BackgroundManager( past, theCallBackCmd->param1 );
+}
+
+/*******************************************************************/
+static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index )
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ /* Has someone asked us to abort by calling Pa_AbortStream()? */
+ if( past->past_StopNow )
+ {
+ SndCommand command;
+ /* Clear the queue of any pending commands. */
+ command.cmd = flushCmd;
+ command.param1 = command.param2 = 0;
+ SndDoImmediate( pahsc->pahsc_Channel, &command );
+ /* Then stop currently playing buffer, if any. */
+ command.cmd = quietCmd;
+ SndDoImmediate( pahsc->pahsc_Channel, &command );
+ past->past_IsActive = 0;
+ }
+ /* Has someone asked us to stop by calling Pa_StopStream()
+ * OR has a user callback returned '1' to indicate finished.
+ */
+ else if( past->past_StopSoon )
+ {
+ if( (pahsc->pahsc_NumOutsQueued - pahsc->pahsc_NumOutsPlayed) <= 0 )
+ {
+ past->past_IsActive = 0; /* We're finally done. */
+ }
+ }
+ else
+ {
+ PaMac_PlayNext( past, index );
+ }
+ return result;
+}
+
+/*************************************************************************************
+** Fill next buffer with sound and queue it for playback.
+*/
+static void PaMac_PlayNext ( internalPortAudioStream *past, int index )
+{
+ OSErr error;
+ long result;
+ SndCommand playCmd;
+ SndCommand callbackCmd;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ /* If this was the last buffer, or abort requested, then just be done. */
+ if ( past->past_StopSoon ) goto done;
+
+ /* Load buffer with sound. */
+ result = PaMac_FillNextOutputBuffer ( past, index );
+ if( result > 0 ) past->past_StopSoon = 1; /* Stop generating audio but wait until buffers play. */
+ else if( result < 0 ) goto done;
+
+ /* Play the next buffer. */
+ playCmd.cmd = bufferCmd;
+ playCmd.param1 = 0;
+ playCmd.param2 = (long) &pahsc->pahsc_SoundHeaders[ index ];
+ error = SndDoCommand (pahsc->pahsc_Channel, &playCmd, true );
+ if( error != noErr ) goto gotError;
+
+ /* Ask for a callback when it is done. */
+ callbackCmd.cmd = callBackCmd;
+ callbackCmd.param1 = index;
+ callbackCmd.param2 = (long)past;
+ error = SndDoCommand (pahsc->pahsc_Channel, &callbackCmd, true );
+ if( error != noErr ) goto gotError;
+ pahsc->pahsc_NumOutsQueued += 1;
+
+ return;
+
+gotError:
+ sPaHostError = error;
+done:
+ return;
+}
diff --git a/pd/portaudio/pa_sgi/Makefile b/pd/portaudio/pa_sgi/Makefile
new file mode 100644
index 00000000..6548c6c5
--- /dev/null
+++ b/pd/portaudio/pa_sgi/Makefile
@@ -0,0 +1,51 @@
+# Make PortAudio for Silicon Graphics IRIX (6.2)
+# Pieter suurmond, september 23, 2001. (pa_sgi sub-version #0.21 for PA v15.)
+# Based on SGI-specific sproc()-method to spawn children, not on POSIX-threads.
+
+# Instead of "-lpthread", as with linux,
+# just the audio- and math-library for SGI:
+LIBS = -laudio -lm
+
+CDEFINES = -I../pa_common
+
+# Possible CFLAGS with MIPSpro compiler are: -32, -o32, -n32, -64,
+# -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging.
+# And use for example -O2 or -O3 for better optimization:
+CFLAGS = -O2
+PASRC = ../pa_common/pa_lib.c pa_sgi.c
+PAINC = ../pa_common/portaudio.h
+
+# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2).
+TESTC = $(PASRC) ../pa_tests/patest_record.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_saw.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK
+#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore.
+
+# Tests that were not yet performed.
+#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # test??
+#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # test??
+#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # test??
+
+TESTH = $(PAINC)
+
+all: patest
+
+# "cc" for the MIPSpro compiler, may be changed to "gcc":
+patest: $(TESTC) $(TESTH) Makefile
+ cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest
+
+run: patest
+ ./patest
+
diff --git a/pd/portaudio/pa_sgi/pa_sgi.c b/pd/portaudio/pa_sgi/pa_sgi.c
new file mode 100644
index 00000000..4b91f02c
--- /dev/null
+++ b/pd/portaudio/pa_sgi/pa_sgi.c
@@ -0,0 +1,999 @@
+/*
+ * $Id: pa_sgi.c,v 1.2 2002/05/04 20:38:42 philburk Exp $
+ * PortAudio Portable Real-Time Audio Library. Copyright (c) 1999-2001 Phil Burk.
+ * Latest Version at: http://www.portaudio.com
+ *
+ * Silicon Graphics IRIX implementation by Pieter Suurmond, september 23, 2001.
+ * pa_sgi-sub-version number 0.21, for PortAudio v15.
+ * This implementation uses the sproc()-method, not the POSIX method.
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+Modfication History:
+ 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2.
+ 8/17/2001 - v15 pa_sgi sub-version #0.04 (unstable alpha release) Sent to Phil & Ross.
+ 9/23/2001 - #0.21 Many fixes and changes: POLLIN for input, not POLLOUT.
+ Open and close ALports in the audio-process-thread.
+ Proper semaphore communication now.
+ Hopefully stable enough now (for beta release?).
+TODO:
+ - Test under IRIX 6.5.
+ - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion),
+ and maybe also the other natively supported formats? (might increase performance)
+ - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4.
+REFERENCES:
+ - IRIX 6.2 man pages regarding SGI AL library.
+ - IRIS Digital MediaProgramming Guide (online books and man-pages come
+ with IRIX 6.2 and may not be publically available on the internet).
+*/
+
+#include <stdio.h> /* Standard libraries. */
+#include <stdlib.h>
+
+#include "../pa_common/portaudio.h" /* BETTER PATH !!!???? Portaudio headers. */
+#include "../pa_common/pa_host.h"
+#include "../pa_common/pa_trace.h"
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+#include <sys/schedctl.h> /* For schedctl(NDPRI, NDPHIMIN). */
+#include <fcntl.h> /* fcntl.h needed. */
+#include <unistd.h> /* For streams, ioctl(), etc. */
+#include <ulocks.h>
+#include <poll.h>
+#include <dmedia/audio.h> /* System specific (IRIX 6.2). */
+
+/*--------------------------------------------*/
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */
+#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */
+
+typedef struct internalPortAudioDevice /* IRIX specific device info: */
+{
+ PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */
+ long pad_ALdevice; /* SGI-number! */
+ double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */
+ char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */
+ PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */
+ /* int structVersion; */
+ /* const char* name; */
+ /* int maxInputChannels, maxOutputChannels; */
+ /* int numSampleRates; Num rates, or -1 if range supprtd. */
+ /* const double* sampleRates; Array of supported sample rates, */
+ /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */
+ struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */
+} internalPortAudioDevice;
+
+typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */
+{
+ ALconfig pahsc_ALconfigIN, /* IRIX-audio-library-datatype. Configuration */
+ pahsc_ALconfigOUT; /* stucts separate for input and output ports. */
+ ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */
+ pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */
+ int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */
+ short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */
+ *pahsc_NativeOutputBuffer;
+ unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */
+ pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */
+ unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */
+ pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */
+ struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */
+ pahsc_LastExitTime;
+ long pahsc_InsideCountSum,
+ pahsc_TotalCountSum;
+} PaHostSoundControl;
+
+/*-------------------------------------------------------- Shared Data -------------------------------*/
+static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */
+static int sPaHostError = 0; /* Maybe more than one process writing errs!? */
+usema_t *SendSema, /* These variables are shared between the */
+ *RcvSema; /* audio handling process and main process. */
+/*--------------------------*/
+long Pa_GetHostError(void)
+{
+ return (long)sPaHostError;
+}
+
+/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/
+/* (copied from source pa_linux_oss/pa_linux_oss.c) */
+static void Pa_StartUsageCalculation( internalPortAudioStream *past )
+{
+ struct itimerval itimer;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+/* Query system timer for usage analysis and to prevent overuse of CPU. */
+ getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime );
+}
+
+static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB )
+{
+ long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec;
+ long usecs = secs * 1000000;
+ usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec);
+ return usecs;
+}
+
+static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+{
+ struct itimerval currentTime;
+ long insideCount;
+ long totalCount; /* Measure CPU utilization during this callback. */
+
+#define LOWPASS_COEFFICIENT_0 (0.95)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (pahsc == NULL)
+ return;
+ if (getitimer( ITIMER_REAL, &currentTime ) == 0 )
+ {
+ if (past->past_IfLastExitValid)
+ {
+ insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, &currentTime );
+ pahsc->pahsc_InsideCountSum += insideCount;
+ totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, &currentTime );
+ pahsc->pahsc_TotalCountSum += totalCount;
+ /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */
+ /* Low pass filter the result because sometimes we get called several times in a row. */
+ /* That can cause the TotalCount to be very low which can cause the usage to appear */
+ /* unnaturally high. So we must filter numerator and denominator separately!!! */
+ if (pahsc->pahsc_InsideCountSum > 0)
+ {
+ past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
+ (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum));
+ past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
+ (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum));
+ past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
+ pahsc->pahsc_InsideCountSum = 0;
+ pahsc->pahsc_TotalCountSum = 0;
+ }
+ }
+ past->past_IfLastExitValid = 1;
+ }
+ pahsc->pahsc_LastExitTime.it_value.tv_sec = 100;
+ pahsc->pahsc_LastExitTime.it_value.tv_usec = 0;
+ setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL );
+ past->past_IfLastExitValid = 1;
+} /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/
+
+
+/*--------------------------------------------------------------------------------------*/
+PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */
+{ /* call to report via ERR_RPT(), yields a PaError-num. */
+ const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */
+ switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */
+ {
+ case AL_BAD_OUT_OF_MEM:
+ ERR_RPT(("%sout of memory.\n", a));
+ return paInsufficientMemory; /* Known PaError. */
+ case AL_BAD_CONFIG:
+ ERR_RPT(("%sconfiguration invalid or NULL.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_CHANNELS:
+ ERR_RPT(("%schannels not 1,2 or 4.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_NO_PORTS:
+ ERR_RPT(("%sout of audio ports.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DEVICE:
+ ERR_RPT(("%swrong device number.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DEVICE_ACCESS:
+ ERR_RPT(("%swrong device access.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DIRECTION:
+ ERR_RPT(("%sinvalid direction.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_SAMPFMT:
+ ERR_RPT(("%sdoesn't accept sampleformat.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_FLOATMAX:
+ ERR_RPT(("%smax float value is zero.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_WIDTH:
+ ERR_RPT(("%sunsupported samplewidth.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_QSIZE:
+ ERR_RPT(("%sinvalid queue size.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_PVBUFFER:
+ ERR_RPT(("%sPVbuffer null.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_BUFFERLENGTH_NEG:
+ ERR_RPT(("%snegative bufferlength.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_BUFFERLENGTH_ODD:
+ ERR_RPT(("%sodd bufferlength.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_PARAM:
+ ERR_RPT(("%sparameter not valid for device.\n", a));
+ return paHostError; /* Generic PaError. */
+ default:
+ ERR_RPT(("%sunknown error.\n", a));
+ return paHostError; /* Generic PaError. */
+ }
+}
+
+/*------------------------------------------------------------------------------------------*/
+/* Tries to set various rates and formats and fill in the device info structure. */
+static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */
+ PaDeviceID id, /* (DefaultI|ODeviceID()) */
+ char* name, /* (for example "SGI AL") */
+ internalPortAudioDevice* pad) /* Result written to pad. */
+{
+ int format;
+ long min, max; /* To catch hardware characteristics. */
+ ALseterrorhandler(0); /* 0 = turn off the default error handler. */
+ /*--------------------------------------------------------------------------------------*/
+ pad->pad_ALdevice = ALdev; /* Set the AL device number. */
+ pad->pad_DeviceID = id; /* Set the PA device number. */
+ if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */
+ {
+ ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name));
+ return paHostError;
+ }
+ strcpy(pad->pad_DeviceName, name); /* Write name-string. */
+ pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */
+ /*--------------------------------- natively supported sample formats: -----------------*/
+ pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */
+ /* Then also choose other CallConvertXX()! */
+ /*--------------------------------- number of available i/o channels: ------------------*/
+ if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max))
+ return translateSGIerror();
+ pad->pad_Info.maxInputChannels = max;
+ DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels))
+ if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max))
+ return translateSGIerror();
+ pad->pad_Info.maxOutputChannels = max;
+ DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels))
+ /*--------------------------------- supported samplerates: ----------------------*/
+ pad->pad_Info.numSampleRates = 7;
+ pad->pad_Info.sampleRates = pad->pad_SampleRates;
+ pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */
+ pad->pad_SampleRates[1] = (double)AL_RATE_11025;
+ pad->pad_SampleRates[2] = (double)AL_RATE_16000;
+ pad->pad_SampleRates[3] = (double)AL_RATE_22050;
+ pad->pad_SampleRates[4] = (double)AL_RATE_32000;
+ pad->pad_SampleRates[5] = (double)AL_RATE_44100;
+ pad->pad_SampleRates[6] = (double)AL_RATE_48000;
+ if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */
+ return translateSGIerror(); /* double -> long. */
+ if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */
+ goto weird;
+ if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */
+ return translateSGIerror();
+ if (max != (long)(0.5 + pad->pad_SampleRates[6]))
+ {
+weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max));
+ return paHostError; /* Or make it a warning and just carry on... */
+ }
+ /*-------------------------------------------------------------------------------*/
+ return paNoError;
+}
+
+
+/*--------------------------------------------------------------------------------*/
+int Pa_CountDevices() /* Name of this function suggests it only counts and */
+{ /* is NOT destructive, it however resets whole PA ! */
+ int numDevices = 0; /* Let 's not do that here. */
+ internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */
+#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */
+ if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */
+ Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */
+#endif /* friendly to clients that forgot to initialize PA. */
+ while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */
+ {
+ numDevices++;
+ currentDevice = currentDevice->pad_Next;
+ }
+ return numDevices;
+}
+
+/*-------------------------------------------------------------------------------*/
+static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id)
+{
+ int numDevices = 0;
+ internalPortAudioDevice *res = (internalPortAudioDevice*)NULL;
+ internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */
+ while (pad) /* pad may be NULL, that's ok, return 0. */
+ { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */
+ if (pad->pad_DeviceID == id) /* This the device we were looking for? */
+ res = pad; /* But keep on(!) counting so we don't */
+ numDevices++; /* have to call Pa_CountDevices() later. */
+ pad = pad->pad_Next; /* Advance to the next device or NULL. */
+ } /* No assumptions about order of ID's in */
+ if (!res) /* the list. */
+ ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id));
+ if ((id < 0) || (id >= numDevices))
+ {
+ ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id));
+#if 1 /* Be strict, even when found, */
+ res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */
+#endif
+ }
+ return res;
+}
+
+/*----------------------------------------------------------------------*/
+const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id)
+{
+ PaDeviceInfo* res = (PaDeviceInfo*)NULL;
+ internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */
+ if (pad)
+ res = &pad->pad_Info; /* Not finding the specified ID is not */
+ if (!res) /* the same as &pad->pad_Info == NULL. */
+ ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id));
+ return res; /* So (maybe) a second/third ERR_RPT(). */
+}
+
+/*------------------------------------------------*/
+PaDeviceID Pa_GetDefaultInputDeviceID(void)
+{
+ return 0; /* 0 is the default device ID. */
+}
+/*------------------------------------------------*/
+PaDeviceID Pa_GetDefaultOutputDeviceID(void)
+{
+ return 0;
+}
+
+/*-------------------------------------------------------------------------------------------------*/
+/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */
+PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */
+{
+ internalPortAudioDevice* pad;
+ PaError r = paNoError;
+ int audioLibFileID; /* To test for the presence of audio. */
+
+ if (sDeviceList) /* Allow re-init, only warn, no error. */
+ {
+ ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n"));
+ return r;
+ }
+ /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/
+ audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */
+ if (audioLibFileID < 0) /* IO port. On failure, machine */
+ { /* has no audio ability. */
+ ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n"));
+ return paHostError;
+ }
+ close(audioLibFileID); /* Allocate fast mem to hold device info. */
+ pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice));
+ if (pad == NULL)
+ return paInsufficientMemory;
+ memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */
+ r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */
+ Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */
+ "AL default", /* A suitable name. */
+ pad); /* Write args and queried info into pad. */
+ if (r != paNoError)
+ {
+ ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r));
+ PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */
+ }
+ else
+ sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */
+ /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/
+ /*---------------------------------------------------------------------------------------------*/
+ return r;
+}
+
+/*--------------------------------------------------------------------------------------------*/
+#define MIN(a,b) ((a)<(b)?(a):(b)) /* MIN()-function is used below. */
+#define kPollSEMA 0 /* To index the pollfd-array, reads nicer than just */
+#define kPollOUT 1 /* numbers. */
+#define kPollIN 2
+void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_StartEngine() */
+{ /* as a separate thread. (Argument must be void*). */
+ short evtLoop; /* Reset by parent indirectly, or at local errors. */
+ PaError result;
+ struct pollfd PollFD[3]; /* To catch kPollSEMA-, kPollOUT- and kPollIN-events. */
+ internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument.*/
+ PaHostSoundControl *pahsc;
+ short inputEvent, outputEvent, /* .revents members are of type short. */
+ semaEvent = 0;
+ DBUG(("Entering sproc-thread.\n"));
+ if (!past)
+ {
+ sPaHostError = paInternalError; /* Or paBadStreamPtr ? */
+ ERR_RPT(("argument NULL!\n"));
+ goto skip;
+ }
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (!pahsc)
+ {
+ sPaHostError = paInternalError; /* The only way is to signal error to shared area?! */
+ ERR_RPT(("past_DeviceData NULL!\n"));
+ goto skip; /* Sproc-ed threads MAY NOT RETURN paInternalError. */
+ }
+ /*----------------------------- open AL-ports here, after sproc(): -----------------------*/
+ if (past->past_NumInputChannels > 0) /* Open input port. */
+ {
+ pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", pahsc->pahsc_ALconfigIN);
+ if (!pahsc->pahsc_ALportIN)
+ {
+ ERR_RPT(("Failed to open AL input port.\n"));
+ sPaHostError = paInternalError;
+ goto skip;
+ }
+ DBUG(("Opened %d input channel(s).\n", past->past_NumInputChannels));
+ }
+ if (past->past_NumOutputChannels > 0) /* Open output port. */
+ {
+ pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", pahsc->pahsc_ALconfigOUT);
+ if (!pahsc->pahsc_ALportOUT)
+ {
+ ERR_RPT(("Failed to open AL output port.\n"));
+ sPaHostError = paInternalError; /* Assume pahsc_ALconfigs are the */
+ goto skip; /* same for IN and OUT in case */
+ } /* both ports are opened (bidir). */
+ DBUG(("Opened %d output channel(s).\n", past->past_NumOutputChannels));
+ }
+ /*-----------------------------------------------------------------------*/
+ past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */
+ PollFD[kPollIN].fd = ALgetfd(pahsc->pahsc_ALportIN); /* ALgetfd returns -1 on failures */
+ PollFD[kPollIN].events = POLLIN; /* such as ALport not there. */
+ PollFD[kPollOUT].fd = ALgetfd(pahsc->pahsc_ALportOUT);
+ PollFD[kPollOUT].events = POLLOUT; /* .events = POLLOUT is OK. */
+ schedctl(NDPRI, NDPHIMIN); /* Sets non-degrading priority for this process. */
+ PollFD[kPollSEMA].fd = usopenpollsema(SendSema, 0777); /* To communicate with parent. */
+ PollFD[kPollSEMA].events = POLLIN; /* .events = POLLIN is OK. */
+ uspsema(SendSema); /* Blocks until ... MUST be here, this uspsema(). */
+ evtLoop = ((past->past_StopNow | past->past_StopSoon) == 0);
+ while (evtLoop)
+ {
+ /*---------------------------- SET FILLPOINTS AND WAIT UNTIL SOMETHING HAPPENS: ----------*/
+ if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */
+ /* For input port, fill point is number of locations in the sample queue that must be */
+ /* filled in order to trigger a return from select(). (or poll()) */
+ /* Notice IRIX docs mention number of samples as argument, not number of sampleframes.*/
+ if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputBuffer))
+ { /* Same amount as transferred per time. */
+ ERR_RPT(("ALsetfillpoint() for ALportIN failed.\n"));
+ sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */
+ goto skip;
+ }
+ if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */
+ /* For output port, fill point is number of locations that must be free in order to */
+ /* wake up from select(). (or poll()) */
+ if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputBuffer))
+ {
+ ERR_RPT(("ALsetfillpoint() for ALportOUT failed.\n"));
+ sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */
+ goto skip;
+ } /* poll() with timeout=-1 makes it block until a requested */
+ poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */
+ /* array <0, events is ignored and revents is set to 0. */
+ /*---------------------------- MESSAGE-EVENT FROM PARENT THREAD: -------------------------*/
+ semaEvent = PollFD[kPollSEMA].revents & POLLIN;
+ if (semaEvent)
+ {
+ if (past->past_StopSoon)
+ evtLoop = 0;
+ if (past->past_StopNow)
+ goto skip;
+ }
+ /*------------------------------------- FILLED-EVENT FROM INPUT BUFFER: --------------------------*/
+ inputEvent = PollFD[kPollIN].revents & POLLIN;
+ if (inputEvent) /* Don't need to check (pahsc->pahsc_NativeInputBuffer): */
+ { /* if buffer was not there, ALport not there, no events! */
+ if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer,
+ pahsc->pahsc_SamplesPerInputBuffer))
+ { /* Here again: number of samples instead of number of frames. */
+ ERR_RPT(("ALreadsamps() failed.\n"));
+ sPaHostError = paInternalError;
+ goto skip;
+ }
+ }
+ outputEvent = PollFD[kPollOUT].revents & POLLOUT;
+ /*------------------------------------- USER-CALLBACK-ROUTINE: -----------------------------------*/
+ if (inputEvent | outputEvent) /* (Bitwise is ok.) */
+ { /* To be sure we that really DID input-transfer or gonna DO output-transfer, and that it is */
+ /* not just "sema"- (i.e. user)-event, or some other system-event that awakened the poll(). */
+ Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */
+ result = Pa_CallConvertInt16(past, /* user data and call user routine. */
+ pahsc->pahsc_NativeInputBuffer,
+ pahsc->pahsc_NativeOutputBuffer);
+ Pa_EndUsageCalculation(past);
+ if (result)
+ {
+ DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result));
+ goto skip; /* This is apparently NOT an error! */
+ } /* Just letting the userCallBack stop us. */
+ }
+ /*------------------------------------- FREE-EVENT FROM OUTPUT BUFFER: ---------------------------*/
+ if (outputEvent) /* Don't need to check (pahsc->pahsc_NativeOutputBuffer) */
+ { /* because if filedescriptor not there, no event for it. */
+ if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer,
+ pahsc->pahsc_SamplesPerOutputBuffer))
+ {
+ ERR_RPT(("ALwritesamps() failed.\n")); /* Better use SEMAS for messaging back to parent! */
+ sPaHostError = paInternalError;
+ goto skip;
+ }
+ }
+ }
+skip:
+ /*------------------------------- close AL-ports ----------------------------*/
+ if (pahsc->pahsc_ALportIN)
+ {
+ if (ALcloseport(pahsc->pahsc_ALportIN))
+ translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
+ else /* But go on anyway... to release other stuff... */
+ pahsc->pahsc_ALportIN = (ALport)0;
+ }
+ if (pahsc->pahsc_ALportOUT)
+ {
+ if (ALcloseport(pahsc->pahsc_ALportOUT))
+ translateSGIerror();
+ else
+ pahsc->pahsc_ALportOUT = (ALport)0;
+ }
+ past->past_IsActive = 0;
+ if (semaEvent)
+ {
+ uspsema(SendSema); /* StopEngine() was still waiting for this acknowledgement. */
+ usvsema(RcvSema); /* (semaEvent initialized with 0.) */
+ }
+ DBUG(("Leaving sproc-thread.\n"));
+}
+
+
+#define kALinternalQueuesizeFact 4L /* Internal queue 4 times as large as transferSize. */
+ /* Used below, twice: for input and for output. */
+/*--------------------------------------------------------------------------------------*/
+PaError PaHost_OpenStream(internalPortAudioStream *past)
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+ unsigned int minNumBuffers;
+ internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */
+ long pvbuf[8]; /* To get/set hardware configs. */
+ long sr;
+ DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */
+ if (!past)
+ {
+ ERR_RPT(("Streampointer NULL!\n"));
+ result = paBadStreamPtr; goto done;
+ }
+ pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
+ if (pahsc == NULL)
+ {
+ ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */
+ result = paInsufficientMemory; goto done; /* code (nothing will be freed). */
+ }
+ memset(pahsc, 0, sizeof(PaHostSoundControl));
+ pahsc->pahsc_threadPID = -1; /* Should pahsc_threadPID be inited to */
+ past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */
+ /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/
+ ALseterrorhandler(0); /* 0 = turn off the default error handler. */
+ pvbuf[0] = AL_INPUT_RATE;
+ pvbuf[2] = AL_INPUT_COUNT;
+ pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */
+ pvbuf[6] = AL_OUTPUT_COUNT;
+ sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */
+ /*---------------------------------------------------- SET INPUT CONFIGURATION: ------------------------*/
+ if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */
+ { /* sponding native AL-number(s). */
+ /*--------------------------------------------------- Allocate native buffers: --------*/
+ pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */
+ past->past_NumInputChannels; /* audio-thread. */
+ pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short);
+ pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer);
+ if (!pahsc->pahsc_NativeInputBuffer)
+ {
+ ERR_RPT(("Fast memory allocation failed (in).\n"));
+ result = paInsufficientMemory;
+ goto done;
+ }
+ padIN = Pa_GetInternalDevice(past->past_InputDeviceID);
+ if (!padIN)
+ {
+ ERR_RPT(("Pa_GetInternalDevice() for input failed.\n"));
+ result = paHostError;
+ goto done;
+ }
+ if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */
+ goto sgiError; /* the same AL-device, the AL-library might */
+ if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */
+ { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */
+ if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */
+ {
+ ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \
+another process is currently using input at %ld kHz.\n", sr, pvbuf[1]));
+ result = paHostError;
+ goto done;
+ }
+ pvbuf[1] = sr; /* Then set input-rate. */
+ if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2))
+ goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */
+ } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */
+ pahsc->pahsc_ALconfigIN = ALnewconfig(); /* Released at PaHost_CloseStream(). */
+ if (pahsc->pahsc_ALconfigIN == (ALconfig)0)
+ goto sgiError;
+ if (ALsetsampfmt(pahsc->pahsc_ALconfigIN, AL_SAMPFMT_TWOSCOMP))/* Choose paInt16 as native i/o-format. */
+ goto sgiError;
+ if (ALsetwidth (pahsc->pahsc_ALconfigIN, AL_SAMPLE_16)) /* Only meaningful when sample format for */
+ goto sgiError; /* config is set to two's complement format. */
+ /************************ Future versions might (dynamically) switch to 32-bit floats? *******
+ if (ALsetsampfmt(pahsc_ALconfigIN, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.)
+ goto sgiError;
+ if (ALsetfloatmax (pahsc_ALconfigIN, 1.0)) Only meaningful when sample format for config
+ goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */
+ /*--------- Set internal AL queuesize (in samples) -------------------------------*/
+ if (ALsetqueuesize(pahsc->pahsc_ALconfigIN, (long)pahsc->pahsc_SamplesPerInputBuffer *
+ (long)kALinternalQueuesizeFact))
+ goto sgiError; /* Or should we use past_NumUserBuffers here? */
+ /* Do 4 timea, using 2 times may give glitches. */
+ if (ALsetchannels (pahsc->pahsc_ALconfigIN, (long)(past->past_NumInputChannels)))
+ goto sgiError; /* Returns 0 on success, -1 on failure. */
+ }
+ /*---------------------------------------------------- SET OUTPUT CONFIGURATION: ------------------------*/
+ if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */
+ { /* We use padOUT/IN later on, or at least 1 of both. */
+ pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */
+ past->past_NumOutputChannels; /* audio-thread. */
+ pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short);
+
+ pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer);
+ if (!pahsc->pahsc_NativeOutputBuffer)
+ {
+ ERR_RPT(("Fast memory allocation failed (out).\n"));
+ result = paInsufficientMemory;
+ goto done;
+ }
+ padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID);
+ if (!padOUT)
+ {
+ ERR_RPT(("Pa_GetInternalDevice() for output failed.\n"));
+ result = paHostError;
+ goto done;
+ }
+ if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4))
+ goto sgiError;
+ if (pvbuf[5] != sr)
+ { /* Output needed and rate different from current harware-rate. */
+ if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */
+ {
+ ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \
+another process is currently using output at %ld kHz.\n", sr, pvbuf[5]));
+ result = paHostError;
+ goto done; /* Will free again the inputbuffer */
+ } /* that was just created above. */
+ pvbuf[5] = sr; /* Then set output-rate. */
+ if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2))
+ goto sgiError;
+ }
+ pahsc->pahsc_ALconfigOUT = ALnewconfig(); /* Released at PaHost_CloseStream(). */
+ if (pahsc->pahsc_ALconfigOUT == (ALconfig)0)
+ goto sgiError;
+ if (ALsetsampfmt(pahsc->pahsc_ALconfigOUT, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */
+ goto sgiError;
+ if (ALsetwidth (pahsc->pahsc_ALconfigOUT, AL_SAMPLE_16)) /* Only meaningful when sample format for */
+ goto sgiError; /* config is set to two's complement format. */
+ /************************************ Future versions might (dynamically) switch to 32-bit floats? *******/
+ if (ALsetqueuesize(pahsc->pahsc_ALconfigOUT, (long)pahsc->pahsc_SamplesPerOutputBuffer *
+ (long)kALinternalQueuesizeFact))
+ goto sgiError; /* Or should we use past_NumUserBuffers here?*/
+ if (ALsetchannels (pahsc->pahsc_ALconfigOUT, (long)(past->past_NumOutputChannels)))
+ goto sgiError;
+ }
+ /*---------- ?? --------------------*/
+ /* DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); */
+ minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, past->past_SampleRate);
+ past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ?
+ minNumBuffers : past->past_NumUserBuffers; /* I don't yet use past_NumUserBuffers */
+ /*----------------------------------------------- TEST DEVICE ID's: --------------------*/
+ if ((past->past_OutputDeviceID != past->past_InputDeviceID) && /* Who SETS these devive-numbers? */
+ (past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0))
+ {
+ ERR_RPT(("Cannot setup bidirectional stream between different devices.\n"));
+ result = paHostError;
+ goto done;
+ }
+ goto done; /* (no errors occured) */
+sgiError:
+ result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
+done:
+ if (result != paNoError)
+ PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */
+ return result;
+}
+
+/*-----------------------------------------------------*/
+PaError PaHost_StartOutput(internalPortAudioStream *past)
+{
+ return paNoError; /* Hmm, not implemented yet? */
+}
+PaError PaHost_StartInput(internalPortAudioStream *past)
+{
+ return paNoError;
+}
+
+/*------------------------------------------------------------------------------*/
+PaError PaHost_StartEngine(internalPortAudioStream *past)
+{
+ PaHostSoundControl *pahsc;
+ usptr_t *arena;
+ if (!past) /* Test argument. */
+ {
+ ERR_RPT(("PaHost_StartEngine(NULL)!\n"));
+ return paBadStreamPtr;
+ }
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (!pahsc)
+ {
+ ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData = NULL!\n"));
+ return paHostError;
+ }
+ past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */
+ past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */
+ past->past_IsActive = 1;
+
+ /* Although the pthread_create() function, as well as <pthread.h>, may be */
+ /* available in IRIX, use sproc() on SGI to create audio-background-thread. */
+ /* (Linux/oss uses pthread_create() instead of __clone() because: */
+ /* - pthread_create also works for other UNIX systems like Solaris, */
+ /* - Java HotSpot VM crashes in pthread_setcanceltype() using __clone().) */
+
+ usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* (From SGI-AL-examples, file */
+ arena = usinit(tmpnam(0)); /* motifexample.c, function */
+ SendSema = usnewpollsema(arena, 0); /* InitializeAudioProcess().) */
+ RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process
+ will be permitted through a semaphore at a time. Values > 1
+ imply that up to val resources may be simultaneously used, but requests
+ for more than val resources cause the calling process to block until a
+ resource comes free (by a process holding a resource performing a
+ usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */
+ prctl(PR_SETEXITSIG, 0); /* No not (void*)9, but 0, which doesn't kill the parent! */
+ /* PR_SETEXITSIG controls whether all members of a share group will be
+ signaled if any one of them leaves the share group (either via exit()
+ or exec()). If 2nd arg, interpreted as an int is 0, then normal IRIX
+ process termination rules apply, namely that the parent is sent a
+ SIGCLD upon death of child, but no indication of death of parent is
+ given. If the second argument is a valid signal number then if any
+ member of a share group leaves the share group, a signal is
+ sent to ALL surviving members of the share group. */
+ /* SPAWN AUDIO-CHILD: */
+ pahsc->pahsc_threadPID = sproc(Pa_SgiAudioProcess, /* Returns process ID of */
+ PR_SALL, /* new process, or -1. */
+ (void*)past); /* Pass past as optional */ /* IS THIS SAFE, will past never */
+ if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ /* be moved around in memory???? */
+ {
+ ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n"));
+ sPaHostError = oserror(); /* Pass native error-number to shared area. */
+ return paHostError; /* But return the generic error-number. */
+ }
+ return paNoError; /* Hmmm, errno may come from other threads in same group! */
+} /* ("man sproc" in IRIX6.2 to read about _SGI_MP_SOURCE.) */
+
+/*------------------------------------------------------------------------------*/
+PaError PaHost_StopEngine(internalPortAudioStream *past, int abort)
+{
+ int hres;
+ long timeOut;
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+
+ DBUG(("PaHost_StopEngine() called.\n"));
+ if (!past)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ /* Prevent from doing this twice!! */
+ if ((!pahsc) || /* Some tests call this CLOSE twice!! */
+ (!past->past_IsActive) ||
+ past->past_StopSoon || past->past_StopNow)
+ return result; /* paNoError (already stopped, no err?). */
+ past->past_StopSoon = 1; /* Tell background thread to stop generating */
+ if (abort) /* more and to let current data play out. If */
+ past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */
+ /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/
+ usvsema(SendSema); /* Increments count associated with SendSema. */
+ /* Wait for the response. */
+ uspsema(RcvSema); /* Decrements count of previously allocated */
+ /* semaphore specified by RcvSema. */
+ while (past->past_IsActive) /* REALLY WAIT. */
+ {
+ /* DBUG(("wait 1 ms for audio-thread to stop.\n")); */
+ Pa_Sleep(1);
+ }
+
+#if 0 /* We don't need to KILL(), just COMMUNICATE and be patient... */
+ if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */
+ {
+ DBUG(("PaHost_StopEngine() is about to kill(SIGKILL) audio-thread.\n"));
+ if (kill(pahsc->pahsc_threadPID, SIGKILL)) /* Or SIGTERM or SIGQUIT(core) */
+ { /* Returns -1 in case of error. */
+ result = paHostError;
+ sPaHostError = oserror(); /* Hmmm, other threads may also write here! */
+ ERR_RPT(("PaHost_StopEngine() failed to kill audio-thread.\n"));
+ }
+ else
+ pahsc->pahsc_threadPID = -1; /* Notify that we've killed this thread. */
+ }
+#endif
+ past->past_IsActive = 0; /* Even when kill() failed and pahsc_threadPID still there??? */
+ return result;
+}
+
+/*---------------------------------------------------------------*/
+PaError PaHost_StopOutput(internalPortAudioStream *past, int abort)
+{
+ return paNoError; /* Not implemented yet? */
+}
+PaError PaHost_StopInput(internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+/*******************************************************************/
+PaError PaHost_CloseStream(internalPortAudioStream *past)
+{
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+
+ DBUG(("PaHost_CloseStream() called.\n"));
+ if (!past)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (!pahsc) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */
+ return result; /* This test prevents from freeing NULL-pointers. */
+
+ if (pahsc->pahsc_ALconfigIN)
+ { /* Release configuration structs, only if allocated. */
+ ALfreeconfig(pahsc->pahsc_ALconfigIN);
+ pahsc->pahsc_ALconfigIN = NULL;
+ }
+ if (pahsc->pahsc_ALconfigOUT)
+ {
+ ALfreeconfig(pahsc->pahsc_ALconfigOUT); /* (Al-ports were already closed by audioProcess). */
+ pahsc->pahsc_ALconfigOUT = NULL;
+ }
+ if (pahsc->pahsc_NativeInputBuffer)
+ {
+ PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer);
+ pahsc->pahsc_NativeInputBuffer = NULL;
+ }
+ if (pahsc->pahsc_NativeOutputBuffer)
+ {
+ PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer);
+ pahsc->pahsc_NativeOutputBuffer = NULL;
+ }
+ PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl));
+ past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST MEM. */
+ return result;
+}
+
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+** set PA_MIN_LATENCY_MSEC=200
+** in the AUTOEXEC.BAT file and reboot.
+** If the environment variable is not set, then the latency will be
+** determined based on the OS. Windows NT has higher latency than Win95.
+*/
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
+{
+ return 2;
+}
+/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */
+/* Do we HAVE to do it this way under IRIX???.... */
+/*--------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------*/
+PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */
+{ /* Called by Pa_Terminate() from pa_lib.c. */
+ internalPortAudioDevice *pad = sDeviceList,
+ *nxt;
+ while (pad)
+ {
+ DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName));
+ nxt = pad->pad_Next;
+ PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice));
+ pad = nxt; /* PaHost_Init allocated this FAST MEM.*/
+ }
+ sDeviceList = (internalPortAudioDevice*)NULL;
+ return 0; /* Got rid of sNumDevices=0; */
+}
+
+/***********************************************************************/
+void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */
+{
+#if 0
+ struct timeval timeout;
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+ select(0, NULL, NULL, NULL, &timeout);
+#else
+ long usecs = msec * 1000;
+ usleep( usecs );
+#endif
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Allocate memory that can be accessed in real-time. This may need to be held in physi- */
+/* cal memory so that it is not paged to virtual memory. This call MUST be balanced with */
+/* a call to PaHost_FreeFastMemory(). */
+void *PaHost_AllocateFastMemory(long numBytes)
+{
+ void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */
+ if (addr) /* range and locks the pages into memory. A counter */
+ { /* is incremented each time the page is locked. The */
+ if (mpin(addr, numBytes)) /* superuser can lock as many pages as it wishes, */
+ { /* others are limited to the configurable PLOCK_MA. */
+ ERR_RPT(("PaHost_AllocateFastMemory() failed to mpin() memory.\n"));
+#if 1
+ free(addr); /* You MAY cut out these 2 lines to be less strict, */
+ addr = NULL; /* you then only get the warning but PA goes on... */
+#endif /* Only problem then may be corresponding munpin() */
+ } /* call at PaHost_FreeFastMemory(), below. */
+ memset(addr, 0, numBytes); /* Locks established with mlock are not inherited by */
+ } /* a child process after a fork. Furthermore, IRIX- */
+ return addr; /* man-pages warn against mixing both mpin and mlock */
+} /* in 1 piece of code, so stick to mpin()/munpin() ! */
+
+
+/*---------------------------------------------------------------------------------------*/
+/* Free memory that could be accessed in real-time. This call MUST be balanced with a */
+/* call to PaHost_AllocateFastMemory(). */
+void PaHost_FreeFastMemory(void *addr, long numBytes)
+{
+ if (addr)
+ {
+ if (munpin(addr, numBytes)) /* Will munpin() fail when it was never mpinned? */
+ ERR_RPT(("WARNING: PaHost_FreeFastMemory() failed to munpin() memory.\n"));
+ free(addr); /* But go on, try to release it, just warn... */
+ }
+}
+
+/*----------------------------------------------------------*/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ if (past == NULL)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (pahsc == NULL)
+ return paInternalError;
+ return (PaError)(past->past_IsActive != 0);
+}
+
+/*-------------------------------------------------------------------*/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+/* FIXME - return actual frames played, not frames generated.
+** Need to query the output device somehow.
+*/
+ return past->past_FrameCount;
+}
diff --git a/pd/portaudio/pa_sgi/pthread-Makefile b/pd/portaudio/pa_sgi/pthread-Makefile
new file mode 100644
index 00000000..527677a8
--- /dev/null
+++ b/pd/portaudio/pa_sgi/pthread-Makefile
@@ -0,0 +1,52 @@
+# Make PortAudio for Silicon Graphics IRIX (6.2)
+# Pieter suurmond, september 22, 2001. (v15 pa_sgi sub-version #0.18)
+
+# pthread, math (as with linux) and SGI audio library:
+# SGI-books say -lpthread should be the last on the line.
+LIBS = -lm -laudio -lpthread
+
+CDEFINES = -I../pa_common
+
+# Possible CFLAGS with MIPSpro compiler are: -32, -o32, -n32, -64,
+# -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging.
+# And use for example -O2 or -O3 for better optimization:
+CFLAGS = -O2
+PASRC = ../pa_common/pa_lib.c pa_sgi.c
+PAINC = ../pa_common/portaudio.h
+
+# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2).
+#TESTC = $(PASRC) ../pa_tests/patest_record.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches.
+TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?).
+#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK
+#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore.
+
+# Tests that do not yet work.
+#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default
+#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default
+#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS FUZZ CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-(
+ # PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH.
+ # OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON???
+ # ANYWAY, I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS!
+TESTH = $(PAINC)
+
+all: patest
+
+# "cc" for the MIPSpro compiler, may be changed to "gcc":
+patest: $(TESTC) $(TESTH) Makefile
+ cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest
+
+run: patest
+ ./patest
+
diff --git a/pd/portaudio/pa_sgi/pthread-pa_sgi.c b/pd/portaudio/pa_sgi/pthread-pa_sgi.c
new file mode 100644
index 00000000..e9ab273c
--- /dev/null
+++ b/pd/portaudio/pa_sgi/pthread-pa_sgi.c
@@ -0,0 +1,908 @@
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * SGI IRIX implementation by Pieter Suurmond, september 22, 2001 (#0.18).
+ *
+ * Copyright (c) 1999-2001 Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+/*
+Modfication History:
+ 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2.
+ 8/17/2001 - alpha release with IRIX sproc()-method, may sometimes let IRIX6.2 crash at closing audiostream.
+ 9/22/2001 - #0.18 pthread starts to work a bit:
+ BUT UNDER IRIX6.2, I DON'T GET IT TO WORK REALLY CORRECTLY,
+ this POSIX-attempt,
+ DON'T USE THIS FILE FOR RELIABLE OPERATION, IT IS HERE JUST
+ FOR DOCUMENTATION/ARCHIVE... OR FOR ANYONE WHO WANTS TO FIX......
+TODO:
+ - Test under IRIX 6.5.
+ - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion),
+ and maybe also the other natively supported formats? (might increase performance)
+ - Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet,
+ seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?)
+ - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4.
+REFERENCES:
+ - IRIX 6.2 man pages regarding SGI AL library.
+ - IRIS Digital MediaProgramming Guide (online books as well as man-pages come with IRIX 6.2 and
+ may not be publically available on the internet).
+*/
+
+#include <stdio.h> /* Standard libraries. */
+#include <stdlib.h>
+
+#include "../pa_common/portaudio.h" /* Portaudio headers. */
+#include "../pa_common/pa_host.h"
+#include "../pa_common/pa_trace.h"
+
+/*
+#include <malloc.h>
+#include <memory.h>
+#include <sys/prctl.h> Not needed
+#include <sys/types.h>
+#include <sys/schedctl.h>
+#include <signal.h>
+#include <sys/ioctl.h> Needed?
+#include <sys/time.h>
+#include <sched.h> sched_param struct and related functions
+ used in setting thread priorities.
+#include <limits.h> Some POSIX constants such as _POSIX_THREAD_THREADS_MAX
+*/
+
+#include <pthread.h> /* Pthreads are supported by IRIX 6.2 after */
+ /* patches 1361, 1367, and 1429 are applied. */
+
+#include <fcntl.h> /* fcntl.h needed for "O_RDONLY". */
+#include <unistd.h> /* For usleep() and constants used when calling sysconf() */
+ /* to query POSIX limits (see the sysconf(3) ref. page. */
+
+#include <dmedia/audio.h> /* SGI-specific audio library. */
+
+
+/*--------------------------------------------*/
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) PRINT(x)
+#define DBUGX(x) /* PRINT(x) */
+
+#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */
+#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */
+
+typedef struct internalPortAudioDevice /* IRIX specific device info: */
+{
+ PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */
+ long pad_ALdevice; /* SGI-number! */
+ double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */
+ char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */
+ PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */
+ /* int structVersion; */
+ /* const char* name; */
+ /* int maxInputChannels, maxOutputChannels; */
+ /* int numSampleRates; Num rates, or -1 if range supprtd. */
+ /* const double* sampleRates; Array of supported sample rates, */
+ /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */
+ struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */
+} internalPortAudioDevice;
+
+typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */
+{
+ ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */
+ pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */
+ pthread_t pahsc_ThreadPID;
+ short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */
+ *pahsc_NativeOutputBuffer;
+ unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */
+ pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */
+ unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */
+ pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */
+ struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */
+ pahsc_LastExitTime;
+ long pahsc_InsideCountSum,
+ pahsc_TotalCountSum;
+} PaHostSoundControl;
+
+/*----------------------------- Shared Data ------------------------------------------------------*/
+static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */
+static int sPaHostError = 0; /* Maybe more than one process writing errs!? */
+
+long Pa_GetHostError(void)
+{
+ return (long)sPaHostError;
+}
+
+/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/
+/* (copied from source pa_linux_oss/pa_linux_oss.c) */
+static void Pa_StartUsageCalculation( internalPortAudioStream *past )
+{
+ struct itimerval itimer;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+/* Query system timer for usage analysis and to prevent overuse of CPU. */
+ getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime );
+}
+
+static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB )
+{
+ long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec;
+ long usecs = secs * 1000000;
+ usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec);
+ return usecs;
+}
+
+static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+{
+ struct itimerval currentTime;
+ long insideCount;
+ long totalCount; /* Measure CPU utilization during this callback. */
+
+#define LOWPASS_COEFFICIENT_0 (0.95)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (pahsc == NULL)
+ return;
+ if (getitimer( ITIMER_REAL, &currentTime ) == 0 )
+ {
+ if (past->past_IfLastExitValid)
+ {
+ insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, &currentTime );
+ pahsc->pahsc_InsideCountSum += insideCount;
+ totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, &currentTime );
+ pahsc->pahsc_TotalCountSum += totalCount;
+ /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */
+ /* Low pass filter the result because sometimes we get called several times in a row. */
+ /* That can cause the TotalCount to be very low which can cause the usage to appear */
+ /* unnaturally high. So we must filter numerator and denominator separately!!! */
+ if (pahsc->pahsc_InsideCountSum > 0)
+ {
+ past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
+ (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum));
+ past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
+ (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum));
+ past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
+ pahsc->pahsc_InsideCountSum = 0;
+ pahsc->pahsc_TotalCountSum = 0;
+ }
+ }
+ past->past_IfLastExitValid = 1;
+ }
+ pahsc->pahsc_LastExitTime.it_value.tv_sec = 100;
+ pahsc->pahsc_LastExitTime.it_value.tv_usec = 0;
+ setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL );
+ past->past_IfLastExitValid = 1;
+} /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/
+
+
+/*--------------------------------------------------------------------------------------*/
+PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */
+{ /* call to report via ERR_RPT(), yields a PaError-num. */
+ const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */
+ switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */
+ {
+ case AL_BAD_OUT_OF_MEM:
+ ERR_RPT(("%sout of memory.\n", a));
+ return paInsufficientMemory; /* Known PaError. */
+ case AL_BAD_CONFIG:
+ ERR_RPT(("%sconfiguration invalid or NULL.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_CHANNELS:
+ ERR_RPT(("%schannels not 1,2 or 4.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_NO_PORTS:
+ ERR_RPT(("%sout of audio ports.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DEVICE:
+ ERR_RPT(("%swrong device number.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DEVICE_ACCESS:
+ ERR_RPT(("%swrong device access.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DIRECTION:
+ ERR_RPT(("%sinvalid direction.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_SAMPFMT:
+ ERR_RPT(("%sdoesn't accept sampleformat.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_FLOATMAX:
+ ERR_RPT(("%smax float value is zero.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_WIDTH:
+ ERR_RPT(("%sunsupported samplewidth.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_QSIZE:
+ ERR_RPT(("%sinvalid queue size.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_PVBUFFER:
+ ERR_RPT(("%sPVbuffer null.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_BUFFERLENGTH_NEG:
+ ERR_RPT(("%snegative bufferlength.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_BUFFERLENGTH_ODD:
+ ERR_RPT(("%sodd bufferlength.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_PARAM:
+ ERR_RPT(("%sparameter not valid for device.\n", a));
+ return paHostError; /* Generic PaError. */
+ default:
+ ERR_RPT(("%sunknown error.\n", a));
+ return paHostError; /* Generic PaError. */
+ }
+}
+
+/*------------------------------------------------------------------------------------------*/
+/* Tries to set various rates and formats and fill in the device info structure. */
+static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */
+ PaDeviceID id, /* (DefaultI|ODeviceID()) */
+ char* name, /* (for example "SGI AL") */
+ internalPortAudioDevice* pad) /* Result written to pad. */
+{
+ int format;
+ long min, max; /* To catch hardware characteristics. */
+ ALseterrorhandler(0); /* 0 = turn off the default error handler. */
+ /*--------------------------------------------------------------------------------------*/
+ pad->pad_ALdevice = ALdev; /* Set the AL device number. */
+ pad->pad_DeviceID = id; /* Set the PA device number. */
+ if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */
+ {
+ ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name));
+ return paHostError;
+ }
+ strcpy(pad->pad_DeviceName, name); /* Write name-string. */
+ pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */
+ /*--------------------------------- natively supported sample formats: -----------------*/
+ pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */
+ /* Then also choose other CallConvertXX()! */
+ /*--------------------------------- number of available i/o channels: ------------------*/
+ if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max))
+ return translateSGIerror();
+ pad->pad_Info.maxInputChannels = max;
+ DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels))
+ if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max))
+ return translateSGIerror();
+ pad->pad_Info.maxOutputChannels = max;
+ DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels))
+ /*--------------------------------- supported samplerates: ----------------------*/
+ pad->pad_Info.numSampleRates = 7;
+ pad->pad_Info.sampleRates = pad->pad_SampleRates;
+ pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */
+ pad->pad_SampleRates[1] = (double)AL_RATE_11025;
+ pad->pad_SampleRates[2] = (double)AL_RATE_16000;
+ pad->pad_SampleRates[3] = (double)AL_RATE_22050;
+ pad->pad_SampleRates[4] = (double)AL_RATE_32000;
+ pad->pad_SampleRates[5] = (double)AL_RATE_44100;
+ pad->pad_SampleRates[6] = (double)AL_RATE_48000;
+ if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */
+ return translateSGIerror(); /* double -> long. */
+ if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */
+ goto weird;
+ if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */
+ return translateSGIerror();
+ if (max != (long)(0.5 + pad->pad_SampleRates[6]))
+ {
+weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max));
+ return paHostError; /* Or make it a warning and just carry on... */
+ }
+ /*-------------------------------------------------------------------------------*/
+ return paNoError;
+}
+
+
+/*--------------------------------------------------------------------------------*/
+int Pa_CountDevices() /* Name of this function suggests it only counts and */
+{ /* is NOT destructive, it however resets whole PA ! */
+ int numDevices = 0; /* Let 's not do that here. */
+ internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */
+#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */
+ if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */
+ Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */
+#endif /* friendly to clients that forgot to initialize PA. */
+ while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */
+ {
+ numDevices++;
+ currentDevice = currentDevice->pad_Next;
+ }
+ return numDevices;
+}
+
+/*-------------------------------------------------------------------------------*/
+static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id)
+{
+ int numDevices = 0;
+ internalPortAudioDevice *res = (internalPortAudioDevice*)NULL;
+ internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */
+ while (pad) /* pad may be NULL, that's ok, return 0. */
+ { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */
+ if (pad->pad_DeviceID == id) /* This the device we were looking for? */
+ res = pad; /* But keep on(!) counting so we don't */
+ numDevices++; /* have to call Pa_CountDevices() later. */
+ pad = pad->pad_Next; /* Advance to the next device or NULL. */
+ } /* No assumptions about order of ID's in */
+ if (!res) /* the list. */
+ ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id));
+ if ((id < 0) || (id >= numDevices))
+ {
+ ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id));
+#if 1 /* Be strict, even when found, */
+ res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */
+#endif
+ }
+ return res;
+}
+
+/*----------------------------------------------------------------------*/
+const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id)
+{
+ PaDeviceInfo* res = (PaDeviceInfo*)NULL;
+ internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */
+ if (pad)
+ res = &pad->pad_Info; /* Not finding the specified ID is not */
+ if (!res) /* the same as &pad->pad_Info == NULL. */
+ ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id));
+ return res; /* So (maybe) a second/third ERR_RPT(). */
+}
+
+/*------------------------------------------------*/
+PaDeviceID Pa_GetDefaultInputDeviceID(void)
+{
+ return 0; /* 0 is the default device ID. */
+}
+/*------------------------------------------------*/
+PaDeviceID Pa_GetDefaultOutputDeviceID(void)
+{
+ return 0;
+}
+
+/*-------------------------------------------------------------------------------------------------*/
+/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */
+PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */
+{
+ internalPortAudioDevice* pad;
+ PaError r = paNoError;
+ int audioLibFileID; /* To test for the presence of audio. */
+
+ if (sDeviceList) /* Allow re-init, only warn, no error. */
+ {
+ ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n"));
+ return r;
+ }
+ /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/
+ audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */
+ if (audioLibFileID < 0) /* IO port. On failure, machine */
+ { /* has no audio ability. */
+ ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n"));
+ return paHostError;
+ }
+ close(audioLibFileID); /* Allocate fast mem to hold device info. */
+ pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice));
+ if (pad == NULL)
+ return paInsufficientMemory;
+ memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */
+ r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */
+ Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */
+ "AL default", /* A suitable name. */
+ pad); /* Write args and queried info into pad. */
+ if (r != paNoError)
+ {
+ ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r));
+ PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */
+ }
+ else
+ sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */
+ /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/
+ /*---------------------------------------------------------------------------------------------*/
+ return r;
+}
+
+/*---------------------------------------------------------------------------------------------------*/
+static PaError Pa_SgiAudioProcess(internalPortAudioStream *past) /* Spawned by PaHost_StartEngine(). */
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+
+ if (!past)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (!pahsc)
+ return paInternalError;
+ past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */
+ DBUG(("entering thread.\n"));
+
+ while (!past->past_StopSoon) /* OR-ing StopSoon and StopNow here gives problems! */
+ {
+ /*---------------------------------------- INPUT: ------------------------------------*/
+ if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */
+ {
+ while (ALgetfilled(pahsc->pahsc_ALportIN) < pahsc->pahsc_SamplesPerInputBuffer)
+ {
+ /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */
+ if (past->past_StopNow) /* Don't let ALreadsamps() block */
+ goto done;
+ }
+ if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer,
+ pahsc->pahsc_SamplesPerInputBuffer)) /* Number of samples instead */
+ { /* of number of frames. */
+ ERR_RPT(("ALreadsamps() failed.\n"));
+ result = paInternalError;
+ goto done;
+ }
+ }
+ /*---------------------------------------------------- USER CALLBACK ROUTINE: ----------*/
+ /* DBUG(("Calling Pa_CallConvertInt16()...\n")); */
+ Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */
+ result = Pa_CallConvertInt16(past, /* user data and call user routine. */
+ pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_NativeOutputBuffer);
+ Pa_EndUsageCalculation(past);
+ if (result)
+ {
+ DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result));
+ goto done; /* This is apparently NOT an error! */
+ } /* Just letting the userCallBack stop us. */
+ /*---------------------------------------- OUTPUT: ------------------------------------*/
+ if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */
+ {
+ while (ALgetfillable(pahsc->pahsc_ALportOUT) < pahsc->pahsc_SamplesPerOutputBuffer)
+ {
+ /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */
+ if (past->past_StopNow) /* Don't let ALwritesamps() block */
+ goto done;
+ }
+ if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer,
+ pahsc->pahsc_SamplesPerOutputBuffer))
+ {
+ ERR_RPT(("ALwritesamps() failed.\n"));
+ result = paInternalError;
+ goto done;
+ }
+ }
+ /*-------------------------------------------------------------------------------------*/
+ }
+done:
+ /* pahsc->pahsc_ThreadPID = -1; Hu? doesn't help!! (added by Pieter) */
+ past->past_IsActive = 0;
+ DBUG(("leaving thread.\n"));
+ return result;
+}
+
+
+/*--------------------------------------------------------------------------------------*/
+PaError PaHost_OpenStream(internalPortAudioStream *past)
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+ unsigned int minNumBuffers;
+ internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */
+ ALconfig sgiALconfig = NULL; /* IRIX-datatype. */
+ long pvbuf[8]; /* To get/set hardware configs. */
+ long sr, ALqsize;
+ DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */
+ if (!past)
+ {
+ ERR_RPT(("Streampointer NULL!\n"));
+ result = paBadStreamPtr; goto done;
+ }
+ pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
+ if (pahsc == NULL)
+ {
+ ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */
+ result = paInsufficientMemory; goto done; /* code (nothing will be freed). */
+ }
+ memset(pahsc, 0, sizeof(PaHostSoundControl));
+/* pahsc->pahsc_threadPID = -1; Should pahsc_threadPID be inited to */
+ past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */
+ /*--------------------------------------------------- Allocate native buffers: --------*/
+ pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */
+ past->past_NumInputChannels; /* audio-thread. */
+ pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short);
+ if (past->past_NumInputChannels > 0) /* Assumes short = 16 bits! */
+ {
+ pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer);
+ if( pahsc->pahsc_NativeInputBuffer == NULL )
+ {
+ ERR_RPT(("Fast memory allocation for input-buffer failed.\n"));
+ result = paInsufficientMemory; goto done;
+ }
+ }
+ pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */
+ past->past_NumOutputChannels; /* audio-thread. */
+ pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short);
+ if (past->past_NumOutputChannels > 0) /* Assumes short = 16 bits! */
+ {
+ pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer);
+ if (pahsc->pahsc_NativeOutputBuffer == NULL)
+ {
+ ERR_RPT(("Fast memory allocation for output-buffer failed.\n"));
+ result = paInsufficientMemory; goto done;
+ }
+ }
+ /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/
+ ALseterrorhandler(0); /* 0 = turn off the default error handler. */
+ pvbuf[0] = AL_INPUT_RATE;
+ pvbuf[2] = AL_INPUT_COUNT;
+ pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */
+ pvbuf[6] = AL_OUTPUT_COUNT;
+ sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */
+ if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */
+ { /* sponding native AL-number(s). */
+ padIN = Pa_GetInternalDevice(past->past_InputDeviceID);
+ if (!padIN)
+ {
+ ERR_RPT(("Pa_GetInternalDevice() for input failed.\n"));
+ result = paHostError; goto done;
+ }
+ if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */
+ goto sgiError; /* the same AL-device, the AL-library might */
+ if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */
+ { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */
+ if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */
+ {
+ ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \
+another process is currently using input at %ld kHz.\n", sr, pvbuf[1]));
+ result = paHostError; goto done;
+ }
+ pvbuf[1] = sr; /* Then set input-rate. */
+ if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2))
+ goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */
+ } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */
+ }
+ if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */
+ { /* We use padOUT/IN later on, or at least 1 of both. */
+ padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID);
+ if (!padOUT)
+ {
+ ERR_RPT(("Pa_GetInternalDevice() for output failed.\n"));
+ result = paHostError; goto done;
+ }
+ if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4))
+ goto sgiError;
+ if ((past->past_NumOutputChannels > 0) && (pvbuf[5] != sr))
+ { /* Output needed and rate different from current harware-rate. */
+ if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */
+ {
+ ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \
+another process is currently using output at %ld kHz.\n", sr, pvbuf[5]));
+ result = paHostError; goto done; /* Will free again the inputbuffer */
+ } /* that was just created above. */
+ pvbuf[5] = sr; /* Then set output-rate. */
+ if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2))
+ goto sgiError;
+ }
+ }
+ /*------------------------------------------ Construct an audio-port-configuration ----------*/
+ sgiALconfig = ALnewconfig(); /* Change the SGI-AL-default-settings. */
+ if (sgiALconfig == (ALconfig)0) /* sgiALconfig is released here after use! */
+ goto sgiError; /* See that sgiALconfig is NOT released! */
+ if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */
+ goto sgiError;
+ if (ALsetwidth (sgiALconfig, AL_SAMPLE_16)) /* Only meaningful when sample format for */
+ goto sgiError; /* config is set to two's complement format. */
+ /************************ Future versions might (dynamically) switch to 32-bit floats? *******
+ if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.)
+ goto sgiError;
+ if (ALsetfloatmax (sgiALconfig, 1.0)) Only meaningful when sample format for config
+ goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */
+ /*---------- ?? --------------------*/
+ /* DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); */
+ minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, past->past_SampleRate);
+ past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ?
+ minNumBuffers : past->past_NumUserBuffers;
+ /*------------------------------------------------ Set internal AL queuesize (in samples) ----*/
+ if (pahsc->pahsc_SamplesPerInputBuffer >= pahsc->pahsc_SamplesPerOutputBuffer)
+ ALqsize = (long)pahsc->pahsc_SamplesPerInputBuffer;
+ else /* Take the largest of the two amounts. */
+ ALqsize = (long)pahsc->pahsc_SamplesPerOutputBuffer;
+ ALqsize *= 4; /* 4 times as large as amount per transfer! */
+ if (ALsetqueuesize(sgiALconfig, ALqsize)) /* Or should we use past_NumUserBuffers here? */
+ goto sgiError; /* Using 2 times may give glitches... */
+ /* Have to work on ALsetqueuesize() above. */
+
+ /* Do ALsetchannels() later, apart per input and/or output. */
+ /*----------------------------------------------- OPEN 1 OR 2 AL-DEVICES: --------------------*/
+ if (past->past_OutputDeviceID == past->past_InputDeviceID) /* Who SETS these devive-numbers? */
+ {
+ if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0))
+ {
+ DBUG(("PaHost_OpenStream: opening both input and output channels.\n"));
+ /*------------------------- open output port: ----------------------------------*/
+ if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels)))
+ goto sgiError; /* Returns 0 on success, -1 on failure. */
+ pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig);
+ if (pahsc->pahsc_ALportOUT == (ALport)0)
+ goto sgiError;
+ /*------------------------- open input port: -----------------------------------*/
+ if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels)))
+ goto sgiError; /* Returns 0 on success, -1 on failure. */
+ pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig);
+ if (pahsc->pahsc_ALportIN == (ALport)0)
+ goto sgiError; /* For some reason the "patest_wire.c"-test crashes! */
+ } /* Probably due to too small buffersizes?.... */
+ else
+ {
+ ERR_RPT(("Cannot setup bidirectional stream between different devices.\n"));
+ result = paHostError;
+ goto done;
+ }
+ }
+ else /* (OutputDeviceID != InputDeviceID) */
+ {
+ if (past->past_NumOutputChannels > 0) /* WRITE-ONLY: */
+ {
+ /*------------------------- open output port: ----------------------------------*/
+ DBUG(("PaHost_OpenStream: opening %d output channel(s) on %s.\n",
+ past->past_NumOutputChannels, padOUT->pad_DeviceName));
+ if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels)))
+ goto sgiError; /* Returns 0 on success, -1 on failure. */
+ pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig);
+ if (pahsc->pahsc_ALportOUT == (ALport)0)
+ goto sgiError;
+ }
+ if (past->past_NumInputChannels > 0) /* READ-ONLY: */
+ {
+ /*------------------------- open input port: -----------------------------------*/
+ DBUG(("PaHost_OpenStream: opening %d input channel(s) on %s.\n",
+ past->past_NumInputChannels, padIN->pad_DeviceName));
+ if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels)))
+ goto sgiError; /* Returns 0 on success, -1 on failure. */
+ pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig);
+ if (pahsc->pahsc_ALportIN == (ALport)0)
+ goto sgiError;
+ }
+ }
+ DBUG(("PaHost_OpenStream() succeeded.\n"));
+ goto done; /* (no errors occured) */
+sgiError:
+ result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
+done:
+ if (sgiALconfig)
+ ALfreeconfig(sgiALconfig); /* We don't need that struct anymore. */
+ if (result != paNoError)
+ PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */
+ return result;
+}
+
+/*-----------------------------------------------------*/
+PaError PaHost_StartOutput(internalPortAudioStream *past)
+{
+ return paNoError; /* Hmm, not implemented yet? */
+}
+PaError PaHost_StartInput(internalPortAudioStream *past)
+{
+ return paNoError;
+}
+
+/*------------------------------------------------------------------------------*/
+PaError PaHost_StartEngine(internalPortAudioStream *past)
+{
+ PaHostSoundControl *pahsc;
+ int hres;
+ PaError result = paNoError;
+
+ if (!past) /* Test argument. */
+ {
+ ERR_RPT(("PaHost_StartEngine(NULL)!\n"));
+ return paBadStreamPtr;
+ }
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (!pahsc)
+ {
+ ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData == NULL!\n"));
+ return paHostError;
+ }
+ past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */
+ past->past_StopNow = 0;
+ past->past_IsActive = 1;
+ DBUG(("PaHost_StartEngine() called.\n"));
+ /* Use pthread_create() instead of __clone() because: */
+ /* - pthread_create also works for other UNIX systems like Solaris, */
+ /* - Java HotSpot VM crashes in pthread_setcanceltype() when using __clone(). */
+ hres = pthread_create(&(pahsc->pahsc_ThreadPID), /* SPAWN AUDIO-CHILD. */
+ NULL, /* pthread_attr_t * attr */
+ (void*)Pa_SgiAudioProcess,
+ past);
+ if (hres)
+ {
+ result = paHostError;
+ sPaHostError = hres;
+ ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n"));
+ }
+ return result;
+}
+
+/*------------------------------------------------------------------------------*/
+PaError PaHost_StopEngine(internalPortAudioStream *past, int abort)
+{
+ int hres;
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+
+ DBUG(("PaHost_StopEngine() called.\n"));
+ if (!past)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (pahsc == NULL)
+ return result; /* paNoError (already stopped, no err?). */
+ past->past_StopSoon = 1; /* Tell background thread to stop generating */
+ if (abort) /* more and to let current data play out. If */
+ past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */
+ if (pahsc->pahsc_ThreadPID != -1) /* Join thread to recover memory resources. */
+ {
+ DBUG(("pthread_join() called.\n"));
+ hres = pthread_join(pahsc->pahsc_ThreadPID, NULL);
+ if (hres)
+ {
+ result = paHostError;
+ sPaHostError = hres;
+ ERR_RPT(("PaHost_StopEngine() failed pthread_join().\n"));
+ }
+ pahsc->pahsc_ThreadPID = -1;
+ }
+ past->past_IsActive = 0;
+ return result;
+}
+
+/*---------------------------------------------------------------*/
+PaError PaHost_StopOutput(internalPortAudioStream *past, int abort)
+{
+ return paNoError; /* Not implemented yet? */
+}
+PaError PaHost_StopInput(internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+/*******************************************************************/
+PaError PaHost_CloseStream(internalPortAudioStream *past)
+{
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+
+ DBUG(("PaHost_CloseStream() called.\n"));
+ if (past == NULL)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (pahsc == NULL) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */
+ return result; /* This test prevents from freeing NULL-pointers. */
+
+ if (pahsc->pahsc_ALportIN)
+ {
+ if (ALcloseport(pahsc->pahsc_ALportIN))
+ result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
+ else /* But go on anyway... to release other stuff... */
+ pahsc->pahsc_ALportIN = (ALport)0;
+ }
+ if (pahsc->pahsc_ALportOUT)
+ {
+ if (ALcloseport(pahsc->pahsc_ALportOUT))
+ result = translateSGIerror();
+ else
+ pahsc->pahsc_ALportOUT = (ALport)0;
+ }
+ if (pahsc->pahsc_NativeInputBuffer)
+ {
+ PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer);
+ pahsc->pahsc_NativeInputBuffer = NULL;
+ }
+ if (pahsc->pahsc_NativeOutputBuffer)
+ {
+ PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer);
+ pahsc->pahsc_NativeOutputBuffer = NULL;
+ }
+ PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl));
+ past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST. */
+ return result;
+}
+
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+** set PA_MIN_LATENCY_MSEC=200
+** in the AUTOEXEC.BAT file and reboot.
+** If the environment variable is not set, then the latency will be
+** determined based on the OS. Windows NT has higher latency than Win95.
+*/
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
+{
+ return 2;
+}
+/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */
+/* Do we HAVE to do it this way under IRIX???.... */
+/*--------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------*/
+PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */
+{ /* Called by Pa_Terminate() from pa_lib.c. */
+ internalPortAudioDevice *pad = sDeviceList,
+ *nxt;
+ while (pad)
+ {
+ DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName));
+ nxt = pad->pad_Next;
+ PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice));
+ pad = nxt; /* PaHost_Init allocated this FAST MEM.*/
+ }
+ sDeviceList = (internalPortAudioDevice*)NULL;
+ return 0; /* Got rid of sNumDevices=0; */
+}
+
+/***********************************************************************/
+void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */
+{
+#if 0
+ struct timeval timeout;
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+ select(0, NULL, NULL, NULL, &timeout);
+#else
+ long usecs = msec * 1000;
+ usleep( usecs );
+#endif
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Allocate memory that can be accessed in real-time. This may need to be held in physi- */
+/* cal memory so that it is not paged to virtual memory. This call MUST be balanced with */
+/* a call to PaHost_FreeFastMemory(). */
+void *PaHost_AllocateFastMemory(long numBytes)
+{
+ void *addr = malloc(numBytes);
+ if (addr)
+ memset(addr, 0, numBytes);
+ return addr;
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Free memory that could be accessed in real-time. This call MUST be balanced with a */
+/* call to PaHost_AllocateFastMemory(). */
+void PaHost_FreeFastMemory(void *addr, long numBytes)
+{
+ if (addr)
+ free(addr);
+}
+
+/*----------------------------------------------------------*/
+PaError PaHost_StreamActive (internalPortAudioStream *past)
+{
+ PaHostSoundControl *pahsc;
+ if (past == NULL)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (pahsc == NULL)
+ return paInternalError;
+ return (PaError)(past->past_IsActive != 0);
+}
+
+/*-------------------------------------------------------------------*/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+/* FIXME - return actual frames played, not frames generated.
+** Need to query the output device somehow.
+*/
+ return past->past_FrameCount;
+}
diff --git a/pd/portaudio/pa_tests/debug_convert.c b/pd/portaudio/pa_tests/debug_convert.c
new file mode 100644
index 00000000..8e9dc6d1
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_convert.c
@@ -0,0 +1,131 @@
+/*
+ * $Id: debug_convert.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Convert tagged values.
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+//#define OUTPUT_DEVICE (11)
+#define NUM_SECONDS (8)
+#define SLEEP_DUR (800)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+
+#define NUM_BUFFERS (0)
+
+typedef struct
+{
+ unsigned int framesToGo;
+}
+paTestData;
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ short *out = (short*)outputBuffer;
+ int i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( data->framesToGo < framesPerBuffer ) finished = 1;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = 0x0000 + i; /* left */
+ *out++ = 0x1000 + i; /* right */
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalSamps;
+ printf("PortAudio Test: output debug values\n" );
+ data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ printf("totalSamps = %d\n", totalSamps );
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE );
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ 2, /* stereo output */
+ paInt16, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
+ paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Is callback being called?\n");
+ for( i=0; i<((NUM_SECONDS+1)*1000); i+=SLEEP_DUR )
+ {
+ printf("data.framesToGo = %d\n", data.framesToGo ); fflush(stdout);
+ Pa_Sleep( SLEEP_DUR );
+ }
+ /* Stop sound until ENTER hit. */
+ printf("Call Pa_StopStream()\n");
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_dither_calc.c b/pd/portaudio/pa_tests/debug_dither_calc.c
new file mode 100644
index 00000000..d751ca39
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_dither_calc.c
@@ -0,0 +1,55 @@
+/*
+ * $Id: debug_dither_calc.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Test Dither calculations.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#include "pa_host.h"
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ long max,min;
+ int i;
+
+ for( i=0; i<10000; i++ )
+ {
+ long dither = PaConvert_TriangularDither();
+ // printf("dither = 0x%08X\n", dither );
+ if( dither < min ) min = dither;
+ else if( dither > max ) max = dither;
+ }
+ printf("min = 0x%08X = %d, max = 0x%08X = %d\n", min, min, max, max );
+}
diff --git a/pd/portaudio/pa_tests/debug_dual.c b/pd/portaudio/pa_tests/debug_dual.c
new file mode 100644
index 00000000..b90ef290
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_dual.c
@@ -0,0 +1,183 @@
+/*
+ * $Id: debug_dual.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_dual.c
+ * Try to open TWO streams on separate cards.
+ * Play a sine sweep using the Portable Audio api for several seconds.
+ * Hacked test for debugging PA.
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define DEV_ID_1 (13)
+#define DEV_ID_2 (15)
+#define NUM_SECONDS (8)
+#define SLEEP_DUR (800)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+#if 0
+#define MIN_LATENCY_MSEC (200)
+#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
+#else
+#define NUM_BUFFERS (0)
+#endif
+#define MIN_FREQ (100.0f)
+#define MAX_FREQ (4000.0f)
+#define FREQ_SCALAR (1.00002f)
+#define CalcPhaseIncrement(freq) (freq/SAMPLE_RATE)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (400)
+typedef struct
+{
+ float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation
+ float phase_increment;
+ float left_phase;
+ float right_phase;
+}
+paTestData;
+/* Convert phase between and 1.0 to sine value
+ * using linear interpolation.
+ */
+float LookupSine( paTestData *data, float phase );
+float LookupSine( paTestData *data, float phase )
+{
+ float fIndex = phase*TABLE_SIZE;
+ int index = (int) fIndex;
+ float fract = fIndex - index;
+ float lo = data->sine[index];
+ float hi = data->sine[index+1];
+ float val = lo + fract*(hi-lo);
+ return val;
+}
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = LookupSine(data, data->left_phase); /* left */
+ *out++ = LookupSine(data, data->right_phase); /* right */
+ data->left_phase += data->phase_increment;
+ if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f;
+ data->right_phase += (data->phase_increment * 1.5f); /* fifth above */
+ if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f;
+ /* sweep frequency then start over. */
+ data->phase_increment *= FREQ_SCALAR;
+ if( data->phase_increment > CalcPhaseIncrement(MAX_FREQ) ) data->phase_increment = CalcPhaseIncrement(MIN_FREQ);
+ }
+ return 0;
+}
+
+PaError TestStart( PortAudioStream **streamPtr, PaDeviceID devID,
+ paTestData *data );
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream1, *stream2;
+ PaError err;
+ paTestData DATA1, DATA2;
+ printf("PortAudio Test: DUAL sine sweep. ask for %d buffers\n", NUM_BUFFERS );
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = TestStart( &stream1, DEV_ID_1, &DATA1 );
+ if( err != paNoError ) goto error;
+ err = TestStart( &stream2, DEV_ID_2, &DATA2 );
+ if( err != paNoError ) goto error;
+ printf("Hit ENTER\n");
+ getchar();
+ err = Pa_StopStream( stream1 );
+ if( err != paNoError ) goto error;
+ err = Pa_StopStream( stream2 );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
+PaError TestStart( PortAudioStream **streamPtr, PaDeviceID devID, paTestData *data )
+{
+ PortAudioStream *stream;
+ PaError err;
+ int i;
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data->sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data->sine[TABLE_SIZE] = data->sine[0]; // set guard point
+ data->left_phase = data->right_phase = 0.0;
+ data->phase_increment = CalcPhaseIncrement(MIN_FREQ);
+ printf("PortAudio Test: output device = %d\n", devID );
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ devID,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
+ paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ *streamPtr = stream;
+ return 0;
+error:
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_multi_in.c b/pd/portaudio/pa_tests/debug_multi_in.c
new file mode 100644
index 00000000..ef1d4a19
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_multi_in.c
@@ -0,0 +1,179 @@
+/*
+ * $Id: debug_multi_in.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_multi_in.c
+ * Pass output from each of multiple channels
+ * to a stereo output using the Portable Audio api.
+ * Hacked test for debugging PA.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include "portaudio.h"
+//#define INPUT_DEVICE_NAME ("EWS88 MT Interleaved Rec")
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+//#define OUTPUT_DEVICE (18)
+#define SAMPLE_RATE (22050)
+#define FRAMES_PER_BUFFER (256)
+#define MIN_LATENCY_MSEC (400)
+#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+typedef struct
+{
+ int liveChannel;
+ int numChannels;
+}
+paTestData;
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ float *in = (float*)inputBuffer;
+ int i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( in == NULL ) return 0;
+ for( i=0; i<(int)framesPerBuffer; i++ )
+ {
+ /* Copy one channel of input to output. */
+ *out++ = in[data->liveChannel];
+ *out++ = in[data->liveChannel];
+ in += data->numChannels;
+ }
+ return 0;
+}
+/*******************************************************************/
+int PaFindDeviceByName( const char *name )
+{
+ int i;
+ int numDevices;
+ const PaDeviceInfo *pdi;
+ int len = strlen( name );
+ PaDeviceID result = paNoDevice;
+ numDevices = Pa_CountDevices();
+ for( i=0; i<numDevices; i++ )
+ {
+ pdi = Pa_GetDeviceInfo( i );
+ if( strncmp( name, pdi->name, len ) == 0 )
+ {
+ result = i;
+ break;
+ }
+ }
+ return result;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ PaDeviceID inputDevice;
+ const PaDeviceInfo *pdi;
+ printf("PortAudio Test: input signal from each channel. %d buffers\n", NUM_BUFFERS );
+ data.liveChannel = 0;
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+#ifdef INPUT_DEVICE_NAME
+ printf("Try to use device: %s\n", INPUT_DEVICE_NAME );
+ inputDevice = PaFindDeviceByName(INPUT_DEVICE_NAME);
+ if( inputDevice == paNoDevice )
+ {
+ printf("Could not find %s. Using default instead.\n", INPUT_DEVICE_NAME );
+ inputDevice = Pa_GetDefaultInputDeviceID();
+ }
+#else
+ printf("Using default input device.\n");
+ inputDevice = Pa_GetDefaultInputDeviceID();
+#endif
+ pdi = Pa_GetDeviceInfo( inputDevice );
+ if( pdi == NULL )
+ {
+ printf("Could not get device info!\n");
+ goto error;
+ }
+ data.numChannels = pdi->maxInputChannels;
+ printf("Input Device name is %s\n", pdi->name );
+ printf("Input Device has %d channels.\n", pdi->maxInputChannels);
+ err = Pa_OpenStream(
+ &stream,
+ inputDevice,
+ pdi->maxInputChannels,
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ 2,
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ data.liveChannel = 0;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ for( i=0; i<data.numChannels; i++ )
+ {
+ data.liveChannel = i;
+ printf("Channel %d being sent to output. Hit ENTER for next channel.", i );
+ fflush(stdout);
+ getchar();
+ }
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( stream );
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_multi_out.c b/pd/portaudio/pa_tests/debug_multi_out.c
new file mode 100644
index 00000000..6ff64ac6
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_multi_out.c
@@ -0,0 +1,144 @@
+/*
+ * $Id: debug_multi_out.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_multi_out.c
+ * Play a different sine wave on each channels,
+ * using the Portable Audio api.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+#define FREQ_INCR (300.0 / SAMPLE_RATE)
+#define MAX_CHANNELS (64)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+typedef struct
+{
+ int numChannels;
+ double phases[MAX_CHANNELS];
+}
+paTestData;
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int frameIndex, channelIndex;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
+ {
+ for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
+ {
+ /* Output sine wave on every channel. */
+ *out++ = (float) sin(data->phases[channelIndex]);
+
+ /* Play each channel at a higher frequency. */
+ data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
+ if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
+ }
+ }
+
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ const PaDeviceInfo *pdi;
+ paTestData data = {0};
+ printf("PortAudio Test: output sine wave on each channel.\n" );
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE );
+ data.numChannels = pdi->maxOutputChannels;
+ if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS;
+ printf("Number of Channels = %d\n", data.numChannels );
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice, /* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ data.numChannels,
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Hit ENTER to stop sound.\n");
+ fflush(stdout);
+ getchar();
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_CloseStream( stream );
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_record.c b/pd/portaudio/pa_tests/debug_record.c
new file mode 100644
index 00000000..f82ea58c
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_record.c
@@ -0,0 +1,339 @@
+/*
+ * $Id: debug_record.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_record.c
+ * Record input into an array.
+ * Save array to a file.
+ * Based on patest_record.c but with various ugly debug hacks thrown in.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include "portaudio.h"
+#define SAMPLE_RATE (22050)
+#define NUM_SECONDS (10)
+#define SLEEP_DUR_MSEC (200)
+#define FRAMES_PER_BUFFER (1<<10)
+#define NUM_REC_BUFS (0)
+
+#if 1
+#define PA_SAMPLE_TYPE paFloat32
+typedef float SAMPLE;
+#else
+#define PA_SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+#endif
+
+typedef struct
+{
+ long frameIndex; /* Index into sample array. */
+ long maxFrameIndex;
+ long samplesPerFrame;
+ long numSamples;
+ SAMPLE *recordedSamples;
+}
+paTestData;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 recordCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = (SAMPLE*)inputBuffer;
+ SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
+ long framesToCalc;
+ unsigned long i;
+ int finished;
+ unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
+
+ (void) outputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ framesToCalc = framesLeft;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ finished = 0;
+ }
+ if( inputBuffer == NULL )
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = 0; /* left */
+ *wptr++ = 0; /* right */
+ }
+ }
+ else
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ }
+ data->frameIndex += framesToCalc;
+ return finished;
+}
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 playCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
+ SAMPLE *wptr = (SAMPLE*)outputBuffer;
+ unsigned long i;
+ int finished;
+ unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;
+ if( outputBuffer == NULL ) return 0;
+ (void) inputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ /* final buffer... */
+ for( i=0; i<framesLeft; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = 0; /* left */
+ *wptr++ = 0; /* right */
+ }
+ data->frameIndex += framesLeft;
+ finished = 1;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ data->frameIndex += framesPerBuffer;
+ finished = 0;
+ }
+ return finished;
+}
+
+/****************************************************************/
+PaError TestRecording( paTestData *dataPtr )
+{
+ PortAudioStream *stream;
+ PaError err;
+ int i;
+
+ /* Record some audio. */
+ err = Pa_OpenStream(
+ &stream,
+ Pa_GetDefaultInputDeviceID(),
+ dataPtr->samplesPerFrame, /* stereo input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ paNoDevice,
+ 0,
+ PA_SAMPLE_TYPE,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ recordCallback,
+ dataPtr );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Now recording!\n"); fflush(stdout);
+ for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
+ {
+ if( Pa_StreamActive( stream ) <= 0)
+ {
+ printf("Stream inactive!\n");
+ break;
+ }
+ if( dataPtr->maxFrameIndex <= dataPtr->frameIndex )
+ {
+ printf("Buffer recording complete.\n");
+ break;
+ }
+ Pa_Sleep(100);
+ printf("index = %d\n", dataPtr->frameIndex ); fflush(stdout);
+ }
+
+ printf("Finished loop. Close stream.\n"); fflush(stdout);
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Done.\n"); fflush(stdout);
+ {
+ SAMPLE max = 0;
+ SAMPLE posVal;
+ int i;
+ for( i=0; i<dataPtr->numSamples; i++ )
+ {
+ posVal = dataPtr->recordedSamples[i];
+ if( posVal < 0 ) posVal = -posVal;
+ if( posVal > max ) max = posVal;
+ }
+ printf("Largest recorded sample = %d\n", max );
+ }
+ /* Write recorded data to a file. */
+#if 0
+ {
+ FILE *fid;
+ fid = fopen("recorded.raw", "wb");
+ if( fid == NULL )
+ {
+ printf("Could not open file.");
+ }
+ else
+ {
+ fwrite( dataPtr->recordedSamples, dataPtr->samplesPerFrame * sizeof(SAMPLE), totalFrames, fid );
+ fclose( fid );
+ printf("Wrote data to 'recorded.raw'\n");
+ }
+ }
+#endif
+
+error:
+ return err;
+}
+
+/****************************************************************/
+PaError TestPlayback( paTestData *dataPtr )
+{
+ PortAudioStream *stream;
+ PaError err;
+ int i;
+
+ /* Playback recorded data. */
+ dataPtr->frameIndex = 0;
+ printf("Begin playback.\n"); fflush(stdout);
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* NO input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ Pa_GetDefaultOutputDeviceID(),
+ dataPtr->samplesPerFrame, /* stereo output */
+ PA_SAMPLE_TYPE,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ playCallback,
+ dataPtr );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for playback to finish.\n"); fflush(stdout);
+ for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
+ {
+ Pa_Sleep(100);
+ printf("index = %d\n", dataPtr->frameIndex );
+ }
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+error:
+ return err;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ paTestData data;
+ long totalFrames;
+ long numBytes;
+ long i;
+ printf("patest_record.c\n"); fflush(stdout);
+
+ data.frameIndex = 0;
+ data.samplesPerFrame = 2;
+ data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE;
+
+ printf("totalFrames = %d\n", totalFrames ); fflush(stdout);
+ data.numSamples = totalFrames * data.samplesPerFrame;
+
+ numBytes = data.numSamples * sizeof(SAMPLE);
+ data.recordedSamples = (SAMPLE *) malloc( numBytes );
+ if( data.recordedSamples == NULL )
+ {
+ printf("Could not allocate record array.\n");
+ exit(1);
+ }
+ for( i=0; i<data.numSamples; i++ ) data.recordedSamples[i] = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ for( i=0; i<2; i++ )
+ {
+ err = TestRecording( &data );
+ if( err != paNoError ) goto error;
+
+ err = TestPlayback( &data );
+ if( err != paNoError ) goto error;
+ }
+
+ free( data.recordedSamples );
+ Pa_Terminate();
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ if( err == paHostError )
+ {
+ fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() );
+ }
+ return -1;
+}
diff --git a/pd/portaudio/pa_tests/debug_record_reuse.c b/pd/portaudio/pa_tests/debug_record_reuse.c
new file mode 100644
index 00000000..4f4fb53d
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_record_reuse.c
@@ -0,0 +1,351 @@
+/*
+ * $Id: debug_record_reuse.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_record_reuse.c
+ * Record input into an array.
+ * Save array to a file.
+ * Based on patest_record.c but with various ugly debug hacks thrown in.
+ * Loop twice and reuse same streams.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include "portaudio.h"
+#define SAMPLE_RATE (22050)
+#define NUM_SECONDS (4)
+#define SLEEP_DUR_MSEC (200)
+#define FRAMES_PER_BUFFER (256)
+#define NUM_REC_BUFS (0)
+
+#if 1
+#define PA_SAMPLE_TYPE paFloat32
+typedef float SAMPLE;
+#else
+#define PA_SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+#endif
+
+typedef struct
+{
+ long frameIndex; /* Index into sample array. */
+ long maxFrameIndex;
+ long samplesPerFrame;
+ long numSamples;
+ PortAudioStream *outputStream;
+ PortAudioStream *inputStream;
+ SAMPLE *recordedSamples;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 recordCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = (SAMPLE*)inputBuffer;
+ SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
+ long framesToCalc;
+ unsigned long i;
+ int finished;
+ unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
+
+ (void) outputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ framesToCalc = framesLeft;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ finished = 0;
+ }
+ if( inputBuffer == NULL )
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = 0; /* left */
+ *wptr++ = 0; /* right */
+ }
+ }
+ else
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ }
+ data->frameIndex += framesToCalc;
+ return finished;
+}
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 playCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
+ SAMPLE *wptr = (SAMPLE*)outputBuffer;
+ unsigned long i;
+ int finished;
+ unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;
+ if( outputBuffer == NULL ) return 0;
+ (void) inputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ /* final buffer... */
+ for( i=0; i<framesLeft; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = 0; /* left */
+ *wptr++ = 0; /* right */
+ }
+ data->frameIndex += framesLeft;
+ finished = 1;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ data->frameIndex += framesPerBuffer;
+ finished = 0;
+ }
+ return finished;
+}
+
+/****************************************************************/
+PaError TestRecording( paTestData *dataPtr )
+{
+ PaError err;
+ int i;
+ int lastIndex = 0;
+
+/* Open input stream if not already open. */
+ if( dataPtr->inputStream == NULL )
+ {
+ /* Record some audio. */
+ err = Pa_OpenStream(
+ &dataPtr->inputStream,
+ Pa_GetDefaultInputDeviceID(),
+ dataPtr->samplesPerFrame, /* stereo input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ paNoDevice,
+ 0,
+ PA_SAMPLE_TYPE,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ recordCallback,
+ dataPtr );
+ if( err != paNoError ) goto error;
+ }
+
+ dataPtr->frameIndex = 0;
+
+ err = Pa_StartStream( dataPtr->inputStream );
+ if( err != paNoError ) goto error;
+
+ printf("Now recording!\n"); fflush(stdout);
+ for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
+ {
+ int frameIndex, delta;
+ Pa_Sleep(SLEEP_DUR_MSEC);
+
+ frameIndex = dataPtr->frameIndex;
+ if( Pa_StreamActive( dataPtr->inputStream ) <= 0)
+ {
+ printf("Stream inactive!\n");
+ break;
+ }
+ if( dataPtr->maxFrameIndex <= frameIndex )
+ {
+ printf("Buffer recording complete.\n");
+ break;
+ }
+
+ delta = frameIndex - lastIndex;
+ lastIndex = frameIndex;
+ printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout);
+ }
+
+ err = Pa_StopStream( dataPtr->inputStream );
+ if( err != paNoError ) goto error;
+
+ printf("Done.\n"); fflush(stdout);
+
+error:
+ return err;
+}
+
+/****************************************************************/
+PaError TestPlayback( paTestData *dataPtr )
+{
+ PaError err;
+ int i;
+ int lastIndex = 0;
+
+ /* Playback recorded data. */
+ dataPtr->frameIndex = 0;
+ printf("Begin playback.\n"); fflush(stdout);
+
+/* Open output stream if not already open. */
+ if( dataPtr->outputStream == NULL )
+ {
+ err = Pa_OpenStream(
+ &dataPtr->outputStream,
+ paNoDevice,
+ 0, /* NO input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ Pa_GetDefaultOutputDeviceID(),
+ dataPtr->samplesPerFrame, /* stereo output */
+ PA_SAMPLE_TYPE,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ playCallback,
+ dataPtr );
+ if( err != paNoError ) goto error;
+ }
+
+ err = Pa_StartStream( dataPtr->outputStream );
+ if( err != paNoError ) goto error;
+
+ printf("Waiting for playback to finish.\n"); fflush(stdout);
+ for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
+ {
+ int frameIndex, delta;
+ Pa_Sleep(SLEEP_DUR_MSEC);
+ frameIndex = dataPtr->frameIndex;
+ delta = frameIndex - lastIndex;
+ lastIndex = frameIndex;
+ printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout);
+ }
+
+ err = Pa_StopStream( dataPtr->outputStream );
+ if( err != paNoError ) goto error;
+
+error:
+ return err;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ paTestData data = { 0 };
+ long totalFrames;
+ long numBytes;
+ long i;
+ printf("patest_record.c\n"); fflush(stdout);
+
+/* Set up test data structure and sample array. */
+ data.frameIndex = 0;
+ data.samplesPerFrame = 2;
+ data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE;
+
+ printf("totalFrames = %d\n", totalFrames ); fflush(stdout);
+ data.numSamples = totalFrames * data.samplesPerFrame;
+
+ numBytes = data.numSamples * sizeof(SAMPLE);
+ data.recordedSamples = (SAMPLE *) malloc( numBytes );
+ if( data.recordedSamples == NULL )
+ {
+ printf("Could not allocate record array.\n");
+ exit(1);
+ }
+ for( i=0; i<data.numSamples; i++ ) data.recordedSamples[i] = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+/* Record and playback multiple times. */
+ for( i=0; i<2; i++ )
+ {
+ err = TestRecording( &data );
+ if( err != paNoError ) goto error;
+
+ err = TestPlayback( &data );
+ if( err != paNoError ) goto error;
+ }
+
+/* Clean up. */
+ err = Pa_CloseStream( data.inputStream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( data.outputStream );
+ if( err != paNoError ) goto error;
+
+ if( err != paNoError ) goto error;
+
+ free( data.recordedSamples );
+ Pa_Terminate();
+
+ printf("Test complete.\n"); fflush(stdout);
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ if( err == paHostError )
+ {
+ fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() );
+ }
+ return -1;
+}
diff --git a/pd/portaudio/pa_tests/debug_sine.c b/pd/portaudio/pa_tests/debug_sine.c
new file mode 100644
index 00000000..93d74160
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_sine.c
@@ -0,0 +1,192 @@
+/*
+ * $Id: debug_sine.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_sine.c
+ * Play a sine sweep using the Portable Audio api for several seconds.
+ * Hacked test for debugging PA.
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+//#define OUTPUT_DEVICE (11)
+#define NUM_SECONDS (8)
+#define SLEEP_DUR (800)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+#if 0
+#define MIN_LATENCY_MSEC (200)
+#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
+#else
+#define NUM_BUFFERS (0)
+#endif
+#define MIN_FREQ (100.0f)
+#define MAX_FREQ (4000.0f)
+#define FREQ_SCALAR (1.00002f)
+#define CalcPhaseIncrement(freq) (freq/SAMPLE_RATE)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (400)
+typedef struct
+{
+ float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation
+ float phase_increment;
+ float left_phase;
+ float right_phase;
+ unsigned int framesToGo;
+}
+paTestData;
+/* Convert phase between and 1.0 to sine value
+ * using linear interpolation.
+ */
+float LookupSine( paTestData *data, float phase );
+float LookupSine( paTestData *data, float phase )
+{
+ float fIndex = phase*TABLE_SIZE;
+ int index = (int) fIndex;
+ float fract = fIndex - index;
+ float lo = data->sine[index];
+ float hi = data->sine[index+1];
+ float val = lo + fract*(hi-lo);
+ return val;
+}
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int framesToCalc;
+ int i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( data->framesToGo < framesPerBuffer )
+ {
+ framesToCalc = data->framesToGo;
+ data->framesToGo = 0;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ data->framesToGo -= framesPerBuffer;
+ }
+
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *out++ = LookupSine(data, data->left_phase); /* left */
+ *out++ = LookupSine(data, data->right_phase); /* right */
+ data->left_phase += data->phase_increment;
+ if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f;
+ data->right_phase += (data->phase_increment * 1.5f); /* fifth above */
+ if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f;
+ /* sweep frequency then start over. */
+ data->phase_increment *= FREQ_SCALAR;
+ if( data->phase_increment > CalcPhaseIncrement(MAX_FREQ) ) data->phase_increment = CalcPhaseIncrement(MIN_FREQ);
+ }
+ /* zero remainder of final buffer */
+ for( ; i<(int)framesPerBuffer; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalSamps;
+ printf("PortAudio Test: output sine sweep. ask for %d buffers\n", NUM_BUFFERS );
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.sine[TABLE_SIZE] = data.sine[0]; // set guard point
+ data.left_phase = data.right_phase = 0.0;
+ data.phase_increment = CalcPhaseIncrement(MIN_FREQ);
+ data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ printf("totalSamps = %d\n", totalSamps );
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE );
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
+ paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Is callback being called?\n");
+ for( i=0; i<((NUM_SECONDS+1)*1000); i+=SLEEP_DUR )
+ {
+ printf("data.framesToGo = %d\n", data.framesToGo ); fflush(stdout);
+ Pa_Sleep( SLEEP_DUR );
+ }
+ /* Stop sound until ENTER hit. */
+ printf("Call Pa_StopStream()\n");
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_sine_amp.c b/pd/portaudio/pa_tests/debug_sine_amp.c
new file mode 100644
index 00000000..b6b21865
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_sine_amp.c
@@ -0,0 +1,157 @@
+/*
+ * $Id: debug_sine_amp.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Play a different sine wave on each channels,
+ * using the Portable Audio api.
+ * Allos amplitude to be set interactively.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+#define FREQ_INCR (300.0 / SAMPLE_RATE)
+#define MAX_CHANNELS (64)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+typedef struct
+{
+ int numChannels;
+ double phases[MAX_CHANNELS];
+ float amplitude;
+}
+paTestData;
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int frameIndex, channelIndex;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
+ {
+ for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
+ {
+ /* Output sine wave on every channel. */
+ *out++ = (float) ( data->amplitude * sin(data->phases[channelIndex]) );
+
+ /* Play each channel at a higher frequency. */
+ data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
+ if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
+ }
+ }
+
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ char pad[256];
+ PortAudioStream *stream;
+ PaError err;
+ const PaDeviceInfo *pdi;
+ paTestData data = {0};
+ printf("PortAudio Test: output sine wave on each channel.\n" );
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE );
+ data.numChannels = pdi->maxOutputChannels;
+ if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS;
+ printf("Number of Channels = %d\n", data.numChannels );
+ data.amplitude = 1.0;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice, /* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ data.numChannels,
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ do
+ {
+ printf("Current amplitude = %f\n", data.amplitude );
+ printf("Enter new amplitude or 'q' to quit.\n");
+ fflush(stdout);
+ gets( pad );
+ if( pad[0] != 'q' )
+ {
+ // I tried to use atof but it seems to be broken on Mac OS X 10.1
+ float amp;
+ sscanf( pad, "%f", &amp );
+ data.amplitude = amp;
+ }
+ } while( pad[0] != 'q' );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_CloseStream( stream );
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_sine_formats.c b/pd/portaudio/pa_tests/debug_sine_formats.c
new file mode 100644
index 00000000..3f75fa2e
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_sine_formats.c
@@ -0,0 +1,202 @@
+/*
+ * $Id: debug_sine_formats.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sine_formats.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ * Test various data formats.
+ *
+ * Author: Phil Burk
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (10)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+
+#define LEFT_FREQ (SAMPLE_RATE/512.0) /* So we hit 1.0 */
+#define RIGHT_FREQ (500.0)
+
+#define AMPLITUDE (1.0)
+
+/* Select ONE format for testing. */
+#define TEST_UINT8 (1)
+#define TEST_INT8 (0)
+#define TEST_INT16 (0)
+#define TEST_FLOAT32 (0)
+
+#if TEST_UINT8
+#define TEST_FORMAT paUInt8
+typedef unsigned char SAMPLE_t;
+#define SAMPLE_ZERO (0x80)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
+#define FORMAT_NAME "Unsigned 8 Bit"
+
+#elif TEST_INT8
+#define TEST_FORMAT paInt8
+typedef char SAMPLE_t;
+#define SAMPLE_ZERO (0)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
+#define FORMAT_NAME "Signed 8 Bit"
+
+#elif TEST_INT16
+#define TEST_FORMAT paInt16
+typedef short SAMPLE_t;
+#define SAMPLE_ZERO (0)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x)))
+#define FORMAT_NAME "Signed 16 Bit"
+
+#elif TEST_FLOAT32
+#define TEST_FORMAT paFloat32
+typedef float SAMPLE_t;
+#define SAMPLE_ZERO (0.0)
+#define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x))
+#define FORMAT_NAME "Float 32 Bit"
+#endif
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+
+typedef struct
+{
+ double left_phase;
+ double right_phase;
+ unsigned int framesToGo;
+}
+paTestData;
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE_t *out = (SAMPLE_t *)outputBuffer;
+ SAMPLE_t sample;
+ int i;
+ int framesToCalc;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( data->framesToGo < framesPerBuffer )
+ {
+ framesToCalc = data->framesToGo;
+ data->framesToGo = 0;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ data->framesToGo -= framesPerBuffer;
+ }
+
+ for( i=0; i<framesToCalc; i++ )
+ {
+ data->left_phase += (LEFT_FREQ / SAMPLE_RATE);
+ if( data->left_phase > 1.0) data->left_phase -= 1.0;
+ sample = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. ))); /**/
+ *out++ = sample;
+/* *out++ = sample; /**/
+/* *out++ = 0; /**/
+
+ data->right_phase += (RIGHT_FREQ / SAMPLE_RATE);
+ if( data->right_phase > 1.0) data->right_phase -= 1.0;
+ *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. ))); /**/
+/* *out++ = 0; /* */
+ }
+ /* zero remainder of final buffer */
+ for( ; i<(int)framesPerBuffer; i++ )
+ {
+ *out++ = SAMPLE_ZERO; /* left */
+ *out++ = SAMPLE_ZERO; /* right */
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int totalSamps;
+
+ printf("PortAudio Test: output " FORMAT_NAME "\n");
+
+
+ data.left_phase = data.right_phase = 0.0;
+ data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ TEST_FORMAT,
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ TEST_FORMAT,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS );
+ while( Pa_StreamActive( stream ) ) Pa_Sleep(10);
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+
+ printf("PortAudio Test Finished: " FORMAT_NAME "\n");
+
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_srate.c b/pd/portaudio/pa_tests/debug_srate.c
new file mode 100644
index 00000000..b3e3b70f
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_srate.c
@@ -0,0 +1,265 @@
+/*
+ * $Id: debug_srate.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_record_reuse.c
+ * Record input into an array.
+ * Save array to a file.
+ * Based on patest_record.c but with various ugly debug hacks thrown in.
+ * Loop twice and reuse same streams.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include "portaudio.h"
+
+#define EWS88MT_12_REC (1)
+#define EWS88MT_12_PLAY (10)
+#define SBLIVE_REC (2)
+#define SBLIVE_PLAY (11)
+
+#if 0
+#define INPUT_DEVICE_ID Pa_GetDefaultInputDeviceID()
+#define OUTPUT_DEVICE_ID Pa_GetDefaultOutputDeviceID()
+#else
+#define INPUT_DEVICE_ID (EWS88MT_12_REC)
+#define OUTPUT_DEVICE_ID (SBLIVE_PLAY)
+#endif
+
+#define INPUT_SAMPLE_RATE (22050.0)
+#define OUTPUT_SAMPLE_RATE (22050.0)
+#define NUM_SECONDS (4)
+#define SLEEP_DUR_MSEC (1000)
+#define FRAMES_PER_BUFFER (64)
+#define NUM_REC_BUFS (0)
+#define SAMPLES_PER_FRAME (2)
+
+#define PA_SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+
+typedef struct
+{
+ long frameIndex; /* Index into sample array. */
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 recordCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData *) userData;
+ (void) outputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( inputBuffer != NULL )
+ {
+ data->frameIndex += framesPerBuffer;
+ }
+ return 0;
+}
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 playCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData *) userData;
+ (void) inputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( outputBuffer != NULL )
+ {
+ data->frameIndex += framesPerBuffer;
+ }
+ return 0;
+}
+
+/****************************************************************/
+PaError MeasureStreamRate( PortAudioStream *stream, paTestData *dataPtr, double *ratePtr )
+{
+ PaError err;
+ int i;
+ int totalFrames = 0;
+ int totalMSec = 0;
+
+ dataPtr->frameIndex = 0;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
+ {
+ int delta, endIndex;
+
+ int startIndex = dataPtr->frameIndex;
+ Pa_Sleep(SLEEP_DUR_MSEC);
+ endIndex = dataPtr->frameIndex;
+
+ delta = endIndex - startIndex;
+ totalFrames += delta;
+ totalMSec += SLEEP_DUR_MSEC;
+
+ printf("index = %d, delta = %d\n", endIndex, delta ); fflush(stdout);
+ }
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ *ratePtr = (totalFrames * 1000.0) / totalMSec;
+
+error:
+ return err;
+}
+
+void ReportRate( double measuredRate, double expectedRate )
+{
+ double error;
+
+ error = (measuredRate - expectedRate) / expectedRate;
+ error = (error < 0 ) ? -error : error;
+
+ printf("Measured rate = %6.1f, expected rate = %6.1f\n",
+ measuredRate, expectedRate );
+ if( error > 0.1 )
+ {
+ printf("ERROR: unexpected rate! --------------------- ERROR!\n");
+ }
+ else
+ {
+ printf("SUCCESS: rate within tolerance!\n");
+ }
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ paTestData data = { 0 };
+ long i;
+ double rate;
+ const PaDeviceInfo *pdi;
+
+ PortAudioStream *outputStream;
+ PortAudioStream *inputStream;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+
+ pdi = Pa_GetDeviceInfo( INPUT_DEVICE_ID );
+ printf("Input device = %s\n", pdi->name );
+ pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE_ID );
+ printf("Output device = %s\n", pdi->name );
+
+/* Open input stream. */
+ err = Pa_OpenStream(
+ &inputStream,
+ INPUT_DEVICE_ID,
+ SAMPLES_PER_FRAME, /* stereo input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ paNoDevice,
+ 0,
+ PA_SAMPLE_TYPE,
+ NULL,
+ INPUT_SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ recordCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &outputStream,
+ paNoDevice,
+ 0, /* NO input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ OUTPUT_DEVICE_ID,
+ SAMPLES_PER_FRAME, /* stereo output */
+ PA_SAMPLE_TYPE,
+ NULL,
+ OUTPUT_SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ playCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+/* Record and playback multiple times. */
+ for( i=0; i<2; i++ )
+ {
+ printf("Measuring INPUT ------------------------- \n");
+ err = MeasureStreamRate( inputStream, &data, &rate );
+ if( err != paNoError ) goto error;
+ ReportRate( rate, INPUT_SAMPLE_RATE );
+
+ printf("Measuring OUTPUT ------------------------- \n");
+ err = MeasureStreamRate( outputStream, &data, &rate );
+ if( err != paNoError ) goto error;
+ ReportRate( rate, OUTPUT_SAMPLE_RATE );
+ }
+
+/* Clean up. */
+ err = Pa_CloseStream( inputStream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( outputStream );
+ if( err != paNoError ) goto error;
+
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+
+ printf("Test complete.\n"); fflush(stdout);
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ if( err == paHostError )
+ {
+ fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() );
+ }
+ return -1;
+}
diff --git a/pd/portaudio/pa_tests/debug_test1.c b/pd/portaudio/pa_tests/debug_test1.c
new file mode 100644
index 00000000..05370b00
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_test1.c
@@ -0,0 +1,114 @@
+/*
+ * $Id: debug_test1.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ patest1.c
+ Ring modulate the audio input with a 441hz sine wave for 20 seconds
+ using the Portable Audio api
+ Author: Ross Bencina <rossb@audiomulch.com>
+ Modifications:
+ April 5th, 2001 - PLB - Check for NULL inputBuffer.
+*/
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+typedef struct
+{
+ float sine[100];
+ int phase;
+ int sampsToGo;
+}
+patest1data;
+static int patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long bufferFrames,
+ PaTimestamp outTime, void *userData )
+{
+ patest1data *data = (patest1data*)userData;
+ float *in = (float*)inputBuffer;
+ float *out = (float*)outputBuffer;
+ int framesToCalc = bufferFrames;
+ unsigned long i;
+ int finished = 0;
+ if(inputBuffer == NULL) return 0;
+ if( data->sampsToGo < bufferFrames )
+ {
+ finished = 1;
+ }
+ for( i=0; i<bufferFrames; i++ )
+ {
+ *out++ = *in++;
+ *out++ = *in++;
+ if( data->phase >= 100 )
+ data->phase = 0;
+ }
+ data->sampsToGo -= bufferFrames;
+ /* zero remainder of final buffer if not already done */
+ for( ; i<bufferFrames; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+ return finished;
+}
+int main(int argc, char* argv[]);
+int main(int argc, char* argv[])
+{
+ PaStream *stream;
+ PaError err;
+ patest1data data;
+ int i;
+ int inputDevice = Pa_GetDefaultInputDeviceID();
+ int outputDevice = Pa_GetDefaultOutputDeviceID();
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<100; i++ )
+ data.sine[i] = sin( ((double)i/100.) * M_PI * 2. );
+ data.phase = 0;
+ data.sampsToGo = 44100 * 4; // 20 seconds
+ /* initialise portaudio subsytem */
+ Pa_Initialize();
+ err = Pa_OpenStream(
+ &stream,
+ inputDevice,
+ 2, /* stereo input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ outputDevice,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ 44100.,
+ // 22050, /* half second buffers */
+ // 4, /* four buffers */
+ 512, /* half second buffers */
+ 0, /* four buffers */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patest1Callback,
+ &data );
+ if( err == paNoError )
+ {
+ err = Pa_StartStream( stream );
+ // printf( "Press any key to end.\n" );
+ // getc( stdin ); //wait for input before exiting
+ // Pa_AbortStream( stream );
+
+ printf( "Waiting for stream to complete...\n" );
+
+ while( Pa_StreamActive( stream ) )
+ Pa_Sleep(1000); /* sleep until playback has finished */
+
+ err = Pa_CloseStream( stream );
+ }
+ else
+ {
+ fprintf( stderr, "An error occured while opening the portaudio stream\n" );
+ if( err == paHostError )
+ fprintf( stderr, "Host error number: %d\n", Pa_GetHostError() );
+ else
+ fprintf( stderr, "Error number: %d\n", err );
+ }
+ Pa_Terminate();
+ printf( "bye\n" );
+
+ return 0;
+}
diff --git a/pd/portaudio/pa_tests/pa_devs.c b/pd/portaudio/pa_tests/pa_devs.c
new file mode 100644
index 00000000..983699d1
--- /dev/null
+++ b/pd/portaudio/pa_tests/pa_devs.c
@@ -0,0 +1,199 @@
+/*
+ * $Id: pa_devs.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * pa_devs.c
+ * List available devices.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+/*******************************************************************/
+static void PrintSupportedStandardSampleRates(
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters )
+{
+ static double standardSampleRates[] = {
+ 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
+ 44100.0, 48000.0, 88200.0, 96000.0, -1 /* negative terminated list */
+ };
+ int i, printCount;
+ PaError err;
+
+ printCount = 0;
+ for( i=0; standardSampleRates[i] > 0; i++ )
+ {
+ err = Pa_IsFormatSupported( inputParameters, outputParameters, standardSampleRates[i] );
+ if( err == paFormatIsSupported )
+ {
+ if( printCount == 0 )
+ {
+ printf( "\t%8.2f", standardSampleRates[i] );
+ printCount = 1;
+ }
+ else if( printCount == 4 )
+ {
+ printf( ",\n\t%8.2f", standardSampleRates[i] );
+ printCount = 1;
+ }
+ else
+ {
+ printf( ", %8.2f", standardSampleRates[i] );
+ ++printCount;
+ }
+ }
+ }
+ if( !printCount )
+ printf( "None\n" );
+ else
+ printf( "\n" );
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i, numDevices, defaultDisplayed;
+ const PaDeviceInfo *deviceInfo;
+ PaStreamParameters inputParameters, outputParameters;
+ PaError err;
+
+
+ Pa_Initialize();
+
+ printf( "PortAudio version number = %d\nPortAudio version text = '%s'\n",
+ Pa_GetVersion(), Pa_GetVersionText() );
+
+
+ numDevices = Pa_CountDevices();
+ if( numDevices < 0 )
+ {
+ printf( "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
+ err = numDevices;
+ goto error;
+ }
+
+ printf( "Number of devices = %d\n", numDevices );
+ for( i=0; i<numDevices; i++ )
+ {
+ deviceInfo = Pa_GetDeviceInfo( i );
+ printf( "--------------------------------------- device #%d\n", i );
+
+ /* Mark global and API specific default devices */
+ defaultDisplayed = 0;
+ if( i == Pa_GetDefaultInputDevice() )
+ {
+ printf( "[ Default Input" );
+ defaultDisplayed = 1;
+ }
+ else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultInputDevice )
+ {
+ const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
+ printf( "[ Default %s Input", hostInfo->name );
+ defaultDisplayed = 1;
+ }
+
+ if( i == Pa_GetDefaultOutputDevice() )
+ {
+ printf( (defaultDisplayed ? "," : "[") );
+ printf( " Default Output" );
+ defaultDisplayed = 1;
+ }
+ else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultOutputDevice )
+ {
+ const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
+ printf( (defaultDisplayed ? "," : "[") );
+ printf( " Default %s Output", hostInfo->name );
+ defaultDisplayed = 1;
+ }
+
+ if( defaultDisplayed )
+ printf( " ]\n" );
+
+ /* print device info fields */
+ printf( "Name = %s\n", deviceInfo->name );
+ printf( "Host API = %s\n", Pa_GetHostApiInfo( deviceInfo->hostApi )->name );
+ printf( "Max inputs = %d", deviceInfo->maxInputChannels );
+ printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels );
+
+ printf( "Default low input latency = %8.3f\n", deviceInfo->defaultLowInputLatency );
+ printf( "Default low output latency = %8.3f\n", deviceInfo->defaultLowOutputLatency );
+ printf( "Default high input latency = %8.3f\n", deviceInfo->defaultHighInputLatency );
+ printf( "Default high output latency = %8.3f\n", deviceInfo->defaultHighOutputLatency );
+
+ printf( "Default sample rate = %8.2f\n", deviceInfo->defaultSampleRate );
+
+ /* poll for standard sample rates */
+ inputParameters.device = i;
+ inputParameters.channelCount = deviceInfo->maxInputChannels;
+ inputParameters.sampleFormat = paInt16;
+ inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+
+ outputParameters.device = i;
+ outputParameters.channelCount = deviceInfo->maxOutputChannels;
+ outputParameters.sampleFormat = paInt16;
+ outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ if( inputParameters.channelCount > 0 )
+ {
+ printf("Supported standard sample rates\n for half-duplex 16 bit %d channel input = \n",
+ inputParameters.channelCount );
+ PrintSupportedStandardSampleRates( &inputParameters, NULL );
+ }
+
+ if( outputParameters.channelCount > 0 )
+ {
+ printf("Supported standard sample rates\n for half-duplex 16 bit %d channel output = \n",
+ outputParameters.channelCount );
+ PrintSupportedStandardSampleRates( NULL, &outputParameters );
+ }
+
+ if( inputParameters.channelCount > 0 && outputParameters.channelCount > 0 )
+ {
+ printf("Supported standard sample rates\n for full-duplex 16 bit %d channel input, %d channel output = \n",
+ inputParameters.channelCount, outputParameters.channelCount );
+ PrintSupportedStandardSampleRates( &inputParameters, &outputParameters );
+ }
+ }
+
+ Pa_Terminate();
+
+ printf("----------------------------------------------\n");
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/pa_fuzz.c b/pd/portaudio/pa_tests/pa_fuzz.c
new file mode 100644
index 00000000..1ec88785
--- /dev/null
+++ b/pd/portaudio/pa_tests/pa_fuzz.c
@@ -0,0 +1,168 @@
+/*
+ * $Id: pa_fuzz.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * pa_fuzz.c
+ * Distort input like a fuzz boz.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+/*
+** Note that many of the older ISA sound cards on PCs do NOT support
+** full duplex audio (simultaneous record and playback).
+** And some only support full duplex at lower sample rates.
+*/
+#define SAMPLE_RATE (44100)
+#define PA_SAMPLE_TYPE paFloat32
+#define FRAMES_PER_BUFFER (64)
+
+typedef float SAMPLE;
+
+float CubicAmplifier( float input );
+static int fuzzCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData );
+
+/* Non-linear amplifier with soft distortion curve. */
+float CubicAmplifier( float input )
+{
+ float output, temp;
+ if( input < 0.0 )
+ {
+ temp = input + 1.0f;
+ output = (temp * temp * temp) - 1.0f;
+ }
+ else
+ {
+ temp = input - 1.0f;
+ output = (temp * temp * temp) + 1.0f;
+ }
+
+ return output;
+}
+#define FUZZ(x) CubicAmplifier(CubicAmplifier(CubicAmplifier(CubicAmplifier(x))))
+
+static int gNumNoInputs = 0;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 fuzzCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData )
+{
+ SAMPLE *out = (SAMPLE*)outputBuffer;
+ SAMPLE *in = (SAMPLE*)inputBuffer;
+ unsigned int i;
+ (void) timeInfo; /* Prevent unused variable warnings. */
+ (void) statusFlags;
+ (void) userData;
+
+ if( inputBuffer == NULL )
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = 0; /* left - silent */
+ *out++ = 0; /* right - silent */
+ }
+ gNumNoInputs += 1;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = FUZZ(*in++); /* left - distorted */
+ *out++ = *in++; /* right - clean */
+ }
+ }
+
+ return paContinue;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStreamParameters inputParameters, outputParameters;
+ PaStream *stream;
+ PaError err;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+
+ inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
+ inputParameters.channelCount = 2; /* stereo input */
+ inputParameters.sampleFormat = PA_SAMPLE_TYPE;
+ inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+
+ outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
+ outputParameters.channelCount = 2; /* stereo output */
+ outputParameters.sampleFormat = PA_SAMPLE_TYPE;
+ outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ err = Pa_OpenStream(
+ &stream,
+ &inputParameters,
+ &outputParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ 0, // paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ fuzzCallback,
+ NULL );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Hit ENTER to stop program.\n");
+ getchar();
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Finished. gNumNoInputs = %d\n", gNumNoInputs );
+ Pa_Terminate();
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
diff --git a/pd/portaudio/pa_tests/pa_minlat.c b/pd/portaudio/pa_tests/pa_minlat.c
new file mode 100644
index 00000000..736445a7
--- /dev/null
+++ b/pd/portaudio/pa_tests/pa_minlat.c
@@ -0,0 +1,176 @@
+/*
+ * $Id: pa_minlat.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * paminlat.c
+ * Experiment with different numbers of buffers to determine the
+ * minimum latency for a computer.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TWOPI (M_PI * 2.0)
+
+#define DEFAULT_BUFFER_SIZE (32)
+
+typedef struct
+{
+ double left_phase;
+ double right_phase;
+}
+paTestData;
+
+/* Very simple synthesis routine to generate two sine waves. */
+static int paminlatCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned int i;
+ double left_phaseInc = 0.02;
+ double right_phaseInc = 0.06;
+
+ double left_phase = data->left_phase;
+ double right_phase = data->right_phase;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ left_phase += left_phaseInc;
+ if( left_phase > TWOPI ) left_phase -= TWOPI;
+ *out++ = (float) sin( left_phase );
+
+ right_phase += right_phaseInc;
+ if( right_phase > TWOPI ) right_phase -= TWOPI;
+ *out++ = (float) sin( right_phase );
+ }
+
+ data->left_phase = left_phase;
+ data->right_phase = right_phase;
+ return 0;
+}
+void main( int argc, char **argv );
+void main( int argc, char **argv )
+{
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int go;
+ int outLatency = 0;
+ int minLatency = DEFAULT_BUFFER_SIZE * 2;
+ int framesPerBuffer;
+ double sampleRate = 44100.0;
+ char str[256];
+ printf("pa_minlat - Determine minimum latency for your computer.\n");
+ printf(" usage: pa_minlat {userBufferSize}\n");
+ printf(" for example: pa_minlat 64\n");
+ printf("Adjust your stereo until you hear a smooth tone in each speaker.\n");
+ printf("Then try to find the smallest number of frames that still sounds smooth.\n");
+ printf("Note that the sound will stop momentarily when you change the number of buffers.\n");
+
+ /* Get bufferSize from command line. */
+ framesPerBuffer = ( argc > 1 ) ? atol( argv[1] ) : DEFAULT_BUFFER_SIZE;
+ printf("Frames per buffer = %d\n", framesPerBuffer );
+
+ data.left_phase = data.right_phase = 0.0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ outLatency = sampleRate * 200.0 / 1000.0; // 200 msec
+
+ /* Try different numBuffers in a loop. */
+ go = 1;
+ while( go )
+ {
+
+ printf("Latency = %d frames = %6.1f msec.\n", outLatency,
+ (outLatency * 1000.0 / sampleRate) );
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ 0,
+ NULL,
+ Pa_GetDefaultOutputDevice(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ outLatency,
+ NULL,
+ sampleRate,
+ framesPerBuffer,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ paminlatCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ if( stream == NULL ) goto error;
+
+ /* Start audio. */
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ /* Ask user for a new nlatency. */
+ printf("\nMove windows around to see if the sound glitches.\n");
+ printf("Latency currently %d, enter new number, or 'q' to quit: ", outLatency );
+ gets( str );
+ if( str[0] == 'q' ) go = 0;
+ else
+ {
+ outLatency = atol( str );
+ if( outLatency < minLatency )
+ {
+ printf( "Latency below minimum of %d! Set to minimum!!!\n", minLatency );
+ outLatency = minLatency;
+ }
+ }
+ /* Stop sound until ENTER hit. */
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ }
+ printf("A good setting for latency would be somewhat higher than\n");
+ printf("the minimum latency that worked.\n");
+ printf("PortAudio: Test finished.\n");
+ Pa_Terminate();
+ return;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+}
diff --git a/pd/portaudio/pa_tests/paqa_devs.c b/pd/portaudio/pa_tests/paqa_devs.c
new file mode 100644
index 00000000..904a6082
--- /dev/null
+++ b/pd/portaudio/pa_tests/paqa_devs.c
@@ -0,0 +1,317 @@
+/*
+ * $Id: paqa_devs.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * paqa_devs.c
+ * Self Testing Quality Assurance app for PortAudio
+ * Try to open each device and run through all the
+ * possible configurations.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#include "pa_trace.h"
+/****************************************** Definitions ***********/
+#define MODE_INPUT (0)
+#define MODE_OUTPUT (1)
+typedef struct PaQaData
+{
+ unsigned long framesLeft;
+ int numChannels;
+ int bytesPerSample;
+ int mode;
+ short sawPhase;
+ PaSampleFormat format;
+}
+PaQaData;
+/****************************************** Prototypes ***********/
+static void TestDevices( int mode );
+static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate,
+ int numChannels );
+static int TestAdvance( int mode, PaDeviceID deviceID, double sampleRate,
+ int numChannels, PaSampleFormat format );
+static int QaCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+/****************************************** Globals ***********/
+static int gNumPassed = 0;
+static int gNumFailed = 0;
+/****************************************** Macros ***********/
+/* Print ERROR if it fails. Tally success or failure. */
+/* Odd do-while wrapper seems to be needed for some compilers. */
+#define EXPECT(_exp) \
+ do \
+ { \
+ if ((_exp)) {\
+ /* printf("SUCCESS for %s\n", #_exp ); */ \
+ gNumPassed++; \
+ } \
+ else { \
+ printf("ERROR - 0x%x - %s for %s\n", result, \
+ ((result == 0) ? "-" : Pa_GetErrorText(result)), \
+ #_exp ); \
+ gNumFailed++; \
+ goto error; \
+ } \
+ } while(0)
+/*******************************************************************/
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 QaCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ unsigned long i;
+ short phase;
+ PaQaData *data = (PaQaData *) userData;
+ (void) inputBuffer;
+ (void) outTime;
+
+ /* Play simle sawtooth wave. */
+ if( data->mode == MODE_OUTPUT )
+ {
+ phase = data->sawPhase;
+ switch( data->format )
+ {
+ case paFloat32:
+ {
+ float *out = (float *) outputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ phase += 0x123;
+ *out++ = (float) (phase * (1.0 / 32768.0));
+ if( data->numChannels == 2 )
+ {
+ *out++ = (float) (phase * (1.0 / 32768.0));
+ }
+ }
+ }
+ break;
+
+ case paInt32:
+ {
+ int *out = (int *) outputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ phase += 0x123;
+ *out++ = ((int) phase ) << 16;
+ if( data->numChannels == 2 )
+ {
+ *out++ = ((int) phase ) << 16;
+ }
+ }
+ }
+ break;
+ case paInt16:
+ {
+ short *out = (short *) outputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ phase += 0x123;
+ *out++ = phase;
+ if( data->numChannels == 2 )
+ {
+ *out++ = phase;
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ unsigned char *out = (unsigned char *) outputBuffer;
+ unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample;
+ for( i=0; i<numBytes; i++ )
+ {
+ *out++ = 0;
+ }
+ }
+ break;
+ }
+ data->sawPhase = phase;
+ }
+ /* Are we through yet? */
+ if( data->framesLeft > framesPerBuffer )
+ {
+ AddTraceMessage("QaCallback: running. framesLeft", data->framesLeft );
+ data->framesLeft -= framesPerBuffer;
+ return 0;
+ }
+ else
+ {
+ AddTraceMessage("QaCallback: DONE! framesLeft", data->framesLeft );
+ data->framesLeft = 0;
+ return 1;
+ }
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError result;
+ EXPECT( ((result=Pa_Initialize()) == 0) );
+ printf("Test OUTPUT ---------------\n");
+ TestDevices( MODE_OUTPUT );
+ printf("Test INPUT ---------------\n");
+ TestDevices( MODE_INPUT );
+error:
+ Pa_Terminate();
+ printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed );
+}
+/*******************************************************************
+* Try each output device, through its full range of capabilities. */
+static void TestDevices( int mode )
+{
+ int id,jc,kr;
+ int maxChannels;
+ const PaDeviceInfo *pdi;
+ int numDevices = Pa_CountDevices();
+ /* Iterate through all devices. */
+ for( id=0; id<numDevices; id++ )
+ {
+ pdi = Pa_GetDeviceInfo( id );
+ /* Try 1 to maxChannels on each device. */
+ maxChannels = ( mode == MODE_INPUT ) ? pdi->maxInputChannels : pdi->maxOutputChannels;
+ for( jc=1; jc<=maxChannels; jc++ )
+ {
+ printf("Name = %s\n", pdi->name );
+ /* Try each legal sample rate. */
+ if( pdi->numSampleRates == -1 )
+ {
+ double low, high;
+ low = pdi->sampleRates[0];
+ high = pdi->sampleRates[1];
+ if( low < 8000.0 ) low = 8000.0;
+ TestFormats( mode, id, low, jc );
+#define TESTSR(sr) {if(((sr)>=low) && ((sr)<=high)) TestFormats( mode, id, (sr), jc ); }
+
+ TESTSR(11025.0);
+ TESTSR(22050.0);
+ TESTSR(44100.0);
+ TestFormats( mode, id, high, jc );
+ }
+ else
+ {
+ for( kr=0; kr<pdi->numSampleRates; kr++ )
+ {
+ TestFormats( mode, id, pdi->sampleRates[kr], jc );
+ }
+ }
+ }
+ }
+}
+/*******************************************************************/
+static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate,
+ int numChannels )
+{
+ TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 ); /* */
+ TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); /* */
+ TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); /* */
+ /* TestAdvance( mode, deviceID, sampleRate, numChannels, paInt24 ); */
+}
+/*******************************************************************/
+static int TestAdvance( int mode, PaDeviceID deviceID, double sampleRate,
+ int numChannels, PaSampleFormat format )
+{
+ PortAudioStream *stream = NULL;
+ PaError result;
+ PaQaData myData;
+#define FRAMES_PER_BUFFER (64)
+ printf("------ TestAdvance: %s, device = %d, rate = %g, numChannels = %d, format = %d -------\n",
+ ( mode == MODE_INPUT ) ? "INPUT" : "OUTPUT",
+ deviceID, sampleRate, numChannels, format);
+ /* Setup data for synthesis thread. */
+ myData.framesLeft = (unsigned long) (sampleRate * 100); /* 100 seconds */
+ myData.numChannels = numChannels;
+ myData.mode = mode;
+ myData.format = format;
+ switch( format )
+ {
+ case paFloat32:
+ case paInt32:
+ case paInt24:
+ myData.bytesPerSample = 4;
+ break;
+ case paPackedInt24:
+ myData.bytesPerSample = 3;
+ break;
+ default:
+ myData.bytesPerSample = 2;
+ break;
+ }
+ EXPECT( ((result = Pa_OpenStream(
+ &stream,
+ ( mode == MODE_INPUT ) ? deviceID : paNoDevice,
+ ( mode == MODE_INPUT ) ? numChannels : 0,
+ format,
+ NULL,
+ ( mode == MODE_OUTPUT ) ? deviceID : paNoDevice,
+ ( mode == MODE_OUTPUT ) ? numChannels : 0,
+ format,
+ NULL,
+ sampleRate,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ QaCallback,
+ &myData )
+ ) == 0) );
+ if( stream )
+ {
+ PaTimestamp oldStamp, newStamp;
+ unsigned long oldFrames;
+ int minDelay = ( mode == MODE_INPUT ) ? 1000 : 400;
+ int minNumBuffers = Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );
+ int msec = (int) ((minNumBuffers * 3 * 1000.0 * FRAMES_PER_BUFFER) / sampleRate);
+ if( msec < minDelay ) msec = minDelay;
+ printf("msec = %d\n", msec); /**/
+ EXPECT( ((result=Pa_StartStream( stream )) == 0) );
+ /* Check to make sure PortAudio is advancing timeStamp. */
+ result = paNoError;
+ oldStamp = Pa_StreamTime(stream);
+ Pa_Sleep(msec);
+ newStamp = Pa_StreamTime(stream);
+ printf("oldStamp = %g,newStamp = %g\n", oldStamp, newStamp ); /**/
+ EXPECT( (oldStamp < newStamp) );
+ /* Check to make sure callback is decrementing framesLeft. */
+ oldFrames = myData.framesLeft;
+ Pa_Sleep(msec);
+ printf("oldFrames = %d, myData.framesLeft = %d\n", oldFrames, myData.framesLeft ); /**/
+ EXPECT( (oldFrames > myData.framesLeft) );
+ EXPECT( ((result=Pa_CloseStream( stream )) == 0) );
+ stream = NULL;
+ }
+error:
+ if( stream != NULL ) Pa_CloseStream( stream );
+ return result;
+}
diff --git a/pd/portaudio/pa_tests/paqa_errs.c b/pd/portaudio/pa_tests/paqa_errs.c
new file mode 100644
index 00000000..d0738602
--- /dev/null
+++ b/pd/portaudio/pa_tests/paqa_errs.c
@@ -0,0 +1,330 @@
+/*
+ * $Id: paqa_errs.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * paqa_devs.c
+ * Self Testing Quality Assurance app for PortAudio
+ * Do lots of bad things to test error reporting.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+/****************************************** Definitions ***********/
+#define MODE_INPUT (0)
+#define MODE_OUTPUT (1)
+#define FRAMES_PER_BUFFER (64)
+#define SAMPLE_RATE (44100.0)
+#define NUM_BUFFERS (0)
+typedef struct PaQaData
+{
+ unsigned long framesLeft;
+ int numChannels;
+ int bytesPerSample;
+ int mode;
+}
+PaQaData;
+/****************************************** Prototypes ***********/
+static void TestDevices( int mode );
+static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate,
+ int numChannels );
+static int TestBadOpens( void );
+static int TestBadActions( void );
+static int QaCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+/****************************************** Globals ***********/
+static int gNumPassed = 0;
+static int gNumFailed = 0;
+/****************************************** Macros ***********/
+/* Print ERROR if it fails. Tally success or failure. */
+/* Odd do-while wrapper seems to be needed for some compilers. */
+#define EXPECT(_exp) \
+ do \
+ { \
+ if ((_exp)) {\
+ gNumPassed++; \
+ } \
+ else { \
+ printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \
+ gNumFailed++; \
+ goto error; \
+ } \
+ } while(0)
+#define HOPEFOR(_exp) \
+ do \
+ { \
+ if ((_exp)) {\
+ gNumPassed++; \
+ } \
+ else { \
+ printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \
+ gNumFailed++; \
+ } \
+ } while(0)
+/*******************************************************************/
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 QaCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ unsigned long i;
+ unsigned char *out = (unsigned char *) outputBuffer;
+ PaQaData *data = (PaQaData *) userData;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+ (void) outTime;
+
+ /* Zero out buffer so we don't hear terrible noise. */
+ if( data->mode == MODE_OUTPUT )
+ {
+ unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample;
+ for( i=0; i<numBytes; i++ )
+ {
+ *out++ = 0;
+ }
+ }
+ /* Are we through yet? */
+ if( data->framesLeft > framesPerBuffer )
+ {
+ data->framesLeft -= framesPerBuffer;
+ return 0;
+ }
+ else
+ {
+ data->framesLeft = 0;
+ return 1;
+ }
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError result;
+ EXPECT( ((result=Pa_Initialize()) == 0) );
+ TestBadOpens();
+ TestBadActions();
+error:
+ Pa_Terminate();
+ printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed );
+ return 0;
+}
+/*******************************************************************/
+static int TestBadOpens( void )
+{
+ PortAudioStream *stream = NULL;
+ PaError result;
+ PaQaData myData;
+ /* Setup data for synthesis thread. */
+ myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */
+ myData.numChannels = 1;
+ myData.mode = MODE_OUTPUT;
+ HOPEFOR( (/* No devices specified. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ paNoDevice, 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidDeviceId) );
+ HOPEFOR( ( /* Out of range input device specified. */
+ (result = Pa_OpenStream(
+ &stream,
+ Pa_CountDevices(), 0, paFloat32, NULL,
+ paNoDevice, 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidDeviceId) );
+
+ HOPEFOR( ( /* Out of range output device specified. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_CountDevices(), 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidDeviceId) );
+ HOPEFOR( ( /* Zero input channels. */
+ (result = Pa_OpenStream(
+ &stream,
+ Pa_GetDefaultInputDeviceID(), 0, paFloat32, NULL,
+ paNoDevice, 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidChannelCount) );
+ HOPEFOR( ( /* Zero output channels. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidChannelCount) );
+ HOPEFOR( ( /* Nonzero input channels but no device. */
+ (result = Pa_OpenStream(
+ &stream,
+ Pa_GetDefaultInputDeviceID(), 2, paFloat32, NULL,
+ paNoDevice, 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidChannelCount) );
+
+ HOPEFOR( ( /* Nonzero output channels but no device. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 2, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidChannelCount) );
+ HOPEFOR( ( /* NULL stream pointer. */
+ (result = Pa_OpenStream(
+ NULL,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paBadStreamPtr) );
+ HOPEFOR( ( /* Low sample rate. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ 1.0, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidSampleRate) );
+ HOPEFOR( ( /* High sample rate. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ 10000000.0, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidSampleRate) );
+ HOPEFOR( ( /* NULL callback. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ NULL,
+ &myData )
+ ) == paNullCallback) );
+ HOPEFOR( ( /* Bad flag. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ (1<<3),
+ QaCallback,
+ &myData )
+ ) == paInvalidFlag) );
+
+#if 0 /* FIXME - this is legal for some implementations. */
+ HOPEFOR( ( /* Use input device as output device. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultInputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidDeviceId) );
+
+ HOPEFOR( ( /* Use output device as input device. */
+ (result = Pa_OpenStream(
+ &stream,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ paNoDevice, 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidDeviceId) );
+#endif
+
+ if( stream != NULL ) Pa_CloseStream( stream );
+ return result;
+}
+/*******************************************************************/
+static int TestBadActions( void )
+{
+ PortAudioStream *stream = NULL;
+ PaError result;
+ PaQaData myData;
+ /* Setup data for synthesis thread. */
+ myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */
+ myData.numChannels = 1;
+ myData.mode = MODE_OUTPUT;
+ /* Default output. */
+ EXPECT( ((result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == 0) );
+ HOPEFOR( ((result = Pa_StartStream( NULL )) == paBadStreamPtr) );
+ HOPEFOR( ((result = Pa_StopStream( NULL )) == paBadStreamPtr) );
+ HOPEFOR( ((result = Pa_StreamActive( NULL )) == paBadStreamPtr) );
+ HOPEFOR( ((result = Pa_CloseStream( NULL )) == paBadStreamPtr) );
+ HOPEFOR( ((result = (PaError)Pa_StreamTime( NULL )) != 0) );
+ HOPEFOR( ((result = (PaError)Pa_GetCPULoad( NULL )) != 0) );
+error:
+ if( stream != NULL ) Pa_CloseStream( stream );
+ return result;
+}
diff --git a/pd/portaudio/pa_tests/patest1.c b/pd/portaudio/pa_tests/patest1.c
new file mode 100644
index 00000000..1f969436
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest1.c
@@ -0,0 +1,119 @@
+/*
+ $Id: patest1.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ patest1.c
+ Ring modulate the audio input with a sine wave for 20 seconds
+ using the Portable Audio api
+ Author: Ross Bencina <rossb@audiomulch.com>
+ Modifications:
+ April 5th, 2001 - PLB - Check for NULL inputBuffer.
+*/
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+typedef struct
+{
+ float sine[100];
+ int phase;
+ int sampsToGo;
+}
+patest1data;
+static int patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long bufferFrames,
+ PaTime outTime, void *userData )
+{
+ patest1data *data = (patest1data*)userData;
+ float *in = (float*)inputBuffer;
+ float *out = (float*)outputBuffer;
+ int framesToCalc = bufferFrames;
+ unsigned long i;
+ int finished = 0;
+ /* Check to see if any input data is available. */
+ if(inputBuffer == NULL) return 0;
+ if( data->sampsToGo < bufferFrames )
+ {
+ framesToCalc = data->sampsToGo;
+ finished = 1;
+ }
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *out++ = *in++ * data->sine[data->phase]; /* left */
+ *out++ = *in++ * data->sine[data->phase++]; /* right */
+ if( data->phase >= 100 )
+ data->phase = 0;
+ }
+ data->sampsToGo -= framesToCalc;
+ /* zero remainder of final buffer if not already done */
+ for( ; i<bufferFrames; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+ return finished;
+}
+int main(int argc, char* argv[]);
+int main(int argc, char* argv[])
+{
+ PaStream *stream;
+ PaError err;
+ patest1data data;
+ int i;
+ int inputDevice = Pa_GetDefaultInputDevice();
+ int outputDevice = Pa_GetDefaultOutputDevice();
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<100; i++ )
+ data.sine[i] = sin( ((double)i/100.) * M_PI * 2. );
+ data.phase = 0;
+ data.sampsToGo = 44100 * 20; // 20 seconds
+ /* initialise portaudio subsytem */
+ Pa_Initialize();
+ err = Pa_OpenStream(
+ &stream,
+ inputDevice,
+ 2, /* stereo input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ outputDevice,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ 44100.,
+ 512, /* small buffers */
+ 0, /* let PA determine number of buffers */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patest1Callback,
+ &data );
+ if( err == paNoError )
+ {
+ err = Pa_StartStream( stream );
+ printf( "Press any key to end.\n" );
+ getc( stdin ); //wait for input before exiting
+ Pa_AbortStream( stream );
+
+ printf( "Waiting for stream to complete...\n" );
+
+ while( Pa_IsStreamActive( stream ) )
+ Pa_Sleep(1000); /* sleep until playback has finished */
+
+ err = Pa_CloseStream( stream );
+ }
+ else
+ {
+ fprintf( stderr, "An error occured while opening the portaudio stream\n" );
+ if( err == paHostError )
+ {
+ fprintf( stderr, "Host error number: %d\n", Pa_GetHostError() );
+ }
+ else
+ {
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error text: %s\n", Pa_GetErrorText( err ) );
+ }
+ }
+ Pa_Terminate();
+ printf( "bye\n" );
+
+ return 0;
+}
diff --git a/pd/portaudio/pa_tests/patest_buffer.c b/pd/portaudio/pa_tests/patest_buffer.c
new file mode 100644
index 00000000..dbc55913
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_buffer.c
@@ -0,0 +1,181 @@
+/*
+ * $Id: patest_buffer.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_buffer.c
+ * Test opening streams with different buffer sizes.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (1)
+#define SAMPLE_RATE (44100)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+
+#define BUFFER_TABLE 9
+long buffer_table[] = {200,256,500,512,600, 723, 1000, 1024, 2345};
+
+typedef struct
+{
+ short sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+ unsigned int sampsToGo;
+}
+paTestData;
+PaError TestOnce( int buffersize );
+
+static int patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+/* 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 patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ short *out = (short*)outputBuffer;
+ unsigned int i;
+ int finished = 0;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+ (void) outTime;
+
+ if( data->sampsToGo < framesPerBuffer )
+ {
+ /* final buffer... */
+
+ for( i=0; i<data->sampsToGo; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ /* zero remainder of final buffer */
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+
+ finished = 1;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ data->sampsToGo -= framesPerBuffer;
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i;
+ PaError err;
+ printf("Test opening streams with different buffer sizes\n\n");
+
+ for (i = 0 ; i < BUFFER_TABLE; i++)
+ {
+ printf("Buffer size %d\n", buffer_table[i]);
+ err = TestOnce(buffer_table[i]);
+ if( err < 0 ) return 0;
+
+ }
+}
+
+
+PaError TestOnce( int buffersize )
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalSamps;
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (short) (32767.0 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ));
+ }
+ data.left_phase = data.right_phase = 0;
+ data.sampsToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paInt16, /* sample format */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paInt16, /* sample format */
+ NULL,
+ SAMPLE_RATE,
+ buffersize, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patest1Callback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for sound to finish.\n");
+ Pa_Sleep(1000);
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ return paNoError;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_clip.c b/pd/portaudio/pa_tests/patest_clip.c
new file mode 100644
index 00000000..c19bf3fe
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_clip.c
@@ -0,0 +1,156 @@
+/*
+ * $Id: patest_clip.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_clip.c
+ * Play a sine wave using the Portable Audio api for several seconds
+ * at an amplitude that would require clipping.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (4)
+#define SAMPLE_RATE (44100)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+typedef struct paTestData
+{
+ float sine[TABLE_SIZE];
+ float amplitude;
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+PaError PlaySine( paTestData *data, unsigned long flags, float amplitude );
+/* 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 sineCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ float amplitude = data->amplitude;
+ unsigned int i;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+ (void) outTime;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = amplitude * data->sine[data->left_phase]; /* left */
+ *out++ = amplitude * data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ paTestData DATA;
+ int i;
+ printf("PortAudio Test: output sine wave with and without clipping.\n");
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ DATA.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ printf("\nHalf amplitude. Should sound like sine wave.\n"); fflush(stdout);
+ err = PlaySine( &DATA, paClipOff | paDitherOff, 0.5f );
+ if( err < 0 ) goto error;
+ printf("\nFull amplitude. Should sound like sine wave.\n"); fflush(stdout);
+ err = PlaySine( &DATA, paClipOff | paDitherOff, 0.999f );
+ if( err < 0 ) goto error;
+ printf("\nOver range with clipping and dithering turned OFF. Should sound very nasty.\n");
+ fflush(stdout);
+ err = PlaySine( &DATA, paClipOff | paDitherOff, 1.1f );
+ if( err < 0 ) goto error;
+ printf("\nOver range with clipping and dithering turned ON. Should sound smoother than previous.\n");
+ fflush(stdout);
+ err = PlaySine( &DATA, paNoFlag, 1.1f );
+ if( err < 0 ) goto error;
+ printf("\nOver range with paClipOff but dithering ON.\n"
+ "That forces clipping ON so it should sound the same as previous.\n");
+ fflush(stdout);
+ err = PlaySine( &DATA, paClipOff, 1.1f );
+ if( err < 0 ) goto error;
+ return 0;
+error:
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return 1;
+}
+/*****************************************************************************/
+PaError PlaySine( paTestData *data, unsigned long flags, float amplitude )
+{
+ PortAudioStream *stream;
+ PaError err;
+ data->left_phase = data->right_phase = 0;
+ data->amplitude = amplitude;
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ 1024,
+ 0, /* number of buffers, if zero then use default minimum */
+ flags, /* we won't output out of range samples so don't bother clipping them */
+ sineCallback,
+ data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Sleep( NUM_SECONDS * 1000 );
+ printf("CPULoad = %8.6f\n", Pa_GetCPULoad( stream ) );
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ return paNoError;
+error:
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_dither.c b/pd/portaudio/pa_tests/patest_dither.c
new file mode 100644
index 00000000..2ab11e7b
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_dither.c
@@ -0,0 +1,152 @@
+/*
+ * $Id: patest_dither.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_dither.c
+ * Attempt to hear difference between dithered and non-dithered signal.
+ * This only has an effect if the native format is 16 bit.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (4)
+#define SAMPLE_RATE (44100)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+typedef struct paTestData
+{
+ float sine[TABLE_SIZE];
+ float amplitude;
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+PaError PlaySine( paTestData *data, PaStreamFlags flags, float amplitude );
+static int sineCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+/* 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 sineCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ float amplitude = data->amplitude;
+ unsigned int i;
+ (void) outTime;
+ (void) inputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = amplitude * data->sine[data->left_phase]; /* left */
+ *out++ = amplitude * data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ paTestData DATA;
+ int i;
+ float amplitude = 32.0 / (1<<15);
+ printf("PortAudio Test: output EXTREMELY QUIET sine wave with and without dithering.\n");
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ DATA.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ printf("\nNo treatment..\n"); fflush(stdout);
+ err = PlaySine( &DATA, paClipOff | paDitherOff, amplitude );
+ if( err < 0 ) goto error;
+ printf("\nClip.\n");
+ fflush(stdout);
+ err = PlaySine( &DATA, paDitherOff, amplitude );
+ if( err < 0 ) goto error;
+ printf("\nClip and Dither.\n");
+ fflush(stdout);
+ err = PlaySine( &DATA, paNoFlag, amplitude );
+ if( err < 0 ) goto error;
+ return 0;
+error:
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
+/*****************************************************************************/
+PaError PlaySine( paTestData *data, PaStreamFlags flags, float amplitude )
+{
+ PortAudioStream *stream;
+ PaError err;
+ data->left_phase = data->right_phase = 0;
+ data->amplitude = amplitude;
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ 1024,
+ 0, /* number of buffers, if zero then use default minimum */
+ flags, /* we won't output out of range samples so don't bother clipping them */
+ sineCallback,
+ (void *)data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Sleep( NUM_SECONDS * 1000 );
+ printf("CPULoad = %8.6f\n", Pa_GetCPULoad( stream ) );
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ return paNoError;
+error:
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_hang.c b/pd/portaudio/pa_tests/patest_hang.c
new file mode 100644
index 00000000..b97727ba
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_hang.c
@@ -0,0 +1,151 @@
+/*
+ * $Id: patest_hang.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Play a sine then hang audio callback to test watchdog.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (1024)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TWOPI (M_PI * 2.0)
+
+typedef struct paTestData
+{
+ int sleepFor;
+ double phase;
+}
+paTestData;
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+ int finished = 0;
+ double phaseInc = 0.02;
+ double phase = data->phase;
+
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ phase += phaseInc;
+ if( phase > TWOPI ) phase -= TWOPI;
+ /* This is not a very efficient way to calc sines. */
+ *out++ = (float) sin( phase ); /* mono */
+ }
+
+ if( data->sleepFor > 0 )
+ {
+ Pa_Sleep( data->sleepFor );
+ }
+
+ data->phase = phase;
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ int i;
+ paTestData data = {0};
+
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n",
+ SAMPLE_RATE, FRAMES_PER_BUFFER );
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 1, /* mono output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+/* Gradually increase sleep time. */
+ for( i=0; i<10000; i+= 1000 )
+ {
+ printf("Sleep for %d milliseconds in audio callback.\n", i );
+ data.sleepFor = i;
+ Pa_Sleep( ((i<1000) ? 1000 : i) );
+ }
+
+ printf("Suffer for 10 seconds.\n");
+ Pa_Sleep( 10000 );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_latency.c b/pd/portaudio/pa_tests/patest_latency.c
new file mode 100644
index 00000000..261a005c
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_latency.c
@@ -0,0 +1,176 @@
+/*
+ * $Id: patest_latency.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Hear the latency caused by big buffers.
+ * Play a sine wave and change frequency based on letter input.
+ *
+ * Author: Phil Burk <philburk@softsynth.com>, and Darren Gibbs
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (64)
+
+#if 0
+#define MIN_LATENCY_MSEC (2000)
+#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
+#else
+#define NUM_BUFFERS (0)
+#endif
+
+#define MIN_FREQ (100.0f)
+#define CalcPhaseIncrement(freq) ((freq)/SAMPLE_RATE)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (400)
+typedef struct
+{
+ float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation
+ float phase_increment;
+ float left_phase;
+ float right_phase;
+}
+paTestData;
+float LookupSine( paTestData *data, float phase );
+/* Convert phase between and 1.0 to sine value
+ * using linear interpolation.
+ */
+float LookupSine( paTestData *data, float phase )
+{
+ float fIndex = phase*TABLE_SIZE;
+ int index = (int) fIndex;
+ float fract = fIndex - index;
+ float lo = data->sine[index];
+ float hi = data->sine[index+1];
+ float val = lo + fract*(hi-lo);
+ return val;
+}
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = LookupSine(data, data->left_phase); /* left */
+ *out++ = LookupSine(data, data->right_phase); /* right */
+ data->left_phase += data->phase_increment;
+ if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f;
+ data->right_phase += (data->phase_increment * 1.5f); /* fifth above */
+ if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f;
+ }
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int done = 0;
+ printf("PortAudio Test: enter letter then hit ENTER. numBuffers = %d\n", NUM_BUFFERS );
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = 0.90f * (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.sine[TABLE_SIZE] = data.sine[0]; // set guard point
+ data.left_phase = data.right_phase = 0.0;
+ data.phase_increment = CalcPhaseIncrement(MIN_FREQ);
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE );
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
+ paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Play ASCII keyboard. Hit 'q' to stop. (Use RETURN key on Mac)\n");
+ fflush(stdout);
+ while ( !done )
+ {
+ float freq;
+ int index;
+ char c;
+ do
+ {
+ c = getchar();
+ }
+ while( c < ' '); /* Strip white space and control chars. */
+
+ if( c == 'q' ) done = 1;
+ index = c % 26;
+ freq = MIN_FREQ + (index * 40.0);
+ data.phase_increment = CalcPhaseIncrement(freq);
+ }
+ printf("Call Pa_StopStream()\n");
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_leftright.c b/pd/portaudio/pa_tests/patest_leftright.c
new file mode 100644
index 00000000..d23c8b2c
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_leftright.c
@@ -0,0 +1,168 @@
+/*
+ * $Id: patest_leftright.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_leftright.c
+ * Play different tone sine waves that alternate between left and right channel.
+ * The low tone should be on the left channel.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (8)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (512)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+ int toggle;
+ int countDown;
+}
+paTestData;
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ if( data->toggle )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = 0; /* right */
+ }
+ else
+ {
+ *out++ = 0; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ }
+
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+
+ if( data->countDown < 0 )
+ {
+ data->countDown = SAMPLE_RATE;
+ data->toggle = !data->toggle;
+ }
+ data->countDown -= framesPerBuffer;
+
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int timeout;
+
+ printf("Play different tone sine waves that alternate between left and right channel.\n");
+ printf("The low tone should be on the left channel.\n");
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = data.toggle = 0;
+ data.countDown = SAMPLE_RATE;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Play for several seconds.\n");
+ timeout = NUM_SECONDS * 4;
+ while( timeout > 0 )
+ {
+ Pa_Sleep( 300 );
+ timeout -= 1;
+ }
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_longsine.c b/pd/portaudio/pa_tests/patest_longsine.c
new file mode 100644
index 00000000..cc48c44a
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_longsine.c
@@ -0,0 +1,137 @@
+/*
+ * $Id: patest_longsine.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_longsine.c
+ * Play a sine wave using the Portable Audio api until ENTER hit.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define SAMPLE_RATE (44100)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned int i;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ return 0;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ printf("PortAudio Test: output sine wave.\n");
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ 256, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Hit ENTER to stop program.\n");
+ getchar();
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+
+ printf("Test finished.\n");
+ return err;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_many.c b/pd/portaudio/pa_tests/patest_many.c
new file mode 100644
index 00000000..f42efb52
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_many.c
@@ -0,0 +1,194 @@
+/*
+ * $Id: patest_many.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_many.c
+ * Start and stop the PortAudio Driver multiple times.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (1)
+#define SAMPLE_RATE (44100)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+typedef struct
+{
+ short sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+ unsigned int sampsToGo;
+}
+paTestData;
+PaError TestOnce( void );
+static int patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+/* 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 patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ short *out = (short*)outputBuffer;
+ unsigned int i;
+ int finished = 0;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+ (void) outTime;
+
+ if( data->sampsToGo < framesPerBuffer )
+ {
+ /* final buffer... */
+
+ for( i=0; i<data->sampsToGo; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ /* zero remainder of final buffer */
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+
+ finished = 1;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ data->sampsToGo -= framesPerBuffer;
+ }
+ return finished;
+}
+/*******************************************************************/
+#ifdef MACINTOSH
+int main(void);
+int main(void)
+{
+ int i;
+ PaError err;
+ int numLoops = 10;
+ printf("Loop %d times.\n", numLoops );
+ for( i=0; i<numLoops; i++ )
+ {
+ printf("Loop %d out of %d.\n", i+1, numLoops );
+ err = TestOnce();
+ if( err < 0 ) return 0;
+ }
+}
+#else
+int main(int argc, char **argv);
+int main(int argc, char **argv)
+{
+ PaError err;
+ int i, numLoops = 10;
+ if( argc > 1 )
+ {
+ numLoops = atoi(argv[1]);
+ }
+ for( i=0; i<numLoops; i++ )
+ {
+ printf("Loop %d out of %d.\n", i+1, numLoops );
+ err = TestOnce();
+ if( err < 0 ) return 1;
+ }
+ printf("Test complete.\n");
+ return 0;
+}
+#endif
+PaError TestOnce( void )
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalSamps;
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (short) (32767.0 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ));
+ }
+ data.left_phase = data.right_phase = 0;
+ data.sampsToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paInt16, /* sample format */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paInt16, /* sample format */
+ NULL,
+ SAMPLE_RATE,
+ 1024, /* frames per buffer */
+ 8, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patest1Callback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for sound to finish.\n");
+ Pa_Sleep(1000);
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ return paNoError;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_maxsines.c b/pd/portaudio/pa_tests/patest_maxsines.c
new file mode 100644
index 00000000..9fcd7ba8
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_maxsines.c
@@ -0,0 +1,197 @@
+/*
+ * $Id: patest_maxsines.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_maxsines.c
+ * How many sine waves can we calculate and play in less than 80% CPU Load.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define MAX_SINES (500)
+#define MAX_USAGE (0.8)
+#define SAMPLE_RATE (44100)
+#define FREQ_TO_PHASE_INC(freq) (freq/(float)SAMPLE_RATE)
+
+#define MIN_PHASE_INC FREQ_TO_PHASE_INC(200.0f)
+#define MAX_PHASE_INC (MIN_PHASE_INC * (1 << 5))
+
+#define FRAMES_PER_BUFFER (512)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TWOPI (M_PI * 2.0)
+
+#define TABLE_SIZE (512)
+
+typedef struct paTestData
+{
+ int numSines;
+ float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */
+ float phases[MAX_SINES];
+}
+paTestData;
+
+/* Convert phase between and 1.0 to sine value
+ * using linear interpolation.
+ */
+float LookupSine( paTestData *data, float phase );
+float LookupSine( paTestData *data, float phase )
+{
+ float fIndex = phase*TABLE_SIZE;
+ int index = (int) fIndex;
+ float fract = fIndex - index;
+ float lo = data->sine[index];
+ float hi = data->sine[index+1];
+ float val = lo + fract*(hi-lo);
+ return val;
+}
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ float outSample;
+ float scaler;
+ int numForScale;
+ unsigned long i;
+ int j;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+/* Detemine amplitude scaling factor */
+ numForScale = data->numSines;
+ if( numForScale < 8 ) numForScale = 8; /* prevent pops at beginning */
+ scaler = 1.0f / numForScale;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ float output = 0.0;
+ float phaseInc = MIN_PHASE_INC;
+ float phase;
+ for( j=0; j<data->numSines; j++ )
+ {
+ /* Advance phase of next oscillator. */
+ phase = data->phases[j];
+ phase += phaseInc;
+ if( phase >= 1.0 ) phase -= 1.0;
+
+ output += LookupSine(data, phase);
+ data->phases[j] = phase;
+
+ phaseInc *= 1.02f;
+ if( phaseInc > MAX_PHASE_INC ) phaseInc = MIN_PHASE_INC;
+ }
+
+ outSample = (float) (output * scaler);
+ *out++ = outSample; /* Left */
+ *out++ = outSample; /* Right */
+ }
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i;
+ PaStream *stream;
+ PaError err;
+ paTestData data = {0};
+ double load;
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.sine[TABLE_SIZE] = data.sine[0]; /* set guard point */
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32,
+ 0, /* default latency */
+ NULL,
+ Pa_GetDefaultOutputDevice(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ 0, /* default latency */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+/* Play an increasing number of sine waves until we hit MAX_USAGE */
+ do
+ {
+ data.numSines++;
+ Pa_Sleep( 200 );
+
+ load = Pa_GetStreamCpuLoad( stream );
+ printf("numSines = %d, CPU load = %f\n", data.numSines, load );
+ fflush( stdout );
+ }
+ while( (load < MAX_USAGE) && (data.numSines < MAX_SINES) );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_multi_sine.c b/pd/portaudio/pa_tests/patest_multi_sine.c
new file mode 100644
index 00000000..2b78e932
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_multi_sine.c
@@ -0,0 +1,175 @@
+/*
+ * $Id: patest_multi_sine.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_multi_out.c
+ * Play a different sine wave on each channels,
+ * using the Portable Audio api.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDevice())
+//#define NON_INTERLEAVED
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (0) // take what we get(256)
+#define FREQ_INCR (300.0 / SAMPLE_RATE)
+#define MAX_CHANNELS (64)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+typedef struct
+{
+ int numChannels;
+ double phases[MAX_CHANNELS];
+}
+paTestData;
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ float **outputs = (float**)outputBuffer;
+
+#ifdef NON_INTERLEAVED
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int frameIndex, channelIndex;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
+ {
+ for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
+ {
+ /* Output sine wave on every channel. */
+ outputs[channelIndex][frameIndex] = (float) sin(data->phases[channelIndex]);
+
+ /* Play each channel at a higher frequency. */
+ data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
+ if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
+ }
+ }
+
+#else /* interleaved version */
+
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int frameIndex, channelIndex;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
+ {
+ for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
+ {
+ /* Output sine wave on every channel. */
+ *out++ = (float) sin(data->phases[channelIndex]);
+
+ /* Play each channel at a higher frequency. */
+ data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
+ if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
+ }
+ }
+#endif /* NON_INTERLEAVED */
+ return 0;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream *stream;
+ PaError err;
+ const PaDeviceInfo *pdi;
+ paTestData data = {0};
+ printf("PortAudio Test: output sine wave on each channel.\n" );
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE );
+ data.numChannels = pdi->maxOutputChannels;
+ if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS;
+ printf("Number of Channels = %d\n", data.numChannels );
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice, /* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ 0, /* default input latency */
+ NULL,
+ OUTPUT_DEVICE,
+ data.numChannels,
+#ifdef NON_INTERLEAVED
+ paFloat32 | paNonInterleaved, /* 32 bit floating point output */
+#else
+ paFloat32,
+#endif
+ 0, /* default output latency */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Hit ENTER to stop sound.\n");
+ getchar();
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_CloseStream( stream );
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_pink.c b/pd/portaudio/pa_tests/patest_pink.c
new file mode 100644
index 00000000..7a3e29cd
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_pink.c
@@ -0,0 +1,245 @@
+/*
+ * $Id: patest_pink.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ patest_pink.c
+ Generate Pink Noise using Gardner method.
+ Optimization suggested by James McCartney uses a tree
+ to select which random value to replace.
+ x x x x x x x x x x x x x x x x
+ x x x x x x x x
+ x x x x
+ x x
+ x
+ Tree is generated by counting trailing zeros in an increasing index.
+ When the index is zero, no random number is selected.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define PINK_MAX_RANDOM_ROWS (30)
+#define PINK_RANDOM_BITS (24)
+#define PINK_RANDOM_SHIFT ((sizeof(long)*8)-PINK_RANDOM_BITS)
+typedef struct
+{
+ long pink_Rows[PINK_MAX_RANDOM_ROWS];
+ long pink_RunningSum; /* Used to optimize summing of generators. */
+ int pink_Index; /* Incremented each sample. */
+ int pink_IndexMask; /* Index wrapped by ANDing with this mask. */
+ float pink_Scalar; /* Used to scale within range of -1.0 to +1.0 */
+}
+PinkNoise;
+/* Prototypes */
+static unsigned long GenerateRandomNumber( void );
+void InitializePinkNoise( PinkNoise *pink, int numRows );
+float GeneratePinkNoise( PinkNoise *pink );
+/************************************************************/
+/* Calculate pseudo-random 32 bit number based on linear congruential method. */
+static unsigned long GenerateRandomNumber( void )
+{
+ /* Change this seed for different random sequences. */
+ static unsigned long randSeed = 22222;
+ randSeed = (randSeed * 196314165) + 907633515;
+ return randSeed;
+}
+/************************************************************/
+/* Setup PinkNoise structure for N rows of generators. */
+void InitializePinkNoise( PinkNoise *pink, int numRows )
+{
+ int i;
+ long pmax;
+ pink->pink_Index = 0;
+ pink->pink_IndexMask = (1<<numRows) - 1;
+ /* Calculate maximum possible signed random value. Extra 1 for white noise always added. */
+ pmax = (numRows + 1) * (1<<(PINK_RANDOM_BITS-1));
+ pink->pink_Scalar = 1.0f / pmax;
+ /* Initialize rows. */
+ for( i=0; i<numRows; i++ ) pink->pink_Rows[i] = 0;
+ pink->pink_RunningSum = 0;
+}
+#define PINK_MEASURE
+#ifdef PINK_MEASURE
+float pinkMax = -999.0;
+float pinkMin = 999.0;
+#endif
+/* Generate Pink noise values between -1.0 and +1.0 */
+float GeneratePinkNoise( PinkNoise *pink )
+{
+ long newRandom;
+ long sum;
+ float output;
+ /* Increment and mask index. */
+ pink->pink_Index = (pink->pink_Index + 1) & pink->pink_IndexMask;
+ /* If index is zero, don't update any random values. */
+ if( pink->pink_Index != 0 )
+ {
+ /* Determine how many trailing zeros in PinkIndex. */
+ /* This algorithm will hang if n==0 so test first. */
+ int numZeros = 0;
+ int n = pink->pink_Index;
+ while( (n & 1) == 0 )
+ {
+ n = n >> 1;
+ numZeros++;
+ }
+ /* Replace the indexed ROWS random value.
+ * Subtract and add back to RunningSum instead of adding all the random
+ * values together. Only one changes each time.
+ */
+ pink->pink_RunningSum -= pink->pink_Rows[numZeros];
+ newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
+ pink->pink_RunningSum += newRandom;
+ pink->pink_Rows[numZeros] = newRandom;
+ }
+
+ /* Add extra white noise value. */
+ newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
+ sum = pink->pink_RunningSum + newRandom;
+ /* Scale to range of -1.0 to 0.9999. */
+ output = pink->pink_Scalar * sum;
+#ifdef PINK_MEASURE
+ /* Check Min/Max */
+ if( output > pinkMax ) pinkMax = output;
+ else if( output < pinkMin ) pinkMin = output;
+#endif
+ return output;
+}
+/*******************************************************************/
+#define PINK_TEST
+#ifdef PINK_TEST
+/* Context for callback routine. */
+typedef struct
+{
+ PinkNoise leftPink;
+ PinkNoise rightPink;
+ unsigned int sampsToGo;
+}
+paTestData;
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ int finished;
+ int i;
+ int numFrames;
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+ (void) outTime;
+
+ /* Are we almost at end. */
+ if( data->sampsToGo < framesPerBuffer )
+ {
+ numFrames = data->sampsToGo;
+ finished = 1;
+ }
+ else
+ {
+ numFrames = framesPerBuffer;
+ finished = 0;
+ }
+ for( i=0; i<numFrames; i++ )
+ {
+ *out++ = GeneratePinkNoise( &data->leftPink );
+ *out++ = GeneratePinkNoise( &data->rightPink );
+ }
+ data->sampsToGo -= numFrames;
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int totalSamps;
+ /* Initialize two pink noise signals with different numbers of rows. */
+ InitializePinkNoise( &data.leftPink, 12 );
+ InitializePinkNoise( &data.rightPink, 16 );
+ /* Look at a few values. */
+ {
+ int i;
+ float pink;
+ for( i=0; i<20; i++ )
+ {
+ pink = GeneratePinkNoise( &data.leftPink );
+ printf("Pink = %f\n", pink );
+ }
+ }
+ data.sampsToGo = totalSamps = 8*44100; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ /* Open a stereo PortAudio stream so we can hear the result. */
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ 44100.,
+ 2048, /* 46 msec buffers */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for sound to finish.\n");
+ while( Pa_StreamActive( stream ) )
+ {
+ Pa_Sleep(100); /* SPIN! */
+ }
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+#ifdef PINK_MEASURE
+ printf("Pink min = %f, max = %f\n", pinkMin, pinkMax );
+#endif
+ Pa_Terminate();
+ return 0;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return 0;
+}
+#endif /* PINK_TEST */
diff --git a/pd/portaudio/pa_tests/patest_record.c b/pd/portaudio/pa_tests/patest_record.c
new file mode 100644
index 00000000..59471aaf
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_record.c
@@ -0,0 +1,327 @@
+/*
+ * $Id: patest_record.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_record.c
+ * Record input into an array.
+ * Save array to a file.
+ * Playback recorded data.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "portaudio.h"
+
+/* #define SAMPLE_RATE (17932) /* Test failure to open with this value. */
+#define SAMPLE_RATE (44100)
+#define NUM_SECONDS (5)
+#define NUM_CHANNELS (2)
+/* #define DITHER_FLAG (paDitherOff) /**/
+#define DITHER_FLAG (0) /**/
+
+/* Select sample format. */
+#if 1
+#define PA_SAMPLE_TYPE paFloat32
+typedef float SAMPLE;
+#define SAMPLE_SILENCE (0.0f)
+#elif 1
+#define PA_SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+#define SAMPLE_SILENCE (0)
+#elif 0
+#define PA_SAMPLE_TYPE paInt8
+typedef char SAMPLE;
+#define SAMPLE_SILENCE (0)
+#else
+#define PA_SAMPLE_TYPE paUInt8
+typedef unsigned char SAMPLE;
+#define SAMPLE_SILENCE (128)
+
+#endif
+
+typedef struct
+{
+ int frameIndex; /* Index into sample array. */
+ int maxFrameIndex;
+ SAMPLE *recordedSamples;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 recordCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = (SAMPLE*)inputBuffer;
+ SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
+ long framesToCalc;
+ long i;
+ int finished;
+ unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
+
+ (void) outputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ framesToCalc = framesLeft;
+ finished = paComplete;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ finished = paContinue;
+ }
+
+ if( inputBuffer == NULL )
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = SAMPLE_SILENCE; /* left */
+ if( NUM_CHANNELS == 2 ) *wptr++ = SAMPLE_SILENCE; /* right */
+ }
+ }
+ else
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
+ }
+ }
+ data->frameIndex += framesToCalc;
+ return finished;
+}
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 playCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
+ SAMPLE *wptr = (SAMPLE*)outputBuffer;
+ unsigned int i;
+ int finished;
+ unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;
+ (void) inputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ /* final buffer... */
+ for( i=0; i<framesLeft; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
+ }
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = 0; /* left */
+ if( NUM_CHANNELS == 2 ) *wptr++ = 0; /* right */
+ }
+ data->frameIndex += framesLeft;
+ finished = paComplete;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
+ }
+ data->frameIndex += framesPerBuffer;
+ finished = paContinue;
+ }
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalFrames;
+ int numSamples;
+ int numBytes;
+ SAMPLE max, average, val;
+ printf("patest_record.c\n"); fflush(stdout);
+
+ data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */
+ data.frameIndex = 0;
+ numSamples = totalFrames * NUM_CHANNELS;
+
+ numBytes = numSamples * sizeof(SAMPLE);
+ data.recordedSamples = (SAMPLE *) malloc( numBytes );
+ if( data.recordedSamples == NULL )
+ {
+ printf("Could not allocate record array.\n");
+ exit(1);
+ }
+ for( i=0; i<numSamples; i++ ) data.recordedSamples[i] = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ /* Record some audio. -------------------------------------------- */
+ err = Pa_OpenStream(
+ &stream,
+ Pa_GetDefaultInputDevice(),
+ NUM_CHANNELS, /* stereo input */
+ PA_SAMPLE_TYPE,
+ 0, /* default latency */
+ NULL,
+ paNoDevice,
+ 0,
+ PA_SAMPLE_TYPE,
+ 0, /* default latency */
+ NULL,
+ SAMPLE_RATE,
+ 1024, /* frames per buffer */
+ 0, //paDitherOff, /* flags */
+ recordCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Now recording!!\n"); fflush(stdout);
+
+ while( Pa_IsStreamActive( stream ) )
+ {
+ Pa_Sleep(1000);
+ printf("index = %d\n", data.frameIndex ); fflush(stdout);
+ }
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ /* Measure maximum peak amplitude. */
+ max = 0;
+ average = 0;
+ for( i=0; i<numSamples; i++ )
+ {
+ val = data.recordedSamples[i];
+ if( val < 0 ) val = -val; /* ABS */
+ if( val > max )
+ {
+ max = val;
+ }
+ average += val;
+ }
+
+ average = average / numSamples;
+
+ if( PA_SAMPLE_TYPE == paFloat32 )
+ {
+ printf("sample max amplitude = %f\n", max );
+ printf("sample average = %f\n", average );
+ }
+ else
+ {
+ printf("sample max amplitude = %d\n", max );
+ printf("sample average = %d\n", average );
+ }
+
+ /* Write recorded data to a file. */
+#if 0
+ {
+ FILE *fid;
+ fid = fopen("recorded.raw", "wb");
+ if( fid == NULL )
+ {
+ printf("Could not open file.");
+ }
+ else
+ {
+ fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid );
+ fclose( fid );
+ printf("Wrote data to 'recorded.raw'\n");
+ }
+ }
+#endif
+
+ /* Playback recorded data. -------------------------------------------- */
+ data.frameIndex = 0;
+ printf("Begin playback.\n"); fflush(stdout);
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* NO input */
+ PA_SAMPLE_TYPE,
+ 0, /* default latency */
+ NULL,
+ Pa_GetDefaultOutputDevice(),
+ NUM_CHANNELS, /* stereo output */
+ PA_SAMPLE_TYPE,
+ 0, /* default latency */
+ NULL,
+ SAMPLE_RATE,
+ 1024, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ playCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ if( stream )
+ {
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for playback to finish.\n"); fflush(stdout);
+
+ while( Pa_IsStreamActive( stream ) ) Pa_Sleep(100);
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Done.\n"); fflush(stdout);
+ }
+ free( data.recordedSamples );
+
+ Pa_Terminate();
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
diff --git a/pd/portaudio/pa_tests/patest_ringmix.c b/pd/portaudio/pa_tests/patest_ringmix.c
new file mode 100644
index 00000000..34c66381
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_ringmix.c
@@ -0,0 +1,41 @@
+/* $Id: patest_ringmix.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $ */
+
+#include "stdio.h"
+#include "portaudio.h"
+/* This will be called asynchronously by the PortAudio engine. */
+static int myCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, PaTimestamp outTime, void *userData )
+{
+ float *out = (float *) outputBuffer;
+ float *in = (float *) inputBuffer;
+ float leftInput, rightInput;
+ unsigned int i;
+ if( inputBuffer == NULL ) return 0;
+ /* Read input buffer, process data, and fill output buffer. */
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ leftInput = *in++; /* Get interleaved samples from input buffer. */
+ rightInput = *in++;
+ *out++ = leftInput * rightInput; /* ring modulation */
+ *out++ = 0.5f * (leftInput + rightInput); /* mix */
+ }
+ return 0;
+}
+/* Open a PortAudioStream to input and output audio data. */
+int main(void)
+{
+ PortAudioStream *stream;
+ Pa_Initialize();
+ Pa_OpenDefaultStream(
+ &stream,
+ 2, 2, /* stereo input and output */
+ paFloat32, 44100.0,
+ 64, 0, /* 64 frames per buffer, let PA determine numBuffers */
+ myCallback, NULL );
+ Pa_StartStream( stream );
+ Pa_Sleep( 10000 ); /* Sleep for 10 seconds while processing. */
+ Pa_StopStream( stream );
+ Pa_CloseStream( stream );
+ Pa_Terminate();
+ return 0;
+}
diff --git a/pd/portaudio/pa_tests/patest_saw.c b/pd/portaudio/pa_tests/patest_saw.c
new file mode 100644
index 00000000..da1851ed
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_saw.c
@@ -0,0 +1,118 @@
+/*
+ * $Id: patest_saw.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_saw.c
+ * Play a simple sawtooth wave.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (4)
+#define SAMPLE_RATE (44100)
+typedef struct
+{
+ float left_phase;
+ float right_phase;
+}
+paTestData;
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ /* Cast data passed through stream to our structure. */
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned int i;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->left_phase; /* left */
+ *out++ = data->right_phase; /* right */
+ /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
+ data->left_phase += 0.01f;
+ /* When signal reaches top, drop back down. */
+ if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
+ /* higher pitch so we can distinguish left and right. */
+ data->right_phase += 0.03f;
+ if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
+ }
+ return 0;
+}
+/*******************************************************************/
+static paTestData data;
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ printf("PortAudio Test: output sawtooth wave.\n");
+ /* Initialize our data for use by callback. */
+ data.left_phase = data.right_phase = 0.0;
+ /* Initialize library before making any other calls. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ /* Open an audio I/O stream. */
+ err = Pa_OpenDefaultStream(
+ &stream,
+ 0, /* no input channels */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ SAMPLE_RATE,
+ 256, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ /* Sleep for several seconds. */
+ Pa_Sleep(NUM_SECONDS*1000);
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_sine.c b/pd/portaudio/pa_tests/patest_sine.c
new file mode 100644
index 00000000..1bebb90e
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_sine.c
@@ -0,0 +1,152 @@
+/*
+ * $Id: patest_sine.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sine.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (5)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (64)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+
+ (void) timeInfo; /* Prevent unused variable warnings. */
+ (void) statusFlags;
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+
+ return paContinue;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStreamParameters outputParameters;
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+
+
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
+ outputParameters.channelCount = 2; /* stereo output */
+ outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
+ outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ err = Pa_OpenStream(
+ &stream,
+ NULL, /* no input */
+ &outputParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Play for %d seconds.\n", NUM_SECONDS );
+ Pa_Sleep( NUM_SECONDS * 1000 );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+ printf("Test finished.\n");
+
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_sine8.c b/pd/portaudio/pa_tests/patest_sine8.c
new file mode 100644
index 00000000..f3ef9ebb
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_sine8.c
@@ -0,0 +1,184 @@
+/*
+ * $Id: patest_sine8.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sine8.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ * Test 8 bit data.
+ *
+ * Author: Ross Bencina <rossb@audiomulch.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (8)
+#define SAMPLE_RATE (44100)
+#define TEST_UNSIGNED (1)
+#if TEST_UNSIGNED
+#define TEST_FORMAT paUInt8
+#else
+#define TEST_FORMAT paInt8
+#endif
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+typedef struct
+{
+#if TEST_UNSIGNED
+ unsigned char sine[TABLE_SIZE];
+#else
+ char sine[TABLE_SIZE];
+#endif
+ int left_phase;
+ int right_phase;
+ unsigned int framesToGo;
+}
+paTestData;
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ char *out = (char*)outputBuffer;
+ int i;
+ int framesToCalc;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( data->framesToGo < framesPerBuffer )
+ {
+ framesToCalc = data->framesToGo;
+ data->framesToGo = 0;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ data->framesToGo -= framesPerBuffer;
+ }
+
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ /* zero remainder of final buffer */
+ for( ; i<(int)framesPerBuffer; i++ )
+ {
+#if TEST_UNSIGNED
+ *out++ = (unsigned char) 0x80; /* left */
+ *out++ = (unsigned char) 0x80; /* right */
+#else
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+#endif
+
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalSamps;
+#if TEST_UNSIGNED
+ printf("PortAudio Test: output UNsigned 8 bit sine wave.\n");
+#else
+ printf("PortAudio Test: output signed 8 bit sine wave.\n");
+#endif
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (char) (127.0 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ));
+#if TEST_UNSIGNED
+ data.sine[i] += (unsigned char) 0x80;
+#endif
+
+ }
+ data.left_phase = data.right_phase = 0;
+ data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ TEST_FORMAT,
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ TEST_FORMAT,
+ NULL,
+ SAMPLE_RATE,
+ 256, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ /* Watch until sound is halfway finished. */
+ while( Pa_StreamTime( stream ) < (totalSamps/2) ) Pa_Sleep(10);
+ /* Stop sound until ENTER hit. */
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Pause for 2 seconds.\n");
+ Pa_Sleep( 2000 );
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for sound to finish.\n");
+ while( Pa_StreamActive( stream ) ) Pa_Sleep(10);
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_sine_formats.c b/pd/portaudio/pa_tests/patest_sine_formats.c
new file mode 100644
index 00000000..74e12022
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_sine_formats.c
@@ -0,0 +1,196 @@
+/*
+ * $Id: patest_sine_formats.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sine_formats.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ * Test various data formats.
+ *
+ * Author: Phil Burk
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (10)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (512)
+#define LEFT_FREQ (SAMPLE_RATE/256.0) /* So we hit 1.0 */
+#define RIGHT_FREQ (500.0)
+#define AMPLITUDE (1.0)
+
+/* Select ONE format for testing. */
+#define TEST_UINT8 (0)
+#define TEST_INT8 (0)
+#define TEST_INT16 (1)
+#define TEST_FLOAT32 (0)
+
+#if TEST_UINT8
+#define TEST_FORMAT paUInt8
+typedef unsigned char SAMPLE_t;
+#define SAMPLE_ZERO (0x80)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
+#define FORMAT_NAME "Unsigned 8 Bit"
+
+#elif TEST_INT8
+#define TEST_FORMAT paInt8
+typedef char SAMPLE_t;
+#define SAMPLE_ZERO (0)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
+#define FORMAT_NAME "Signed 8 Bit"
+
+#elif TEST_INT16
+#define TEST_FORMAT paInt16
+typedef short SAMPLE_t;
+#define SAMPLE_ZERO (0)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x)))
+#define FORMAT_NAME "Signed 16 Bit"
+
+#elif TEST_FLOAT32
+#define TEST_FORMAT paFloat32
+typedef float SAMPLE_t;
+#define SAMPLE_ZERO (0.0)
+#define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x))
+#define FORMAT_NAME "Float 32 Bit"
+#endif
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+
+typedef struct
+{
+ double left_phase;
+ double right_phase;
+ unsigned int framesToGo;
+}
+paTestData;
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE_t *out = (SAMPLE_t *)outputBuffer;
+ int i;
+ int framesToCalc;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( data->framesToGo < framesPerBuffer )
+ {
+ framesToCalc = data->framesToGo;
+ data->framesToGo = 0;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ data->framesToGo -= framesPerBuffer;
+ }
+
+ for( i=0; i<framesToCalc; i++ )
+ {
+ data->left_phase += (LEFT_FREQ / SAMPLE_RATE);
+ if( data->left_phase > 1.0) data->left_phase -= 1.0;
+ *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. )));
+
+ data->right_phase += (RIGHT_FREQ / SAMPLE_RATE);
+ if( data->right_phase > 1.0) data->right_phase -= 1.0;
+ *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. )));
+ }
+ /* zero remainder of final buffer */
+ for( ; i<(int)framesPerBuffer; i++ )
+ {
+ *out++ = SAMPLE_ZERO; /* left */
+ *out++ = SAMPLE_ZERO; /* right */
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int totalSamps;
+
+ printf("PortAudio Test: output " FORMAT_NAME "\n");
+
+
+ data.left_phase = data.right_phase = 0.0;
+ data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ TEST_FORMAT,
+ 0, /* default latency */
+ NULL,
+ Pa_GetDefaultOutputDevice(), /* default output device */
+ 2, /* stereo output */
+ TEST_FORMAT,
+ 0, /* default latency */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS );
+ while( Pa_IsStreamActive( stream ) ) Pa_Sleep(10);
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+
+ printf("PortAudio Test Finished: " FORMAT_NAME "\n");
+
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_sine_time.c b/pd/portaudio/pa_tests/patest_sine_time.c
new file mode 100644
index 00000000..c849af0a
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_sine_time.c
@@ -0,0 +1,194 @@
+/*
+ * $Id: patest_sine_time.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sine_time.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ * Pausing in the middle.
+ * use the Pa_GetStreamTime() and Pa_IsStreamActive() calls.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#include "pa_util.h"
+#define NUM_SECONDS (8)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (64)
+#define NUM_BUFFERS (0)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TWOPI (M_PI * 2.0)
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ double left_phase;
+ double right_phase;
+ volatile PaTimestamp outTime;
+}
+paTestData;
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned int i;
+
+ double left_phaseInc = 0.02;
+ double right_phaseInc = 0.06;
+
+ double left_phase = data->left_phase;
+ double right_phase = data->right_phase;
+
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+ data->outTime = outTime;\
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ left_phase += left_phaseInc;
+ if( left_phase > TWOPI ) left_phase -= TWOPI;
+ *out++ = (float) sin( left_phase );
+
+ right_phase += right_phaseInc;
+ if( right_phase > TWOPI ) right_phase -= TWOPI;
+ *out++ = (float) sin( right_phase );
+ }
+
+ data->left_phase = left_phase;
+ data->right_phase = right_phase;
+
+ return paContinue;
+}
+/*******************************************************************/
+static void ReportStreamTime( PaStream *stream, paTestData *data );
+static void ReportStreamTime( PaStream *stream, paTestData *data )
+{
+ PaTimestamp streamTime, latency, outTime;
+
+ streamTime = Pa_GetStreamTime( stream );
+ outTime = data->outTime;
+ if( outTime < 0.0 )
+ {
+ printf("Stream time = %8.1f\n", streamTime );
+ }
+ else
+ {
+ latency = outTime - streamTime;
+ printf("Stream time = %8.1f, outTime = %8.1f, latency = %8.1f\n",
+ streamTime, outTime, latency );
+ }
+ fflush(stdout);
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream *stream;
+ PaError err;
+ paTestData DATA;
+ int totalSamps;
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+ DATA.left_phase = DATA.right_phase = 0;
+ totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ 0, /* default latency */
+ NULL,
+ Pa_GetDefaultOutputDevice(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ 0, /* default latency */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &DATA );
+ if( err != paNoError ) goto error;
+
+ /* Watch until sound is halfway finished. */
+ printf("Play for %d seconds.\n", NUM_SECONDS/2 ); fflush(stdout);
+
+ DATA.outTime = -1.0; // mark time for callback as undefined
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ do
+ {
+ ReportStreamTime( stream, &DATA );
+ Pa_Sleep(100);
+ } while( Pa_GetStreamTime( stream ) < (totalSamps/2) );
+
+ /* Stop sound until ENTER hit. */
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Pause for 2 seconds.\n"); fflush(stdout);
+ Pa_Sleep( 2000 );
+
+ DATA.outTime = -1.0; // mark time for callback as undefined
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Play until sound is finished.\n"); fflush(stdout);
+ do
+ {
+ ReportStreamTime( stream, &DATA );
+ Pa_Sleep(100);
+ } while( Pa_GetStreamTime( stream ) < (totalSamps/2) );
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_start_stop.c b/pd/portaudio/pa_tests/patest_start_stop.c
new file mode 100644
index 00000000..0e183708
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_start_stop.c
@@ -0,0 +1,160 @@
+/*
+ * $Id: patest_start_stop.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_start_stop.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ * Start and stop the stream multiple times.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (3)
+#define NUM_LOOPS (4)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (400)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+
+ (void) timeInfo; /* Prevent unused variable warnings. */
+ (void) statusFlags;
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+
+ return paContinue;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStreamParameters outputParameters;
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+
+
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
+ outputParameters.channelCount = 2; /* stereo output */
+ outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
+ outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ err = Pa_OpenStream(
+ &stream,
+ NULL, /* no input */
+ &outputParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ for( i=0; i<NUM_LOOPS; i++ )
+ {
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Play for %d seconds.\n", NUM_SECONDS );
+ Pa_Sleep( NUM_SECONDS * 1000 );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Stopped.\n" );
+ Pa_Sleep( 1000 );
+ }
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+ printf("Test finished.\n");
+
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_stop.c b/pd/portaudio/pa_tests/patest_stop.c
new file mode 100644
index 00000000..54e72ff7
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_stop.c
@@ -0,0 +1,288 @@
+/*
+ * $Id: patest_stop.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_stop.c
+ *
+ * Test the three ways of stopping audio:
+ * calling Pa_StopStream(),
+ * calling Pa_AbortStream(),
+ * and returning a 1 from the callback function.
+ *
+ * A long latency is set up so that you can hear the difference.
+ * Then a simple 8 note sequence is repeated twice.
+ * The program will print what you should hear.
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDevice())
+#define SLEEP_DUR (200)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+#define LATENCY_MSEC (3000)
+#define FRAMES_PER_NOTE (SAMPLE_RATE/2)
+#define MAX_REPEATS (2)
+#define FUNDAMENTAL (400.0f / SAMPLE_RATE)
+#define NOTE_0 (FUNDAMENTAL * 1.0f / 1.0f)
+#define NOTE_1 (FUNDAMENTAL * 5.0f / 4.0f)
+#define NOTE_2 (FUNDAMENTAL * 4.0f / 3.0f)
+#define NOTE_3 (FUNDAMENTAL * 3.0f / 2.0f)
+#define NOTE_4 (FUNDAMENTAL * 2.0f / 1.0f)
+#define MODE_FINISH (0)
+#define MODE_STOP (1)
+#define MODE_ABORT (2)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (400)
+typedef struct
+{
+ float waveform[TABLE_SIZE + 1]; // add one for guard point for interpolation
+ float phase_increment;
+ float phase;
+ float *tune;
+ int notesPerTune;
+ int frameCounter;
+ int noteCounter;
+ int repeatCounter;
+ PaTimestamp outTime;
+ int stopMode;
+ int done;
+}
+paTestData;
+/************* Prototypes *****************************/
+int TestStopMode( paTestData *data );
+float LookupWaveform( paTestData *data, float phase );
+/******************************************************
+ * Convert phase between 0.0 and 1.0 to waveform value
+ * using linear interpolation.
+ */
+float LookupWaveform( paTestData *data, float phase )
+{
+ float fIndex = phase*TABLE_SIZE;
+ int index = (int) fIndex;
+ float fract = fIndex - index;
+ float lo = data->waveform[index];
+ float hi = data->waveform[index+1];
+ float val = lo + fract*(hi-lo);
+ return val;
+}
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ float value;
+ unsigned int i = 0;
+ int finished = paContinue;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ data->outTime = outTime;
+ if( !data->done )
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ /* Are we done with this note? */
+ if( data->frameCounter >= FRAMES_PER_NOTE )
+ {
+ data->noteCounter += 1;
+ data->frameCounter = 0;
+ /* Are we done with this tune? */
+ if( data->noteCounter >= data->notesPerTune )
+ {
+ data->noteCounter = 0;
+ data->repeatCounter += 1;
+ /* Are we totally done? */
+ if( data->repeatCounter >= MAX_REPEATS )
+ {
+ data->done = 1;
+ if( data->stopMode == MODE_FINISH )
+ {
+ finished = paComplete;
+ break;
+ }
+ }
+ }
+ data->phase_increment = data->tune[data->noteCounter];
+ }
+ value = LookupWaveform(data, data->phase);
+ *out++ = value; /* left */
+ *out++ = value; /* right */
+ data->phase += data->phase_increment;
+ if( data->phase >= 1.0f ) data->phase -= 1.0f;
+
+ data->frameCounter += 1;
+ }
+ }
+ /* zero remainder of final buffer */
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ paTestData DATA;
+ int i;
+ float simpleTune[] = { NOTE_0, NOTE_1, NOTE_2, NOTE_3, NOTE_4, NOTE_3, NOTE_2, NOTE_1 };
+ printf("PortAudio Test: play song and test stopping. ask for %d latency\n", LATENCY_MSEC );
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ DATA.waveform[i] = (float) (
+ (0.2 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. )) +
+ (0.2 * sin( ((double)(3*i)/(double)TABLE_SIZE) * M_PI * 2. )) +
+ (0.1 * sin( ((double)(5*i)/(double)TABLE_SIZE) * M_PI * 2. ))
+ );
+ }
+ DATA.waveform[TABLE_SIZE] = DATA.waveform[0]; // set guard point
+ DATA.tune = &simpleTune[0];
+ DATA.notesPerTune = sizeof(simpleTune) / sizeof(float);
+ printf("Test MODE_FINISH - callback returns 1.\n");
+ printf("Should hear entire %d note tune repeated twice.\n", DATA.notesPerTune);
+ DATA.stopMode = MODE_FINISH;
+ if( TestStopMode( &DATA ) != paNoError )
+ {
+ printf("Test of MODE_FINISH failed!\n");
+ goto error;
+ }
+ printf("Test MODE_STOP - stop when song is done.\n");
+ printf("Should hear entire %d note tune repeated twice.\n", DATA.notesPerTune);
+ DATA.stopMode = MODE_STOP;
+ if( TestStopMode( &DATA ) != paNoError )
+ {
+ printf("Test of MODE_STOP failed!\n");
+ goto error;
+ }
+
+ printf("Test MODE_ABORT - abort immediately.\n");
+ printf("Should hear last repetition cut short by %d msec.\n", LATENCY_MSEC);
+ DATA.stopMode = MODE_ABORT;
+ if( TestStopMode( &DATA ) != paNoError )
+ {
+ printf("Test of MODE_ABORT failed!\n");
+ goto error;
+ }
+ return 0;
+error:
+ return 1;
+}
+
+int TestStopMode( paTestData *data )
+{
+ PaStream *stream;
+ PaError err;
+ data->done = 0;
+ data->phase = 0.0;
+ data->frameCounter = 0;
+ data->noteCounter = 0;
+ data->repeatCounter = 0;
+ data->phase_increment = data->tune[data->noteCounter];
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ 0,
+ NULL,
+ OUTPUT_DEVICE,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ LATENCY_MSEC,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ if( data->stopMode == MODE_FINISH )
+ {
+ while( Pa_IsStreamActive( stream ) )
+ {
+ /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime,
+ data->noteCounter, data->repeatCounter );
+ fflush(stdout); /**/
+ Pa_Sleep( SLEEP_DUR );
+ }
+ }
+ else
+ {
+ while( data->repeatCounter < MAX_REPEATS )
+ {
+ /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime,
+ data->noteCounter, data->repeatCounter );
+ fflush(stdout); /**/
+ Pa_Sleep( SLEEP_DUR );
+ }
+ }
+
+ if( data->stopMode == MODE_ABORT )
+ {
+ printf("Call Pa_AbortStream()\n");
+ err = Pa_AbortStream( stream );
+ }
+ else
+ {
+ printf("Call Pa_StopStream()\n");
+ err = Pa_StopStream( stream );
+ }
+ if( err != paNoError ) goto error;
+
+ printf("Call Pa_CloseStream()\n"); fflush(stdout);
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_sync.c b/pd/portaudio/pa_tests/patest_sync.c
new file mode 100644
index 00000000..46854eb6
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_sync.c
@@ -0,0 +1,257 @@
+/*
+ * $Id: patest_sync.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sync.c
+ * Test time stamping and synchronization of audio and video.
+ * A high latency is used so we can hear the difference in time.
+ * Random durations are used so we know we are hearing the right beep
+ * and not the one before or after.
+ *
+ * Sequence of events:
+ * Foreground requests a beep.
+ * Background randomly schedules a beep.
+ * Foreground waits for the beep to be heard based on PaUtil_GetTime().
+ * Foreground outputs video (printf) in sync with audio.
+ * Repeat.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#include "pa_util.h"
+#define NUM_BEEPS (6)
+#define SAMPLE_RATE (44100)
+#define SAMPLE_PERIOD (1.0/44100.0)
+#define FRAMES_PER_BUFFER (256)
+#define BEEP_DURATION (400)
+#define LATENCY_MSEC (2000)
+#define SLEEP_MSEC (10)
+#define TIMEOUT_MSEC (15000)
+
+#define STATE_BKG_IDLE (0)
+#define STATE_BKG_PENDING (1)
+#define STATE_BKG_BEEPING (2)
+typedef struct
+{
+ float left_phase;
+ float right_phase;
+ int state;
+ int requestBeep; /* Set by foreground, cleared by background. */
+ PaTime beepTime;
+ int beepCount;
+ double latency; /* For debugging. */
+}
+paTestData;
+
+static unsigned long GenerateRandomNumber( void );
+/************************************************************/
+/* Calculate pseudo-random 32 bit number based on linear congruential method. */
+static unsigned long GenerateRandomNumber( void )
+{
+ static unsigned long randSeed = 99887766; /* Change this for different random sequences. */
+ randSeed = (randSeed * 196314165) + 907633515;
+ return randSeed;
+}
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo *timeInfo,
+ PaStreamCallbackFlags statusFlags, void *userData )
+{
+ /* Cast data passed through stream to our structure. */
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned int i;
+ (void) inputBuffer;
+
+ data->latency = timeInfo->outputBufferDacTime - timeInfo->currentTime;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ switch( data->state )
+ {
+ case STATE_BKG_IDLE:
+ /* Schedule beep at some random time in the future. */
+ if( data->requestBeep )
+ {
+ int random = GenerateRandomNumber() >> 14;
+ data->beepTime = timeInfo->outputBufferDacTime + (( (double)(random + SAMPLE_RATE)) * SAMPLE_PERIOD );
+ data->state = STATE_BKG_PENDING;
+ }
+ *out++ = 0.0; /* left */
+ *out++ = 0.0; /* right */
+ break;
+
+ case STATE_BKG_PENDING:
+ if( (timeInfo->outputBufferDacTime + (i*SAMPLE_PERIOD)) >= data->beepTime )
+ {
+ data->state = STATE_BKG_BEEPING;
+ data->beepCount = BEEP_DURATION;
+ data->left_phase = data->right_phase = 0.0;
+ }
+ *out++ = 0.0; /* left */
+ *out++ = 0.0; /* right */
+ break;
+
+ case STATE_BKG_BEEPING:
+ if( data->beepCount <= 0 )
+ {
+ data->state = STATE_BKG_IDLE;
+ data->requestBeep = 0;
+ *out++ = 0.0; /* left */
+ *out++ = 0.0; /* right */
+ }
+ else
+ {
+ /* Play sawtooth wave. */
+ *out++ = data->left_phase; /* left */
+ *out++ = data->right_phase; /* right */
+ /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
+ data->left_phase += 0.01f;
+ /* When signal reaches top, drop back down. */
+ if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
+ /* higher pitch so we can distinguish left and right. */
+ data->right_phase += 0.03f;
+ if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
+ }
+ data->beepCount -= 1;
+ break;
+
+ default:
+ data->state = STATE_BKG_IDLE;
+ break;
+ }
+ }
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream *stream;
+ PaError err;
+ paTestData DATA;
+ int i, timeout;
+ PaTime previousTime;
+ PaStreamParameters outputParameters;
+ printf("PortAudio Test: you should see BEEP at the same time you hear it.\n");
+ printf("Wait for a few seconds random delay between BEEPs.\n");
+ printf("BEEP %d times.\n", NUM_BEEPS );
+ /* Initialize our DATA for use by callback. */
+ DATA.left_phase = DATA.right_phase = 0.0;
+ DATA.state = STATE_BKG_IDLE;
+ DATA.requestBeep = 0;
+ /* Initialize library before making any other calls. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ outputParameters.device = Pa_GetDefaultOutputDevice();
+ outputParameters.channelCount = 2;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+ outputParameters.sampleFormat = paFloat32;
+ outputParameters.suggestedLatency = (double)LATENCY_MSEC / 1000;
+
+ /* Open an audio I/O stream. */
+ err = Pa_OpenStream(
+ &stream,
+ NULL, /* no input */
+ &outputParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &DATA );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("started\n");
+ fflush(stdout);
+
+ previousTime = Pa_GetStreamTime( stream );
+ for( i=0; i<NUM_BEEPS; i++ )
+ {
+ /* Request a beep from background. */
+ DATA.requestBeep = 1;
+
+ /* Wait for background to acknowledge request. */
+ timeout = TIMEOUT_MSEC;
+ while( (DATA.requestBeep == 1) && (timeout-- > 0 ) ) Pa_Sleep(SLEEP_MSEC);
+ if( timeout <= 0 )
+ {
+ fprintf( stderr, "Timed out waiting for background to acknowledge request.\n" );
+ goto error;
+ }
+ printf("calc beep for %9.3f, latency = %6.3f\n", DATA.beepTime, DATA.latency );
+ fflush(stdout);
+
+ /* Wait for scheduled beep time. */
+ timeout = TIMEOUT_MSEC + (10000/SLEEP_MSEC);
+ while( (Pa_GetStreamTime( stream ) < DATA.beepTime) && (timeout-- > 0 ) )
+ {
+ Pa_Sleep(SLEEP_MSEC);
+ }
+ if( timeout <= 0 )
+ {
+ fprintf( stderr, "Timed out waiting for time. Now = %9.3f, Beep for %9.3f.\n",
+ PaUtil_GetTime(), DATA.beepTime );
+ goto error;
+ }
+
+ /* Beep should be sounding now so print synchronized BEEP. */
+ printf("hear \"BEEP\" at %9.3f, delta = %9.3f\n",
+ Pa_GetStreamTime( stream ), (DATA.beepTime - previousTime) );
+ fflush(stdout);
+
+ previousTime = DATA.beepTime;
+ }
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_toomanysines.c b/pd/portaudio/pa_tests/patest_toomanysines.c
new file mode 100644
index 00000000..2fbb8433
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_toomanysines.c
@@ -0,0 +1,172 @@
+/*
+ * $Id: patest_toomanysines.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Play more sine waves than we can handle in real time as a stress test,
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define MAX_SINES (500)
+#define MAX_LOAD (1.2)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (512)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TWOPI (M_PI * 2.0)
+
+typedef struct paTestData
+{
+ int numSines;
+ double phases[MAX_SINES];
+}
+paTestData;
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+ int j;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ float output = 0.0;
+ double phaseInc = 0.02;
+ double phase;
+ for( j=0; j<data->numSines; j++ )
+ {
+ /* Advance phase of next oscillator. */
+ phase = data->phases[j];
+ phase += phaseInc;
+ if( phase > TWOPI ) phase -= TWOPI;
+
+ phaseInc *= 1.02;
+ if( phaseInc > 0.5 ) phaseInc *= 0.5;
+
+ /* This is not a very efficient way to calc sines. */
+ output += (float) sin( phase );
+ data->phases[j] = phase;
+ }
+
+
+ *out++ = (float) (output / data->numSines);
+ }
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ int numStress;
+ paTestData data = {0};
+ double load;
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d. MAX_LOAD = %f\n",
+ SAMPLE_RATE, FRAMES_PER_BUFFER, MAX_LOAD );
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 1, /* mono output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ /* Determine number of sines required to get to 50% */
+ do
+ {
+ data.numSines++;
+ Pa_Sleep( 100 );
+
+ load = Pa_GetCPULoad( stream );
+ printf("numSines = %d, CPU load = %f\n", data.numSines, load );
+ }
+ while( load < 0.5 );
+
+ /* Calculate target stress value then ramp up to that level*/
+ numStress = (int) (2.0 * data.numSines * MAX_LOAD );
+ for( ; data.numSines < numStress; data.numSines++ )
+ {
+ Pa_Sleep( 200 );
+ load = Pa_GetCPULoad( stream );
+ printf("STRESSING: numSines = %d, CPU load = %f\n", data.numSines, load );
+ }
+
+ printf("Suffer for 5 seconds.\n");
+ Pa_Sleep( 5000 );
+
+ printf("Stop stream.\n");
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_underflow.c b/pd/portaudio/pa_tests/patest_underflow.c
new file mode 100644
index 00000000..3f02c5a4
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_underflow.c
@@ -0,0 +1,151 @@
+/*
+ * $Id: patest_underflow.c,v 1.1.1.1 2003-05-09 16:03:57 ggeiger Exp $
+ * patest_underflow.c
+ * Simulate an output buffer underflow condition.
+ * Tests whether the stream can be stopped when underflowing buffers.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (20)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (2048)
+#define MSEC_PER_BUFFER ( (FRAMES_PER_BUFFER * 1000) / SAMPLE_RATE )
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+ int sleepTime;
+}
+paTestData;
+
+/* 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( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+
+ /* Cause underflow to occur. */
+ if( data->sleepTime > 0 ) Pa_Sleep( data->sleepTime );
+ data->sleepTime += 1;
+
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = data.sleepTime = 0;
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ while( data.sleepTime < (2 * MSEC_PER_BUFFER) )
+ {
+ printf("SleepTime = %d\n", data.sleepTime );
+ Pa_Sleep( data.sleepTime );
+ }
+
+ printf("Try to stop stream.\n");
+ err = Pa_StopStream( stream ); /* */
+ err = Pa_AbortStream( stream ); /* */
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_wire.c b/pd/portaudio/pa_tests/patest_wire.c
new file mode 100644
index 00000000..51531395
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_wire.c
@@ -0,0 +1,277 @@
+/*
+ * $Id: patest_wire.c,v 1.1.1.1 2003-05-09 16:03:57 ggeiger Exp $
+ * patest_wire.c
+ *
+ * Pass input directly to output.
+ * Note that some HW devices, for example many ISA audio cards
+ * on PCs, do NOT support full duplex! For a PC, you normally need
+ * a PCI based audio card such as the SBLive.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define SAMPLE_RATE (44100)
+
+typedef struct WireConfig_s
+{
+ int isInputInterleaved;
+ int isOutputInterleaved;
+ int numInputChannels;
+ int numOutputChannels;
+ int framesPerCallback;
+} WireConfig_t;
+
+#define USE_FLOAT_INPUT (1)
+#define USE_FLOAT_OUTPUT (1)
+
+#define INPUT_LATENCY_MSEC (0)
+#define INPUT_LATENCY_FRAMES ((INPUT_LATENCY_MSEC * SAMPLE_RATE) / 1000)
+#define OUTPUT_LATENCY_MSEC (0)
+#define OUTPUT_LATENCY_FRAMES ((OUTPUT_LATENCY_MSEC * SAMPLE_RATE) / 1000)
+
+
+#if USE_FLOAT_INPUT
+ #define INPUT_FORMAT paFloat32
+ typedef float INPUT_SAMPLE;
+#else
+ #define INPUT_FORMAT paInt16
+ typedef short INPUT_SAMPLE;
+#endif
+
+#if USE_FLOAT_OUTPUT
+ #define OUTPUT_FORMAT paFloat32
+ typedef float OUTPUT_SAMPLE;
+#else
+ #define OUTPUT_FORMAT paInt16
+ typedef short OUTPUT_SAMPLE;
+#endif
+
+double gInOutScaler = 1.0;
+#define CONVERT_IN_TO_OUT(in) ((OUTPUT_SAMPLE) ((in) * gInOutScaler))
+
+#define INPUT_DEVICE (Pa_GetDefaultInputDevice())
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDevice())
+
+static PaError TestConfiguration( WireConfig_t *config );
+
+static int wireCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be 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 wireCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ INPUT_SAMPLE *in;
+ OUTPUT_SAMPLE *out;
+ int inStride;
+ int outStride;
+
+ int inDone = 0;
+ int outDone = 0;
+ WireConfig_t *config = (WireConfig_t *) userData;
+ unsigned int i;
+ int inChannel, outChannel;
+ (void) outTime;
+
+ /* This may get called with NULL inputBuffer during initial setup. */
+ if( inputBuffer == NULL) return 0;
+
+ inChannel=0, outChannel=0;
+ while( !(inDone && outDone) )
+ {
+ if( config->isInputInterleaved )
+ {
+ in = ((INPUT_SAMPLE*)inputBuffer) + inChannel;
+ inStride = config->numInputChannels;
+ }
+ else
+ {
+ in = ((INPUT_SAMPLE**)inputBuffer)[inChannel];
+ inStride = 1;
+ }
+
+ if( config->isOutputInterleaved )
+ {
+ out = ((OUTPUT_SAMPLE*)outputBuffer) + outChannel;
+ outStride = config->numOutputChannels;
+ }
+ else
+ {
+ out = ((OUTPUT_SAMPLE**)outputBuffer)[outChannel];
+ outStride = 1;
+ }
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out = CONVERT_IN_TO_OUT( *in );
+ out += outStride;
+ in += inStride;
+ }
+
+ if(inChannel < (config->numInputChannels - 1)) inChannel++;
+ else inDone = 1;
+ if(outChannel < (config->numOutputChannels - 1)) outChannel++;
+ else outDone = 1;
+ }
+ return 0;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ WireConfig_t CONFIG;
+ WireConfig_t *config = &CONFIG;
+ int configIndex = 0;;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ printf("Please connect audio signal to input and listen for it on output!\n");
+ printf("input format = %d\n", INPUT_FORMAT );
+ printf("output format = %d\n", OUTPUT_FORMAT );
+ printf("input device ID = %d\n", INPUT_DEVICE );
+ printf("output device ID = %d\n", OUTPUT_DEVICE );
+
+ if( INPUT_FORMAT == OUTPUT_FORMAT )
+ {
+ gInOutScaler = 1.0;
+ }
+ else if( (INPUT_FORMAT == paInt16) && (OUTPUT_FORMAT == paFloat32) )
+ {
+ gInOutScaler = 1.0/32768.0;
+ }
+ else if( (INPUT_FORMAT == paFloat32) && (OUTPUT_FORMAT == paInt16) )
+ {
+ gInOutScaler = 32768.0;
+ }
+
+ for( config->isInputInterleaved = 0; config->isInputInterleaved < 2; config->isInputInterleaved++ )
+ {
+ for( config->isOutputInterleaved = 0; config->isOutputInterleaved < 2; config->isOutputInterleaved++ )
+ {
+ for( config->numInputChannels = 1; config->numInputChannels < 3; config->numInputChannels++ )
+ {
+ for( config->numOutputChannels = 1; config->numOutputChannels < 3; config->numOutputChannels++ )
+ {
+ for( config->framesPerCallback = 0; config->framesPerCallback < 65; config->framesPerCallback += 64 )
+ {
+ printf("-----------------------------------------------\n" );
+ printf("Configuration #%d\n", configIndex++ );
+ err = TestConfiguration( config );
+ // give user a chance to bail out
+ if( err == 1 )
+ {
+ err = paNoError;
+ goto done;
+ }
+ else if( err != paNoError ) goto error;
+ }
+ }
+ }
+ }
+ }
+
+done:
+ Pa_Terminate();
+
+ printf("Full duplex sound test complete.\n"); fflush(stdout);
+
+ printf("Hit ENTER to quit.\n"); fflush(stdout);
+ getchar();
+
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ printf("Hit ENTER to quit.\n"); fflush(stdout);
+ getchar();
+ return -1;
+}
+
+static PaError TestConfiguration( WireConfig_t *config )
+{
+ int c;
+ PaError err;
+ PaStream *stream;
+ printf("input %sinterleaved!\n", (config->isInputInterleaved ? " " : "NOT ") );
+ printf("output %sinterleaved!\n", (config->isOutputInterleaved ? " " : "NOT ") );
+ printf("input channels = %d\n", config->numInputChannels );
+ printf("output channels = %d\n", config->numOutputChannels );
+ printf("framesPerCallback = %d\n", config->framesPerCallback );
+
+ err = Pa_OpenStream(
+ &stream,
+ INPUT_DEVICE,
+ config->numInputChannels,
+ INPUT_FORMAT | (config->isInputInterleaved ? 0 : paNonInterleaved),
+ INPUT_LATENCY_FRAMES, /* input latency */
+ NULL,
+ OUTPUT_DEVICE,
+ config->numOutputChannels,
+ OUTPUT_FORMAT | (config->isOutputInterleaved ? 0 : paNonInterleaved),
+ OUTPUT_LATENCY_FRAMES, /* output latency */
+ NULL,
+ SAMPLE_RATE,
+ config->framesPerCallback, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ wireCallback,
+ config ); /* user data */
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Hit ENTER for next configuration, or 'q' to quit.\n"); fflush(stdout);
+ c = getchar();
+
+ printf("Closing stream.\n");
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ if( c == 'q' ) return 1;
+
+error:
+ return err;
+}
diff --git a/pd/portaudio/pa_unix/pa_unix_hostapis.c b/pd/portaudio/pa_unix/pa_unix_hostapis.c
new file mode 100644
index 00000000..4d10ef93
--- /dev/null
+++ b/pd/portaudio/pa_unix/pa_unix_hostapis.c
@@ -0,0 +1,60 @@
+/*
+ * $Id: pa_unix_hostapis.c,v 1.1.2.4 2003/02/10 01:06:09 dmazzoni Exp $
+ * Portable Audio I/O Library UNIX initialization table
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+
+#include "pa_hostapi.h"
+
+PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+
+
+PaUtilHostApiInitializer *paHostApiInitializers[] =
+ {
+#ifdef PA_USE_OSS
+ PaOSS_Initialize,
+#endif
+
+#ifdef PA_USE_ALSA
+ PaAlsa_Initialize,
+#endif
+
+#ifdef PA_USE_JACK
+ PaJack_Initialize,
+#endif
+
+
+ 0 /* NULL terminated array */
+ };
+
+int paDefaultHostApiIndex = 0;
+
+
diff --git a/pd/portaudio/pa_unix/pa_unix_hostapis.o b/pd/portaudio/pa_unix/pa_unix_hostapis.o
new file mode 100644
index 00000000..e8d68536
--- /dev/null
+++ b/pd/portaudio/pa_unix/pa_unix_hostapis.o
Binary files differ
diff --git a/pd/portaudio/pa_unix/pa_unix_util.c b/pd/portaudio/pa_unix/pa_unix_util.c
new file mode 100644
index 00000000..826d4e7c
--- /dev/null
+++ b/pd/portaudio/pa_unix/pa_unix_util.c
@@ -0,0 +1,102 @@
+/*
+ * $Id: pa_unix_util.c,v 1.1.2.1 2002/07/31 04:22:56 joshua Exp $
+ * Portable Audio I/O Library
+ * UNIX platform-specific support functions
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "pa_util.h"
+
+
+/*
+ Track memory allocations to avoid leaks.
+ */
+
+#if PA_TRACK_MEMORY
+static int numAllocations_ = 0;
+#endif
+
+
+void *PaUtil_AllocateMemory( long size )
+{
+ void *result = malloc( size );
+
+#if PA_TRACK_MEMORY
+ if( result != NULL ) numAllocations_ += 1;
+#endif
+ return result;
+}
+
+
+void PaUtil_FreeMemory( void *block )
+{
+ if( block != NULL )
+ {
+ free( block );
+#if PA_TRACK_MEMORY
+ numAllocations_ -= 1;
+#endif
+
+ }
+}
+
+
+int PaUtil_CountCurrentlyAllocatedBlocks( void )
+{
+#if PA_TRACK_MEMORY
+ return numAllocations_;
+#else
+ return 0;
+#endif
+}
+
+
+void Pa_Sleep( long msec )
+{
+ usleep( msec * 1000 );
+}
+
+
+static int usePerformanceCounter_;
+static double microsecondsPerTick_;
+
+void PaUtil_InitializeClock( void )
+{
+ /* TODO */
+}
+
+
+double PaUtil_GetTime( void )
+{
+ /* TODO */
+ return (0);
+}
diff --git a/pd/portaudio/pa_unix/pa_unix_util.o b/pd/portaudio/pa_unix/pa_unix_util.o
new file mode 100644
index 00000000..52868e5f
--- /dev/null
+++ b/pd/portaudio/pa_unix/pa_unix_util.o
Binary files differ
diff --git a/pd/portaudio/pa_unix_oss/Makefile b/pd/portaudio/pa_unix_oss/Makefile
new file mode 100644
index 00000000..f5015631
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/Makefile
@@ -0,0 +1,43 @@
+# Make PortAudio for Linux
+
+LIBS = -lm -lpthread
+
+CDEFINES = -I../pa_common
+CFLAGS = -g -Wall
+PASRC = ../pa_common/pa_lib.c pa_unix_oss.c
+PAINC = ../pa_common/portaudio.h
+
+# Tests that work.
+TESTC = $(PASRC) ../pa_tests/patest_sine.c
+#TESTC = $(PASRC) ../pa_tests/patest_longsine.c
+#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c
+#TESTC = $(PASRC) ../pa_tests/patest_maxsines.c
+#TESTC = $(PASRC) ../pa_tests/patest_toomanysines.c
+#TESTC = $(PASRC) ../pa_tests/patest_underflow.c
+#TESTC = $(PASRC) ../pa_tests/patest_hang.c
+#TESTC = $(PASRC) ../pa_tests/patest_sync.c
+#TESTC = $(PASRC) ../pa_tests/patest_pink.c
+#TESTC = $(PASRC) ../pa_tests/patest_leftright.c
+#TESTC = $(PASRC) ../pa_tests/patest_clip.c
+#TESTC = $(PASRC) ../pa_tests/patest_dither.c
+#TESTC = $(PASRC) ../pa_tests/pa_devs.c
+#TESTC = $(PASRC) ../pa_tests/patest_many.c
+#TESTC = $(PASRC) ../pa_tests/patest_record.c
+#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c
+#TESTC = $(PASRC) ../pa_tests/patest_wire.c
+#TESTC = $(PASRC) ../pa_tests/paqa_devs.c
+
+# Tests that do not yet work.
+# OSS doesn't let us make obscenely huge buffers so the test will seem to fail. But its OK.
+#TESTC = $(PASRC) ../pa_tests/patest_stop.c
+
+TESTH = $(PAINC)
+
+all: patest
+
+patest: $(TESTC) $(TESTH) Makefile
+ gcc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest
+
+run: patest
+ ./patest
+
diff --git a/pd/portaudio/pa_unix_oss/Makefile_freebsd b/pd/portaudio/pa_unix_oss/Makefile_freebsd
new file mode 100644
index 00000000..fc8b14db
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/Makefile_freebsd
@@ -0,0 +1,36 @@
+# Make PortAudio for FreeBSD
+
+LIBS = -lm -pthread
+
+CDEFINES = -I../pa_common
+CFLAGS = -g
+PASRC = ../pa_common/pa_lib.c pa_freebsd.c
+PAINC = ../pa_common/portaudio.h
+
+# Tests that work.
+#TESTC = $(PASRC) ../pa_tests/patest_sine.c
+TESTC = $(PASRC) ../pa_tests/patest_sine_time.c
+#TESTC = $(PASRC) ../pa_tests/patest_stop.c
+#TESTC = $(PASRC) ../pa_tests/patest_sync.c
+#TESTC = $(PASRC) ../pa_tests/patest_pink.c
+#TESTC = $(PASRC) ../pa_tests/patest_leftright.c
+#TESTC = $(PASRC) ../pa_tests/patest_clip.c
+#TESTC = $(PASRC) ../pa_tests/patest_dither.c
+#TESTC = $(PASRC) ../pa_tests/pa_devs.c
+#TESTC = $(PASRC) ../pa_tests/patest_many.c
+#TESTC = $(PASRC) ../pa_tests/patest_record.c
+#TESTC = $(PASRC) ../pa_tests/patest_wire.c
+#TESTC = $(PASRC) ../pa_tests/paqa_devs.c
+
+# Tests that do not yet work.
+
+TESTH = $(PAINC)
+
+all: patest
+
+patest: $(TESTC) $(TESTH) Makefile
+ gcc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest
+
+run: patest
+ ./patest
+
diff --git a/pd/portaudio/pa_unix_oss/low_latency_tip.txt b/pd/portaudio/pa_unix_oss/low_latency_tip.txt
new file mode 100644
index 00000000..2d982b79
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/low_latency_tip.txt
Binary files differ
diff --git a/pd/portaudio/pa_unix_oss/pa_unix_oss.c b/pd/portaudio/pa_unix_oss/pa_unix_oss.c
new file mode 100644
index 00000000..2e51b245
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/pa_unix_oss.c
@@ -0,0 +1,1187 @@
+/*
+ * $Id
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * OSS implementation by:
+ * Douglas Repetto
+ * Phil Burk
+ * Dominic Mazzoni
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#ifdef __linux__
+# include <linux/soundcard.h>
+# define DEVICE_NAME_BASE "/dev/dsp"
+#else
+# include <machine/soundcard.h> /* JH20010905 */
+# define DEVICE_NAME_BASE "/dev/audio"
+#endif
+
+#include "portaudio.h"
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
+
+/* TODO: add error text handling
+#define PA_UNIX_OSS_ERROR( errorCode, errorText ) \
+ PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
+*/
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define DBUG(x) /* PRINT(x) */
+
+/* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */
+
+typedef struct
+{
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
+
+ PaUtilAllocationGroup *allocations;
+
+ PaHostApiIndex hostApiIndex;
+}
+PaOSSHostApiRepresentation;
+
+typedef struct PaOSS_DeviceList {
+ PaDeviceInfo *deviceInfo;
+ struct PaOSS_DeviceList *next;
+}
+PaOSS_DeviceList;
+
+/* prototypes for functions declared in this file */
+
+PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData );
+static PaError CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+static signed long GetStreamReadAvailable( PaStream* stream );
+static signed long GetStreamWriteAvailable( PaStream* stream );
+static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi );
+
+
+PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ PaOSSHostApiRepresentation *ossHostApi;
+
+ DBUG(("PaOSS_Initialize\n"));
+
+ ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) );
+ if( !ossHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ ossHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !ossHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ *hostApi = &ossHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paOSS;
+ (*hostApi)->info.name = "OSS";
+ ossHostApi->hostApiIndex = hostApiIndex;
+
+ BuildDeviceList( ossHostApi );
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite,
+ PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+
+ return result;
+
+error:
+ if( ossHostApi )
+ {
+ if( ossHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( ossHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( ossHostApi );
+ }
+ return result;
+}
+
+#ifndef AFMT_S16_NE
+#define AFMT_S16_NE Get_AFMT_S16_NE()
+/*********************************************************************
+ * Some versions of OSS do not define AFMT_S16_NE. So check CPU.
+ * PowerPC is Big Endian. X86 is Little Endian.
+ */
+static int Get_AFMT_S16_NE( void )
+{
+ long testData = 1;
+ char *ptr = (char *) &testData;
+ int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */
+ return isLittle ? AFMT_S16_LE : AFMT_S16_BE;
+}
+#endif
+
+PaError PaOSS_SetFormat(const char *callingFunctionName, int deviceHandle,
+ char *deviceName, int inputChannelCount, int outputChannelCount,
+ double *sampleRate)
+{
+ int format;
+ int rate;
+ int temp;
+
+ /* Attempt to set format to 16-bit */
+
+ format = AFMT_S16_NE;
+ if (ioctl(deviceHandle, SNDCTL_DSP_SETFMT, &format) == -1) {
+ DBUG(("%s: could not set format: %s\n", callingFunctionName, deviceName ));
+ return paSampleFormatNotSupported;
+ }
+ if (format != AFMT_S16_NE) {
+ DBUG(("%s: device does not support AFMT_S16_NE: %s\n", callingFunctionName, deviceName ));
+ return paSampleFormatNotSupported;
+ }
+
+ /* try to set the number of channels */
+
+ if (inputChannelCount > 0) {
+ temp = inputChannelCount;
+
+ if( ioctl(deviceHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 ) {
+ DBUG(("%s: Couldn't set device %s to %d channels\n", callingFunctionName, deviceName, inputChannelCount ));
+ return paSampleFormatNotSupported;
+ }
+ }
+
+ if (outputChannelCount > 0) {
+ temp = outputChannelCount;
+
+ if( ioctl(deviceHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 ) {
+ DBUG(("%s: Couldn't set device %s to %d channels\n", callingFunctionName, deviceName, outputChannelCount ));
+ return paSampleFormatNotSupported;
+ }
+ }
+
+ /* try to set the sample rate */
+
+ rate = (int)(*sampleRate);
+ if (ioctl(deviceHandle, SNDCTL_DSP_SPEED, &rate) == -1)
+ {
+ DBUG(("%s: Device %s, couldn't set sample rate to %d\n",
+ callingFunctionName, deviceName, (int)*sampleRate ));
+ return paInvalidSampleRate;
+ }
+
+ /* reject if there's no sample rate within 1% of the one requested */
+ if ((fabs(*sampleRate - rate) / *sampleRate) > 0.01)
+ {
+ DBUG(("%s: Device %s, wanted %d, closest sample rate was %d\n",
+ callingFunctionName, deviceName, (int)*sampleRate, rate ));
+ return paInvalidSampleRate;
+ }
+
+ *sampleRate = rate;
+
+ return paNoError;
+}
+
+static PaError PaOSS_QueryDevice(char *deviceName, PaDeviceInfo *deviceInfo)
+{
+ PaError result = paNoError;
+ int tempDevHandle;
+ int numChannels, maxNumChannels;
+ int sampleRate;
+ int format;
+
+ /* douglas:
+ we have to do this querying in a slightly different order. apparently
+ some sound cards will give you different info based on their settins.
+ e.g. a card might give you stereo at 22kHz but only mono at 44kHz.
+ the correct order for OSS is: format, channels, sample rate
+ */
+
+ if ( (tempDevHandle = open(deviceName,O_WRONLY|O_NONBLOCK)) == -1 )
+ {
+ DBUG(("PaOSS_QueryDevice: could not open %s\n", deviceName ));
+ return paDeviceUnavailable;
+ }
+
+ /* Attempt to set format to 16-bit */
+ format = AFMT_S16_NE;
+ if (ioctl(tempDevHandle, SNDCTL_DSP_SETFMT, &format) == -1) {
+ DBUG(("PaOSS_QueryDevice: could not set format: %s\n", deviceName ));
+ result = paSampleFormatNotSupported;
+ goto error;
+ }
+ if (format != AFMT_S16_NE) {
+ DBUG(("PaOSS_QueryDevice: device does not support AFMT_S16_NE: %s\n", deviceName ));
+ result = paSampleFormatNotSupported;
+ goto error;
+ }
+
+ /* Negotiate for the maximum number of channels for this device. PLB20010927
+ * Consider up to 16 as the upper number of channels.
+ * Variable maxNumChannels should contain the actual upper limit after the call.
+ * Thanks to John Lazzaro and Heiko Purnhagen for suggestions.
+ */
+ maxNumChannels = 0;
+ for( numChannels = 1; numChannels <= 16; numChannels++ )
+ {
+ int temp = numChannels;
+ DBUG(("PaOSS_QueryDevice: use SNDCTL_DSP_CHANNELS, numChannels = %d\n", numChannels ))
+ if(ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 )
+ {
+ /* ioctl() failed so bail out if we already have stereo */
+ if( numChannels > 2 ) break;
+ }
+ else
+ {
+ /* ioctl() worked but bail out if it does not support numChannels.
+ * We don't want to leave gaps in the numChannels supported.
+ */
+ if( (numChannels > 2) && (temp != numChannels) ) break;
+ DBUG(("PaOSS_QueryDevice: temp = %d\n", temp ))
+ if( temp > maxNumChannels ) maxNumChannels = temp; /* Save maximum. */
+ }
+ }
+
+ /* The above negotiation may fail for an old driver so try this older technique. */
+ if( maxNumChannels < 1 )
+ {
+ int stereo = 1;
+ if(ioctl(tempDevHandle, SNDCTL_DSP_STEREO, &stereo) < 0)
+ {
+ maxNumChannels = 1;
+ }
+ else
+ {
+ maxNumChannels = (stereo) ? 2 : 1;
+ }
+ DBUG(("PaOSS_QueryDevice: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", maxNumChannels ))
+ }
+
+ DBUG(("PaOSS_QueryDevice: maxNumChannels = %d\n", maxNumChannels))
+
+ deviceInfo->maxOutputChannels = maxNumChannels;
+ /* FIXME - for now, assume maxInputChannels = maxOutputChannels.
+ * Eventually do separate queries for O_WRONLY and O_RDONLY
+ */
+ deviceInfo->maxInputChannels = deviceInfo->maxOutputChannels;
+
+ /* During channel negotiation, the last ioctl() may have failed. This can
+ * also cause sample rate negotiation to fail. Hence the following, to return
+ * to a supported number of channels. SG20011005 */
+ {
+ int temp = maxNumChannels;
+ if( temp > 2 ) temp = 2; /* use most reasonable default value */
+ ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp);
+ }
+
+ /* Get supported sample rate closest to 44100 Hz */
+ sampleRate = 44100;
+ if (ioctl(tempDevHandle, SNDCTL_DSP_SPEED, &sampleRate) == -1)
+ {
+ result = paUnanticipatedHostError;
+ goto error;
+ }
+
+ deviceInfo->defaultSampleRate = sampleRate;
+
+ deviceInfo->structVersion = 2;
+
+ /* TODO */
+ deviceInfo->defaultLowInputLatency = 128.0 / sampleRate;
+ deviceInfo->defaultLowOutputLatency = 128.0 / sampleRate;
+ deviceInfo->defaultHighInputLatency = 16384.0 / sampleRate;
+ deviceInfo->defaultHighOutputLatency = 16384.0 / sampleRate;
+
+ result = paNoError;
+
+error:
+ /* We MUST close the handle here or we won't be able to reopen it later!!! */
+ close(tempDevHandle);
+
+ return result;
+}
+
+static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi )
+{
+ PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep;
+ PaOSS_DeviceList *head = NULL, *tail = NULL, *entry;
+ int i;
+ int numDevices;
+
+ /* Find devices by calling PaOSS_QueryDevice on each
+ potential device names. When we find a valid one,
+ add it to a linked list. */
+
+ for(i=0; i<10; i++) {
+ char deviceName[32];
+ PaDeviceInfo deviceInfo;
+ int testResult;
+
+ if (i==0)
+ sprintf(deviceName, "%s", DEVICE_NAME_BASE);
+ else
+ sprintf(deviceName, "%s%d", DEVICE_NAME_BASE, i);
+
+ DBUG(("PaOSS BuildDeviceList: trying device %s\n", deviceName ));
+ testResult = PaOSS_QueryDevice(deviceName, &deviceInfo);
+ DBUG(("PaOSS BuildDeviceList: PaOSS_QueryDevice returned %d\n", testResult ));
+
+ if (testResult == paNoError) {
+ DBUG(("PaOSS BuildDeviceList: Adding device %s to list\n", deviceName));
+ deviceInfo.hostApi = ossApi->hostApiIndex;
+ deviceInfo.name = PaUtil_GroupAllocateMemory(
+ ossApi->allocations, strlen(deviceName)+1);
+ strcpy((char *)deviceInfo.name, deviceName);
+ entry = (PaOSS_DeviceList *)PaUtil_AllocateMemory(sizeof(PaOSS_DeviceList));
+ entry->deviceInfo = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ ossApi->allocations, sizeof(PaDeviceInfo) );
+ entry->next = NULL;
+ memcpy(entry->deviceInfo, &deviceInfo, sizeof(PaDeviceInfo));
+ if (tail)
+ tail->next = entry;
+ else {
+ head = entry;
+ tail = entry;
+ }
+ }
+ }
+
+ /* Make an array of PaDeviceInfo pointers out of the linked list */
+
+ numDevices = 0;
+ entry = head;
+ while(entry) {
+ numDevices++;
+ entry = entry->next;
+ }
+
+ DBUG(("PaOSS BuildDeviceList: Total number of devices found: %d\n", numDevices));
+
+ commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ ossApi->allocations, sizeof(PaDeviceInfo*) *numDevices );
+
+ entry = head;
+ i = 0;
+ while(entry) {
+ commonApi->deviceInfos[i] = entry->deviceInfo;
+ i++;
+ entry = entry->next;
+ }
+
+ commonApi->info.deviceCount = numDevices;
+ commonApi->info.defaultInputDevice = 0;
+ commonApi->info.defaultOutputDevice = 0;
+
+ return paNoError;
+}
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
+
+ if( ossHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( ossHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( ossHostApi );
+}
+
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
+{
+ PaDeviceIndex device;
+ PaDeviceInfo *deviceInfo;
+ PaError result = paNoError;
+ char *deviceName;
+ int inputChannelCount, outputChannelCount;
+ int tempDevHandle = 0;
+ int flags;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ if (inputChannelCount == 0 && outputChannelCount == 0)
+ return paInvalidChannelCount;
+
+ /* if full duplex, make sure that they're the same device */
+
+ if (inputChannelCount > 0 && outputChannelCount > 0 &&
+ inputParameters->device != outputParameters->device)
+ return paInvalidDevice;
+
+ /* if full duplex, also make sure that they're the same number of channels */
+
+ if (inputChannelCount > 0 && outputChannelCount > 0 &&
+ inputChannelCount != outputChannelCount)
+ return paInvalidChannelCount;
+
+ /* open the device so we can do more tests */
+
+ if (inputChannelCount > 0) {
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi);
+ if (result != paNoError)
+ return result;
+ }
+ else {
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi);
+ if (result != paNoError)
+ return result;
+ }
+
+ deviceInfo = hostApi->deviceInfos[device];
+ deviceName = (char *)deviceInfo->name;
+
+ flags = O_NONBLOCK;
+ if (inputChannelCount > 0 && outputChannelCount > 0)
+ flags |= O_RDWR;
+ else if (inputChannelCount > 0)
+ flags |= O_RDONLY;
+ else
+ flags |= O_WRONLY;
+
+ if ( (tempDevHandle = open(deviceInfo->name, flags)) == -1 )
+ {
+ DBUG(("PaOSS IsFormatSupported: could not open %s\n", deviceName ));
+ return paDeviceUnavailable;
+ }
+
+ /* PaOSS_SetFormat will do the rest of the checking for us */
+
+ if ((result = PaOSS_SetFormat("PaOSS IsFormatSupported", tempDevHandle,
+ deviceName, inputChannelCount, outputChannelCount,
+ &sampleRate)) != paNoError)
+ {
+ goto error;
+ }
+
+ /* everything succeeded! */
+
+ close(tempDevHandle);
+
+ return paFormatIsSupported;
+
+ error:
+ if (tempDevHandle)
+ close(tempDevHandle);
+
+ return paSampleFormatNotSupported;
+}
+
+/* PaOSSStream - a stream data structure specifically for this implementation */
+
+typedef struct PaOSSStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ int deviceHandle;
+
+ int stopSoon;
+ int stopNow;
+ int isActive;
+
+ int inputChannelCount;
+ int outputChannelCount;
+
+ pthread_t thread;
+
+ void *inputBuffer;
+ void *outputBuffer;
+
+ int lastPosPtr;
+ double lastStreamBytes;
+
+ int framesProcessed;
+
+ double sampleRate;
+
+ unsigned long framesPerHostCallback;
+}
+PaOSSStream;
+
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
+ PaOSSStream *stream = 0;
+ PaDeviceIndex device;
+ PaDeviceInfo *deviceInfo;
+ audio_buf_info bufinfo;
+ int bytesPerHostBuffer;
+ int flags;
+ int deviceHandle = 0;
+ char *deviceName;
+ unsigned long framesPerHostBuffer;
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat = paInt16, outputSampleFormat = paInt16;
+ PaSampleFormat hostInputSampleFormat = paInt16, hostOutputSampleFormat = paInt16;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16, inputSampleFormat );
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16, outputSampleFormat );
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ if( inputChannelCount == 0 && outputChannelCount == 0 )
+ {
+ DBUG(("Both inputChannelCount and outputChannelCount are zero!\n"));
+ return paUnanticipatedHostError;
+ }
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
+
+ /*
+ * open the device and set parameters here
+ */
+
+ if (inputChannelCount == 0 && outputChannelCount == 0)
+ return paInvalidChannelCount;
+
+ /* if full duplex, make sure that they're the same device */
+
+ if (inputChannelCount > 0 && outputChannelCount > 0 &&
+ inputParameters->device != outputParameters->device)
+ return paInvalidDevice;
+
+ /* if full duplex, also make sure that they're the same number of channels */
+
+ if (inputChannelCount > 0 && outputChannelCount > 0 &&
+ inputChannelCount != outputChannelCount)
+ return paInvalidChannelCount;
+
+ if (inputChannelCount > 0) {
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi);
+ if (result != paNoError)
+ return result;
+ }
+ else {
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi);
+ if (result != paNoError)
+ return result;
+ }
+
+ deviceInfo = hostApi->deviceInfos[device];
+ deviceName = (char *)deviceInfo->name;
+
+ flags = O_NONBLOCK;
+ if (inputChannelCount > 0 && outputChannelCount > 0)
+ flags |= O_RDWR;
+ else if (inputChannelCount > 0)
+ flags |= O_RDONLY;
+ else
+ flags |= O_WRONLY;
+
+ /* open first in nonblocking mode, in case it's busy... */
+ if ( (deviceHandle = open(deviceInfo->name, flags)) == -1 )
+ {
+ DBUG(("PaOSS OpenStream: could not open %s\n", deviceName ));
+ return paDeviceUnavailable;
+ }
+
+ /* if that succeeded, immediately open it again in blocking mode */
+ close(deviceHandle);
+ flags -= O_NONBLOCK;
+ if ( (deviceHandle = open(deviceInfo->name, flags)) == -1 )
+ {
+ DBUG(("PaOSS OpenStream: could not open %s in blocking mode\n", deviceName ));
+ return paDeviceUnavailable;
+ }
+
+ if ((result = PaOSS_SetFormat("PaOSS OpenStream", deviceHandle,
+ deviceName, inputChannelCount, outputChannelCount,
+ &sampleRate)) != paNoError)
+ {
+ goto error;
+ }
+
+ /* Compute number of frames per host buffer - if we can't retrieve the
+ * value, use the user's value instead
+ */
+
+ if ( ioctl(deviceHandle, SNDCTL_DSP_GETBLKSIZE, &bytesPerHostBuffer) == 0)
+ {
+ framesPerHostBuffer = bytesPerHostBuffer / 2 / (inputChannelCount>0? inputChannelCount: outputChannelCount);
+ }
+ else
+ framesPerHostBuffer = framesPerBuffer;
+
+ /* Allocate stream and fill in structure */
+
+ stream = (PaOSSStream*)PaUtil_AllocateMemory( sizeof(PaOSSStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( streamCallback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &ossHostApi->callbackStreamInterface, streamCallback, userData );
+ }
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &ossHostApi->blockingStreamInterface, streamCallback, userData );
+ }
+
+ stream->streamRepresentation.streamInfo.inputLatency = 0.;
+ stream->streamRepresentation.streamInfo.outputLatency = 0.;
+
+ if (inputChannelCount > 0) {
+ if (ioctl( deviceHandle, SNDCTL_DSP_GETISPACE, &bufinfo) == 0)
+ stream->streamRepresentation.streamInfo.inputLatency =
+ (bufinfo.fragsize * bufinfo.fragstotal) / sampleRate;
+ }
+
+ if (outputChannelCount > 0) {
+ if (ioctl( deviceHandle, SNDCTL_DSP_GETOSPACE, &bufinfo) == 0)
+ stream->streamRepresentation.streamInfo.outputLatency =
+ (bufinfo.fragsize * bufinfo.fragstotal) / sampleRate;
+ }
+
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+ /* we assume a fixed host buffer size in this example, but the buffer processor
+ can also support bounded and unknown host buffer sizes by passing
+ paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
+ paUtilFixedHostBufferSize below. */
+
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ inputChannelCount, inputSampleFormat, hostInputSampleFormat,
+ outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer,
+ framesPerHostBuffer, paUtilFixedHostBufferSize,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+
+ stream->framesPerHostCallback = framesPerHostBuffer;
+
+ stream->stopSoon = 0;
+ stream->stopNow = 0;
+ stream->isActive = 0;
+ stream->thread = 0;
+ stream->lastPosPtr = 0;
+ stream->lastStreamBytes = 0;
+ stream->sampleRate = sampleRate;
+ stream->framesProcessed = 0;
+ stream->deviceHandle = deviceHandle;
+
+ if (inputChannelCount > 0)
+ stream->inputBuffer = PaUtil_AllocateMemory( 2 * framesPerHostBuffer * inputChannelCount );
+ else
+ stream->inputBuffer = NULL;
+
+ if (outputChannelCount > 0)
+ stream->outputBuffer = PaUtil_AllocateMemory( 2 * framesPerHostBuffer * outputChannelCount );
+ else
+ stream->outputBuffer = NULL;
+
+ stream->inputChannelCount = inputChannelCount;
+ stream->outputChannelCount = outputChannelCount;
+
+ *s = (PaStream*)stream;
+
+ result = paNoError;
+
+ return result;
+
+error:
+ if( stream )
+ PaUtil_FreeMemory( stream );
+
+ if( deviceHandle )
+ close( deviceHandle );
+
+ return result;
+}
+
+static void *PaOSS_AudioThreadProc(void *userData)
+{
+ PaOSSStream *stream = (PaOSSStream*)userData;
+
+ DBUG(("PaOSS AudioThread: %d in, %d out\n", stream->inputChannelCount, stream->outputChannelCount));
+
+ while( (stream->stopNow == 0) && (stream->stopSoon == 0) ) {
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* TODO: IMPLEMENT ME */
+ int callbackResult;
+ unsigned long framesProcessed;
+ int bytesRequested;
+ int bytesRead, bytesWritten;
+ int delta;
+ int result;
+ count_info info;
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo );
+
+ /*
+ depending on whether the host buffers are interleaved, non-interleaved
+ or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
+ PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
+ */
+
+ if ( stream->inputChannelCount > 0 )
+ {
+ bytesRequested = stream->framesPerHostCallback * 2 * stream->inputChannelCount;
+ bytesRead = read( stream->deviceHandle, stream->inputBuffer, bytesRequested );
+
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, bytesRead/(2*stream->inputChannelCount));
+ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
+ 0, /* first channel of inputBuffer is channel 0 */
+ stream->inputBuffer,
+ 0 ); /* 0 - use inputChannelCount passed to init buffer processor */
+ }
+
+ if ( stream->outputChannelCount > 0 )
+ {
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
+ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
+ 0, /* first channel of outputBuffer is channel 0 */
+ stream->outputBuffer,
+ 0 ); /* 0 - use outputChannelCount passed to init buffer processor */
+ }
+
+ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+
+ if( callbackResult == paContinue )
+ {
+ /* nothing special to do */
+ }
+ else if( callbackResult == paAbort )
+ {
+ /* once finished, call the finished callback */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+
+ return NULL; /* return from the loop */
+ }
+ else if ( callbackResult == paComplete )
+ {
+ /* User callback has asked us to stop with paComplete or other non-zero value */
+
+ /* once finished, call the finished callback */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+
+ stream->stopSoon = 1;
+ }
+
+ if ( stream->outputChannelCount > 0 ) {
+ /* write output samples AFTER we've checked the callback result code */
+
+ bytesRequested = stream->framesPerHostCallback * 2 * stream->outputChannelCount;
+ bytesWritten = write( stream->deviceHandle, stream->outputBuffer, bytesRequested );
+
+ /* TODO: handle bytesWritten != bytesRequested (slippage?) */
+ }
+
+ /* Update current stream time (using a double so that
+ we don't wrap around like info.bytes does) */
+ if( stream->outputChannelCount > 0 )
+ result = ioctl( stream->deviceHandle, SNDCTL_DSP_GETOPTR, &info);
+ else
+ result = ioctl( stream->deviceHandle, SNDCTL_DSP_GETIPTR, &info);
+
+ if (result == 0) {
+ delta = ( info.bytes - stream->lastPosPtr ) & 0x000FFFFF;
+ stream->lastStreamBytes += delta;
+ stream->lastPosPtr = info.bytes;
+ }
+
+ stream->framesProcessed += stream->framesPerHostCallback;
+ }
+
+ return NULL;
+}
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ close(stream->deviceHandle);
+
+ if ( stream->inputBuffer )
+ PaUtil_FreeMemory( stream->inputBuffer );
+ if ( stream->outputBuffer )
+ PaUtil_FreeMemory( stream->outputBuffer );
+
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaOSSStream *stream = (PaOSSStream*)s;
+ int presult;
+
+ stream->isActive = 1;
+ stream->lastPosPtr = 0;
+ stream->lastStreamBytes = 0;
+ stream->framesProcessed = 0;
+
+ DBUG(("PaOSS StartStream\n"));
+
+ presult = pthread_create(&stream->thread,
+ NULL /*pthread_attr_t * attr*/,
+ (void*)PaOSS_AudioThreadProc, (void *)stream);
+
+ return result;
+}
+
+
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ stream->stopSoon = 1;
+ pthread_join( stream->thread, NULL );
+ stream->stopSoon = 0;
+ stream->stopNow = 0;
+ stream->isActive = 0;
+
+ DBUG(("PaOSS StopStream: Stopped stream\n"));
+
+ return result;
+}
+
+
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ stream->stopNow = 1;
+ pthread_join( stream->thread, NULL );
+ stream->stopSoon = 0;
+ stream->stopNow = 0;
+ stream->isActive = 0;
+
+ DBUG(("PaOSS AbortStream: Stopped stream\n"));
+
+ return result;
+}
+
+
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ return (!stream->isActive);
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ return (stream->isActive);
+}
+
+
+static PaTime GetStreamTime( PaStream *s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+ count_info info;
+ int delta;
+
+ if( stream->outputChannelCount > 0 ) {
+ if (ioctl( stream->deviceHandle, SNDCTL_DSP_GETOPTR, &info) == 0) {
+ delta = ( info.bytes - stream->lastPosPtr ) & 0x000FFFFF;
+ return ( stream->lastStreamBytes + delta) / ( stream->outputChannelCount * 2 ) / stream->sampleRate;
+ }
+ }
+ else {
+ if (ioctl( stream->deviceHandle, SNDCTL_DSP_GETIPTR, &info) == 0) {
+ delta = (info.bytes - stream->lastPosPtr) & 0x000FFFFF;
+ return ( stream->lastStreamBytes + delta) / ( stream->inputChannelCount * 2 ) / stream->sampleRate;
+ }
+ }
+
+ /* the ioctl failed, but we can still give a coarse estimate */
+
+ return stream->framesProcessed / stream->sampleRate;
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
+/*
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
+
+
+static PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+ int bytesRequested, bytesRead;
+
+ bytesRequested = frames * 2 * stream->inputChannelCount;
+ bytesRead = read( stream->deviceHandle, stream->inputBuffer, bytesRequested );
+
+ if ( bytesRequested != bytesRead )
+ return paUnanticipatedHostError;
+ else
+ return paNoError;
+}
+
+
+static PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+ int bytesRequested, bytesWritten;
+
+ bytesRequested = frames * 2 * stream->outputChannelCount;
+ bytesWritten = write( stream->deviceHandle, buffer, bytesRequested );
+
+ if ( bytesRequested != bytesWritten )
+ return paUnanticipatedHostError;
+ else
+ return paNoError;
+}
+
+
+static signed long GetStreamReadAvailable( PaStream* s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+ audio_buf_info info;
+
+ if ( ioctl(stream->deviceHandle, SNDCTL_DSP_GETISPACE, &info) == 0)
+ {
+ int bytesAvailable = info.fragments * info.fragsize;
+ return ( bytesAvailable / 2 / stream->inputChannelCount );
+ }
+ else
+ return 0; /* TODO: is this right for "don't know"? */
+}
+
+
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ audio_buf_info info;
+
+ if ( ioctl(stream->deviceHandle, SNDCTL_DSP_GETOSPACE, &info) == 0)
+ {
+ int bytesAvailable = info.fragments * info.fragsize;
+ return ( bytesAvailable / 2 / stream->outputChannelCount );
+ }
+ else
+ return 0; /* TODO: is this right for "don't know"? */
+}
+
diff --git a/pd/portaudio/pa_unix_oss/pa_unix_oss.o b/pd/portaudio/pa_unix_oss/pa_unix_oss.o
new file mode 100644
index 00000000..604f9798
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/pa_unix_oss.o
Binary files differ
diff --git a/pd/portaudio/pa_unix_oss/recplay.c b/pd/portaudio/pa_unix_oss/recplay.c
new file mode 100644
index 00000000..9d4c78cf
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/recplay.c
@@ -0,0 +1,114 @@
+/*
+ * recplay.c
+ * Phil Burk
+ * Minimal record and playback test.
+ *
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifndef __STDC__
+/* #include <getopt.h> */
+#endif /* __STDC__ */
+#include <fcntl.h>
+#ifdef __STDC__
+#include <string.h>
+#else /* __STDC__ */
+#include <strings.h>
+#endif /* __STDC__ */
+#include <sys/soundcard.h>
+
+#define NUM_BYTES (64*1024)
+#define BLOCK_SIZE (4*1024)
+
+#define AUDIO "/dev/dsp"
+
+char buffer[NUM_BYTES];
+
+int audioDev = 0;
+
+main (int argc, char *argv[])
+{
+ int numLeft;
+ char *ptr;
+ int num;
+ int samplesize;
+
+ /********** RECORD ********************/
+ /* Open audio device. */
+ audioDev = open (AUDIO, O_RDONLY, 0);
+ if (audioDev == -1)
+ {
+ perror (AUDIO);
+ exit (-1);
+ }
+
+ /* Set to 16 bit samples. */
+ samplesize = 16;
+ ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize);
+ if (samplesize != 16)
+ {
+ perror("Unable to set the sample size.");
+ exit(-1);
+ }
+
+ /* Record in blocks */
+ printf("Begin recording.\n");
+ numLeft = NUM_BYTES;
+ ptr = buffer;
+ while( numLeft >= BLOCK_SIZE )
+ {
+ if ( (num = read (audioDev, ptr, BLOCK_SIZE)) < 0 )
+ {
+ perror (AUDIO);
+ exit (-1);
+ }
+ else
+ {
+ printf("Read %d bytes\n", num);
+ ptr += num;
+ numLeft -= num;
+ }
+ }
+
+ close( audioDev );
+
+ /********** PLAYBACK ********************/
+ /* Open audio device for writing. */
+ audioDev = open (AUDIO, O_WRONLY, 0);
+ if (audioDev == -1)
+ {
+ perror (AUDIO);
+ exit (-1);
+ }
+
+ /* Set to 16 bit samples. */
+ samplesize = 16;
+ ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize);
+ if (samplesize != 16)
+ {
+ perror("Unable to set the sample size.");
+ exit(-1);
+ }
+
+ /* Play in blocks */
+ printf("Begin playing.\n");
+ numLeft = NUM_BYTES;
+ ptr = buffer;
+ while( numLeft >= BLOCK_SIZE )
+ {
+ if ( (num = write (audioDev, ptr, BLOCK_SIZE)) < 0 )
+ {
+ perror (AUDIO);
+ exit (-1);
+ }
+ else
+ {
+ printf("Wrote %d bytes\n", num);
+ ptr += num;
+ numLeft -= num;
+ }
+ }
+
+ close( audioDev );
+}
diff --git a/pd/portaudio/pa_win/pa_win_hostapis.c b/pd/portaudio/pa_win/pa_win_hostapis.c
new file mode 100644
index 00000000..2b518512
--- /dev/null
+++ b/pd/portaudio/pa_win/pa_win_hostapis.c
@@ -0,0 +1,63 @@
+/*
+ * $Id: pa_win_hostapis.c,v 1.1.2.6 2002/10/26 05:32:35 rossbencina Exp $
+ * Portable Audio I/O Library Windows initialization table
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+
+#include "pa_hostapi.h"
+
+PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+
+
+PaUtilHostApiInitializer *paHostApiInitializers[] =
+ {
+
+#ifndef PA_NO_WMME
+ PaWinMme_Initialize,
+#endif
+
+#ifndef PA_NO_DS
+ PaWinDs_Initialize,
+#endif
+
+#ifndef PA_NO_ASIO
+ PaAsio_Initialize,
+#endif
+
+ PaSkeleton_Initialize, /* just for testing */
+
+ 0 /* NULL terminated array */
+ };
+
+
+int paDefaultHostApiIndex = 0;
+
diff --git a/pd/portaudio/pa_win/pa_win_util.c b/pd/portaudio/pa_win/pa_win_util.c
new file mode 100644
index 00000000..f92d1e35
--- /dev/null
+++ b/pd/portaudio/pa_win/pa_win_util.c
@@ -0,0 +1,128 @@
+/*
+ * $Id: pa_win_util.c,v 1.1.2.5 2002/10/18 18:36:57 rossbencina Exp $
+ * Portable Audio I/O Library
+ * Win32 platform-specific support functions
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Ross Bencina
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+
+#include <windows.h>
+#include <mmsystem.h> /* for timeGetTime() */
+
+#include "pa_util.h"
+
+
+/*
+ Track memory allocations to avoid leaks.
+ */
+
+#if PA_TRACK_MEMORY
+static int numAllocations_ = 0;
+#endif
+
+
+void *PaUtil_AllocateMemory( long size )
+{
+ void *result = GlobalAlloc( GPTR, size );
+
+#if PA_TRACK_MEMORY
+ if( result != NULL ) numAllocations_ += 1;
+#endif
+ return result;
+}
+
+
+void PaUtil_FreeMemory( void *block )
+{
+ if( block != NULL )
+ {
+ GlobalFree( block );
+#if PA_TRACK_MEMORY
+ numAllocations_ -= 1;
+#endif
+
+ }
+}
+
+
+int PaUtil_CountCurrentlyAllocatedBlocks( void )
+{
+#if PA_TRACK_MEMORY
+ return numAllocations_;
+#else
+ return 0;
+#endif
+}
+
+
+void Pa_Sleep( long msec )
+{
+ Sleep( msec );
+}
+
+static int usePerformanceCounter_;
+static double secondsPerTick_;
+
+void PaUtil_InitializeClock( void )
+{
+ LARGE_INTEGER ticksPerSecond;
+
+ if( QueryPerformanceFrequency( &ticksPerSecond ) != 0 )
+ {
+ usePerformanceCounter_ = 1;
+ secondsPerTick_ = 1.0 / (double)ticksPerSecond.QuadPart;
+ }
+ else
+ {
+ usePerformanceCounter_ = 0;
+ }
+}
+
+
+double PaUtil_GetTime( void )
+{
+ LARGE_INTEGER time;
+
+ if( usePerformanceCounter_ )
+ {
+ /* FIXME:
+ according to this knowledge-base article, QueryPerformanceCounter
+ can skip forward by seconds!
+ http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323&
+
+ it may be better to use the rtdsc instruction using inline asm,
+ however then a method is needed to calculate a ticks/seconds ratio.
+ */
+ QueryPerformanceCounter( &time );
+ return time.QuadPart * secondsPerTick_;
+ }
+ else
+ {
+ return timeGetTime() * .001;
+ }
+}
diff --git a/pd/portaudio/pa_win/pa_x86_plain_converters.c b/pd/portaudio/pa_win/pa_x86_plain_converters.c
new file mode 100644
index 00000000..98442a8c
--- /dev/null
+++ b/pd/portaudio/pa_win/pa_x86_plain_converters.c
@@ -0,0 +1,1167 @@
+#include "pa_x86_plain_converters.h"
+
+#include "pa_converters.h"
+#include "pa_dither.h"
+
+/*
+ plain intel assemby versions of standard pa converter functions.
+
+ the main reason these versions are faster than the equivalent C versions
+ is that float -> int casting is expensive in C on x86 because the rounding
+ mode needs to be changed for every cast. these versions only set
+ the rounding mode once outside the loop.
+
+ small additional speed gains are made by the way that clamping is
+ implemented.
+
+TODO:
+ o- inline dither code
+ o- implement Dither only (no-clip) versions
+ o- implement int8 and uint8 versions
+ o- test thouroughly
+
+ o- the packed 24 bit functions could benefit from unrolling and avoiding
+ byte and word sized register access.
+*/
+
+/* -------------------------------------------------------------------------- */
+
+/*
+#define PA_CLIP_( val, min, max )\
+ { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
+*/
+
+/*
+ the following notes were used to determine whether a floating point
+ value should be saturated (ie >1 or <-1) by loading it into an integer
+ register. these should be rewritten so that they make sense.
+
+ an ieee floating point value
+
+ 1.xxxxxxxxxxxxxxxxxxxx?
+
+
+ is less than or equal to 1 and greater than or equal to -1 either:
+
+ if the mantissa is 0 and the unbiased exponent is 0
+
+ OR
+
+ if the unbiased exponent < 0
+
+ this translates to:
+
+ if the mantissa is 0 and the biased exponent is 7F
+
+ or
+
+ if the biased exponent is less than 7F
+
+
+ therefore the value is greater than 1 or less than -1 if
+
+ the mantissa is not 0 and the biased exponent is 7F
+
+ or
+
+ if the biased exponent is greater than 7F
+
+
+ in other words, if we mask out the sign bit, the value is
+ greater than 1 or less than -1 if its integer representation is greater than:
+
+ 0 01111111 0000 0000 0000 0000 0000 000
+
+ 0011 1111 1000 0000 0000 0000 0000 0000 => 0x3F800000
+*/
+
+/* -------------------------------------------------------------------------- */
+
+static const short fpuControlWord_ = 0x033F; /*round to nearest, 64 bit precision, all exceptions masked*/
+static const double int32Scaler_ = 0x7FFFFFFF;
+static const double ditheredInt32Scaler_ = 0x7FFFFFFE;
+static const double int24Scaler_ = 0x7FFFFF;
+static const double ditheredInt24Scaler_ = 0x7FFFFE;
+static const double int16Scaler_ = 0x7FFF;
+static const double ditheredInt16Scaler_ = 0x7FFE;
+
+#define PA_DITHER_BITS_ (15)
+/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */
+#define PA_FLOAT_DITHER_SCALE_ (1.0 / ((1<<PA_DITHER_BITS_)-1))
+static const float const_float_dither_scale_ = PA_FLOAT_DITHER_SCALE_;
+#define PA_DITHER_SHIFT_ ((32 - PA_DITHER_BITS_) + 1)
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void)ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+ // REVIEW
+ double scaled = *src * 0x7FFFFFFF;
+ *dest = (signed long) scaled;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ (void) ditherGenerator; /* unused parameter */
+
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32 and int32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int32Scaler_ // stack: (int)0x7FFFFFFF
+
+ Float32_To_Int32_loop:
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFFFFFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFFFF, (int)0x7FFFFFFF
+ /*
+ note: we could store to a temporary qword here which would cause
+ wraparound distortion instead of int indefinite 0x10. that would
+ be more work, and given that not enabling clipping is only advisable
+ when you know that your signal isn't going to clip it isn't worth it.
+ */
+ fistp dword ptr [edi] // pop st(0) into dest, stack: (int)0x7FFFFFFF
+
+ add edi, ebx // increment destination ptr
+ //lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int32_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void) ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+ // REVIEW
+ double scaled = *src * 0x7FFFFFFF;
+ PA_CLIP_( scaled, -2147483648., 2147483647. );
+ *dest = (signed long) scaled;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32 and int32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int32Scaler_ // stack: (int)0x7FFFFFFF
+
+ Float32_To_Int32_Clip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int32_Clip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFFFFFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFFFF, (int)0x7FFFFFFF
+ fistp dword ptr [edi] // pop st(0) into dest, stack: (int)0x7FFFFFFF
+ jmp Float32_To_Int32_Clip_stored
+
+ Float32_To_Int32_Clip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add edx, 0x7FFFFFFF // convert to maximum range integers
+ mov dword ptr [edi], edx
+
+ Float32_To_Int32_Clip_stored:
+
+ //add edi, ebx // increment destination ptr
+ lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int32_Clip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ /*
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+
+ while( count-- )
+ {
+ // REVIEW
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ // use smaller scaler to prevent overflow when we add the dither
+ double dithered = ((double)*src * (2147483646.0)) + dither;
+ PA_CLIP_( dithered, -2147483648., 2147483647. );
+ *dest = (signed long) dithered;
+
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+ */
+
+ short savedFpuControlWord;
+
+ // spill storage:
+ signed long sourceByteStride;
+ signed long highpassedDither;
+
+ // dither state:
+ unsigned long ditherPrevious = ditherGenerator->previous;
+ unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
+ unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32 and int32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld ditheredInt32Scaler_ // stack: int scaler
+
+ Float32_To_Int32_DitherClip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int32_DitherClip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, int scaler
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler
+
+ /*
+ // call PaUtil_GenerateFloatTriangularDither with C calling convention
+ mov sourceByteStride, eax // save eax
+ mov sourceEnd, ecx // save ecx
+ push ditherGenerator // pass ditherGenerator parameter on stack
+ call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler
+ pop edx // clear parameter off stack
+ mov ecx, sourceEnd // restore ecx
+ mov eax, sourceByteStride // restore eax
+ */
+
+ // generate dither
+ mov sourceByteStride, eax // save eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed1
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov ditherRandSeed1, eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed2
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov edx, ditherRandSeed1
+ shr edx, PA_DITHER_SHIFT_
+ mov ditherRandSeed2, eax
+ shr eax, PA_DITHER_SHIFT_
+ //add eax, edx // eax -> current
+ lea eax, [eax+edx]
+ mov edx, ditherPrevious
+ neg edx
+ lea edx, [eax+edx] // highpass = current - previous
+ mov highpassedDither, edx
+ mov ditherPrevious, eax // previous = current
+ mov eax, sourceByteStride // restore eax
+ fild highpassedDither
+ fmul const_float_dither_scale_
+ // end generate dither, dither signal in st(0)
+
+ faddp st(1), st(0) // stack: dither + value*(int scaler), int scaler
+ fistp dword ptr [edi] // pop st(0) into dest, stack: int scaler
+ jmp Float32_To_Int32_DitherClip_stored
+
+ Float32_To_Int32_DitherClip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add edx, 0x7FFFFFFF // convert to maximum range integers
+ mov dword ptr [edi], edx
+
+ Float32_To_Int32_DitherClip_stored:
+
+ //add edi, ebx // increment destination ptr
+ lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int32_DitherClip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+
+ ditherGenerator->previous = ditherPrevious;
+ ditherGenerator->randSeed1 = ditherRandSeed1;
+ ditherGenerator->randSeed2 = ditherRandSeed2;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ (void) ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+ // convert to 32 bit and drop the low 8 bits
+ double scaled = *src * 0x7FFFFFFF;
+ temp = (signed long) scaled;
+
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ signed long tempInt32;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov edx, 3 // sizeof int24
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int24Scaler_ // stack: (int)0x7FFFFF
+
+ Float32_To_Int24_loop:
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFFFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFF, (int)0x7FFFFF
+ fistp tempInt32 // pop st(0) into tempInt32, stack: (int)0x7FFFFF
+ mov edx, tempInt32
+
+ mov byte ptr [edi], DL
+ shr edx, 8
+ //mov byte ptr [edi+1], DL
+ //mov byte ptr [edi+2], DH
+ mov word ptr [edi+1], DX
+
+ //add edi, ebx // increment destination ptr
+ lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int24_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ (void) ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+ // convert to 32 bit and drop the low 8 bits
+ double scaled = *src * 0x7FFFFFFF;
+ PA_CLIP_( scaled, -2147483648., 2147483647. );
+ temp = (signed long) scaled;
+
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ signed long tempInt32;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov edx, 3 // sizeof int24
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int24Scaler_ // stack: (int)0x7FFFFF
+
+ Float32_To_Int24_Clip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int24_Clip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFFFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFF, (int)0x7FFFFF
+ fistp tempInt32 // pop st(0) into tempInt32, stack: (int)0x7FFFFF
+ mov edx, tempInt32
+ jmp Float32_To_Int24_Clip_store
+
+ Float32_To_Int24_Clip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add edx, 0x7FFFFF // convert to maximum range integers
+
+ Float32_To_Int24_Clip_store:
+
+ mov byte ptr [edi], DL
+ shr edx, 8
+ //mov byte ptr [edi+1], DL
+ //mov byte ptr [edi+2], DH
+ mov word ptr [edi+1], DX
+
+ //add edi, ebx // increment destination ptr
+ lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int24_Clip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ while( count-- )
+ {
+ // convert to 32 bit and drop the low 8 bits
+
+ // FIXME: the dither amplitude here appears to be too small by 8 bits
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ // use smaller scaler to prevent overflow when we add the dither
+ double dithered = ((double)*src * (2147483646.0)) + dither;
+ PA_CLIP_( dithered, -2147483648., 2147483647. );
+
+ temp = (signed long) dithered;
+
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ // spill storage:
+ signed long sourceByteStride;
+ signed long highpassedDither;
+
+ // dither state:
+ unsigned long ditherPrevious = ditherGenerator->previous;
+ unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
+ unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
+
+ signed long tempInt32;
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov edx, 3 // sizeof int24
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld ditheredInt24Scaler_ // stack: int scaler
+
+ Float32_To_Int24_DitherClip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int24_DitherClip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, int scaler
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler
+
+ /*
+ // call PaUtil_GenerateFloatTriangularDither with C calling convention
+ mov sourceByteStride, eax // save eax
+ mov sourceEnd, ecx // save ecx
+ push ditherGenerator // pass ditherGenerator parameter on stack
+ call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler
+ pop edx // clear parameter off stack
+ mov ecx, sourceEnd // restore ecx
+ mov eax, sourceByteStride // restore eax
+ */
+
+ // generate dither
+ mov sourceByteStride, eax // save eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed1
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov ditherRandSeed1, eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed2
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov edx, ditherRandSeed1
+ shr edx, PA_DITHER_SHIFT_
+ mov ditherRandSeed2, eax
+ shr eax, PA_DITHER_SHIFT_
+ //add eax, edx // eax -> current
+ lea eax, [eax+edx]
+ mov edx, ditherPrevious
+ neg edx
+ lea edx, [eax+edx] // highpass = current - previous
+ mov highpassedDither, edx
+ mov ditherPrevious, eax // previous = current
+ mov eax, sourceByteStride // restore eax
+ fild highpassedDither
+ fmul const_float_dither_scale_
+ // end generate dither, dither signal in st(0)
+
+ faddp st(1), st(0) // stack: dither * value*(int scaler), int scaler
+ fistp tempInt32 // pop st(0) into tempInt32, stack: int scaler
+ mov edx, tempInt32
+ jmp Float32_To_Int24_DitherClip_store
+
+ Float32_To_Int24_DitherClip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add edx, 0x7FFFFF // convert to maximum range integers
+
+ Float32_To_Int24_DitherClip_store:
+
+ mov byte ptr [edi], DL
+ shr edx, 8
+ //mov byte ptr [edi+1], DL
+ //mov byte ptr [edi+2], DH
+ mov word ptr [edi+1], DX
+
+ //add edi, ebx // increment destination ptr
+ lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int24_DitherClip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+
+ ditherGenerator->previous = ditherPrevious;
+ ditherGenerator->randSeed1 = ditherRandSeed1;
+ ditherGenerator->randSeed2 = ditherRandSeed2;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+
+ short samp = (short) (*src * (32767.0f));
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx // source byte stride
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi // source end ptr = count * source byte stride + source ptr
+
+ mov edi, destinationBuffer
+
+ mov edx, 2 // sizeof int16
+ mov ebx, destinationStride
+ imul ebx, edx // destination byte stride
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int16Scaler_ // stack: (int)0x7FFF
+
+ Float32_To_Int16_loop:
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFF, (int)0x7FFF
+ fistp word ptr [edi] // store scaled int into dest, stack: (int)0x7FFF
+
+ add edi, ebx // increment destination ptr
+ //lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int16_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+ long samp = (signed long) (*src * (32767.0f));
+ PA_CLIP_( samp, -0x8000, 0x7FFF );
+ *dest = (signed short) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx // source byte stride
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi // source end ptr = count * source byte stride + source ptr
+
+ mov edi, destinationBuffer
+
+ mov edx, 2 // sizeof int16
+ mov ebx, destinationStride
+ imul ebx, edx // destination byte stride
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int16Scaler_ // stack: (int)0x7FFF
+
+ Float32_To_Int16_Clip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int16_Clip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFF, (int)0x7FFF
+ fistp word ptr [edi] // store scaled int into dest, stack: (int)0x7FFF
+ jmp Float32_To_Int16_Clip_stored
+
+ Float32_To_Int16_Clip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add dx, 0x7FFF // convert to maximum range integers
+ mov word ptr [edi], dx // store clamped into into dest
+
+ Float32_To_Int16_Clip_stored:
+
+ add edi, ebx // increment destination ptr
+ //lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int16_Clip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+
+ float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ // use smaller scaler to prevent overflow when we add the dither
+ float dithered = (*src * (32766.0f)) + dither;
+ signed long samp = (signed long) dithered;
+ PA_CLIP_( samp, -0x8000, 0x7FFF );
+ *dest = (signed short) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ // spill storage:
+ signed long sourceByteStride;
+ signed long highpassedDither;
+
+ // dither state:
+ unsigned long ditherPrevious = ditherGenerator->previous;
+ unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
+ unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx // source byte stride
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi // source end ptr = count * source byte stride + source ptr
+
+ mov edi, destinationBuffer
+
+ mov edx, 2 // sizeof int16
+ mov ebx, destinationStride
+ imul ebx, edx // destination byte stride
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld ditheredInt16Scaler_ // stack: int scaler
+
+ Float32_To_Int16_DitherClip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int16_DitherClip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, int scaler
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler
+
+ /*
+ // call PaUtil_GenerateFloatTriangularDither with C calling convention
+ mov sourceByteStride, eax // save eax
+ mov sourceEnd, ecx // save ecx
+ push ditherGenerator // pass ditherGenerator parameter on stack
+ call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler
+ pop edx // clear parameter off stack
+ mov ecx, sourceEnd // restore ecx
+ mov eax, sourceByteStride // restore eax
+ */
+
+ // generate dither
+ mov sourceByteStride, eax // save eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed1
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov ditherRandSeed1, eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed2
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov edx, ditherRandSeed1
+ shr edx, PA_DITHER_SHIFT_
+ mov ditherRandSeed2, eax
+ shr eax, PA_DITHER_SHIFT_
+ //add eax, edx // eax -> current
+ lea eax, [eax+edx] // current = randSeed1>>x + randSeed2>>x
+ mov edx, ditherPrevious
+ neg edx
+ lea edx, [eax+edx] // highpass = current - previous
+ mov highpassedDither, edx
+ mov ditherPrevious, eax // previous = current
+ mov eax, sourceByteStride // restore eax
+ fild highpassedDither
+ fmul const_float_dither_scale_
+ // end generate dither, dither signal in st(0)
+
+ faddp st(1), st(0) // stack: dither * value*(int scaler), int scaler
+ fistp word ptr [edi] // store scaled int into dest, stack: int scaler
+ jmp Float32_To_Int16_DitherClip_stored
+
+ Float32_To_Int16_DitherClip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add dx, 0x7FFF // convert to maximum range integers
+ mov word ptr [edi], dx // store clamped into into dest
+
+ Float32_To_Int16_DitherClip_stored:
+
+ add edi, ebx // increment destination ptr
+ //lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int16_DitherClip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+
+ ditherGenerator->previous = ditherPrevious;
+ ditherGenerator->randSeed1 = ditherRandSeed1;
+ ditherGenerator->randSeed2 = ditherRandSeed2;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void PaUtil_InitializeX86PlainConverters( void )
+{
+ paConverters.Float32_To_Int32 = Float32_To_Int32;
+ paConverters.Float32_To_Int32_Clip = Float32_To_Int32_Clip;
+ paConverters.Float32_To_Int32_DitherClip = Float32_To_Int32_DitherClip;
+
+ paConverters.Float32_To_Int24 = Float32_To_Int24;
+ paConverters.Float32_To_Int24_Clip = Float32_To_Int24_Clip;
+ paConverters.Float32_To_Int24_DitherClip = Float32_To_Int24_DitherClip;
+
+ paConverters.Float32_To_Int16 = Float32_To_Int16;
+ paConverters.Float32_To_Int16_Clip = Float32_To_Int16_Clip;
+ paConverters.Float32_To_Int16_DitherClip = Float32_To_Int16_DitherClip;
+}
+
+/* -------------------------------------------------------------------------- */
diff --git a/pd/portaudio/pa_win/pa_x86_plain_converters.h b/pd/portaudio/pa_win/pa_x86_plain_converters.h
new file mode 100644
index 00000000..b93a291c
--- /dev/null
+++ b/pd/portaudio/pa_win/pa_x86_plain_converters.h
@@ -0,0 +1,19 @@
+#ifndef PA_X86_PLAIN_CONVERTERS_H
+#define PA_X86_PLAIN_CONVERTERS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+/**
+ Install optimised converter functions suitable for all IA32 processors
+*/
+void PaUtil_InitializeX86PlainConverters( void );
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_X86_PLAIN_CONVERTERS_H */
diff --git a/pd/portaudio/pa_win_ds/dsound_wrapper.c b/pd/portaudio/pa_win_ds/dsound_wrapper.c
new file mode 100644
index 00000000..ac8c927d
--- /dev/null
+++ b/pd/portaudio/pa_win_ds/dsound_wrapper.c
@@ -0,0 +1,604 @@
+/*
+ * $Id: dsound_wrapper.c,v 1.1.1.1.2.5 2002/07/01 00:49:41 philburk Exp $
+ * Simplified DirectSound interface.
+ *
+ * Author: Phil Burk & Robert Marsanyi
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * For more information see: http://www.softsynth.com/portaudio/
+ * DirectSound Implementation
+ * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define INITGUID // Needed to build IID_IDirectSoundNotify. See objbase.h for info.
+#include <objbase.h>
+#include <unknwn.h>
+#include "dsound_wrapper.h"
+#include "pa_trace.h"
+
+/************************************************************************************/
+DSoundEntryPoints dswDSoundEntryPoints = { 0, 0, 0, 0, 0, 0, 0 };
+/************************************************************************************/
+static HRESULT WINAPI DummyDirectSoundCreate(LPGUID lpcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter)
+{
+ (void)lpcGuidDevice; /* unused parameter */
+ (void)ppDS; /* unused parameter */
+ (void)pUnkOuter; /* unused parameter */
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDirectSoundEnumerateW(LPDSENUMCALLBACKW lpDSEnumCallback, LPVOID lpContext)
+{
+ (void)lpDSEnumCallback; /* unused parameter */
+ (void)lpContext; /* unused parameter */
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDirectSoundEnumerateA(LPDSENUMCALLBACKA lpDSEnumCallback, LPVOID lpContext)
+{
+ (void)lpDSEnumCallback; /* unused parameter */
+ (void)lpContext; /* unused parameter */
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDirectSoundCaptureCreate(LPGUID lpcGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter)
+{
+ (void)lpcGUID; /* unused parameter */
+ (void)lplpDSC; /* unused parameter */
+ (void)pUnkOuter; /* unused parameter */
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW lpDSCEnumCallback, LPVOID lpContext)
+{
+ (void)lpDSCEnumCallback; /* unused parameter */
+ (void)lpContext; /* unused parameter */
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA lpDSCEnumCallback, LPVOID lpContext)
+{
+ (void)lpDSCEnumCallback; /* unused parameter */
+ (void)lpContext; /* unused parameter */
+ return E_NOTIMPL;
+}
+/************************************************************************************/
+void DSW_InitializeDSoundEntryPoints(void)
+{
+ dswDSoundEntryPoints.hInstance_ = LoadLibrary("dsound.dll");
+ if( dswDSoundEntryPoints.hInstance_ != NULL )
+ {
+ dswDSoundEntryPoints.DirectSoundCreate =
+ (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCreate" );
+ if( dswDSoundEntryPoints.DirectSoundCreate == NULL )
+ dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
+
+ dswDSoundEntryPoints.DirectSoundEnumerateW =
+ (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundEnumerateW" );
+ if( dswDSoundEntryPoints.DirectSoundEnumerateW == NULL )
+ dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
+
+ dswDSoundEntryPoints.DirectSoundEnumerateA =
+ (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundEnumerateA" );
+ if( dswDSoundEntryPoints.DirectSoundEnumerateA == NULL )
+ dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
+
+ dswDSoundEntryPoints.DirectSoundCaptureCreate =
+ (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureCreate" );
+ if( dswDSoundEntryPoints.DirectSoundCaptureCreate == NULL )
+ dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
+
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateW =
+ (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateW" );
+ if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateW == NULL )
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
+
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateA =
+ (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateA" );
+ if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateA == NULL )
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
+ }
+ else
+ {
+ /* initialize with dummy entry points to make live easy when ds isn't present */
+ dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
+ dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
+ dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
+ dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
+ }
+}
+/************************************************************************************/
+void DSW_TerminateDSoundEntryPoints(void)
+{
+ if( dswDSoundEntryPoints.hInstance_ != NULL )
+ {
+ FreeLibrary( dswDSoundEntryPoints.hInstance_ );
+ dswDSoundEntryPoints.hInstance_ = NULL;
+ /* ensure that we crash reliably if the entry points arent initialised */
+ dswDSoundEntryPoints.DirectSoundCreate = 0;
+ dswDSoundEntryPoints.DirectSoundEnumerateW = 0;
+ dswDSoundEntryPoints.DirectSoundEnumerateA = 0;
+ dswDSoundEntryPoints.DirectSoundCaptureCreate = 0;
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = 0;
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = 0;
+ }
+}
+/************************************************************************************/
+void DSW_Term( DSoundWrapper *dsw )
+{
+ // Cleanup the sound buffers
+ if (dsw->dsw_OutputBuffer)
+ {
+ IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
+ IDirectSoundBuffer_Release( dsw->dsw_OutputBuffer );
+ dsw->dsw_OutputBuffer = NULL;
+ }
+
+ if (dsw->dsw_InputBuffer)
+ {
+ IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
+ IDirectSoundCaptureBuffer_Release( dsw->dsw_InputBuffer );
+ dsw->dsw_InputBuffer = NULL;
+ }
+
+ if (dsw->dsw_pDirectSoundCapture)
+ {
+ IDirectSoundCapture_Release( dsw->dsw_pDirectSoundCapture );
+ dsw->dsw_pDirectSoundCapture = NULL;
+ }
+
+ if (dsw->dsw_pDirectSound)
+ {
+ IDirectSound_Release( dsw->dsw_pDirectSound );
+ dsw->dsw_pDirectSound = NULL;
+ }
+}
+/************************************************************************************/
+HRESULT DSW_Init( DSoundWrapper *dsw )
+{
+ memset( dsw, 0, sizeof(DSoundWrapper) );
+ return 0;
+}
+/************************************************************************************/
+HRESULT DSW_InitOutputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
+{
+ // Create the DS object
+ HRESULT hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &dsw->dsw_pDirectSound, NULL );
+ if( hr != DS_OK ) return hr;
+ return hr;
+}
+
+/************************************************************************************/
+HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bytesPerBuffer )
+{
+ DWORD dwDataLen;
+ DWORD playCursor;
+ HRESULT result;
+ LPDIRECTSOUNDBUFFER pPrimaryBuffer;
+ HWND hWnd;
+ HRESULT hr;
+ WAVEFORMATEX wfFormat;
+ DSBUFFERDESC primaryDesc;
+ DSBUFFERDESC secondaryDesc;
+ unsigned char* pDSBuffData;
+ LARGE_INTEGER counterFrequency;
+
+ dsw->dsw_OutputSize = bytesPerBuffer;
+ dsw->dsw_OutputRunning = FALSE;
+ dsw->dsw_OutputUnderflows = 0;
+ dsw->dsw_FramesWritten = 0;
+ dsw->dsw_BytesPerOutputFrame = nChannels * sizeof(short);
+
+ // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the
+ // applications's window. Also if that window is closed before the Buffer is closed
+ // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.)
+ // So we will use GetDesktopWindow() which was suggested by Miller Puckette.
+ // hWnd = GetForegroundWindow();
+ hWnd = GetDesktopWindow();
+
+ // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz.
+ // Exclusize also prevents unexpected sounds from other apps during a performance.
+ if ((hr = IDirectSound_SetCooperativeLevel( dsw->dsw_pDirectSound,
+ hWnd, DSSCL_EXCLUSIVE)) != DS_OK)
+ {
+ return hr;
+ }
+
+ // -----------------------------------------------------------------------
+ // Create primary buffer and set format just so we can specify our custom format.
+ // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz.
+ // Setup the primary buffer description
+ ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC));
+ primaryDesc.dwSize = sizeof(DSBUFFERDESC);
+ primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth
+ primaryDesc.dwBufferBytes = 0;
+ primaryDesc.lpwfxFormat = NULL;
+ // Create the buffer
+ if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,
+ &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result;
+ // Define the buffer format
+ wfFormat.wFormatTag = WAVE_FORMAT_PCM;
+ wfFormat.nChannels = nChannels;
+ wfFormat.nSamplesPerSec = nFrameRate;
+ wfFormat.wBitsPerSample = 8 * sizeof(short);
+ wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8;
+ wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
+ wfFormat.cbSize = 0; /* No extended format info. */
+ // Set the primary buffer's format
+ if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &wfFormat)) != DS_OK) return result;
+
+ // ----------------------------------------------------------------------
+ // Setup the secondary buffer description
+ ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC));
+ secondaryDesc.dwSize = sizeof(DSBUFFERDESC);
+ secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
+ secondaryDesc.dwBufferBytes = bytesPerBuffer;
+ secondaryDesc.lpwfxFormat = &wfFormat;
+ // Create the secondary buffer
+ if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,
+ &secondaryDesc, &dsw->dsw_OutputBuffer, NULL)) != DS_OK) return result;
+ // Lock the DS buffer
+ if ((result = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, 0, dsw->dsw_OutputSize, (LPVOID*)&pDSBuffData,
+ &dwDataLen, NULL, 0, 0)) != DS_OK) return result;
+ // Zero the DS buffer
+ ZeroMemory(pDSBuffData, dwDataLen);
+ // Unlock the DS buffer
+ if ((result = IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result;
+ if( QueryPerformanceFrequency( &counterFrequency ) )
+ {
+ int framesInBuffer = bytesPerBuffer / (nChannels * sizeof(short));
+ dsw->dsw_CounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate;
+ }
+ else
+ {
+ dsw->dsw_CounterTicksPerBuffer.QuadPart = 0;
+ }
+ // Let DSound set the starting write position because if we set it to zero, it looks like the
+ // buffer is full to begin with. This causes a long pause before sound starts when using large buffers.
+ hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &dsw->dsw_WriteOffset );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ dsw->dsw_FramesWritten = dsw->dsw_WriteOffset / dsw->dsw_BytesPerOutputFrame;
+ /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */
+ return DS_OK;
+}
+
+/************************************************************************************/
+HRESULT DSW_StartOutput( DSoundWrapper *dsw )
+{
+ HRESULT hr;
+ QueryPerformanceCounter( &dsw->dsw_LastPlayTime );
+ dsw->dsw_LastPlayCursor = 0;
+ dsw->dsw_FramesPlayed = 0;
+ hr = IDirectSoundBuffer_SetCurrentPosition( dsw->dsw_OutputBuffer, 0 );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ // Start the buffer playback in a loop.
+ if( dsw->dsw_OutputBuffer != NULL )
+ {
+ hr = IDirectSoundBuffer_Play( dsw->dsw_OutputBuffer, 0, 0, DSBPLAY_LOOPING );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ dsw->dsw_OutputRunning = TRUE;
+ }
+
+ return 0;
+}
+/************************************************************************************/
+HRESULT DSW_StopOutput( DSoundWrapper *dsw )
+{
+ // Stop the buffer playback
+ if( dsw->dsw_OutputBuffer != NULL )
+ {
+ dsw->dsw_OutputRunning = FALSE;
+ return IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
+ }
+ else return 0;
+}
+
+/************************************************************************************/
+HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilledPtr )
+{
+ HRESULT hr;
+ DWORD playCursor;
+ DWORD writeCursor;
+ long bytesFilled;
+ // Query to see where play position is.
+ // We don't need the writeCursor but sometimes DirectSound doesn't handle NULLS correctly
+ // so let's pass a pointer just to be safe.
+ hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ bytesFilled = dsw->dsw_WriteOffset - playCursor;
+ if( bytesFilled < 0 ) bytesFilled += dsw->dsw_OutputSize; // unwrap offset
+ *bytesFilledPtr = bytesFilled;
+ return hr;
+}
+
+/************************************************************************************
+ * Determine how much space can be safely written to in DS buffer.
+ * Detect underflows and overflows.
+ * Does not allow writing into safety gap maintained by DirectSound.
+ */
+HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty )
+{
+ HRESULT hr;
+ DWORD playCursor;
+ DWORD writeCursor;
+ long numBytesEmpty;
+ long playWriteGap;
+ // Query to see how much room is in buffer.
+ hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ // Determine size of gap between playIndex and WriteIndex that we cannot write into.
+ playWriteGap = writeCursor - playCursor;
+ if( playWriteGap < 0 ) playWriteGap += dsw->dsw_OutputSize; // unwrap
+ /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */
+ /* Attempt to detect playCursor wrap-around and correct it. */
+ if( dsw->dsw_OutputRunning && (dsw->dsw_CounterTicksPerBuffer.QuadPart != 0) )
+ {
+ /* How much time has elapsed since last check. */
+ LARGE_INTEGER currentTime;
+ LARGE_INTEGER elapsedTime;
+ long bytesPlayed;
+ long bytesExpected;
+ long buffersWrapped;
+ QueryPerformanceCounter( &currentTime );
+ elapsedTime.QuadPart = currentTime.QuadPart - dsw->dsw_LastPlayTime.QuadPart;
+ dsw->dsw_LastPlayTime = currentTime;
+ /* How many bytes does DirectSound say have been played. */
+ bytesPlayed = playCursor - dsw->dsw_LastPlayCursor;
+ if( bytesPlayed < 0 ) bytesPlayed += dsw->dsw_OutputSize; // unwrap
+ dsw->dsw_LastPlayCursor = playCursor;
+ /* Calculate how many bytes we would have expected to been played by now. */
+ bytesExpected = (long) ((elapsedTime.QuadPart * dsw->dsw_OutputSize) / dsw->dsw_CounterTicksPerBuffer.QuadPart);
+ buffersWrapped = (bytesExpected - bytesPlayed) / dsw->dsw_OutputSize;
+ if( buffersWrapped > 0 )
+ {
+ playCursor += (buffersWrapped * dsw->dsw_OutputSize);
+ bytesPlayed += (buffersWrapped * dsw->dsw_OutputSize);
+ }
+ /* Maintain frame output cursor. */
+ dsw->dsw_FramesPlayed += (bytesPlayed / dsw->dsw_BytesPerOutputFrame);
+ }
+ numBytesEmpty = playCursor - dsw->dsw_WriteOffset;
+ if( numBytesEmpty < 0 ) numBytesEmpty += dsw->dsw_OutputSize; // unwrap offset
+ /* Have we underflowed? */
+ if( numBytesEmpty > (dsw->dsw_OutputSize - playWriteGap) )
+ {
+ if( dsw->dsw_OutputRunning )
+ {
+ dsw->dsw_OutputUnderflows += 1;
+ }
+ dsw->dsw_WriteOffset = writeCursor;
+ numBytesEmpty = dsw->dsw_OutputSize - playWriteGap;
+ }
+ *bytesEmpty = numBytesEmpty;
+ return hr;
+}
+
+/************************************************************************************/
+HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw )
+{
+ HRESULT hr;
+ LPBYTE lpbuf1 = NULL;
+ LPBYTE lpbuf2 = NULL;
+ DWORD dwsize1 = 0;
+ DWORD dwsize2 = 0;
+ long bytesEmpty;
+ hr = DSW_QueryOutputSpace( dsw, &bytesEmpty ); // updates dsw_FramesPlayed
+ if (hr != DS_OK) return hr;
+ if( bytesEmpty == 0 ) return DS_OK;
+ // Lock free space in the DS
+ hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, bytesEmpty, (void **) &lpbuf1, &dwsize1,
+ (void **) &lpbuf2, &dwsize2, 0);
+ if (hr == DS_OK)
+ {
+ // Copy the buffer into the DS
+ ZeroMemory(lpbuf1, dwsize1);
+ if(lpbuf2 != NULL)
+ {
+ ZeroMemory(lpbuf2, dwsize2);
+ }
+ // Update our buffer offset and unlock sound buffer
+ dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
+ IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
+ dsw->dsw_FramesWritten += bytesEmpty / dsw->dsw_BytesPerOutputFrame;
+ }
+ return hr;
+}
+
+/************************************************************************************/
+HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes )
+{
+ HRESULT hr;
+ LPBYTE lpbuf1 = NULL;
+ LPBYTE lpbuf2 = NULL;
+ DWORD dwsize1 = 0;
+ DWORD dwsize2 = 0;
+ // Lock free space in the DS
+ hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, numBytes, (void **) &lpbuf1, &dwsize1,
+ (void **) &lpbuf2, &dwsize2, 0);
+ if (hr == DS_OK)
+ {
+ // Copy the buffer into the DS
+ CopyMemory(lpbuf1, buf, dwsize1);
+ if(lpbuf2 != NULL)
+ {
+ CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
+ }
+ // Update our buffer offset and unlock sound buffer
+ dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
+ IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
+ dsw->dsw_FramesWritten += numBytes / dsw->dsw_BytesPerOutputFrame;
+ }
+ return hr;
+}
+
+/************************************************************************************/
+DWORD DSW_GetOutputStatus( DSoundWrapper *dsw )
+{
+ DWORD status;
+ if (IDirectSoundBuffer_GetStatus( dsw->dsw_OutputBuffer, &status ) != DS_OK)
+ return( DSERR_INVALIDPARAM );
+ else
+ return( status );
+}
+
+/* These routines are used to support audio input.
+ * Do NOT compile these calls when using NT4 because it does
+ * not support the entry points.
+ */
+/************************************************************************************/
+HRESULT DSW_InitInputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
+{
+ HRESULT hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &dsw->dsw_pDirectSoundCapture, NULL );
+ if( hr != DS_OK ) return hr;
+ return hr;
+}
+/************************************************************************************/
+HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bytesPerBuffer )
+{
+ DSCBUFFERDESC captureDesc;
+ WAVEFORMATEX wfFormat;
+ HRESULT result;
+
+ dsw->dsw_BytesPerInputFrame = nChannels * sizeof(short);
+
+ // Define the buffer format
+ wfFormat.wFormatTag = WAVE_FORMAT_PCM;
+ wfFormat.nChannels = nChannels;
+ wfFormat.nSamplesPerSec = nFrameRate;
+ wfFormat.wBitsPerSample = 8 * sizeof(short);
+ wfFormat.nBlockAlign = wfFormat.nChannels * (wfFormat.wBitsPerSample / 8);
+ wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
+ wfFormat.cbSize = 0; /* No extended format info. */
+ dsw->dsw_InputSize = bytesPerBuffer;
+ // ----------------------------------------------------------------------
+ // Setup the secondary buffer description
+ ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
+ captureDesc.dwSize = sizeof(DSCBUFFERDESC);
+ captureDesc.dwFlags = 0;
+ captureDesc.dwBufferBytes = bytesPerBuffer;
+ captureDesc.lpwfxFormat = &wfFormat;
+ // Create the capture buffer
+ if ((result = IDirectSoundCapture_CreateCaptureBuffer( dsw->dsw_pDirectSoundCapture,
+ &captureDesc, &dsw->dsw_InputBuffer, NULL)) != DS_OK) return result;
+ dsw->dsw_ReadOffset = 0; // reset last read position to start of buffer
+ return DS_OK;
+}
+
+/************************************************************************************/
+HRESULT DSW_StartInput( DSoundWrapper *dsw )
+{
+ // Start the buffer playback
+ if( dsw->dsw_InputBuffer != NULL )
+ {
+ return IDirectSoundCaptureBuffer_Start( dsw->dsw_InputBuffer, DSCBSTART_LOOPING );
+ }
+ else return 0;
+}
+
+/************************************************************************************/
+HRESULT DSW_StopInput( DSoundWrapper *dsw )
+{
+ // Stop the buffer playback
+ if( dsw->dsw_InputBuffer != NULL )
+ {
+ return IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
+ }
+ else return 0;
+}
+
+/************************************************************************************/
+HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled )
+{
+ HRESULT hr;
+ DWORD capturePos;
+ DWORD readPos;
+ long filled;
+ // Query to see how much data is in buffer.
+ // We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly
+ // so let's pass a pointer just to be safe.
+ hr = IDirectSoundCaptureBuffer_GetCurrentPosition( dsw->dsw_InputBuffer, &capturePos, &readPos );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ filled = readPos - dsw->dsw_ReadOffset;
+ if( filled < 0 ) filled += dsw->dsw_InputSize; // unwrap offset
+ *bytesFilled = filled;
+ return hr;
+}
+
+/************************************************************************************/
+HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes )
+{
+ HRESULT hr;
+ LPBYTE lpbuf1 = NULL;
+ LPBYTE lpbuf2 = NULL;
+ DWORD dwsize1 = 0;
+ DWORD dwsize2 = 0;
+ // Lock free space in the DS
+ hr = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, numBytes, (void **) &lpbuf1, &dwsize1,
+ (void **) &lpbuf2, &dwsize2, 0);
+ if (hr == DS_OK)
+ {
+ // Copy from DS to the buffer
+ CopyMemory( buf, lpbuf1, dwsize1);
+ if(lpbuf2 != NULL)
+ {
+ CopyMemory( buf+dwsize1, lpbuf2, dwsize2);
+ }
+ // Update our buffer offset and unlock sound buffer
+ dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + dwsize1 + dwsize2) % dsw->dsw_InputSize;
+ IDirectSoundCaptureBuffer_Unlock ( dsw->dsw_InputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
+ }
+ return hr;
+}
+
diff --git a/pd/portaudio/pa_win_ds/dsound_wrapper.h b/pd/portaudio/pa_win_ds/dsound_wrapper.h
new file mode 100644
index 00000000..e9ce4c6b
--- /dev/null
+++ b/pd/portaudio/pa_win_ds/dsound_wrapper.h
@@ -0,0 +1,129 @@
+#ifndef __DSOUND_WRAPPER_H
+#define __DSOUND_WRAPPER_H
+/*
+ * $Id: dsound_wrapper.h,v 1.1.1.1.2.5 2002/07/03 01:43:56 rossbencina Exp $
+ * Simplified DirectSound interface.
+ *
+ * Author: Phil Burk & Robert Marsanyi
+ *
+ * For PortAudio Portable Real-Time Audio Library
+ * For more information see: http://www.softsynth.com/portaudio/
+ * DirectSound Implementation
+ * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+/* on Borland compilers, WIN32 doesn't seem to be defined by default, which
+ breaks DSound.h. Adding the define here fixes the problem. - rossb. */
+#ifdef __BORLANDC__
+#if !defined(WIN32)
+#define WIN32
+#endif
+#endif
+
+#include <DSound.h>
+#if !defined(BOOL)
+#define BOOL short
+#endif
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+typedef struct
+{
+ HINSTANCE hInstance_;
+
+ HRESULT (WINAPI *DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
+ HRESULT (WINAPI *DirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
+ HRESULT (WINAPI *DirectSoundEnumerateA)(LPDSENUMCALLBACKA, LPVOID);
+
+ HRESULT (WINAPI *DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN);
+ HRESULT (WINAPI *DirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
+ HRESULT (WINAPI *DirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA, LPVOID);
+}DSoundEntryPoints;
+
+extern DSoundEntryPoints dswDSoundEntryPoints;
+
+void DSW_InitializeDSoundEntryPoints(void);
+void DSW_TerminateDSoundEntryPoints(void);
+
+#define DSW_NUM_POSITIONS (4)
+#define DSW_NUM_EVENTS (5)
+#define DSW_TERMINATION_EVENT (DSW_NUM_POSITIONS)
+
+typedef struct
+{
+/* Output */
+ LPDIRECTSOUND dsw_pDirectSound;
+ LPDIRECTSOUNDBUFFER dsw_OutputBuffer;
+ DWORD dsw_WriteOffset; /* last write position */
+ INT dsw_OutputSize;
+ INT dsw_BytesPerOutputFrame;
+ /* Try to detect play buffer underflows. */
+ LARGE_INTEGER dsw_CounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */
+ LARGE_INTEGER dsw_LastPlayTime;
+ UINT dsw_LastPlayCursor;
+ UINT dsw_OutputUnderflows;
+ BOOL dsw_OutputRunning;
+ /* use double which lets us can play for several thousand years with enough precision */
+ double dsw_FramesWritten;
+ double dsw_FramesPlayed;
+/* Input */
+ INT dsw_BytesPerInputFrame;
+ LPDIRECTSOUNDCAPTURE dsw_pDirectSoundCapture;
+ LPDIRECTSOUNDCAPTUREBUFFER dsw_InputBuffer;
+ UINT dsw_ReadOffset; /* last read position */
+ UINT dsw_InputSize;
+} DSoundWrapper;
+
+HRESULT DSW_Init( DSoundWrapper *dsw );
+void DSW_Term( DSoundWrapper *dsw );
+HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate,
+ int nChannels, int bufSize );
+HRESULT DSW_StartOutput( DSoundWrapper *dsw );
+HRESULT DSW_StopOutput( DSoundWrapper *dsw );
+DWORD DSW_GetOutputStatus( DSoundWrapper *dsw );
+HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes );
+HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw );
+HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty );
+HRESULT DSW_Enumerate( DSoundWrapper *dsw );
+
+HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate,
+ int nChannels, int bufSize );
+HRESULT DSW_StartInput( DSoundWrapper *dsw );
+HRESULT DSW_StopInput( DSoundWrapper *dsw );
+HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes );
+HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled );
+HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilled );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __DSOUND_WRAPPER_H */
diff --git a/pd/portaudio/pa_win_ds/pa_dsound.c b/pd/portaudio/pa_win_ds/pa_dsound.c
new file mode 100644
index 00000000..8fa343cf
--- /dev/null
+++ b/pd/portaudio/pa_win_ds/pa_dsound.c
@@ -0,0 +1,1021 @@
+/*
+ * $Id: pa_dsound.c,v 1.1.1.1 2003-05-09 16:03:58 ggeiger Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.softsynth.com/portaudio/
+ * DirectSound Implementation
+ *
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+/* Modifications
+ * 7/19/01 Mike Berry - casts for compiling with __MWERKS__ CodeWarrior
+ * 9/27/01 Phil Burk - use number of frames instead of real-time for CPULoad calculation.
+ * 4/19/02 Phil Burk - Check for Win XP for system latency calculation.
+ */
+/* Compiler flags:
+ SUPPORT_AUDIO_CAPTURE - define this flag if you want to SUPPORT_AUDIO_CAPTURE
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __MWERKS__
+#include <malloc.h>
+#include <memory.h>
+#endif //__MWERKS__
+#include <math.h>
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+#include "dsound_wrapper.h"
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+#define PA_USE_HIGH_LATENCY (0)
+#if PA_USE_HIGH_LATENCY
+#define PA_WIN_9X_LATENCY (500)
+#define PA_WIN_NT_LATENCY (600)
+#else
+#define PA_WIN_9X_LATENCY (140)
+#define PA_WIN_NT_LATENCY (280)
+#endif
+
+#define PA_WIN_WDM_LATENCY (120)
+
+/* Trigger an underflow for testing purposes. Should normally be (0). */
+#define PA_SIMULATE_UNDERFLOW (0)
+#if PA_SIMULATE_UNDERFLOW
+static gUnderCallbackCounter = 0;
+#define UNDER_START_GAP (10)
+#define UNDER_STOP_GAP (UNDER_START_GAP + 4)
+#endif
+
+/************************************************* Definitions ********/
+typedef struct internalPortAudioStream internalPortAudioStream;
+typedef struct internalPortAudioDevice
+{
+ GUID pad_GUID;
+ GUID *pad_lpGUID;
+ double pad_SampleRates[10]; /* for pointing to from pad_Info FIXME?!*/
+ PaDeviceInfo pad_Info;
+}
+internalPortAudioDevice;
+
+/* Define structure to contain all DirectSound and Windows specific data. */
+typedef struct PaHostSoundControl
+{
+ DSoundWrapper pahsc_DSoundWrapper;
+ MMRESULT pahsc_TimerID;
+ BOOL pahsc_IfInsideCallback; /* Test for reentrancy. */
+ short *pahsc_NativeBuffer;
+ unsigned int pahsc_BytesPerBuffer; /* native buffer size in bytes */
+ double pahsc_ValidFramesWritten;
+ int pahsc_FramesPerDSBuffer;
+ /* For measuring CPU utilization. */
+ LARGE_INTEGER pahsc_EntryCount;
+ double pahsc_InverseTicksPerUserBuffer;
+}
+PaHostSoundControl;
+
+/************************************************* Shared Data ********/
+/* FIXME - put Mutex around this shared data. */
+static int sNumDevices = 0;
+static int sDeviceIndex = 0;
+static internalPortAudioDevice *sDevices = NULL;
+static int sDefaultInputDeviceID = paNoDevice;
+static int sDefaultOutputDeviceID = paNoDevice;
+static int sEnumerationError;
+static int sPaHostError = 0;
+/************************************************* Prototypes **********/
+static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id );
+static BOOL CALLBACK Pa_EnumProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext );
+static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext );
+static Pa_QueryDevices( void );
+static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg,
+ DWORD dwUser, DWORD dw1, DWORD dw2);
+
+/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
+static void Pa_StartUsageCalculation( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+ /* Query system timer for usage analysis and to prevent overuse of CPU. */
+ QueryPerformanceCounter( &pahsc->pahsc_EntryCount );
+}
+
+static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+{
+ LARGE_INTEGER CurrentCount = { 0, 0 };
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+ /*
+ ** Measure CPU utilization during this callback. Note that this calculation
+ ** assumes that we had the processor the whole time.
+ */
+#define LOWPASS_COEFFICIENT_0 (0.9)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+ if( QueryPerformanceCounter( &CurrentCount ) )
+ {
+ LONGLONG InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart;
+ double newUsage = InsideCount * pahsc->pahsc_InverseTicksPerUserBuffer;
+ past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
+ (LOWPASS_COEFFICIENT_1 * newUsage);
+ }
+}
+
+/****************************************** END CPU UTILIZATION *******/
+static PaError Pa_QueryDevices( void )
+{
+ int numBytes;
+ sDefaultInputDeviceID = paNoDevice;
+ sDefaultOutputDeviceID = paNoDevice;
+ /* Enumerate once just to count devices. */
+ sNumDevices = 0; // for default device
+ DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, NULL );
+#if SUPPORT_AUDIO_CAPTURE
+ DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, NULL );
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ /* Allocate structures to hold device info. */
+ numBytes = sNumDevices * sizeof(internalPortAudioDevice);
+ sDevices = (internalPortAudioDevice *)PaHost_AllocateFastMemory( numBytes ); /* MEM */
+ if( sDevices == NULL ) return paInsufficientMemory;
+ /* Enumerate again to fill in structures. */
+ sDeviceIndex = 0;
+ sEnumerationError = 0;
+ DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_EnumProc, (void *)0 );
+#if SUPPORT_AUDIO_CAPTURE
+ if( sEnumerationError != paNoError ) return sEnumerationError;
+ sEnumerationError = 0;
+ DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_EnumProc, (void *)1 );
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ return sEnumerationError;
+}
+/************************************************************************************/
+long Pa_GetHostError()
+{
+ return sPaHostError;
+}
+/************************************************************************************
+** Just count devices so we know how much memory to allocate.
+*/
+static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext )
+{
+ sNumDevices++;
+ return TRUE;
+}
+/************************************************************************************
+** Extract capabilities info from each device.
+*/
+static BOOL CALLBACK Pa_EnumProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext )
+{
+ HRESULT hr;
+ LPDIRECTSOUND lpDirectSound;
+#if SUPPORT_AUDIO_CAPTURE
+ LPDIRECTSOUNDCAPTURE lpDirectSoundCapture;
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ int isInput = (int) lpContext; /* Passed from Pa_CountDevices() */
+ internalPortAudioDevice *pad;
+
+ if( sDeviceIndex >= sNumDevices )
+ {
+ sEnumerationError = paInternalError;
+ return FALSE;
+ }
+ pad = &sDevices[sDeviceIndex];
+ /* Copy GUID to static array. Set pointer. */
+ if( lpGUID == NULL )
+ {
+ pad->pad_lpGUID = NULL;
+ }
+ else
+ {
+ memcpy( &pad->pad_GUID, lpGUID, sizeof(GUID) );
+ pad->pad_lpGUID = &pad->pad_GUID;
+ }
+ pad->pad_Info.sampleRates = pad->pad_SampleRates; /* Point to array. */
+ /* Allocate room for descriptive name. */
+ if( lpszDesc != NULL )
+ {
+ int len = strlen(lpszDesc);
+ pad->pad_Info.name = (char *)malloc( len+1 );
+ if( pad->pad_Info.name == NULL )
+ {
+ sEnumerationError = paInsufficientMemory;
+ return FALSE;
+ }
+ memcpy( (void *) pad->pad_Info.name, lpszDesc, len+1 );
+ }
+#if SUPPORT_AUDIO_CAPTURE
+ if( isInput )
+ {
+ /********** Input ******************************/
+ DSCCAPS caps;
+ if( lpGUID == NULL ) sDefaultInputDeviceID = sDeviceIndex;
+ hr = DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL );
+ if( hr != DS_OK )
+ {
+ pad->pad_Info.maxInputChannels = 0;
+ DBUG(("Cannot create Capture for %s. Result = 0x%x\n", lpszDesc, hr ));
+ }
+ else
+ {
+ /* Query device characteristics. */
+ caps.dwSize = sizeof(caps);
+ IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps );
+ /* printf("caps.dwFormats = 0x%x\n", caps.dwFormats ); */
+ pad->pad_Info.maxInputChannels = caps.dwChannels;
+ /* Determine sample rates from flags. */
+ if( caps.dwChannels == 2 )
+ {
+ int index = 0;
+ if( caps.dwFormats & WAVE_FORMAT_1S16) pad->pad_SampleRates[index++] = 11025.0;
+ if( caps.dwFormats & WAVE_FORMAT_2S16) pad->pad_SampleRates[index++] = 22050.0;
+ if( caps.dwFormats & WAVE_FORMAT_4S16) pad->pad_SampleRates[index++] = 44100.0;
+ pad->pad_Info.numSampleRates = index;
+ }
+ else if( caps.dwChannels == 1 )
+ {
+ int index = 0;
+ if( caps.dwFormats & WAVE_FORMAT_1M16) pad->pad_SampleRates[index++] = 11025.0;
+ if( caps.dwFormats & WAVE_FORMAT_2M16) pad->pad_SampleRates[index++] = 22050.0;
+ if( caps.dwFormats & WAVE_FORMAT_4M16) pad->pad_SampleRates[index++] = 44100.0;
+ pad->pad_Info.numSampleRates = index;
+ }
+ else pad->pad_Info.numSampleRates = 0;
+ IDirectSoundCapture_Release( lpDirectSoundCapture );
+ }
+ }
+ else
+#endif /* SUPPORT_AUDIO_CAPTURE */
+
+ {
+ /********** Output ******************************/
+ DSCAPS caps;
+ if( lpGUID == NULL ) sDefaultOutputDeviceID = sDeviceIndex;
+ /* Create interfaces for each object. */
+ hr = DirectSoundCreate( lpGUID, &lpDirectSound, NULL );
+ if( hr != DS_OK )
+ {
+ pad->pad_Info.maxOutputChannels = 0;
+ DBUG(("Cannot create dsound for %s. Result = 0x%x\n", lpszDesc, hr ));
+ }
+ else
+ {
+ /* Query device characteristics. */
+ caps.dwSize = sizeof(caps);
+ IDirectSound_GetCaps( lpDirectSound, &caps );
+ pad->pad_Info.maxOutputChannels = ( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
+ /* Get sample rates. */
+ pad->pad_SampleRates[0] = (double) caps.dwMinSecondarySampleRate;
+ pad->pad_SampleRates[1] = (double) caps.dwMaxSecondarySampleRate;
+ if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) pad->pad_Info.numSampleRates = -1;
+ else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate )
+ {
+ if( caps.dwMinSecondarySampleRate == 0 )
+ {
+ /*
+ ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !!
+ ** But it supports continuous sampling.
+ ** So fake range of rates, and hope it really supports it.
+ */
+ pad->pad_SampleRates[0] = 11025.0f;
+ pad->pad_SampleRates[1] = 48000.0f;
+ pad->pad_Info.numSampleRates = -1; /* continuous range */
+
+ DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex ));
+ }
+ else
+ {
+ pad->pad_Info.numSampleRates = 1;
+ }
+ }
+ else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) )
+ {
+ /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000.
+ ** But we know that they really support a range of rates!
+ ** So when we see a ridiculous set of rates, assume it is a range.
+ */
+ pad->pad_Info.numSampleRates = -1;
+ DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex ));
+ }
+ else pad->pad_Info.numSampleRates = 2;
+ IDirectSound_Release( lpDirectSound );
+ }
+ }
+ pad->pad_Info.nativeSampleFormats = paInt16;
+ sDeviceIndex++;
+ return( TRUE );
+}
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ if( sNumDevices <= 0 ) Pa_Initialize();
+ return sNumDevices;
+}
+static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id )
+{
+ if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
+ return &sDevices[id];
+}
+/*************************************************************************/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ internalPortAudioDevice *pad;
+ if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
+ pad = Pa_GetInternalDevice( id );
+ return &pad->pad_Info ;
+}
+static PaError Pa_MaybeQueryDevices( void )
+{
+ if( sNumDevices == 0 )
+ {
+ return Pa_QueryDevices();
+ }
+ return 0;
+}
+/*************************************************************************
+** Returns recommended device ID.
+** On the PC, the recommended device can be specified by the user by
+** setting an environment variable. For example, to use device #1.
+**
+** set PA_RECOMMENDED_OUTPUT_DEVICE=1
+**
+** The user should first determine the available device ID by using
+** the supplied application "pa_devs".
+*/
+#define PA_ENV_BUF_SIZE (32)
+#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE")
+#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE")
+static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName )
+{
+ DWORD hresult;
+ char envbuf[PA_ENV_BUF_SIZE];
+ PaDeviceID recommendedID = paNoDevice;
+ /* Let user determine default device by setting environment variable. */
+ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE );
+ if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
+ {
+ recommendedID = atoi( envbuf );
+ }
+ return recommendedID;
+}
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
+{
+ PaError result;
+ result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME );
+ if( result < 0 )
+ {
+ result = Pa_MaybeQueryDevices();
+ if( result < 0 ) return result;
+ result = sDefaultInputDeviceID;
+ }
+ return result;
+}
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
+{
+ PaError result;
+ result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME );
+ if( result < 0 )
+ {
+ result = Pa_MaybeQueryDevices();
+ if( result < 0 ) return result;
+ result = sDefaultOutputDeviceID;
+ }
+ return result;
+}
+/**********************************************************************
+** Make sure that we have queried the device capabilities.
+*/
+PaError PaHost_Init( void )
+{
+#if PA_SIMULATE_UNDERFLOW
+ PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n"));
+#endif
+ return Pa_MaybeQueryDevices();
+}
+static PaError Pa_TimeSlice( internalPortAudioStream *past )
+{
+ PaError result = 0;
+ long bytesEmpty = 0;
+ long bytesFilled = 0;
+ long bytesToXfer = 0;
+ long numChunks;
+ HRESULT hresult;
+ PaHostSoundControl *pahsc;
+ short *nativeBufPtr;
+ past->past_NumCallbacks += 1;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+ /* How much input data is available? */
+#if SUPPORT_AUDIO_CAPTURE
+ if( past->past_NumInputChannels > 0 )
+ {
+ DSW_QueryInputFilled( &pahsc->pahsc_DSoundWrapper, &bytesFilled );
+ bytesToXfer = bytesFilled;
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ /* How much output room is available? */
+ if( past->past_NumOutputChannels > 0 )
+ {
+ DSW_QueryOutputSpace( &pahsc->pahsc_DSoundWrapper, &bytesEmpty );
+ bytesToXfer = bytesEmpty;
+ }
+ AddTraceMessage( "bytesEmpty ", bytesEmpty );
+ /* Choose smallest value if both are active. */
+ if( (past->past_NumInputChannels > 0) && (past->past_NumOutputChannels > 0) )
+ {
+ bytesToXfer = ( bytesFilled < bytesEmpty ) ? bytesFilled : bytesEmpty;
+ }
+ /* printf("bytesFilled = %d, bytesEmpty = %d, bytesToXfer = %d\n",
+ bytesFilled, bytesEmpty, bytesToXfer);
+ */
+ /* Quantize to multiples of a buffer. */
+ numChunks = bytesToXfer / pahsc->pahsc_BytesPerBuffer;
+ if( numChunks > (long)(past->past_NumUserBuffers/2) )
+ {
+ numChunks = (long)past->past_NumUserBuffers/2;
+ }
+ else if( numChunks < 0 )
+ {
+ numChunks = 0;
+ }
+ AddTraceMessage( "numChunks ", numChunks );
+ nativeBufPtr = pahsc->pahsc_NativeBuffer;
+ if( numChunks > 0 )
+ {
+ while( numChunks-- > 0 )
+ {
+ /* Measure usage based on time to process one user buffer. */
+ Pa_StartUsageCalculation( past );
+#if SUPPORT_AUDIO_CAPTURE
+ /* Get native data from DirectSound. */
+ if( past->past_NumInputChannels > 0 )
+ {
+ hresult = DSW_ReadBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer );
+ if( hresult < 0 )
+ {
+ ERR_RPT(("DirectSound ReadBlock failed, hresult = 0x%x\n",hresult));
+ sPaHostError = hresult;
+ break;
+ }
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ /* Convert 16 bit native data to user data and call user routine. */
+ result = Pa_CallConvertInt16( past, nativeBufPtr, nativeBufPtr );
+ if( result != 0) break;
+ /* Pass native data to DirectSound. */
+ if( past->past_NumOutputChannels > 0 )
+ {
+ /* static short DEBUGHACK = 0;
+ DEBUGHACK += 0x0049;
+ nativeBufPtr[0] = DEBUGHACK; /* Make buzz to see if DirectSound still running. */
+ hresult = DSW_WriteBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer );
+ if( hresult < 0 )
+ {
+ ERR_RPT(("DirectSound WriteBlock failed, result = 0x%x\n",hresult));
+ sPaHostError = hresult;
+ break;
+ }
+ }
+ Pa_EndUsageCalculation( past );
+ }
+ }
+ return result;
+}
+/*******************************************************************/
+static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+ internalPortAudioStream *past;
+ PaHostSoundControl *pahsc;
+#if PA_SIMULATE_UNDERFLOW
+ gUnderCallbackCounter++;
+ if( (gUnderCallbackCounter >= UNDER_START_GAP) &&
+ (gUnderCallbackCounter <= UNDER_STOP_GAP) )
+ {
+ if( gUnderCallbackCounter == UNDER_START_GAP)
+ {
+ AddTraceMessage("Begin stall: gUnderCallbackCounter =======", gUnderCallbackCounter );
+ }
+ if( gUnderCallbackCounter == UNDER_STOP_GAP)
+ {
+ AddTraceMessage("End stall: gUnderCallbackCounter =======", gUnderCallbackCounter );
+ }
+ return;
+ }
+#endif
+ past = (internalPortAudioStream *) dwUser;
+ if( past == NULL ) return;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+ if( !pahsc->pahsc_IfInsideCallback && past->past_IsActive )
+ {
+ if( past->past_StopNow )
+ {
+ past->past_IsActive = 0;
+ }
+ else if( past->past_StopSoon )
+ {
+ DSoundWrapper *dsw = &pahsc->pahsc_DSoundWrapper;
+ if( past->past_NumOutputChannels > 0 )
+ {
+ DSW_ZeroEmptySpace( dsw );
+ AddTraceMessage("Pa_TimerCallback: waiting - written ", (int) dsw->dsw_FramesWritten );
+ AddTraceMessage("Pa_TimerCallback: waiting - played ", (int) dsw->dsw_FramesPlayed );
+ /* clear past_IsActive when all sound played */
+ if( dsw->dsw_FramesPlayed >= past->past_FrameCount )
+ {
+ past->past_IsActive = 0;
+ }
+ }
+ else
+ {
+ past->past_IsActive = 0;
+ }
+ }
+ else
+ {
+ pahsc->pahsc_IfInsideCallback = 1;
+ if( Pa_TimeSlice( past ) != 0) /* Call time slice independant of timing method. */
+ {
+ past->past_StopSoon = 1;
+ }
+ pahsc->pahsc_IfInsideCallback = 0;
+ }
+ }
+}
+/*******************************************************************/
+PaError PaHost_OpenStream( internalPortAudioStream *past )
+{
+ HRESULT hr;
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+ int numBytes, maxChannels;
+ unsigned int minNumBuffers;
+ internalPortAudioDevice *pad;
+ DSoundWrapper *dsw;
+ /* Allocate and initialize host data. */
+ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */
+ if( pahsc == NULL )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ memset( pahsc, 0, sizeof(PaHostSoundControl) );
+ past->past_DeviceData = (void *) pahsc;
+ pahsc->pahsc_TimerID = 0;
+ dsw = &pahsc->pahsc_DSoundWrapper;
+ DSW_Init( dsw );
+ /* Allocate native buffer. */
+ maxChannels = ( past->past_NumOutputChannels > past->past_NumInputChannels ) ?
+ past->past_NumOutputChannels : past->past_NumInputChannels;
+ pahsc->pahsc_BytesPerBuffer = past->past_FramesPerUserBuffer * maxChannels * sizeof(short);
+ if( maxChannels > 0 )
+ {
+ pahsc->pahsc_NativeBuffer = (short *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerBuffer); /* MEM */
+ if( pahsc->pahsc_NativeBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ }
+ else
+ {
+ result = paInvalidChannelCount;
+ goto error;
+ }
+
+ DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer ));
+ minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
+ past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers;
+ numBytes = pahsc->pahsc_BytesPerBuffer * past->past_NumUserBuffers;
+ if( numBytes < DSBSIZE_MIN )
+ {
+ result = paBufferTooSmall;
+ goto error;
+ }
+ if( numBytes > DSBSIZE_MAX )
+ {
+ result = paBufferTooBig;
+ goto error;
+ }
+ pahsc->pahsc_FramesPerDSBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers;
+ {
+ int msecLatency = (int) ((pahsc->pahsc_FramesPerDSBuffer * 1000) / past->past_SampleRate);
+ PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", pahsc->pahsc_FramesPerDSBuffer, msecLatency ));
+ }
+ /* ------------------ OUTPUT */
+ if( (past->past_OutputDeviceID >= 0) && (past->past_NumOutputChannels > 0) )
+ {
+ DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID));
+ pad = Pa_GetInternalDevice( past->past_OutputDeviceID );
+ hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL );
+ /* If this fails, then try each output device until we find one that works. */
+ if( hr != DS_OK )
+ {
+ int i;
+ ERR_RPT(("Creation of requested Audio Output device '%s' failed.\n",
+ ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) ));
+ for( i=0; i<Pa_CountDevices(); i++ )
+ {
+ pad = Pa_GetInternalDevice( i );
+ if( pad->pad_Info.maxOutputChannels >= past->past_NumOutputChannels )
+ {
+ DBUG(("Try device '%s' instead.\n", pad->pad_Info.name ));
+ hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL );
+ if( hr == DS_OK )
+ {
+ ERR_RPT(("Using device '%s' instead.\n", pad->pad_Info.name ));
+ break;
+ }
+ }
+ }
+ }
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n"));
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+ hr = DSW_InitOutputBuffer( dsw,
+ (unsigned long) (past->past_SampleRate + 0.5),
+ past->past_NumOutputChannels, numBytes );
+ DBUG(("DSW_InitOutputBuffer() returns %x\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+ past->past_FrameCount = pahsc->pahsc_DSoundWrapper.dsw_FramesWritten;
+ }
+#if SUPPORT_AUDIO_CAPTURE
+ /* ------------------ INPUT */
+ if( (past->past_InputDeviceID >= 0) && (past->past_NumInputChannels > 0) )
+ {
+ pad = Pa_GetInternalDevice( past->past_InputDeviceID );
+ hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL );
+ /* If this fails, then try each input device until we find one that works. */
+ if( hr != DS_OK )
+ {
+ int i;
+ ERR_RPT(("Creation of requested Audio Capture device '%s' failed.\n",
+ ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) ));
+ for( i=0; i<Pa_CountDevices(); i++ )
+ {
+ pad = Pa_GetInternalDevice( i );
+ if( pad->pad_Info.maxInputChannels >= past->past_NumInputChannels )
+ {
+ PRINT(("Try device '%s' instead.\n", pad->pad_Info.name ));
+ hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL );
+ if( hr == DS_OK ) break;
+ }
+ }
+ }
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n"));
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+ hr = DSW_InitInputBuffer( dsw,
+ (unsigned long) (past->past_SampleRate + 0.5),
+ past->past_NumInputChannels, numBytes );
+ DBUG(("DSW_InitInputBuffer() returns %x\n", hr));
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr));
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ /* Calculate scalar used in CPULoad calculation. */
+ {
+ LARGE_INTEGER frequency;
+ if( QueryPerformanceFrequency( &frequency ) == 0 )
+ {
+ pahsc->pahsc_InverseTicksPerUserBuffer = 0.0;
+ }
+ else
+ {
+ pahsc->pahsc_InverseTicksPerUserBuffer = past->past_SampleRate /
+ ( (double)frequency.QuadPart * past->past_FramesPerUserBuffer );
+ DBUG(("pahsc_InverseTicksPerUserBuffer = %g\n", pahsc->pahsc_InverseTicksPerUserBuffer ));
+ }
+ }
+ return result;
+error:
+ PaHost_CloseStream( past );
+ return result;
+}
+/*************************************************************************/
+PaError PaHost_StartOutput( internalPortAudioStream *past )
+{
+ HRESULT hr;
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ /* Give user callback a chance to pre-fill buffer. */
+ result = Pa_TimeSlice( past );
+ if( result != paNoError ) return result; // FIXME - what if finished?
+ hr = DSW_StartOutput( &pahsc->pahsc_DSoundWrapper );
+ DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+error:
+ return result;
+}
+/*************************************************************************/
+PaError PaHost_StartInput( internalPortAudioStream *past )
+{
+ PaError result = paNoError;
+#if SUPPORT_AUDIO_CAPTURE
+ HRESULT hr;
+ PaHostSoundControl *pahsc;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ hr = DSW_StartInput( &pahsc->pahsc_DSoundWrapper );
+ DBUG(("Pa_StartStream: DSW_StartInput returned = 0x%X.\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+error:
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ return result;
+}
+/*************************************************************************/
+PaError PaHost_StartEngine( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ past->past_StopNow = 0;
+ past->past_StopSoon = 0;
+ past->past_IsActive = 1;
+ /* Create timer that will wake us up so we can fill the DSound buffer. */
+ {
+ int msecPerBuffer;
+ int resolution;
+ int bufsPerInterrupt = past->past_NumUserBuffers/4;
+ if( bufsPerInterrupt < 1 ) bufsPerInterrupt = 1;
+ msecPerBuffer = 1000 * (bufsPerInterrupt * past->past_FramesPerUserBuffer) / (int) past->past_SampleRate;
+ if( msecPerBuffer < 10 ) msecPerBuffer = 10;
+ else if( msecPerBuffer > 100 ) msecPerBuffer = 100;
+ resolution = msecPerBuffer/4;
+ pahsc->pahsc_TimerID = timeSetEvent( msecPerBuffer, resolution, (LPTIMECALLBACK) Pa_TimerCallback,
+ (DWORD) past, TIME_PERIODIC );
+ }
+ if( pahsc->pahsc_TimerID == 0 )
+ {
+ past->past_IsActive = 0;
+ result = paHostError;
+ sPaHostError = 0;
+ goto error;
+ }
+error:
+ return result;
+}
+/*************************************************************************/
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+{
+ int timeoutMsec;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ if( abort ) past->past_StopNow = 1;
+ past->past_StopSoon = 1;
+ /* Set timeout at 20% beyond maximum time we might wait. */
+ timeoutMsec = (int) (1200.0 * pahsc->pahsc_FramesPerDSBuffer / past->past_SampleRate);
+ while( past->past_IsActive && (timeoutMsec > 0) )
+ {
+ Sleep(10);
+ timeoutMsec -= 10;
+ }
+ if( pahsc->pahsc_TimerID != 0 )
+ {
+ timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */
+ pahsc->pahsc_TimerID = 0;
+ }
+ return paNoError;
+}
+/*************************************************************************/
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
+{
+#if SUPPORT_AUDIO_CAPTURE
+ HRESULT hr;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ (void) abort;
+ hr = DSW_StopInput( &pahsc->pahsc_DSoundWrapper );
+ DBUG(("DSW_StopInput() result is %x\n", hr));
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ return paNoError;
+}
+/*************************************************************************/
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+{
+ HRESULT hr;
+ PaHostSoundControl *pahsc;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ (void) abort;
+ hr = DSW_StopOutput( &pahsc->pahsc_DSoundWrapper );
+ DBUG(("DSW_StopOutput() result is %x\n", hr));
+ return paNoError;
+}
+/*******************************************************************/
+PaError PaHost_CloseStream( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ DSW_Term( &pahsc->pahsc_DSoundWrapper );
+ if( pahsc->pahsc_NativeBuffer )
+ {
+ PaHost_FreeFastMemory( pahsc->pahsc_NativeBuffer, pahsc->pahsc_BytesPerBuffer ); /* MEM */
+ pahsc->pahsc_NativeBuffer = NULL;
+ }
+ PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); /* MEM */
+ past->past_DeviceData = NULL;
+ return paNoError;
+}
+
+/* Set minimal latency based on whether NT or Win95.
+ * NT has higher latency.
+ */
+static int PaHost_GetMinSystemLatency( void )
+{
+ int minLatencyMsec;
+ /* Set minimal latency based on whether NT or other OS.
+ * NT has higher latency.
+ */
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof( osvi );
+ GetVersionEx( &osvi );
+ DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId ));
+ DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion ));
+ DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion ));
+ /* Check for NT */
+ if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
+ {
+ minLatencyMsec = PA_WIN_NT_LATENCY;
+ }
+ else if(osvi.dwMajorVersion >= 5)
+ {
+ minLatencyMsec = PA_WIN_WDM_LATENCY;
+ }
+ else
+ {
+ minLatencyMsec = PA_WIN_9X_LATENCY;
+ }
+ return minLatencyMsec;
+}
+
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+**
+** set PA_MIN_LATENCY_MSEC=200
+**
+** in the AUTOEXEC.BAT file and reboot.
+** If the environment variable is not set, then the latency will be determined
+** based on the OS. Windows NT has higher latency than Win95.
+*/
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
+{
+ char envbuf[PA_ENV_BUF_SIZE];
+ DWORD hresult;
+ int minLatencyMsec = 0;
+ double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate;
+ int minBuffers;
+ /* Let user determine minimal latency by setting environment variable. */
+ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE );
+ if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
+ {
+ minLatencyMsec = atoi( envbuf );
+ }
+ else
+ {
+ minLatencyMsec = PaHost_GetMinSystemLatency();
+#if PA_USE_HIGH_LATENCY
+ PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));
+#endif
+
+ }
+ minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer));
+ if( minBuffers < 2 ) minBuffers = 2;
+ return minBuffers;
+}
+/*************************************************************************/
+PaError PaHost_Term( void )
+{
+ int i;
+ /* Free names allocated during enumeration. */
+ for( i=0; i<sNumDevices; i++ )
+ {
+ if( sDevices[i].pad_Info.name != NULL )
+ {
+ free( (void *) sDevices[i].pad_Info.name );
+ sDevices[i].pad_Info.name = NULL;
+ }
+ }
+ if( sDevices != NULL )
+ {
+ PaHost_FreeFastMemory( sDevices, sNumDevices * sizeof(internalPortAudioDevice) ); /* MEM */
+ sDevices = NULL;
+ sNumDevices = 0;
+ }
+ return 0;
+}
+void Pa_Sleep( long msec )
+{
+ Sleep( msec );
+}
+/*************************************************************************
+ * Allocate memory that can be accessed in real-time.
+ * This may need to be held in physical memory so that it is not
+ * paged to virtual memory.
+ * This call MUST be balanced with a call to PaHost_FreeFastMemory().
+ * Memory will be set to zero.
+ */
+void *PaHost_AllocateFastMemory( long numBytes )
+{
+ void *addr = GlobalAlloc( GPTR, numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */
+ return addr;
+}
+/*************************************************************************
+ * Free memory that could be accessed in real-time.
+ * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
+ */
+void PaHost_FreeFastMemory( void *addr, long numBytes )
+{
+ if( addr != NULL ) GlobalFree( addr ); /* MEM */
+}
+/***********************************************************************/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+ return (PaError) (past->past_IsActive);
+}
+/*************************************************************************/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ DSoundWrapper *dsw;
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ PaHostSoundControl *pahsc;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ dsw = &pahsc->pahsc_DSoundWrapper;
+ return dsw->dsw_FramesPlayed;
+}
diff --git a/pd/portaudio/pa_win_ds/pa_win_ds.c b/pd/portaudio/pa_win_ds/pa_win_ds.c
new file mode 100644
index 00000000..b23a407e
--- /dev/null
+++ b/pd/portaudio/pa_win_ds/pa_win_ds.c
@@ -0,0 +1,1441 @@
+/*
+ * $Id: pa_win_ds.c,v 1.1.2.29 2002/12/03 06:30:40 rossbencina Exp $
+ * Portable Audio I/O Library DirectSound implementation
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ */
+
+/** @file
+
+ @todo implement underflow/overflow streamCallback statusFlags, paNeverDropInput.
+
+ @todo implement host api specific extension to set i/o buffer sizes in frames
+
+ @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.)
+
+ @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
+
+ @todo audit handling of DirectSound result codes - in many cases we could convert a HRESULT into
+ a native portaudio error code. Standard DirectSound result codes are documented at msdn.
+
+ @todo implement IsFormatSupported
+
+ @todo implement PaDeviceInfo.defaultSampleRate;
+*/
+
+#include <stdio.h>
+#include <string.h> /* strlen() */
+
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
+
+#include "dsound_wrapper.h"
+
+/* TODO
+O- fix "patest_stop.c"
+O- Handle buffer underflow, overflow, etc.
+*/
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+#define PA_USE_HIGH_LATENCY (0)
+#if PA_USE_HIGH_LATENCY
+#define PA_WIN_9X_LATENCY (500)
+#define PA_WIN_NT_LATENCY (600)
+#else
+#define PA_WIN_9X_LATENCY (140)
+#define PA_WIN_NT_LATENCY (280)
+#endif
+
+#define PA_WIN_WDM_LATENCY (120)
+
+#define SECONDS_PER_MSEC (0.001)
+#define MSEC_PER_SECOND (1000)
+
+/* prototypes for functions declared in this file */
+
+PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData );
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate );
+static PaError CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+static signed long GetStreamReadAvailable( PaStream* stream );
+static signed long GetStreamWriteAvailable( PaStream* stream );
+
+
+/* FIXME: should convert hr to a string */
+#define PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ) \
+ PaUtil_SetLastHostErrorInfo( paDirectSound, hr, "DirectSound error" )
+
+/************************************************* DX Prototypes **********/
+static BOOL CALLBACK Pa_EnumOutputProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext );
+static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext );
+
+/************************************************************************************/
+/********************** Structures **************************************************/
+/************************************************************************************/
+/* PaWinDsHostApiRepresentation - host api datastructure specific to this implementation */
+
+typedef struct PaWinDsDeviceInfo
+{
+ GUID GUID;
+ GUID *lpGUID;
+ double sampleRates[3];
+} PaWinDsDeviceInfo;
+
+typedef struct
+{
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
+
+ PaUtilAllocationGroup *allocations;
+
+ /* implementation specific data goes here */
+ PaWinDsDeviceInfo *winDsDeviceInfos;
+ PaError enumerationError;
+
+} PaWinDsHostApiRepresentation;
+
+/* PaWinDsStream - a stream data structure specifically for this implementation */
+
+typedef struct PaWinDsStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+/* DirectSound specific data. */
+ DSoundWrapper directSoundWrapper;
+ MMRESULT timerID;
+ BOOL ifInsideCallback; /* Test for reentrancy. */
+ int framesPerDSBuffer;
+ double framesWritten;
+ double secondsPerHostByte; /* Used to optimize latency calculation for outTime */
+
+/* FIXME - move all below to PaUtilStreamRepresentation */
+ volatile int isStarted;
+ volatile int isActive;
+ volatile int stopProcessing; /* stop thread once existing buffers have been returned */
+ volatile int abortProcessing; /* stop thread immediately */
+} PaWinDsStream;
+
+
+/************************************************************************************
+** Just count devices so we know how much memory to allocate.
+*/
+static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext )
+{
+ int *counterPtr = (int *)lpContext;
+ *counterPtr += 1;
+ return TRUE;
+}
+
+/************************************************************************************
+** Extract capabilities info from each device.
+*/
+static BOOL CALLBACK Pa_EnumOutputProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext )
+{
+ HRESULT hr;
+ DSCAPS caps;
+ LPDIRECTSOUND lpDirectSound;
+ PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation *) lpContext;
+ PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep;
+ int index = hostApi->info.deviceCount;
+ PaDeviceInfo *deviceInfo = hostApi->deviceInfos[index];
+ PaWinDsDeviceInfo *winDsDeviceInfo = &winDsHostApi->winDsDeviceInfos[index];
+ int deviceOK = TRUE;
+
+ /* Copy GUID to static array. Set pointer. */
+ if( lpGUID == NULL )
+ {
+ winDsDeviceInfo->lpGUID = NULL;
+ }
+ else
+ {
+ winDsDeviceInfo->lpGUID = &winDsDeviceInfo->GUID;
+ memcpy( &winDsDeviceInfo->GUID, lpGUID, sizeof(GUID) );
+ }
+
+
+ /********** Output ******************************/
+
+ /* Create interfaces for each object. */
+ hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &lpDirectSound, NULL );
+ if( hr != DS_OK )
+ {
+ deviceInfo->maxOutputChannels = 0;
+ DBUG(("Cannot create dsound for %s. Result = 0x%x\n", lpszDesc, hr ));
+ deviceOK = FALSE;
+ }
+ else
+ {
+ /* Query device characteristics. */
+ caps.dwSize = sizeof(caps);
+ IDirectSound_GetCaps( lpDirectSound, &caps );
+
+#ifndef PA_NO_WMME
+ if( caps.dwFlags & DSCAPS_EMULDRIVER )
+ {
+ /* If WMME supported, then reject Emulated drivers because they are lousy. */
+ deviceOK = FALSE;
+ }
+#endif
+
+ if( deviceOK )
+ {
+ /* Mono or stereo device? */
+ deviceInfo->maxOutputChannels = ( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
+
+ deviceInfo->defaultSampleRate = 0.; /* @todo IMPLEMENT ME */
+
+ /* Get sample rates. */
+ /*
+ winDsDeviceInfo->sampleRates[0] = (double) caps.dwMinSecondarySampleRate;
+ winDsDeviceInfo->sampleRates[1] = (double) caps.dwMaxSecondarySampleRate;
+ if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) deviceInfo->numSampleRates = -1;
+ else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate )
+ {
+ if( caps.dwMinSecondarySampleRate == 0 )
+ {
+ //
+ // On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !!
+ // But it supports continuous sampling.
+ // So fake range of rates, and hope it really supports it.
+ //
+ winDsDeviceInfo->sampleRates[0] = 11025.0f;
+ winDsDeviceInfo->sampleRates[1] = 48000.0f;
+ deviceInfo->numSampleRates = -1; // continuous range
+
+ DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex ));
+ }
+ else
+ {
+ deviceInfo->numSampleRates = 1;
+ }
+ }
+ else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) )
+ {
+ // The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000.
+ // But we know that they really support a range of rates!
+ // So when we see a ridiculous set of rates, assume it is a range.
+ //
+ deviceInfo->numSampleRates = -1;
+ DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex ));
+ }
+ else deviceInfo->numSampleRates = 2;
+ */
+ }
+
+ IDirectSound_Release( lpDirectSound );
+ }
+
+ if( deviceOK )
+ {
+ if( lpGUID == NULL ) hostApi->info.defaultOutputDevice = index;
+
+ /* Allocate room for descriptive name. */
+ if( lpszDesc != NULL )
+ {
+ char *deviceName;
+ int len = strlen(lpszDesc);
+ deviceName = (char*)PaUtil_GroupAllocateMemory( winDsHostApi->allocations, len + 1 );
+ if( !deviceName )
+ {
+ winDsHostApi->enumerationError = paInsufficientMemory;
+ return FALSE;
+ }
+ memcpy( (void *) deviceName, lpszDesc, len+1 );
+ deviceInfo->name = deviceName;
+ }
+
+ hostApi->info.deviceCount++;
+ }
+
+ return( TRUE );
+}
+
+
+/************************************************************************************
+** Extract capabilities info from each device.
+*/
+static BOOL CALLBACK Pa_EnumInputProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext )
+{
+ HRESULT hr;
+ DSCCAPS caps;
+ LPDIRECTSOUNDCAPTURE lpDirectSoundCapture;
+ PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation *) lpContext;
+ PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep;
+ int index = hostApi->info.deviceCount;
+ PaDeviceInfo *deviceInfo = hostApi->deviceInfos[index];
+ PaWinDsDeviceInfo *winDsDeviceInfo = &winDsHostApi->winDsDeviceInfos[index];
+ int deviceOK = TRUE;
+
+ /* Copy GUID to static array. Set pointer. */
+ if( lpGUID == NULL )
+ {
+ winDsDeviceInfo->lpGUID = NULL;
+ }
+ else
+ {
+ winDsDeviceInfo->lpGUID = &winDsDeviceInfo->GUID;
+ memcpy( &winDsDeviceInfo->GUID, lpGUID, sizeof(GUID) );
+ }
+
+ /********** Input ******************************/
+
+ hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL );
+ if( hr != DS_OK )
+ {
+ deviceInfo->maxInputChannels = 0;
+ DBUG(("Cannot create Capture for %s. Result = 0x%x\n", lpszDesc, hr ));
+ deviceOK = FALSE;
+ }
+ else
+ {
+ /* Query device characteristics. */
+ caps.dwSize = sizeof(caps);
+ IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps );
+
+ /* printf("caps.dwFormats = 0x%x\n", caps.dwFormats ); */
+ deviceInfo->maxInputChannels = caps.dwChannels;
+ /* Determine sample rates from flags. */
+ /*
+ if( caps.dwChannels == 2 )
+ {
+ int index = 0;
+ if( caps.dwFormats & WAVE_FORMAT_1S16) winDsDeviceInfo->sampleRates[index++] = 11025.0;
+ if( caps.dwFormats & WAVE_FORMAT_2S16) winDsDeviceInfo->sampleRates[index++] = 22050.0;
+ if( caps.dwFormats & WAVE_FORMAT_4S16) winDsDeviceInfo->sampleRates[index++] = 44100.0;
+ deviceInfo->numSampleRates = index;
+ }
+ else if( caps.dwChannels == 1 )
+ {
+ int index = 0;
+ if( caps.dwFormats & WAVE_FORMAT_1M16) winDsDeviceInfo->sampleRates[index++] = 11025.0;
+ if( caps.dwFormats & WAVE_FORMAT_2M16) winDsDeviceInfo->sampleRates[index++] = 22050.0;
+ if( caps.dwFormats & WAVE_FORMAT_4M16) winDsDeviceInfo->sampleRates[index++] = 44100.0;
+ deviceInfo->numSampleRates = index;
+ }
+ else
+ {
+ deviceInfo->numSampleRates = 0;
+ deviceOK = FALSE;
+ }
+ */
+ IDirectSoundCapture_Release( lpDirectSoundCapture );
+ }
+
+ if( deviceOK )
+ {
+ /* Allocate room for descriptive name. */
+ if( lpszDesc != NULL )
+ {
+ char *deviceName;
+ int len = strlen(lpszDesc);
+ deviceName = (char*)PaUtil_GroupAllocateMemory( winDsHostApi->allocations, len + 1 );
+ if( !deviceName )
+ {
+ winDsHostApi->enumerationError = paInsufficientMemory;
+ return FALSE;
+ }
+ memcpy( (void *) deviceName, lpszDesc, len+1 );
+ deviceInfo->name = deviceName;
+ }
+
+ if( lpGUID == NULL ) hostApi->info.defaultInputDevice = index;
+
+ hostApi->info.deviceCount++;
+ }
+
+ return TRUE;
+}
+
+
+/***********************************************************************************/
+PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ int i, deviceCount;
+ PaWinDsHostApiRepresentation *winDsHostApi;
+ PaDeviceInfo *deviceInfoArray;
+
+ DSW_InitializeDSoundEntryPoints();
+
+ winDsHostApi = (PaWinDsHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinDsHostApiRepresentation) );
+ if( !winDsHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ winDsHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !winDsHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ *hostApi = &winDsHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paDirectSound;
+ (*hostApi)->info.name = "Windows DirectSound";
+
+ (*hostApi)->info.deviceCount = 0;
+ (*hostApi)->info.defaultInputDevice = paNoDevice;
+ (*hostApi)->info.defaultOutputDevice = paNoDevice;
+
+ deviceCount = 0;
+/* DSound - enumerate devices to count them. */
+ dswDSoundEntryPoints.DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, &deviceCount );
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, &deviceCount );
+
+ if( deviceCount > 0 )
+ {
+ /* allocate array for pointers to PaDeviceInfo structs */
+ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
+ if( !(*hostApi)->deviceInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* allocate all PaDeviceInfo structs in a contiguous block */
+ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ winDsHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
+ if( !deviceInfoArray )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* allocate all DSound specific info structs in a contiguous block */
+ winDsHostApi->winDsDeviceInfos = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory(
+ winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount );
+ if( !winDsHostApi->winDsDeviceInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i=0; i < deviceCount; ++i )
+ {
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+ deviceInfo->name = 0;
+
+ deviceInfo->defaultLowInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultLowOutputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighOutputLatency = 0.; /* @todo IMPLEMENT ME */
+
+ (*hostApi)->deviceInfos[i] = deviceInfo;
+ }
+
+ /* DSound - Enumerate again to fill in structures. */
+ winDsHostApi->enumerationError = 0;
+ dswDSoundEntryPoints.DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_EnumOutputProc, (void *)winDsHostApi );
+ if( winDsHostApi->enumerationError != paNoError ) return winDsHostApi->enumerationError;
+
+ winDsHostApi->enumerationError = 0;
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_EnumInputProc, (void *)winDsHostApi );
+ if( winDsHostApi->enumerationError != paNoError ) return winDsHostApi->enumerationError;
+ }
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &winDsHostApi->blockingStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+
+ return result;
+
+error:
+ if( winDsHostApi )
+ {
+ if( winDsHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( winDsHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( winDsHostApi );
+ }
+ return result;
+}
+
+
+/***********************************************************************************/
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
+
+ /*
+ IMPLEMENT ME:
+ - clean up any resourced not handled by the allocation group
+ */
+
+ if( winDsHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( winDsHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( winDsHostApi );
+
+ DSW_TerminateDSoundEntryPoints();
+}
+
+
+/* Set minimal latency based on whether NT or Win95.
+ * NT has higher latency.
+ */
+static int PaWinDS_GetMinSystemLatency( void )
+{
+ int minLatencyMsec;
+ /* Set minimal latency based on whether NT or other OS.
+ * NT has higher latency.
+ */
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof( osvi );
+ GetVersionEx( &osvi );
+ DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId ));
+ DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion ));
+ DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion ));
+ /* Check for NT */
+ if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
+ {
+ minLatencyMsec = PA_WIN_NT_LATENCY;
+ }
+ else if(osvi.dwMajorVersion >= 5)
+ {
+ minLatencyMsec = PA_WIN_WDM_LATENCY;
+ }
+ else
+ {
+ minLatencyMsec = PA_WIN_9X_LATENCY;
+ }
+ return minLatencyMsec;
+}
+
+/***********************************************************************************/
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
+{
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ /*
+ IMPLEMENT ME:
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+ */
+
+ return paFormatIsSupported;
+}
+
+
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+**
+** set PA_MIN_LATENCY_MSEC=200
+**
+** in the AUTOEXEC.BAT file and reboot.
+** If the environment variable is not set, then the latency will be determined
+** based on the OS. Windows NT has higher latency than Win95.
+*/
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+#define PA_ENV_BUF_SIZE (32)
+
+static int PaWinDs_GetMinLatencyFrames( double sampleRate )
+{
+ char envbuf[PA_ENV_BUF_SIZE];
+ DWORD hresult;
+ int minLatencyMsec = 0;
+
+ /* Let user determine minimal latency by setting environment variable. */
+ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE );
+ if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
+ {
+ minLatencyMsec = atoi( envbuf );
+ }
+ else
+ {
+ minLatencyMsec = PaWinDS_GetMinSystemLatency();
+#if PA_USE_HIGH_LATENCY
+ PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));
+#endif
+
+ }
+
+ return (int) (minLatencyMsec * sampleRate * SECONDS_PER_MSEC);
+}
+
+/***********************************************************************************/
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
+ PaWinDsStream *stream = 0;
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+ PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
+ unsigned long suggestedInputLatencyFrames, suggestedOutputLatencyFrames;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+ suggestedInputLatencyFrames = inputParameters->suggestedLatency * sampleRate;
+
+ /* IDEA: the following 3 checks could be performed by default by pa_front
+ unless some flag indicated otherwise */
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate hostApiSpecificStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ inputChannelCount = 0;
+ suggestedInputLatencyFrames = 0;
+ }
+
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+ suggestedOutputLatencyFrames = outputParameters->suggestedLatency * sampleRate;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate hostApiSpecificStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ outputChannelCount = 0;
+ suggestedOutputLatencyFrames = 0;
+ }
+
+
+ /*
+ IMPLEMENT ME:
+
+ ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() )
+
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+
+ - alter sampleRate to a close allowable rate if possible / necessary
+
+ - validate suggestedInputLatency and suggestedOutputLatency parameters,
+ use default values where necessary
+ */
+
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
+
+
+ stream = (PaWinDsStream*)PaUtil_AllocateMemory( sizeof(PaWinDsStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( streamCallback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &winDsHostApi->callbackStreamInterface, streamCallback, userData );
+ }
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &winDsHostApi->blockingStreamInterface, streamCallback, userData );
+ }
+
+ stream->streamRepresentation.streamInfo.inputLatency = 0.; /* FIXME: not initialised anywhere else */
+ stream->streamRepresentation.streamInfo.outputLatency = 0.;
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+
+ if( inputParameters )
+ {
+ /* IMPLEMENT ME - establish which host formats are available */
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputParameters->sampleFormat );
+ }
+
+ if( outputParameters )
+ {
+ /* IMPLEMENT ME - establish which host formats are available */
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputParameters->sampleFormat );
+ }
+
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ inputChannelCount, inputSampleFormat, hostInputSampleFormat,
+ outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer,
+ framesPerBuffer, /* ignored in paUtilVariableHostBufferSizePartialUsageAllowed mode. */
+ /* This next mode is required because DS can split the host buffer when it wraps around. */
+ paUtilVariableHostBufferSizePartialUsageAllowed,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+
+/* DirectSound specific initialization */
+ {
+ HRESULT hr;
+ int bytesPerDirectSoundBuffer;
+ DSoundWrapper *dsw;
+ int userLatencyFrames;
+ int minLatencyFrames;
+
+ stream->timerID = 0;
+ dsw = &stream->directSoundWrapper;
+ DSW_Init( dsw );
+
+ /* Get system minimum latency. */
+ minLatencyFrames = PaWinDs_GetMinLatencyFrames( sampleRate );
+
+ /* Let user override latency by passing latency parameter. */
+ userLatencyFrames = (suggestedInputLatencyFrames > suggestedOutputLatencyFrames)
+ ? suggestedInputLatencyFrames
+ : suggestedOutputLatencyFrames;
+ if( userLatencyFrames > 0 ) minLatencyFrames = userLatencyFrames;
+
+ /* Calculate stream->framesPerDSBuffer depending on framesPerBuffer */
+ if( framesPerBuffer == paFramesPerBufferUnspecified )
+ {
+ /* App support variable framesPerBuffer */
+ stream->framesPerDSBuffer = minLatencyFrames;
+
+ stream->streamRepresentation.streamInfo.outputLatency = (double)(minLatencyFrames - 1) / sampleRate;
+ }
+ else
+ {
+ /* Round up to number of buffers needed to guarantee that latency. */
+ int numUserBuffers = (minLatencyFrames + framesPerBuffer - 1) / framesPerBuffer;
+ if( numUserBuffers < 1 ) numUserBuffers = 1;
+ numUserBuffers += 1; /* So we have latency worth of buffers ahead of current buffer. */
+ stream->framesPerDSBuffer = framesPerBuffer * numUserBuffers;
+
+ stream->streamRepresentation.streamInfo.outputLatency = (double)(framesPerBuffer * (numUserBuffers-1)) / sampleRate;
+ }
+
+ {
+ /* @todo REVIEW: this calculation seems incorrect to me - rossb. */
+ int msecLatency = (int) ((stream->framesPerDSBuffer * MSEC_PER_SECOND) / sampleRate);
+ PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", stream->framesPerDSBuffer, msecLatency ));
+ }
+
+
+ /* ------------------ OUTPUT */
+ if( outputParameters )
+ {
+ PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ outputParameters->device ];
+ DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", outputDevice));
+
+ bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * outputParameters->channelCount * sizeof(short);
+ if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )
+ {
+ result = paBufferTooSmall;
+ goto error;
+ }
+ else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )
+ {
+ result = paBufferTooBig;
+ goto error;
+ }
+
+
+ hr = dswDSoundEntryPoints.DirectSoundCreate( winDsHostApi->winDsDeviceInfos[outputParameters->device].lpGUID,
+ &dsw->dsw_pDirectSound, NULL );
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n"));
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ hr = DSW_InitOutputBuffer( dsw,
+ (unsigned long) (sampleRate + 0.5),
+ outputParameters->channelCount, bytesPerDirectSoundBuffer );
+ DBUG(("DSW_InitOutputBuffer() returns %x\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ /* Calculate value used in latency calculation to avoid real-time divides. */
+ stream->secondsPerHostByte = 1.0 /
+ (stream->bufferProcessor.bytesPerHostOutputSample *
+ outputChannelCount * sampleRate);
+ }
+
+ /* ------------------ INPUT */
+ if( inputParameters )
+ {
+ PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ inputParameters->device ];
+
+ bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * inputParameters->channelCount * sizeof(short);
+ if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )
+ {
+ result = paBufferTooSmall;
+ goto error;
+ }
+ else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )
+ {
+ result = paBufferTooBig;
+ goto error;
+ }
+
+ hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( winDsHostApi->winDsDeviceInfos[inputParameters->device].lpGUID,
+ &dsw->dsw_pDirectSoundCapture, NULL );
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n"));
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ hr = DSW_InitInputBuffer( dsw,
+ (unsigned long) (sampleRate + 0.5),
+ inputParameters->channelCount, bytesPerDirectSoundBuffer );
+ DBUG(("DSW_InitInputBuffer() returns %x\n", hr));
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr));
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ }
+
+ }
+
+ *s = (PaStream*)stream;
+
+ return result;
+
+error:
+ if( stream )
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+/***********************************************************************************/
+static PaError Pa_TimeSlice( PaWinDsStream *stream )
+{
+ PaError result = 0; /* FIXME: this should be declared int and this function should also return that type (same as stream callback return type)*/
+ DSoundWrapper *dsw;
+ long numFrames = 0;
+ long bytesEmpty = 0;
+ long bytesFilled = 0;
+ long bytesToXfer = 0;
+ long framesToXfer = 0;
+ long numInFramesReady = 0;
+ long numOutFramesReady = 0;
+ long bytesProcessed;
+ HRESULT hresult;
+ double outputLatency = 0;
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* @todo implement inputBufferAdcTime */
+/* Input */
+ LPBYTE lpInBuf1 = NULL;
+ LPBYTE lpInBuf2 = NULL;
+ DWORD dwInSize1 = 0;
+ DWORD dwInSize2 = 0;
+/* Output */
+ LPBYTE lpOutBuf1 = NULL;
+ LPBYTE lpOutBuf2 = NULL;
+ DWORD dwOutSize1 = 0;
+ DWORD dwOutSize2 = 0;
+
+ dsw = &stream->directSoundWrapper;
+
+ /* How much input data is available? */
+ if( stream->bufferProcessor.inputChannelCount > 0 )
+ {
+ DSW_QueryInputFilled( dsw, &bytesFilled );
+ framesToXfer = numInFramesReady = bytesFilled / dsw->dsw_BytesPerInputFrame;
+ outputLatency = ((double)bytesFilled) * stream->secondsPerHostByte;
+ }
+
+ /* How much output room is available? */
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ DSW_QueryOutputSpace( dsw, &bytesEmpty );
+ framesToXfer = numOutFramesReady = bytesEmpty / dsw->dsw_BytesPerOutputFrame;
+ }
+
+ if( (numInFramesReady > 0) && (numOutFramesReady > 0) )
+ {
+ framesToXfer = (numOutFramesReady < numInFramesReady) ? numOutFramesReady : numInFramesReady;
+ }
+
+ if( framesToXfer > 0 )
+ {
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ /* The outputBufferDacTime parameter should indicates the time at which
+ the first sample of the output buffer is heard at the DACs. */
+ timeInfo.currentTime = PaUtil_GetTime();
+ timeInfo.outputBufferDacTime = timeInfo.currentTime + outputLatency;
+
+
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo );
+
+ /* Input */
+ if( stream->bufferProcessor.inputChannelCount > 0 )
+ {
+ bytesToXfer = framesToXfer * dsw->dsw_BytesPerInputFrame;
+ hresult = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer,
+ dsw->dsw_ReadOffset, bytesToXfer,
+ (void **) &lpInBuf1, &dwInSize1,
+ (void **) &lpInBuf2, &dwInSize2, 0);
+ if (hresult != DS_OK)
+ {
+ ERR_RPT(("DirectSound IDirectSoundCaptureBuffer_Lock failed, hresult = 0x%x\n",hresult));
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );
+ goto error2;
+ }
+
+ numFrames = dwInSize1 / dsw->dsw_BytesPerInputFrame;
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, numFrames );
+ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf1, 0 );
+ /* Is input split into two regions. */
+ if( dwInSize2 > 0 )
+ {
+ numFrames = dwInSize2 / dsw->dsw_BytesPerInputFrame;
+ PaUtil_Set2ndInputFrameCount( &stream->bufferProcessor, numFrames );
+ PaUtil_Set2ndInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf2, 0 );
+ }
+ }
+
+ /* Output */
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ bytesToXfer = framesToXfer * dsw->dsw_BytesPerOutputFrame;
+ hresult = IDirectSoundBuffer_Lock ( dsw->dsw_OutputBuffer,
+ dsw->dsw_WriteOffset, bytesToXfer,
+ (void **) &lpOutBuf1, &dwOutSize1,
+ (void **) &lpOutBuf2, &dwOutSize2, 0);
+ if (hresult != DS_OK)
+ {
+ ERR_RPT(("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n",hresult));
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );
+ goto error1;
+ }
+
+ numFrames = dwOutSize1 / dsw->dsw_BytesPerOutputFrame;
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, numFrames );
+ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf1, 0 );
+
+ /* Is output split into two regions. */
+ if( dwOutSize2 > 0 )
+ {
+ numFrames = dwOutSize2 / dsw->dsw_BytesPerOutputFrame;
+ PaUtil_Set2ndOutputFrameCount( &stream->bufferProcessor, numFrames );
+ PaUtil_Set2ndInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf2, 0 );
+ }
+ }
+
+ numFrames = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &result );
+ stream->framesWritten += numFrames;
+
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ /* Update our buffer offset and unlock sound buffer */
+ bytesProcessed = numFrames * dsw->dsw_BytesPerOutputFrame;
+ dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + bytesProcessed) % dsw->dsw_OutputSize;
+ IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2);
+ dsw->dsw_FramesWritten += numFrames;
+ }
+
+error1:
+ if( stream->bufferProcessor.inputChannelCount > 0 )
+ {
+ /* Update our buffer offset and unlock sound buffer */
+ bytesProcessed = numFrames * dsw->dsw_BytesPerInputFrame;
+ dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + bytesProcessed) % dsw->dsw_InputSize;
+ IDirectSoundCaptureBuffer_Unlock( dsw->dsw_InputBuffer, lpInBuf1, dwInSize1, lpInBuf2, dwInSize2);
+ }
+error2:
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, numFrames );
+
+ }
+
+ return result;
+}
+/*******************************************************************/
+static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+ PaWinDsStream *stream;
+
+ stream = (PaWinDsStream *) dwUser;
+ if( stream == NULL ) return;
+
+ if( stream->isActive )
+ {
+ if( stream->abortProcessing )
+ {
+ stream->isActive = 0;
+ }
+ else if( stream->stopProcessing )
+ {
+ DSoundWrapper *dsw = &stream->directSoundWrapper;
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ DSW_ZeroEmptySpace( dsw );
+ /* clear isActive when all sound played */
+ if( dsw->dsw_FramesPlayed >= stream->framesWritten )
+ {
+ stream->isActive = 0;
+ }
+ }
+ else
+ {
+ stream->isActive = 0;
+ }
+ }
+ else
+ {
+ if( Pa_TimeSlice( stream ) != 0) /* Call time slice independant of timing method. */
+ {
+ /* FIXME implement handling of paComplete and paAbort if possible */
+ stream->stopProcessing = 1;
+ }
+ }
+
+ if( !stream->isActive ){
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+ }
+ }
+}
+
+/***********************************************************************************
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ DSW_Term( &stream->directSoundWrapper );
+
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+/***********************************************************************************/
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+ HRESULT hr;
+
+ if( stream->bufferProcessor.inputChannelCount > 0 )
+ {
+ hr = DSW_StartInput( &stream->directSoundWrapper );
+ DBUG(("StartStream: DSW_StartInput returned = 0x%X.\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ }
+
+ stream->framesWritten = 0;
+
+ stream->abortProcessing = 0;
+ stream->stopProcessing = 0;
+ stream->isActive = 1;
+
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ /* Give user callback a chance to pre-fill buffer. REVIEW - i thought we weren't pre-filling, rb. */
+ result = Pa_TimeSlice( stream );
+ if( result != paNoError ) return result; // FIXME - what if finished?
+
+ hr = DSW_StartOutput( &stream->directSoundWrapper );
+ DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ }
+
+
+ /* Create timer that will wake us up so we can fill the DSound buffer. */
+ {
+ int resolution;
+ int framesPerWakeup = stream->framesPerDSBuffer / 4;
+ int msecPerWakeup = MSEC_PER_SECOND * framesPerWakeup / (int) stream->streamRepresentation.streamInfo.sampleRate;
+ if( msecPerWakeup < 10 ) msecPerWakeup = 10;
+ else if( msecPerWakeup > 100 ) msecPerWakeup = 100;
+ resolution = msecPerWakeup/4;
+ stream->timerID = timeSetEvent( msecPerWakeup, resolution, (LPTIMECALLBACK) Pa_TimerCallback,
+ (DWORD) stream, TIME_PERIODIC );
+ }
+ if( stream->timerID == 0 )
+ {
+ stream->isActive = 0;
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+
+ stream->isStarted = TRUE;
+
+error:
+ return result;
+}
+
+
+/***********************************************************************************/
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+ HRESULT hr;
+ int timeoutMsec;
+
+ stream->stopProcessing = 1;
+ /* Set timeout at 20% beyond maximum time we might wait. */
+ timeoutMsec = (int) (1200.0 * stream->framesPerDSBuffer / stream->streamRepresentation.streamInfo.sampleRate);
+ while( stream->isActive && (timeoutMsec > 0) )
+ {
+ Sleep(10);
+ timeoutMsec -= 10;
+ }
+ if( stream->timerID != 0 )
+ {
+ timeKillEvent(stream->timerID); /* Stop callback timer. */
+ stream->timerID = 0;
+ }
+
+
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ hr = DSW_StopOutput( &stream->directSoundWrapper );
+ }
+
+ if( stream->bufferProcessor.inputChannelCount > 0 )
+ {
+ hr = DSW_StopInput( &stream->directSoundWrapper );
+ }
+
+ stream->isStarted = FALSE;
+
+ return result;
+}
+
+
+/***********************************************************************************/
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ stream->abortProcessing = 1;
+ return StopStream( s );
+}
+
+
+/***********************************************************************************/
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ return !stream->isStarted;
+}
+
+
+/***********************************************************************************/
+static PaError IsStreamActive( PaStream *s )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ return stream->isActive;
+}
+
+/***********************************************************************************/
+static PaTime GetStreamTime( PaStream *s )
+{
+/*
+ new behavior for GetStreamTime is to return a stream based seconds clock
+ used for the outTime parameter to the callback.
+ FIXME: delete this comment when the other unnecessary related code has
+ been cleaned from this file.
+
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+ DSoundWrapper *dsw;
+ dsw = &stream->directSoundWrapper;
+ return dsw->dsw_FramesPlayed;
+*/
+ return PaUtil_GetTime();
+}
+
+
+/***********************************************************************************/
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
+
+/***********************************************************************************
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
+
+static PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return paNoError;
+}
+
+
+/***********************************************************************************/
+static PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return paNoError;
+}
+
+
+/***********************************************************************************/
+static signed long GetStreamReadAvailable( PaStream* s )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
+}
+
+
+/***********************************************************************************/
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
+}
+
+
+
diff --git a/pd/portaudio/pa_win_ds/portaudio.def b/pd/portaudio/pa_win_ds/portaudio.def
new file mode 100644
index 00000000..8012b99e
--- /dev/null
+++ b/pd/portaudio/pa_win_ds/portaudio.def
@@ -0,0 +1,28 @@
+LIBRARY PortAudio
+DESCRIPTION 'PortAudio Portable interface to audio HW'
+
+EXPORTS
+ ; Explicit exports can go here
+ Pa_Initialize @1
+ Pa_Terminate @2
+ Pa_GetHostError @3
+ Pa_GetErrorText @4
+ Pa_CountDevices @5
+ Pa_GetDefaultInputDeviceID @6
+ Pa_GetDefaultOutputDeviceID @7
+ Pa_GetDeviceInfo @8
+ Pa_OpenStream @9
+ Pa_OpenDefaultStream @10
+ Pa_CloseStream @11
+ Pa_StartStream @12
+ Pa_StopStream @13
+ Pa_StreamActive @14
+ Pa_StreamTime @15
+ Pa_GetCPULoad @16
+ Pa_GetMinNumBuffers @17
+ Pa_Sleep @18
+
+ ;123456789012345678901234567890123456
+ ;000000000111111111122222222223333333
+
+
diff --git a/pd/portaudio/pa_win_wmme/Makefile.cygwin b/pd/portaudio/pa_win_wmme/Makefile.cygwin
new file mode 100644
index 00000000..5cb4acef
--- /dev/null
+++ b/pd/portaudio/pa_win_wmme/Makefile.cygwin
@@ -0,0 +1,34 @@
+
+# Makefile for PortAudio on cygwin
+# Contributed by Bill Eldridge on 6/13/2001
+
+ARCH= pa_win_wmme
+
+TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c)
+
+.c.o:
+ -gcc -c -I./pa_common $< -o $*.o
+ -gcc $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm
+
+all: sharedlib tests
+
+sharedlib: ./pa_common/pa_lib.c
+ gcc -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o
+ gcc -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o
+ dlltool --export-all --output-def pa_win_wmme/pa_lib.def pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o
+ gcc -shared -Wl,--enable-auto-image-base -o pa_win_wmme/portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_win_wmme/pa_lib.def pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/lib/w32api -lwinmm
+ cp pa_win_wmme/portaudio.dll /usr/local/bin
+
+tests: $(TESTS:.c=.o)
+
+sine:
+ gcc -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o
+ gcc pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm
+
+clean:
+ -rm ./pa_tests/*.exe
+
+nothing:
+ gcc pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm
+
+
diff --git a/pd/portaudio/pa_win_wmme/pa_win_wmme.c b/pd/portaudio/pa_win_wmme/pa_win_wmme.c
new file mode 100644
index 00000000..2b1cc57d
--- /dev/null
+++ b/pd/portaudio/pa_win_wmme/pa_win_wmme.c
@@ -0,0 +1,2672 @@
+/*
+ * $Id: pa_win_wmme.c,v 1.6.2.44 2003/03/18 14:27:58 rossbencina Exp $
+ * pa_win_wmme.c
+ * Implementation of PortAudio for Windows MultiMedia Extensions (WMME)
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ *
+ * Authors: Ross Bencina and Phil Burk
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+/* Modification History:
+ PLB = Phil Burk
+ JM = Julien Maillard
+ RDB = Ross Bencina
+ PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer)
+ PLB20010413 - check for excessive numbers of channels
+ PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
+ including conditional inclusion of memory.h,
+ and explicit typecasting on memory allocation
+ PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory
+ PLB20010816 - pass process instead of thread to SetPriorityClass()
+ PLB20010927 - use number of frames instead of real-time for CPULoad calculation.
+ JM20020118 - prevent hung thread when buffers underflow.
+ PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount
+ RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init
+ RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices
+ refactoring, renaming and fixed a few edge case bugs
+ RDB20020531 - converted to V19 framework
+ ** NOTE maintanance history is now stored in CVS **
+*/
+
+/** @file
+
+ @todo Handle case where user supplied full duplex buffer sizes are not compatible
+ (must be common multiples)
+
+ @todo Fix buffer catch up code, can sometimes get stuck
+
+ @todo Implement "close sample rate matching" if needed - is this really needed
+ in mme?
+
+ @todo Investigate supporting host buffer formats > 16 bits
+
+ @todo Implement buffer size and number of buffers code,
+ this code should generate defaults the way the old code did
+
+ @todo implement underflow/overflow streamCallback statusFlags, paNeverDropInput.
+
+ @todo Fix fixmes
+
+ @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.)
+
+ @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
+
+ @todo implement IsFormatSupported
+
+ @todo implement PaDeviceInfo.defaultSampleRate;
+
+ @todo define UNICODE and _UNICODE in the project settings and see what breaks
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <windows.h>
+#include <mmsystem.h>
+#include <process.h>
+#include <assert.h>
+/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
+#ifndef __MWERKS__
+#include <malloc.h>
+#include <memory.h>
+#endif /* __MWERKS__ */
+
+#include "portaudio.h"
+#include "pa_trace.h"
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
+
+#include "pa_win_wmme.h"
+
+/************************************************* Constants ********/
+
+/* Switches for debugging. */
+#define PA_SIMULATE_UNDERFLOW_ (0) /* Set to one to force an underflow of the output buffer. */
+
+#define PA_USE_HIGH_LATENCY_ (0) /* For debugging glitches. */
+
+#if PA_USE_HIGH_LATENCY_
+ #define PA_MIN_MSEC_PER_HOST_BUFFER_ (100)
+ #define PA_MAX_MSEC_PER_HOST_BUFFER_ (300) /* Do not exceed unless user buffer exceeds */
+ #define PA_MIN_NUM_HOST_BUFFERS_ (4)
+ #define PA_MAX_NUM_HOST_BUFFERS_ (16) /* OK to exceed if necessary */
+ #define PA_WIN_9X_LATENCY_ (400)
+#else
+ #define PA_MIN_MSEC_PER_HOST_BUFFER_ (10)
+ #define PA_MAX_MSEC_PER_HOST_BUFFER_ (100) /* Do not exceed unless user buffer exceeds */
+ #define PA_MIN_NUM_HOST_BUFFERS_ (3)
+ #define PA_MAX_NUM_HOST_BUFFERS_ (16) /* OK to exceed if necessary */
+ #define PA_WIN_9X_LATENCY_ (200)
+#endif
+
+#define PA_MIN_TIMEOUT_MSEC_ (1000)
+
+/*
+** Use higher latency for NT because it is even worse at real-time
+** operation than Win9x.
+*/
+#define PA_WIN_NT_LATENCY_ (PA_WIN_9X_LATENCY_ * 2)
+#define PA_WIN_WDM_LATENCY_ (PA_WIN_9X_LATENCY_)
+
+
+static const char constInputMapperSuffix_[] = " - Input";
+static const char constOutputMapperSuffix_[] = " - Output";
+
+
+typedef struct PaWinMmeStream PaWinMmeStream; /* forward reference */
+
+/* prototypes for functions declared in this file */
+
+PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** stream,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData );
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate );
+static PaError CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+static signed long GetStreamReadAvailable( PaStream* stream );
+static signed long GetStreamWriteAvailable( PaStream* stream );
+
+static PaError UpdateStreamTime( PaWinMmeStream *stream );
+
+/* macros for setting last host error information */
+
+#ifdef UNICODE
+
+#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \
+ { \
+ wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \
+ char mmeErrorText[ MAXERRORLENGTH ]; \
+ waveInGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \
+ WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\
+ mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \
+ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
+ }
+
+#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \
+ { \
+ wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \
+ char mmeErrorText[ MAXERRORLENGTH ]; \
+ waveOutGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \
+ WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\
+ mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \
+ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
+ }
+
+#else /* !UNICODE */
+
+#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \
+ { \
+ char mmeErrorText[ MAXERRORLENGTH ]; \
+ waveInGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \
+ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
+ }
+
+#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \
+ { \
+ char mmeErrorText[ MAXERRORLENGTH ]; \
+ waveOutGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \
+ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
+ }
+
+#endif /* UNICODE */
+
+
+static void PaMme_SetLastSystemError( DWORD errorCode )
+{
+ LPVOID lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ errorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+ PaUtil_SetLastHostErrorInfo( paMME, errorCode, lpMsgBuf );
+ LocalFree( lpMsgBuf );
+}
+
+#define PA_MME_SET_LAST_SYSTEM_ERROR( errorCode ) \
+ PaMme_SetLastSystemError( errorCode )
+
+
+/* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */
+
+typedef struct
+{
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
+
+ PaUtilAllocationGroup *allocations;
+
+ int numInputDevices, numOutputDevices;
+
+ /** winMmeDeviceIds is an array of WinMme device ids.
+ fields in the range [0, numInputDevices) are input device ids,
+ and [numInputDevices, numInputDevices + numOutputDevices) are output
+ device ids.
+ */
+ int *winMmeDeviceIds;
+}
+PaWinMmeHostApiRepresentation;
+
+
+/*************************************************************************
+ * Returns recommended device ID.
+ * On the PC, the recommended device can be specified by the user by
+ * setting an environment variable. For example, to use device #1.
+ *
+ * set PA_RECOMMENDED_OUTPUT_DEVICE=1
+ *
+ * The user should first determine the available device ID by using
+ * the supplied application "pa_devs".
+ */
+#define PA_ENV_BUF_SIZE_ (32)
+#define PA_REC_IN_DEV_ENV_NAME_ ("PA_RECOMMENDED_INPUT_DEVICE")
+#define PA_REC_OUT_DEV_ENV_NAME_ ("PA_RECOMMENDED_OUTPUT_DEVICE")
+static PaDeviceIndex GetEnvDefaultDeviceID( char *envName )
+{
+ PaDeviceIndex recommendedIndex = paNoDevice;
+ DWORD hresult;
+ char envbuf[PA_ENV_BUF_SIZE_];
+
+#ifndef WIN32_PLATFORM_PSPC /* no GetEnvironmentVariable on PocketPC */
+
+ /* Let user determine default device by setting environment variable. */
+ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE_ );
+ if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE_) )
+ {
+ recommendedIndex = atoi( envbuf );
+ }
+#endif
+
+ return recommendedIndex;
+}
+
+static void InitializeDefaultDeviceIdsFromEnv( PaWinMmeHostApiRepresentation *hostApi )
+{
+ PaDeviceIndex device;
+
+ /* input */
+ device = GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME_ );
+ if( device != paNoDevice &&
+ ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
+ hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxInputChannels > 0 )
+ {
+ hostApi->inheritedHostApiRep.info.defaultInputDevice = device;
+ }
+
+ /* output */
+ device = GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME_ );
+ if( device != paNoDevice &&
+ ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
+ hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxOutputChannels > 0 )
+ {
+ hostApi->inheritedHostApiRep.info.defaultOutputDevice = device;
+ }
+}
+
+
+/** Convert external PA ID to a windows multimedia device ID
+*/
+static int LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hostApi, PaDeviceIndex device )
+{
+ assert( device >= 0 && device < hostApi->numInputDevices + hostApi->numOutputDevices );
+
+ return hostApi->winMmeDeviceIds[ device ];
+}
+
+
+static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
+ PaDeviceInfo *deviceInfo, int winMmeInputDeviceId, int *success )
+{
+ PaError result = paNoError;
+ char *deviceName; /* non-const ptr */
+ MMRESULT mmresult;
+ WAVEINCAPS wic;
+
+ *success = 0;
+
+ mmresult = waveInGetDevCaps( winMmeInputDeviceId, &wic, sizeof( WAVEINCAPS ) );
+ if( mmresult == MMSYSERR_NOMEM )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ else if( mmresult != MMSYSERR_NOERROR )
+ {
+ /* instead of returning paUnanticipatedHostError we return
+ paNoError, but leave success set as 0. This allows
+ Pa_Initialize to just ignore this device, without failing
+ the entire initialisation process.
+ */
+ return paNoError;
+ }
+
+ if( winMmeInputDeviceId == WAVE_MAPPER )
+ {
+ /* Append I/O suffix to WAVE_MAPPER device. */
+ deviceName = (char *)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, strlen( wic.szPname ) + 1 + sizeof(constInputMapperSuffix_) );
+ if( !deviceName )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ strcpy( deviceName, wic.szPname );
+ strcat( deviceName, constInputMapperSuffix_ );
+ }
+ else
+ {
+ deviceName = (char*)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, strlen( wic.szPname ) + 1 );
+ if( !deviceName )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ strcpy( deviceName, wic.szPname );
+ }
+ deviceInfo->name = deviceName;
+
+ deviceInfo->maxInputChannels = wic.wChannels;
+ /* Sometimes a device can return a rediculously large number of channels.
+ * This happened with an SBLive card on a Windows ME box.
+ * If that happens, then force it to 2 channels. PLB20010413
+ */
+ if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) )
+ {
+ PA_DEBUG(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxInputChannels ));
+ deviceInfo->maxInputChannels = 2;
+ }
+
+ deviceInfo->defaultSampleRate = 0.; /* @todo IMPLEMENT ME */
+
+ *success = 1;
+
+error:
+ return result;
+}
+
+
+static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
+ PaDeviceInfo *deviceInfo, int winMmeOutputDeviceId, int *success )
+{
+ PaError result = paNoError;
+ char *deviceName; /* non-const ptr */
+ MMRESULT mmresult;
+ WAVEOUTCAPS woc;
+
+ *success = 0;
+
+ mmresult = waveOutGetDevCaps( winMmeOutputDeviceId, &woc, sizeof( WAVEOUTCAPS ) );
+ if( mmresult == MMSYSERR_NOMEM )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ else if( mmresult != MMSYSERR_NOERROR )
+ {
+ /* instead of returning paUnanticipatedHostError we return
+ paNoError, but leave success set as 0. This allows
+ Pa_Initialize to just ignore this device, without failing
+ the entire initialisation process.
+ */
+ return paNoError;
+ }
+
+ if( winMmeOutputDeviceId == WAVE_MAPPER )
+ {
+ /* Append I/O suffix to WAVE_MAPPER device. */
+ deviceName = (char *)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, strlen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_) );
+ if( !deviceName )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ strcpy( deviceName, woc.szPname );
+ strcat( deviceName, constOutputMapperSuffix_ );
+ }
+ else
+ {
+ deviceName = (char*)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, strlen( woc.szPname ) + 1 );
+ if( !deviceName )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ strcpy( deviceName, woc.szPname );
+ }
+ deviceInfo->name = deviceName;
+
+ deviceInfo->maxOutputChannels = woc.wChannels;
+ /* Sometimes a device can return a rediculously large number of channels.
+ * This happened with an SBLive card on a Windows ME box.
+ * It also happens on Win XP!
+ */
+ if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) )
+ {
+ PA_DEBUG(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels ));
+ deviceInfo->maxOutputChannels = 2;
+ }
+
+ deviceInfo->defaultSampleRate = 0.; /* @todo IMPLEMENT ME */
+
+ *success = 1;
+
+error:
+ return result;
+}
+
+
+PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ int i;
+ PaWinMmeHostApiRepresentation *winMmeHostApi;
+ int numInputDevices, numOutputDevices, maximumPossibleNumDevices;
+ PaDeviceInfo *deviceInfoArray;
+ int deviceInfoInitializationSucceeded;
+
+ winMmeHostApi = (PaWinMmeHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinMmeHostApiRepresentation) );
+ if( !winMmeHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ winMmeHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !winMmeHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ *hostApi = &winMmeHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paMME;
+ (*hostApi)->info.name = "MME";
+
+
+ /* initialise device counts and default devices under the assumption that
+ there are no devices. These values are incremented below if and when
+ devices are successfully initialized.
+ */
+ (*hostApi)->info.deviceCount = 0;
+ (*hostApi)->info.defaultInputDevice = paNoDevice;
+ (*hostApi)->info.defaultOutputDevice = paNoDevice;
+ winMmeHostApi->numInputDevices = 0;
+ winMmeHostApi->numOutputDevices = 0;
+
+
+ maximumPossibleNumDevices = 0;
+
+ numInputDevices = waveInGetNumDevs();
+ if( numInputDevices > 0 )
+ maximumPossibleNumDevices += numInputDevices + 1; /* assume there is a WAVE_MAPPER */
+
+ numOutputDevices = waveOutGetNumDevs();
+ if( numOutputDevices > 0 )
+ maximumPossibleNumDevices += numOutputDevices + 1; /* assume there is a WAVE_MAPPER */
+
+
+ if( maximumPossibleNumDevices > 0 ){
+
+ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleNumDevices );
+ if( !(*hostApi)->deviceInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* allocate all device info structs in a contiguous block */
+ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, sizeof(PaDeviceInfo) * maximumPossibleNumDevices );
+ if( !deviceInfoArray )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ winMmeHostApi->winMmeDeviceIds = (int*)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, sizeof(int) * maximumPossibleNumDevices );
+ if( !winMmeHostApi->winMmeDeviceIds )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( numInputDevices > 0 ){
+ // -1 is the WAVE_MAPPER
+ for( i = -1; i < numInputDevices; ++i ){
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+
+ deviceInfo->maxInputChannels = 0;
+ deviceInfo->maxOutputChannels = 0;
+
+ deviceInfo->defaultLowInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultLowOutputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighOutputLatency = 0.; /* @todo IMPLEMENT ME */
+
+ result = InitializeInputDeviceInfo( winMmeHostApi, deviceInfo, i, &deviceInfoInitializationSucceeded );
+ if( result != paNoError )
+ goto error;
+
+ if( deviceInfoInitializationSucceeded ){
+ if( (*hostApi)->info.defaultInputDevice == paNoDevice )
+ (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
+
+ winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = i;
+ (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
+
+ winMmeHostApi->numInputDevices++;
+ (*hostApi)->info.deviceCount++;
+ }
+ }
+ }
+
+ if( numOutputDevices > 0 ){
+ // -1 is the WAVE_MAPPER
+ for( i = -1; i < numOutputDevices; ++i ){
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+
+ deviceInfo->maxInputChannels = 0;
+ deviceInfo->maxOutputChannels = 0;
+
+ deviceInfo->defaultLowInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultLowOutputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighOutputLatency = 0.; /* @todo IMPLEMENT ME */
+
+ result = InitializeOutputDeviceInfo( winMmeHostApi, deviceInfo, i, &deviceInfoInitializationSucceeded );
+ if( result != paNoError )
+ goto error;
+
+ if( deviceInfoInitializationSucceeded ){
+ if( (*hostApi)->info.defaultOutputDevice == paNoDevice )
+ (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
+
+ winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = i;
+ (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
+
+ winMmeHostApi->numOutputDevices++;
+ (*hostApi)->info.deviceCount++;
+ }
+ }
+ }
+ }
+
+
+ InitializeDefaultDeviceIdsFromEnv( winMmeHostApi );
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &winMmeHostApi->blockingStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+
+ return result;
+
+error:
+ if( winMmeHostApi )
+ {
+ if( winMmeHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( winMmeHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( winMmeHostApi );
+ }
+
+ return result;
+}
+
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
+
+ if( winMmeHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( winMmeHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( winMmeHostApi );
+}
+
+
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
+{
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ /*
+ IMPLEMENT ME:
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+ */
+
+ return paFormatIsSupported;
+}
+
+
+/* CalculateBufferSettings() fills the framesPerHostInputBuffer, numHostInputBuffers,
+ framesPerHostOutputBuffer and numHostOutputBuffers parameters based on the values
+ of the other parameters.
+
+*/
+
+static PaError CalculateBufferSettings(
+ unsigned long *framesPerHostInputBuffer, unsigned long *numHostInputBuffers,
+ unsigned long *framesPerHostOutputBuffer, unsigned long *numHostOutputBuffers,
+ int inputChannelCount, PaSampleFormat hostInputSampleFormat,
+ PaTime suggestedInputLatency, PaWinMmeStreamInfo *inputStreamInfo,
+ int outputChannelCount, PaSampleFormat hostOutputSampleFormat,
+ PaTime suggestedOutputLatency, PaWinMmeStreamInfo *outputStreamInfo,
+ double sampleRate, unsigned long framesPerBuffer )
+{
+ PaError result = paNoError;
+
+ if( inputChannelCount > 0 )
+ {
+ if( inputStreamInfo )
+ {
+ if( inputStreamInfo->flags & PaWinMmeUseLowLevelLatencyParameters )
+ {
+ if( inputStreamInfo->numBuffers <= 0
+ || inputStreamInfo->framesPerBuffer <= 0 )
+ {
+ result = paIncompatibleHostApiSpecificStreamInfo;
+ goto error;
+ }
+
+ *framesPerHostInputBuffer = inputStreamInfo->framesPerBuffer;
+ *numHostInputBuffers = inputStreamInfo->numBuffers;
+ }
+ }
+ else
+ {
+ /* hardwire for now, FIXME */
+ /* don't forget that there will be one more buffer than the number required to achieve the requested latency */
+ *framesPerHostInputBuffer = 4096;
+ *numHostInputBuffers = 4;
+
+ /*
+ Need to determine the right heuristic for mapping latency in
+ seconds to buffer sizes and number of buffers.
+
+ - for output don't allocate less than 1+1 buffers
+
+ - for input don't allocate less than 2+1 buffers
+ (less than 1+1 if input only)
+
+ - don't allocate buffers smaller than framesPerBuffer
+
+ - if the client doesn't care about the buffer size use a power
+ of two buffer size. otherwise use a multiple of the user
+ buffer size. if the user buffer size is a power of 2, it
+ might be wise to make the host buffer size a power of 2 too.
+
+ - there probably shouldn't be too many buffers ( 3 to 10 seems
+ reasonable).
+
+ - aside from a limit on what constitutes a "reasonable" number
+ of buffers, there should be as many buffers as possible,
+ because this will place a less bursty load on CPU resources
+
+ - the host buffers should be as big as practical (ie multiple
+ user buffers per host buffer).
+
+
+ . One way to achieve the above is to say: Try to have 8
+ host buffers, and host buffers cannot be larger than 32k
+ unless the user buffer size requires it"
+ I say 32k because buffers larger than this are known to
+ crash some drivers (Turtle Beach for example.)
+
+ just some idle rambling:
+
+ if( framesPerBuffer == 0 ){
+ // use a power of two buffer size
+
+ }else{
+ latencySamples = ceil(requestedLatency * sampleRate)
+
+ numBuffers = ceil(latencySamples / framesPerBuffer);
+
+ bufferSize = framesPerBuffer;
+
+ minBuffers = ( inputChannelCount > 0 && outputChannelCount > 0 ) ? 2 : 1;
+
+ if( numBuffers <= minBuffers ){
+ numBuffers = minBuffers;
+ }else{
+ make buffer size a multiple of framesPerBuffer until numBuffers is
+ greater than 4 and less than 10.
+ }
+ }
+ */
+ }
+ }
+ else
+ {
+ *framesPerHostInputBuffer = 0;
+ *numHostInputBuffers = 0;
+ }
+
+ if( outputChannelCount > 0 )
+ {
+ if( outputStreamInfo )
+ {
+ if( outputStreamInfo->flags & PaWinMmeUseLowLevelLatencyParameters )
+ {
+ if( outputStreamInfo->numBuffers <= 0
+ || outputStreamInfo->framesPerBuffer <= 0 )
+ {
+ result = paIncompatibleHostApiSpecificStreamInfo;
+ goto error;
+ }
+
+ *framesPerHostOutputBuffer = outputStreamInfo->framesPerBuffer;
+ *numHostOutputBuffers = outputStreamInfo->numBuffers;
+ }
+ }
+ else
+ {
+ /* hardwire for now, FIXME */
+ /* don't forget that there will be one more buffer than the number required to achieve the requested latency */
+ *framesPerHostOutputBuffer = 4096;
+ *numHostOutputBuffers = 4;
+ }
+ }
+ else
+ {
+ *framesPerHostOutputBuffer = 0;
+ *numHostOutputBuffers = 0;
+ }
+
+error:
+ return result;
+}
+
+
+
+typedef HWAVEIN MmeHandle;
+
+static PaError InitializeBufferSet( WAVEHDR **bufferSet, int numBuffers, int bufferBytes,
+ int isInput, /* if 0, then output */
+ MmeHandle mmeWaveHandle, int numDeviceChannels )
+{
+ PaError result = paNoError;
+ MMRESULT mmresult;
+ int i;
+
+ *bufferSet = 0;
+
+ /* Allocate an array to hold the buffer pointers. */
+ *bufferSet = (WAVEHDR *) PaUtil_AllocateMemory( sizeof(WAVEHDR)*numBuffers );
+ if( !*bufferSet )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i=0; i<numBuffers; ++i )
+ {
+ (*bufferSet)[i].lpData = 0;
+ }
+
+ /* Allocate each buffer. */
+ for( i=0; i<numBuffers; ++i )
+ {
+ (*bufferSet)[i].lpData = (char *)PaUtil_AllocateMemory( bufferBytes );
+ if( !(*bufferSet)[i].lpData )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ (*bufferSet)[i].dwBufferLength = bufferBytes;
+ (*bufferSet)[i].dwUser = 0xFFFFFFFF; /* indicates unprepared to error clean up code */
+
+ if( isInput )
+ {
+ mmresult = waveInPrepareHeader( mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ goto error;
+ }
+ }
+ else /* output */
+ {
+ mmresult = waveOutPrepareHeader( (HWAVEOUT)mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ goto error;
+ }
+ }
+
+ (*bufferSet)[i].dwUser = numDeviceChannels;
+ }
+
+ return result;
+
+error:
+ if( *bufferSet )
+ {
+ for( i=0; i<numBuffers; ++i )
+ {
+ if( (*bufferSet)[i].lpData )
+ {
+
+ if( (*bufferSet)[i].dwUser != 0xFFFFFFFF )
+ {
+ if( isInput )
+ waveInUnprepareHeader( mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+ else
+ waveOutUnprepareHeader( (HWAVEOUT)mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+ }
+ PaUtil_FreeMemory( (*bufferSet)[i].lpData );
+ }
+ }
+
+ PaUtil_FreeMemory( *bufferSet );
+ }
+
+ return result;
+}
+
+
+static void TerminateBufferSet( WAVEHDR * *bufferSet, unsigned int numBuffers, int isInput, MmeHandle mmeWaveHandle )
+{
+ unsigned int i;
+
+ for( i=0; i<numBuffers; ++i )
+ {
+ if( (*bufferSet)[i].lpData )
+ {
+ if( isInput )
+ waveInUnprepareHeader( mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+ else
+ waveOutUnprepareHeader( (HWAVEOUT)mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+
+ PaUtil_FreeMemory( (*bufferSet)[i].lpData );
+ }
+ }
+
+ if( *bufferSet )
+ PaUtil_FreeMemory( *bufferSet );
+}
+
+
+/* PaWinMmeStream - a stream data structure specifically for this implementation */
+
+typedef struct PaWinMmeStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ CRITICAL_SECTION lock;
+
+ /* Input -------------- */
+ HWAVEIN *hWaveIns;
+ unsigned int numInputDevices;
+ /* unsigned int inputChannelCount; */
+ WAVEHDR **inputBuffers;
+ unsigned int numInputBuffers;
+ unsigned int currentInputBufferIndex;
+ unsigned int framesPerInputBuffer;
+ unsigned int framesUsedInCurrentInputBuffer;
+
+ /* Output -------------- */
+ HWAVEOUT *hWaveOuts;
+ unsigned int numOutputDevices;
+ /* unsigned int outputChannelCount; */
+ WAVEHDR **outputBuffers;
+ unsigned int numOutputBuffers;
+ unsigned int currentOutputBufferIndex;
+ unsigned int framesPerOutputBuffer;
+ unsigned int framesUsedInCurrentOutputBuffer;
+
+ /* Processing thread management -------------- */
+ HANDLE abortEvent;
+ HANDLE bufferEvent;
+ HANDLE processingThread;
+ DWORD processingThreadId;
+
+ char noHighPriorityProcessClass;
+ char useTimeCriticalProcessingThreadPriority;
+ char throttleProcessingThreadOnOverload; /* 0 -> don't throtte, non-0 -> throttle */
+ int processingThreadPriority;
+ int highThreadPriority;
+ int throttledThreadPriority;
+
+ volatile int isActive;
+ volatile int stopProcessing; /* stop thread once existing buffers have been returned */
+ volatile int abortProcessing; /* stop thread immediately */
+
+ DWORD allBuffersDurationMs; /* used to calculate timeouts */
+
+ /* @todo FIXME: we no longer need the following for GetStreamTime support */
+ /* GetStreamTime() support ------------- */
+
+ PaTime streamPosition;
+ long previousStreamPosition; /* used to track frames played. */
+}
+PaWinMmeStream;
+
+
+/* the following macros are intended to improve the readability of the following code */
+#define PA_IS_INPUT_STREAM_( stream ) ( stream ->hWaveIns )
+#define PA_IS_OUTPUT_STREAM_( stream ) ( stream ->hWaveOuts )
+#define PA_IS_FULL_DUPLEX_STREAM_( stream ) ( stream ->hWaveIns && stream ->hWaveOuts )
+
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
+ PaWinMmeStream *stream = 0;
+ PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+ double suggestedInputLatency, suggestedOutputLatency;
+ PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo;
+ unsigned long bytesPerInputFrame, bytesPerOutputFrame;
+ unsigned long framesPerHostInputBuffer;
+ unsigned long numHostInputBuffers;
+ unsigned long framesPerHostOutputBuffer;
+ unsigned long numHostOutputBuffers;
+ unsigned long framesPerBufferProcessorCall;
+ int lockInited = 0;
+ int bufferEventInited = 0;
+ int abortEventInited = 0;
+ WAVEFORMATEX wfx;
+ MMRESULT mmresult;
+ unsigned int i;
+ int channelCount;
+ PaWinMmeDeviceAndChannelCount *inputDevices = 0;
+ unsigned long numInputDevices = (inputParameters) ? 1 : 0;
+ PaWinMmeDeviceAndChannelCount *outputDevices = 0;
+ unsigned long numOutputDevices = (outputParameters) ? 1 : 0;
+ char noHighPriorityProcessClass = 0;
+ char useTimeCriticalProcessingThreadPriority = 0;
+ char throttleProcessingThreadOnOverload = 1;
+
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+ suggestedInputLatency = inputParameters->suggestedLatency;
+
+ /* check that input device can support inputChannelCount */
+ if( (inputParameters->device != paUseHostApiSpecificDeviceSpecification) &&
+ (inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels) )
+ return paInvalidChannelCount;
+
+
+ /* validate input hostApiSpecificStreamInfo */
+ inputStreamInfo = (PaWinMmeStreamInfo*)inputParameters->hostApiSpecificStreamInfo;
+ if( inputStreamInfo )
+ {
+ if( inputStreamInfo->size != sizeof( PaWinMmeStreamInfo )
+ || inputStreamInfo->version != 1 )
+ {
+ return paIncompatibleHostApiSpecificStreamInfo;
+ }
+
+ if( inputStreamInfo->flags & PaWinMmeNoHighPriorityProcessClass )
+ noHighPriorityProcessClass = 1;
+ if( inputStreamInfo->flags & PaWinMmeDontThrottleOverloadedProcessingThread )
+ throttleProcessingThreadOnOverload = 0;
+ if( inputStreamInfo->flags & PaWinMmeUseTimeCriticalThreadPriority )
+ useTimeCriticalProcessingThreadPriority = 1;
+
+ /* validate multidevice fields */
+
+ if( inputStreamInfo->flags & PaWinMmeUseMultipleDevices )
+ {
+ int totalChannels = 0;
+ for( i=0; i< inputStreamInfo->deviceCount; ++i )
+ {
+ /* validate that the device number is within range, and that
+ the number of channels is legal */
+ PaDeviceIndex hostApiDevice;
+
+ if( inputParameters->device != paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ channelCount = inputStreamInfo->devices[i].channelCount;
+
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
+ inputStreamInfo->devices[i].device, hostApi );
+ if( result != paNoError )
+ return result;
+
+ if( channelCount < 1 || channelCount > hostApi->deviceInfos[ hostApiDevice ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* FIXME this validation might be easier and better if there was a pautil
+ function which performed the validation in pa_front:ValidateOpenStreamParameters() */
+
+ totalChannels += channelCount;
+ }
+
+ if( totalChannels != inputChannelCount )
+ {
+ /* inputChannelCount must match total channels specified by multiple devices */
+ return paInvalidChannelCount; /* REVIEW use of this error code */
+ }
+
+ inputDevices = inputStreamInfo->devices;
+ numInputDevices = inputStreamInfo->deviceCount;
+ }
+ }
+
+ /* FIXME: establish which host formats are available */
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
+
+ }
+ else
+ {
+ inputChannelCount = 0;
+ inputSampleFormat = -1;
+ suggestedInputLatency = 0.;
+ inputStreamInfo = 0;
+ hostInputSampleFormat = -1;
+ }
+
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+ suggestedOutputLatency = outputParameters->suggestedLatency;
+
+ /* check that input device can support inputChannelCount */
+ if( (outputParameters->device != paUseHostApiSpecificDeviceSpecification) &&
+ (inputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels) )
+ return paInvalidChannelCount;
+
+
+ /* validate input hostApiSpecificStreamInfo */
+ outputStreamInfo = (PaWinMmeStreamInfo*)outputParameters->hostApiSpecificStreamInfo;
+ if( outputStreamInfo )
+ {
+ if( outputStreamInfo->size != sizeof( PaWinMmeStreamInfo )
+ || outputStreamInfo->version != 1 )
+ {
+ return paIncompatibleHostApiSpecificStreamInfo;
+ }
+
+ if( outputStreamInfo->flags & PaWinMmeNoHighPriorityProcessClass )
+ noHighPriorityProcessClass = 1;
+ if( outputStreamInfo->flags & PaWinMmeDontThrottleOverloadedProcessingThread )
+ throttleProcessingThreadOnOverload = 0;
+ if( outputStreamInfo->flags & PaWinMmeUseTimeCriticalThreadPriority )
+ useTimeCriticalProcessingThreadPriority = 1;
+
+ /* validate multidevice fields */
+
+ if( outputStreamInfo->flags & PaWinMmeUseMultipleDevices )
+ {
+ int totalChannels = 0;
+ for( i=0; i< outputStreamInfo->deviceCount; ++i )
+ {
+ /* validate that the device number is within range, and that
+ the number of channels is legal */
+ PaDeviceIndex hostApiDevice;
+
+ if( outputParameters->device != paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ channelCount = outputStreamInfo->devices[i].channelCount;
+
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
+ outputStreamInfo->devices[i].device,
+ hostApi );
+ if( result != paNoError )
+ return result;
+
+ if( channelCount < 1 || channelCount > hostApi->deviceInfos[ hostApiDevice ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* FIXME this validation might be easier and better if there was a pautil
+ function which performed the validation in pa_front:ValidateOpenStreamParameters() */
+
+ totalChannels += channelCount;
+ }
+
+ if( totalChannels != outputChannelCount )
+ {
+ /* outputChannelCount must match total channels specified by multiple devices */
+ return paInvalidChannelCount; /* REVIEW use of this error code */
+ }
+
+ outputDevices = outputStreamInfo->devices;
+ numOutputDevices = outputStreamInfo->deviceCount;
+ }
+ }
+
+ /* FIXME: establish which host formats are available */
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
+ }
+ else
+ {
+ outputChannelCount = 0;
+ outputSampleFormat = -1;
+ outputStreamInfo = 0;
+ hostOutputSampleFormat = -1;
+ suggestedOutputLatency = 0.;
+ }
+
+
+ /*
+ IMPLEMENT ME:
+ - alter sampleRate to a close allowable rate if possible / necessary
+ */
+
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
+
+
+ result = CalculateBufferSettings( &framesPerHostInputBuffer, &numHostInputBuffers,
+ &framesPerHostOutputBuffer, &numHostOutputBuffers,
+ inputChannelCount, hostInputSampleFormat, suggestedInputLatency, inputStreamInfo,
+ outputChannelCount, hostOutputSampleFormat, suggestedOutputLatency, outputStreamInfo,
+ sampleRate, framesPerBuffer );
+ if( result != paNoError )
+ goto error;
+
+
+ stream = (PaWinMmeStream*)PaUtil_AllocateMemory( sizeof(PaWinMmeStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ stream->hWaveIns = 0;
+ stream->inputBuffers = 0;
+ stream->hWaveOuts = 0;
+ stream->outputBuffers = 0;
+ stream->processingThread = 0;
+
+ stream->noHighPriorityProcessClass = noHighPriorityProcessClass;
+ stream->useTimeCriticalProcessingThreadPriority = useTimeCriticalProcessingThreadPriority;
+ stream->throttleProcessingThreadOnOverload = throttleProcessingThreadOnOverload;
+
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &winMmeHostApi->callbackStreamInterface, streamCallback, userData );
+
+ stream->streamRepresentation.streamInfo.inputLatency = (double)(framesPerHostInputBuffer * (numHostInputBuffers-1)) / sampleRate;
+ stream->streamRepresentation.streamInfo.outputLatency = (double)(framesPerHostOutputBuffer * (numHostOutputBuffers-1)) / sampleRate;
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+
+ if( inputParameters && outputParameters ) /* full duplex */
+ {
+ /*
+ either host input and output buffers must be the same size, or the
+ larger one must be an integer multiple of the smaller one.
+ FIXME: should this return an error if the host specific latency
+ settings don't fulfill these constraints? rb: probably
+ */
+
+ if( framesPerHostInputBuffer < framesPerHostOutputBuffer )
+ {
+ assert( (framesPerHostOutputBuffer % framesPerHostInputBuffer) == 0 );
+
+ framesPerBufferProcessorCall = framesPerHostInputBuffer;
+ }
+ else
+ {
+ assert( (framesPerHostInputBuffer % framesPerHostOutputBuffer) == 0 );
+
+ framesPerBufferProcessorCall = framesPerHostOutputBuffer;
+ }
+ }
+ else if( inputParameters )
+ {
+ framesPerBufferProcessorCall = framesPerHostInputBuffer;
+ }
+ else if( outputParameters )
+ {
+ framesPerBufferProcessorCall = framesPerHostOutputBuffer;
+ }
+
+ stream->framesPerInputBuffer = framesPerHostInputBuffer;
+ stream->framesPerOutputBuffer = framesPerHostOutputBuffer;
+
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ inputChannelCount, inputSampleFormat, hostInputSampleFormat,
+ outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer,
+ framesPerBufferProcessorCall, paUtilFixedHostBufferSize,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+
+ stream->isActive = 0;
+
+ stream->streamPosition = 0.;
+ stream->previousStreamPosition = 0;
+
+
+ stream->bufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if( stream->bufferEvent == NULL )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+ bufferEventInited = 1;
+
+ if( inputParameters )
+ {
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nSamplesPerSec = (DWORD) sampleRate;
+ wfx.cbSize = 0;
+
+ stream->numInputDevices = numInputDevices;
+ stream->hWaveIns = (HWAVEIN*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * stream->numInputDevices );
+ if( !stream->hWaveIns )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i = 0; i < stream->numInputDevices; ++i )
+ stream->hWaveIns[i] = 0;
+
+ for( i = 0; i < stream->numInputDevices; ++i )
+ {
+ int inputWinMmeId;
+
+ if( inputDevices )
+ {
+ PaDeviceIndex hostApiDevice;
+
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
+ inputDevices[i].device, hostApi );
+ if( result != paNoError )
+ return result;
+
+ inputWinMmeId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, hostApiDevice );
+ wfx.nChannels = (WORD) inputDevices[i].channelCount;
+ }
+ else
+ {
+ inputWinMmeId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputParameters->device );
+ wfx.nChannels = (WORD) inputChannelCount;
+ }
+
+ bytesPerInputFrame = wfx.nChannels * stream->bufferProcessor.bytesPerHostInputSample;
+
+ wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * sampleRate);
+ wfx.nBlockAlign = (WORD)bytesPerInputFrame;
+ wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/wfx.nChannels) * 8);
+
+ /* REVIEW: consider not firing an event for input when a full duplex stream is being used */
+
+ mmresult = waveInOpen( &stream->hWaveIns[i], inputWinMmeId, &wfx,
+ (DWORD)stream->bufferEvent, (DWORD) stream, CALLBACK_EVENT );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ switch( mmresult )
+ {
+ case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
+ result = paDeviceUnavailable;
+ break;
+ case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
+ result = paInternalError; /* portaudio should ensure that only good device ids are used */
+ break;
+ case MMSYSERR_NODRIVER: /* No device driver is present. */
+ result = paDeviceUnavailable;
+ break;
+ case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
+ result = paInsufficientMemory;
+ break;
+ case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
+ result = paInternalError; /* REVIEW: port audio shouldn't get this far without using compatible format info */
+ break;
+ default:
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ }
+ goto error;
+ }
+ }
+ }
+
+ if( outputParameters )
+ {
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nSamplesPerSec = (DWORD) sampleRate;
+ wfx.cbSize = 0;
+
+ stream->numOutputDevices = numOutputDevices;
+ stream->hWaveOuts = (HWAVEOUT*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * stream->numOutputDevices );
+ if( !stream->hWaveOuts )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i = 0; i < stream->numOutputDevices; ++i )
+ stream->hWaveOuts[i] = 0;
+
+ for( i = 0; i < stream->numOutputDevices; ++i )
+ {
+ int outputWinMmeId;
+
+ if( outputDevices )
+ {
+ PaDeviceIndex hostApiDevice;
+
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
+ outputDevices[i].device, hostApi );
+ if( result != paNoError )
+ return result;
+
+ outputWinMmeId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, hostApiDevice );
+ wfx.nChannels = (WORD) outputDevices[i].channelCount;
+ }
+ else
+ {
+ outputWinMmeId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputParameters->device );
+ wfx.nChannels = (WORD) outputChannelCount;
+ }
+
+ bytesPerOutputFrame = wfx.nChannels * stream->bufferProcessor.bytesPerHostOutputSample;
+
+ wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * sampleRate);
+ wfx.nBlockAlign = (WORD)bytesPerOutputFrame;
+ wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/wfx.nChannels) * 8);
+
+ mmresult = waveOutOpen( &stream->hWaveOuts[i], outputWinMmeId, &wfx,
+ (DWORD)stream->bufferEvent, (DWORD) stream, CALLBACK_EVENT );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ switch( mmresult )
+ {
+ case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
+ result = paDeviceUnavailable;
+ break;
+ case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
+ result = paInternalError; /* portaudio should ensure that only good device ids are used */
+ break;
+ case MMSYSERR_NODRIVER: /* No device driver is present. */
+ result = paDeviceUnavailable;
+ break;
+ case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
+ result = paInsufficientMemory;
+ break;
+ case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
+ result = paInternalError; /* REVIEW: port audio shouldn't get this far without using compatible format info */
+ break;
+ default:
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ }
+ goto error;
+ }
+ }
+ }
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ stream->inputBuffers = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * stream->numInputDevices );
+ if( stream->inputBuffers == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i =0; i < stream->numInputDevices; ++i )
+ stream->inputBuffers[i] = 0;
+
+ stream->numInputBuffers = numHostInputBuffers;
+
+ for( i =0; i < stream->numInputDevices; ++i )
+ {
+ int hostInputBufferBytes = Pa_GetSampleSize( hostInputSampleFormat ) *
+ framesPerHostInputBuffer *
+ ((inputDevices) ? inputDevices[i].channelCount : inputChannelCount);
+ if( hostInputBufferBytes < 0 )
+ {
+ result = paInternalError;
+ goto error;
+ }
+
+ result = InitializeBufferSet( &stream->inputBuffers[i], numHostInputBuffers, hostInputBufferBytes,
+ 1 /* isInput */,
+ (MmeHandle)stream->hWaveIns[i],
+ ((inputDevices) ? inputDevices[i].channelCount : inputChannelCount) );
+
+ if( result != paNoError )
+ goto error;
+ }
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ stream->outputBuffers = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * stream->numOutputDevices );
+ if( stream->outputBuffers == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i =0; i < stream->numOutputDevices; ++i )
+ stream->outputBuffers[i] = 0;
+
+ stream->numOutputBuffers = numHostOutputBuffers;
+
+ for( i=0; i < stream->numOutputDevices; ++i )
+ {
+ int hostOutputBufferBytes = Pa_GetSampleSize( hostOutputSampleFormat ) *
+ framesPerHostOutputBuffer *
+ ((outputDevices) ? outputDevices[i].channelCount : outputChannelCount);
+ if( hostOutputBufferBytes < 0 )
+ {
+ result = paInternalError;
+ goto error;
+ }
+
+ result = InitializeBufferSet( &stream->outputBuffers[i], numHostOutputBuffers, hostOutputBufferBytes,
+ 0 /* not isInput */,
+ (MmeHandle)stream->hWaveOuts[i],
+ ((outputDevices) ? outputDevices[i].channelCount : outputChannelCount) );
+
+ if( result != paNoError )
+ goto error;
+ }
+ }
+
+ stream->abortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ if( stream->abortEvent == NULL )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+ abortEventInited = 1;
+
+ InitializeCriticalSection( &stream->lock );
+ lockInited = 1;
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostOutputBuffer * stream->numOutputBuffers) / sampleRate);
+ else
+ stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostInputBuffer * stream->numInputBuffers) / sampleRate);
+
+
+ *s = (PaStream*)stream;
+
+ return result;
+
+error:
+ if( lockInited )
+ DeleteCriticalSection( &stream->lock );
+
+ if( abortEventInited )
+ CloseHandle( stream->abortEvent );
+
+
+ if( stream->inputBuffers )
+ {
+ for( i =0 ; i< stream->numInputDevices; ++i )
+ {
+ if( stream->inputBuffers[i] )
+ {
+ TerminateBufferSet( &stream->inputBuffers[i], stream->numInputBuffers,
+ 1 /* isInput */, (MmeHandle)stream->hWaveIns[i] );
+ }
+ }
+
+ PaUtil_FreeMemory( stream->inputBuffers );
+ }
+
+ if( stream->outputBuffers )
+ {
+ for( i =0 ; i< stream->numOutputDevices; ++i )
+ {
+ if( stream->outputBuffers[i] )
+ {
+ TerminateBufferSet( &stream->outputBuffers[i], stream->numOutputBuffers,
+ 0 /* not isInput */, (MmeHandle)stream->hWaveOuts[i] );
+ }
+ }
+
+ PaUtil_FreeMemory( stream->outputBuffers );
+ }
+
+ if( stream->hWaveIns )
+ {
+ for( i =0 ; i< stream->numInputDevices; ++i )
+ {
+ if( stream->hWaveIns[i] )
+ waveInClose( stream->hWaveIns[i] );
+ }
+
+ PaUtil_FreeMemory( stream->hWaveIns );
+ }
+
+ if( stream->hWaveOuts )
+ {
+ for( i =0 ; i< stream->numOutputDevices; ++i )
+ {
+ if( stream->hWaveOuts[i] )
+ waveOutClose( stream->hWaveOuts[i] );
+ }
+
+ PaUtil_FreeMemory( stream->hWaveOuts );
+ }
+
+ if( bufferEventInited )
+ CloseHandle( stream->bufferEvent );
+
+ if( stream )
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+/* return non-zero if any output buffers are queued */
+static int OutputBuffersAreQueued( PaWinMmeStream *stream )
+{
+ int result = 0;
+ unsigned int i, j;
+
+ if( PA_IS_OUTPUT_STREAM_( stream ) )
+ {
+ for( i=0; i<stream->numOutputBuffers; ++i )
+ {
+ for( j=0; j < stream->numOutputDevices; ++j )
+ {
+ if( !( stream->outputBuffers[ j ][ i ].dwFlags & WHDR_DONE) )
+ {
+ result++;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+
+static PaError AdvanceToNextInputBuffer( PaWinMmeStream *stream )
+{
+ PaError result = paNoError;
+ MMRESULT mmresult;
+ unsigned int i;
+
+ for( i=0; i< stream->numInputDevices; ++i )
+ {
+ mmresult = waveInAddBuffer( stream->hWaveIns[i],
+ &stream->inputBuffers[i][ stream->currentInputBufferIndex ],
+ sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ }
+ }
+ stream->currentInputBufferIndex = (stream->currentInputBufferIndex+1 >= stream->numInputBuffers) ?
+ 0 : stream->currentInputBufferIndex+1;
+
+ stream->framesUsedInCurrentInputBuffer = 0;
+
+ return result;
+}
+
+
+static PaError AdvanceToNextOutputBuffer( PaWinMmeStream *stream )
+{
+ PaError result = paNoError;
+ MMRESULT mmresult;
+ unsigned int i;
+
+ for( i=0; i< stream->numOutputDevices; ++i )
+ {
+ mmresult = waveOutWrite( stream->hWaveOuts[i],
+ &stream->outputBuffers[i][ stream->currentOutputBufferIndex ],
+ sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ }
+ }
+
+ stream->currentOutputBufferIndex = (stream->currentOutputBufferIndex+1 >= stream->numOutputBuffers) ?
+ 0 : stream->currentOutputBufferIndex+1;
+
+ stream->framesUsedInCurrentOutputBuffer = 0;
+
+ return result;
+}
+
+
+static DWORD WINAPI ProcessingThreadProc( void *pArg )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream *)pArg;
+ HANDLE events[2];
+ int numEvents = 0;
+ DWORD result = paNoError;
+ DWORD waitResult;
+/** @todo:
+Gordon Gidluck:
+> function: ProcessingThreadProc()
+> line #1665 DWORD timeout = stream->allBuffersDurationMs * 0.5;
+> conversion from 'double ' to 'unsigned long ', possible loss of data
+*/
+ DWORD timeout = stream->allBuffersDurationMs * 0.5;
+ DWORD numTimeouts = 0;
+ int hostBuffersAvailable;
+ signed int hostInputBufferIndex, hostOutputBufferIndex;
+ int callbackResult;
+ int done = 0;
+ unsigned int channel, i, j;
+ unsigned long framesProcessed;
+
+ /* prepare event array for call to WaitForMultipleObjects() */
+ events[numEvents++] = stream->bufferEvent;
+ events[numEvents++] = stream->abortEvent;
+
+ /* loop until something causes us to stop */
+ while( !done )
+ {
+ /* wait for MME to signal that a buffer is available, or for
+ the PA abort event to be signaled */
+ waitResult = WaitForMultipleObjects( numEvents, events, FALSE, timeout );
+ if( waitResult == WAIT_FAILED )
+ {
+ result = paUnanticipatedHostError;
+ /* FIXME/REVIEW: can't return host error info from an asyncronous thread */
+ done = 1;
+ }
+ else if( waitResult == WAIT_TIMEOUT )
+ {
+ /* if a timeout is encountered, continue */
+ numTimeouts += 1;
+ }
+
+ if( stream->abortProcessing )
+ {
+ /* Pa_AbortStream() has been called, stop processing immediately */
+ done = 1;
+ }
+ else if( stream->stopProcessing )
+ {
+ /* Pa_StopStream() has been called or the user callback returned
+ non-zero, processing will continue until all output buffers
+ are marked as done. The stream will stop immediately if it
+ is input-only.
+ */
+
+ if( !OutputBuffersAreQueued( stream ) )
+ {
+ done = 1; /* Will cause thread to return. */
+ }
+ }
+ else
+ {
+ hostBuffersAvailable = 1;
+
+ /* process all available host buffers */
+ do
+ {
+ hostInputBufferIndex = -1;
+ hostOutputBufferIndex = -1;
+
+ if( PA_IS_INPUT_STREAM_(stream))
+ {
+ hostInputBufferIndex = stream->currentInputBufferIndex;
+ for( i=0; i<stream->numInputDevices; ++i )
+ {
+ if( !(stream->inputBuffers[i][ stream->currentInputBufferIndex ].dwFlags & WHDR_DONE) )
+ {
+ hostInputBufferIndex = -1;
+ break;
+ }
+ }
+
+ if( hostInputBufferIndex != -1 )
+ {
+ /* if all of the other buffers are also ready then we dicard all but the
+ most recent. */
+ int inputCatchUp = 1;
+
+ for( i=0; i < stream->numInputBuffers && inputCatchUp == 1; ++i )
+ {
+ for( j=0; j<stream->numInputDevices; ++j )
+ {
+ if( !(stream->inputBuffers[ j ][ i ].dwFlags & WHDR_DONE) )
+ {
+ inputCatchUp = 0;
+ break;
+ }
+ }
+ }
+
+ if( inputCatchUp )
+ {
+ for( i=0; i < stream->numInputBuffers - 1; ++i )
+ {
+ result = AdvanceToNextInputBuffer( stream );
+ if( result != paNoError )
+ done = 1;
+ }
+ }
+ }
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ hostOutputBufferIndex = stream->currentOutputBufferIndex;
+ for( i=0; i<stream->numOutputDevices; ++i )
+ {
+ if( !(stream->outputBuffers[i][ stream->currentOutputBufferIndex ].dwFlags & WHDR_DONE) )
+ {
+ hostOutputBufferIndex = -1;
+ break;
+ }
+ }
+
+ if( hostOutputBufferIndex != - 1 )
+ {
+ /* if all of the other buffers are also ready, catch up by copying
+ the most recently generated buffer into all but one of the output
+ buffers */
+ int outputCatchUp = 1;
+
+ for( i=0; i < stream->numOutputBuffers && outputCatchUp == 1; ++i )
+ {
+ for( j=0; j<stream->numOutputDevices; ++j )
+ {
+ if( !(stream->outputBuffers[ j ][ i ].dwFlags & WHDR_DONE) )
+ {
+ outputCatchUp = 0;
+ break;
+ }
+ }
+ }
+
+ if( outputCatchUp )
+ {
+ /* FIXME: this is an output underflow buffer slip and should be flagged as such */
+ unsigned int previousBufferIndex = (stream->currentOutputBufferIndex==0)
+ ? stream->numOutputBuffers - 1
+ : stream->currentOutputBufferIndex - 1;
+
+ for( i=0; i < stream->numOutputBuffers - 1; ++i )
+ {
+ for( j=0; j<stream->numOutputDevices; ++j )
+ {
+ if( stream->outputBuffers[j][ stream->currentOutputBufferIndex ].lpData
+ != stream->outputBuffers[j][ previousBufferIndex ].lpData )
+ {
+ CopyMemory( stream->outputBuffers[j][ stream->currentOutputBufferIndex ].lpData,
+ stream->outputBuffers[j][ previousBufferIndex ].lpData,
+ stream->outputBuffers[j][ stream->currentOutputBufferIndex ].dwBufferLength );
+ }
+ }
+
+ result = AdvanceToNextOutputBuffer( stream );
+ if( result != paNoError )
+ done = 1;
+ }
+ }
+ }
+ }
+
+
+ if( (PA_IS_FULL_DUPLEX_STREAM_(stream) && hostInputBufferIndex != -1 && hostOutputBufferIndex != -1) ||
+ (!PA_IS_FULL_DUPLEX_STREAM_(stream) && ( hostInputBufferIndex != -1 || hostOutputBufferIndex != -1 ) ) )
+ {
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* @todo implement inputBufferAdcTime and currentTime */
+
+
+ if( hostOutputBufferIndex != -1 ){
+ MMTIME time;
+ double now;
+ long totalRingFrames;
+ long ringPosition;
+ long playbackPosition;
+
+ time.wType = TIME_SAMPLES;
+ waveOutGetPosition( stream->hWaveOuts[0], &time, sizeof(MMTIME) );
+ now = PaUtil_GetTime();
+
+ totalRingFrames = stream->numOutputBuffers * stream->bufferProcessor.framesPerHostBuffer;
+
+ ringPosition = stream->currentOutputBufferIndex * stream->bufferProcessor.framesPerHostBuffer;
+
+ playbackPosition = time.u.sample % totalRingFrames;
+
+ if( playbackPosition >= ringPosition ){
+ timeInfo.outputBufferDacTime =
+ now + ((double)( ringPosition + (totalRingFrames - playbackPosition) ) * stream->bufferProcessor.samplePeriod );
+ }else{
+ timeInfo.outputBufferDacTime =
+ now + ((double)( ringPosition - playbackPosition ) * stream->bufferProcessor.samplePeriod );
+ }
+ }
+
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo );
+
+ if( hostInputBufferIndex != -1 )
+ {
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
+
+ channel = 0;
+ for( i=0; i<stream->numInputDevices; ++i )
+ {
+ /* we have stored the number of channels in the buffer in dwUser */
+ int channelCount = stream->inputBuffers[i][ hostInputBufferIndex ].dwUser;
+
+ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel,
+ stream->inputBuffers[i][ hostInputBufferIndex ].lpData +
+ stream->framesUsedInCurrentInputBuffer * channelCount *
+ stream->bufferProcessor.bytesPerHostInputSample,
+ channelCount );
+
+
+ channel += channelCount;
+ }
+ }
+
+ if( hostOutputBufferIndex != -1 )
+ {
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
+
+ channel = 0;
+ for( i=0; i<stream->numOutputDevices; ++i )
+ {
+ /* we have stored the number of channels in the buffer in dwUser */
+ int channelCount = stream->outputBuffers[i][ hostOutputBufferIndex ].dwUser;
+
+ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
+ stream->outputBuffers[i][ hostOutputBufferIndex ].lpData +
+ stream->framesUsedInCurrentOutputBuffer * channelCount *
+ stream->bufferProcessor.bytesPerHostOutputSample,
+ channelCount );
+
+ /* we have stored the number of channels in the buffer in dwUser */
+ channel += channelCount;
+ }
+ }
+
+ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
+
+ stream->framesUsedInCurrentInputBuffer += framesProcessed;
+ stream->framesUsedInCurrentOutputBuffer += framesProcessed;
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+
+ if( callbackResult == paContinue )
+ {
+ /* nothing special to do */
+ }
+ else if( callbackResult == paAbort )
+ {
+ stream->abortProcessing = 1;
+ done = 1;
+ /* FIXME: should probably do a reset here */
+ result = paNoError;
+ }
+ else
+ {
+ /* User cllback has asked us to stop with paComplete or other non-zero value */
+ stream->stopProcessing = 1; /* stop once currently queued audio has finished */
+ result = paNoError;
+ }
+
+ /*
+ FIXME: the following code is incorrect, because stopProcessing should
+ still queue the current buffer.
+ */
+ if( stream->stopProcessing == 0 && stream->abortProcessing == 0 )
+ {
+ if( stream->throttleProcessingThreadOnOverload != 0 )
+ {
+ if( PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) > 1. )
+ {
+ if( stream->processingThreadPriority != stream->throttledThreadPriority )
+ {
+ SetThreadPriority( stream->processingThread, stream->throttledThreadPriority );
+ stream->processingThreadPriority = stream->throttledThreadPriority;
+ }
+
+/** @todo:
+Gordon Gidluck:
+> function: ProcessingThreadProc()
+> line #1947/1948 Sleep( stream->bufferProcessor.framesPerHostBuffer *
+> stream->bufferProcessor.samplePeriod * .25 );
+> conversion from 'double ' to 'unsigned long ', possible loss of data
+> integral size mismatch in argument; conversion supplied
+*/
+ /* sleep for a quater of a buffer's duration to give other processes a go */
+ Sleep( stream->bufferProcessor.framesPerHostBuffer *
+ stream->bufferProcessor.samplePeriod * .25 );
+ }
+ else
+ {
+ if( stream->processingThreadPriority != stream->highThreadPriority )
+ {
+ SetThreadPriority( stream->processingThread, stream->highThreadPriority );
+ stream->processingThreadPriority = stream->highThreadPriority;
+ }
+ }
+ }
+
+ if( PA_IS_INPUT_STREAM_(stream) &&
+ stream->framesUsedInCurrentInputBuffer == stream->framesPerInputBuffer )
+ {
+ result = AdvanceToNextInputBuffer( stream );
+ if( result != paNoError )
+ done = 1;
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) &&
+ stream->framesUsedInCurrentOutputBuffer == stream->framesPerOutputBuffer )
+ {
+ result = AdvanceToNextOutputBuffer( stream );
+ if( result != paNoError )
+ done = 1;
+ }
+ }
+ }
+ else
+ {
+ hostBuffersAvailable = 0;
+ }
+ }
+ while( hostBuffersAvailable &&
+ stream->stopProcessing == 0 &&
+ stream->abortProcessing == 0 &&
+ !done );
+ }
+
+ result = UpdateStreamTime( stream );
+ if( result != paNoError )
+ done = 1;
+ }
+
+ stream->isActive = 0;
+
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+
+ return result;
+}
+
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+ MMRESULT mmresult;
+ unsigned int i;
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numInputDevices; ++i )
+ {
+ TerminateBufferSet( &stream->inputBuffers[i], stream->numInputBuffers,
+ 1 /* isInput */, (MmeHandle)stream->hWaveIns[i] );
+ }
+
+ PaUtil_FreeMemory( stream->inputBuffers );
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numOutputDevices; ++i )
+ {
+ TerminateBufferSet( &stream->outputBuffers[i], stream->numOutputBuffers,
+ 0 /* not isInput */, (MmeHandle)stream->hWaveOuts[i] );
+ }
+
+ PaUtil_FreeMemory( stream->outputBuffers );
+ }
+
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numInputDevices; ++i )
+ {
+ mmresult = waveInClose( stream->hWaveIns[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ goto error;
+ }
+ }
+
+ PaUtil_FreeMemory( stream->hWaveIns );
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numOutputDevices; ++i )
+ {
+ mmresult = waveOutClose( stream->hWaveOuts[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ goto error;
+ }
+ }
+
+ PaUtil_FreeMemory( stream->hWaveOuts );
+ }
+
+ if( CloseHandle( stream->bufferEvent ) == 0 )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+
+ if( CloseHandle( stream->abortEvent ) == 0 )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+
+ DeleteCriticalSection( &stream->lock );
+
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+error:
+ /* FIXME: consider how to best clean up on failure */
+ return result;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+ MMRESULT mmresult;
+ unsigned int i, j;
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numInputBuffers; ++i )
+ {
+ for( j=0; j<stream->numInputDevices; ++j )
+ {
+ mmresult = waveInAddBuffer( stream->hWaveIns[j], &stream->inputBuffers[j][i], sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ goto error;
+ }
+ }
+ }
+ stream->currentInputBufferIndex = 0;
+ stream->framesUsedInCurrentInputBuffer = 0;
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numOutputDevices; ++i )
+ {
+ if( (mmresult = waveOutPause( stream->hWaveOuts[i] )) != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ goto error;
+ }
+ }
+
+ for( i=0; i<stream->numOutputBuffers; ++i )
+ {
+ for( j=0; j<stream->numOutputDevices; ++j )
+ {
+ ZeroMemory( stream->outputBuffers[j][i].lpData, stream->outputBuffers[j][i].dwBufferLength );
+ mmresult = waveOutWrite( stream->hWaveOuts[j], &stream->outputBuffers[j][i], sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ goto error;
+ }
+ }
+ }
+ stream->currentOutputBufferIndex = 0;
+ stream->framesUsedInCurrentOutputBuffer = 0;
+ }
+
+ stream->streamPosition = 0.;
+ stream->previousStreamPosition = 0;
+
+ stream->isActive = 1;
+ stream->stopProcessing = 0;
+ stream->abortProcessing = 0;
+
+ if( ResetEvent( stream->bufferEvent ) == 0 )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+
+ if( ResetEvent( stream->abortEvent ) == 0 )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+
+ /* Create thread that waits for audio buffers to be ready for processing. */
+ stream->processingThread = CreateThread( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId );
+ if( !stream->processingThread )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+
+ /* I used to pass the thread which was failing. I now pass GetCurrentProcess().
+ * This fix could improve latency for some applications. It could also result in CPU
+ * starvation if the callback did too much processing.
+ * I also added result checks, so we might see more failures at initialization.
+ * Thanks to Alberto di Bene for spotting this.
+ */
+ /* REVIEW: should we reset the priority class when the stream has stopped?
+ - would be best to refcount priority boosts incase more than one
+ stream is open
+ */
+
+ if( !stream->noHighPriorityProcessClass )
+ {
+#ifndef WIN32_PLATFORM_PSPC /* no SetPriorityClass or HIGH_PRIORITY_CLASS on PocketPC */
+
+ if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) /* PLB20010816 */
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+#endif
+ }
+
+ if( stream->useTimeCriticalProcessingThreadPriority )
+ stream->highThreadPriority = THREAD_PRIORITY_TIME_CRITICAL;
+ else
+ stream->highThreadPriority = THREAD_PRIORITY_HIGHEST;
+
+ stream->throttledThreadPriority = THREAD_PRIORITY_NORMAL;
+
+ if( !SetThreadPriority( stream->processingThread, stream->highThreadPriority ) )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+ stream->processingThreadPriority = stream->highThreadPriority;
+
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i < stream->numInputDevices; ++i )
+ {
+ mmresult = waveInStart( stream->hWaveIns[i] );
+ PA_DEBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult));
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ goto error;
+ }
+ }
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i=0; i < stream->numOutputDevices; ++i )
+ {
+ if( (mmresult = waveOutRestart( stream->hWaveOuts[i] )) != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ goto error;
+ }
+ }
+ }
+
+ return result;
+
+error:
+ /* FIXME: implement recovery as best we can
+ This should involve rolling back to a state as-if this function had never been called
+ */
+ return result;
+}
+
+
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+ int timeout;
+ DWORD waitResult;
+ MMRESULT mmresult;
+ unsigned int i;
+
+ /*
+ FIXME: the error checking in this function needs review. the basic
+ idea is to return from this function in a known state - for example
+ there is no point avoiding calling waveInReset just because
+ the thread times out.
+ */
+
+
+ /* Tell processing thread to stop generating more data and to let current data play out. */
+ stream->stopProcessing = 1;
+
+ /* Calculate timeOut longer than longest time it could take to return all buffers. */
+ timeout = stream->allBuffersDurationMs * 1.5;
+ if( timeout < PA_MIN_TIMEOUT_MSEC_ )
+ timeout = PA_MIN_TIMEOUT_MSEC_;
+
+ PA_DEBUG(("WinMME StopStream: waiting for background thread.\n"));
+
+ waitResult = WaitForSingleObject( stream->processingThread, timeout );
+ if( waitResult == WAIT_TIMEOUT )
+ {
+ /* try to abort */
+ stream->abortProcessing = 1;
+ SetEvent( stream->abortEvent );
+ waitResult = WaitForSingleObject( stream->processingThread, timeout );
+ if( waitResult == WAIT_TIMEOUT )
+ {
+ PA_DEBUG(("WinMME StopStream: timed out while waiting for background thread to finish.\n"));
+ result = paTimedOut;
+ }
+ }
+
+ CloseHandle( stream->processingThread );
+ stream->processingThread = NULL;
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i =0; i < stream->numOutputDevices; ++i )
+ {
+ mmresult = waveOutReset( stream->hWaveOuts[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ }
+ }
+ }
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i < stream->numInputDevices; ++i )
+ {
+ mmresult = waveInReset( stream->hWaveIns[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ }
+ }
+ }
+
+ stream->isActive = 0;
+
+ return result;
+}
+
+
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+ int timeout;
+ DWORD waitResult;
+ MMRESULT mmresult;
+ unsigned int i;
+
+ /*
+ FIXME: the error checking in this function needs review. the basic
+ idea is to return from this function in a known state - for example
+ there is no point avoiding calling waveInReset just because
+ the thread times out.
+ */
+
+ /* Tell processing thread to abort immediately */
+ stream->abortProcessing = 1;
+ SetEvent( stream->abortEvent );
+
+ /* Calculate timeOut longer than longest time it could take to return all buffers. */
+ timeout = stream->allBuffersDurationMs * 1.5;
+ if( timeout < PA_MIN_TIMEOUT_MSEC_ )
+ timeout = PA_MIN_TIMEOUT_MSEC_;
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i =0; i < stream->numOutputDevices; ++i )
+ {
+ mmresult = waveOutReset( stream->hWaveOuts[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ return paUnanticipatedHostError;
+ }
+ }
+ }
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i < stream->numInputDevices; ++i )
+ {
+ mmresult = waveInReset( stream->hWaveIns[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ return paUnanticipatedHostError;
+ }
+ }
+ }
+
+
+ PA_DEBUG(("WinMME AbortStream: waiting for background thread.\n"));
+
+ waitResult = WaitForSingleObject( stream->processingThread, timeout );
+ if( waitResult == WAIT_TIMEOUT )
+ {
+ PA_DEBUG(("WinMME AbortStream: timed out while waiting for background thread to finish.\n"));
+ return paTimedOut;
+ }
+
+ CloseHandle( stream->processingThread );
+ stream->processingThread = NULL;
+
+ stream->isActive = 0;
+
+ return result;
+}
+
+
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ return ( stream->processingThread == NULL );
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ return stream->isActive;
+}
+
+
+/* UpdateStreamTime() must be called periodically because mmtime.u.sample
+ is a DWORD and can wrap and lose sync after a few hours.
+ */
+static PaError UpdateStreamTime( PaWinMmeStream *stream )
+{
+ MMRESULT mmresult;
+ MMTIME mmtime;
+ mmtime.wType = TIME_SAMPLES;
+
+ if( stream->hWaveOuts )
+ {
+ /* assume that all devices have the same position */
+ mmresult = waveOutGetPosition( stream->hWaveOuts[0], &mmtime, sizeof(mmtime) );
+
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ return paUnanticipatedHostError;
+ }
+ }
+ else
+ {
+ /* assume that all devices have the same position */
+ mmresult = waveInGetPosition( stream->hWaveIns[0], &mmtime, sizeof(mmtime) );
+
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ return paUnanticipatedHostError;
+ }
+ }
+
+
+ /* This data has two variables and is shared by foreground and background.
+ * So we need to make it thread safe. */
+ EnterCriticalSection( &stream->lock );
+ stream->streamPosition += ((long)mmtime.u.sample) - stream->previousStreamPosition;
+ stream->previousStreamPosition = (long)mmtime.u.sample;
+ LeaveCriticalSection( &stream->lock );
+
+ return paNoError;
+}
+
+
+static PaTime GetStreamTime( PaStream *s )
+{
+/*
+ new behavior for GetStreamTime is to return a stream based seconds clock
+ used for the outTime parameter to the callback.
+ FIXME: delete this comment when the other unnecessary related code has
+ been cleaned from this file.
+
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+ PaError error = UpdateStreamTime( stream );
+
+ if( error == paNoError )
+ return stream->streamPosition;
+ else
+ return 0;
+*/
+ (void) s; /* unused parameter */
+ return PaUtil_GetTime();
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
+/*
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
+
+static PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameters */
+ (void) buffer;
+ (void) frames;
+
+ return paNoError;
+}
+
+
+static PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameters */
+ (void) buffer;
+ (void) frames;
+
+ return paNoError;
+}
+
+
+static signed long GetStreamReadAvailable( PaStream* s )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameter */
+
+ return 0;
+}
+
+
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameter */
+
+ return 0;
+}
+
+
+
+
diff --git a/pd/portaudio/pa_win_wmme/pa_win_wmme.h b/pd/portaudio/pa_win_wmme/pa_win_wmme.h
new file mode 100644
index 00000000..d5c18a28
--- /dev/null
+++ b/pd/portaudio/pa_win_wmme/pa_win_wmme.h
@@ -0,0 +1,105 @@
+#ifndef PA_WIN_WMME_H
+#define PA_WIN_WMME_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * MME specific extensions
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * 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.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * 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.
+ *
+ */
+
+
+#include "portaudio.h"
+
+#define PaWinMmeUseLowLevelLatencyParameters (0x01)
+#define PaWinMmeUseMultipleDevices (0x02) /* use mme specific multiple device feature */
+
+/* by default, the mme implementation boosts the process priority class to
+ HIGH_PRIORITY_CLASS. This flag disables that priority boost */
+#define PaWinMmeNoHighPriorityProcessClass (0x03)
+
+/* by default, the mme implementation drops the processing thread's priority
+ to THREAD_PRIORITY_NORMAL and sleeps the thread if the CPU load exceeds 100% */
+#define PaWinMmeDontThrottleOverloadedProcessingThread (0x04)
+
+/* by default, the mme implementation sets the processing thread's priority to
+ THREAD_PRIORITY_HIGHEST. This flag sets the priority to
+ THREAD_PRIORITY_TIME_CRITICAL instead. Note that this has the potential
+ to freeze the machine, especially when used in combination with
+ PaWinMmeDontThrottleOverloadedProcessingThread */
+#define PaWinMmeUseTimeCriticalThreadPriority (0x05)
+
+typedef struct PaWinMmeDeviceAndChannelCount{
+ PaDeviceIndex device;
+ int channelCount;
+}PaWinMmeDeviceAndChannelCount;
+
+
+typedef struct PaWinMmeStreamInfo{
+ unsigned long size; /* sizeof(PaWinMmeStreamInfo) */
+ PaHostApiTypeId hostApiType; /* paMME */
+ unsigned long version; /* 1 */
+
+ unsigned long flags;
+
+ /* low-level latency setting support
+ These settings control the number and size of host buffers in order
+ to set latency. They will be used instead of the generic parameters
+ to Pa_OpenStream() if flags contains the PaWinMmeUseLowLevelLatencyParameters
+ flag.
+ */
+ unsigned long framesPerBuffer;
+ unsigned long numBuffers;
+
+ /* multiple devices per direction support
+ If flags contains the PaWinMmeUseMultipleDevices flag,
+ this functionality will be used, otherwise the device parameter to
+ Pa_OpenStream() will be used instead.
+ If devices are specified here, the corresponding device parameter
+ to Pa_OpenStream() should be set to paUseHostApiSpecificDeviceSpecification,
+ otherwise an paInvalidDevice error will result.
+ The total number of channels accross all specified devices
+ must agree with the corresponding channelCount parameter to
+ Pa_OpenStream() otherwise a paInvalidChannelCount error will result.
+ */
+ PaWinMmeDeviceAndChannelCount *devices;
+ unsigned long deviceCount;
+
+}PaWinMmeStreamInfo;
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PA_WIN_WMME_H */
diff --git a/pd/portaudio/pablio/pablio.h b/pd/portaudio/pablio/pablio.h
index 9060c560..85843ae9 100644
--- a/pd/portaudio/pablio/pablio.h
+++ b/pd/portaudio/pablio/pablio.h
@@ -7,7 +7,7 @@ extern "C"
#endif /* __cplusplus */
/*
- * $Id: pablio.h,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * $Id: pablio.h,v 1.1.1.2 2003-05-09 16:03:59 ggeiger Exp $
* PABLIO.h
* Portable Audio Blocking read/write utility.
*
@@ -96,8 +96,9 @@ long GetAudioStreamReadable( PABLIO_Stream *aStream );
*
* flags parameter can be an ORed combination of:
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
+ * and either PABLIO_MONO or PABLIO_STEREO
*/
-PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,
PaSampleFormat format, long flags );
PaError CloseAudioStream( PABLIO_Stream *aStream );
diff --git a/pd/portaudio/pablio/pablio_pd.c b/pd/portaudio/pablio/pablio_pd.c
index e7105e9b..49323ef1 100644
--- a/pd/portaudio/pablio/pablio_pd.c
+++ b/pd/portaudio/pablio/pablio_pd.c
@@ -1,5 +1,5 @@
/*
- * $Id: pablio_pd.c,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * $Id: pablio_pd.c,v 1.1.1.2 2003-05-09 16:03:59 ggeiger Exp $
* pablio.c
* Portable Audio Blocking Input/Output utility.
*
@@ -54,7 +54,9 @@
static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
- PaTimestamp outTime, void *userData );
+ const PaStreamCallbackTimeInfo *outTime,
+ PaStreamCallbackFlags myflags,
+ void *userData );
static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );
static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
@@ -67,7 +69,9 @@ static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
*/
static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
- PaTimestamp outTime, void *userData )
+ const PaStreamCallbackTimeInfo *outTime,
+ PaStreamCallbackFlags myflags,
+ void *userData )
{
PABLIO_Stream *data = (PABLIO_Stream*)userData;
long numBytes = data->bytesPerFrame * framesPerBuffer;
@@ -198,6 +202,7 @@ PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
long doWrite = 0;
PaError err;
PABLIO_Stream *aStream;
+ PaStreamParameters instreamparams, outstreamparams; /* MSP */
long minNumBuffers;
long numFrames;
@@ -208,16 +213,16 @@ PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
if (indeviceno < 0) /* MSP... */
{
- indeviceno = Pa_GetDefaultInputDeviceID();
+ indeviceno = Pa_GetDefaultInputDevice();
fprintf(stderr, "using default input device number: %d\n", indeviceno);
}
if (outdeviceno < 0)
{
- outdeviceno = Pa_GetDefaultOutputDeviceID();
+ outdeviceno = Pa_GetDefaultOutputDevice();
fprintf(stderr, "using default output device number: %d\n", outdeviceno);
}
nbuffers = RoundUpToNextPowerOf2(nbuffers);
- fprintf(stderr, "nchan %d, flags %d, bufs %d, framesperbuf %d\n",
+ fprintf(stderr, "nchan %d, flags %ld, bufs %d, framesperbuf %d\n",
nchannels, flags, nbuffers, framesperbuf);
/* ...MSP */
@@ -236,19 +241,22 @@ PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
aStream->samplesPerFrame = nchannels; /* MSP */
aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
- /* Initialize PortAudio */
- err = Pa_Initialize();
- if( err != paNoError ) goto error;
-/* Warning: numFrames must be larger than amount of data processed per
- interrupt inside PA to prevent glitches. */ /* MSP */
- minNumBuffers = Pa_GetMinNumBuffers(framesperbuf, sampleRate);
- if (minNumBuffers > nbuffers)
- fprintf(stderr,
- "warning: number of buffers %d less than recommended minimum %d\n",
- (int)nbuffers, (int)minNumBuffers);
numFrames = nbuffers * framesperbuf;
+ instreamparams.device = indeviceno; /* MSP */
+ instreamparams.channelCount = nchannels;
+ instreamparams.sampleFormat = format;
+ instreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
+ instreamparams.hostApiSpecificStreamInfo = 0;
+
+ outstreamparams.device = outdeviceno;
+ outstreamparams.channelCount = nchannels;
+ outstreamparams.sampleFormat = format;
+ outstreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
+ outstreamparams.hostApiSpecificStreamInfo = 0;
+
+
/* Initialize Ring Buffers */
doRead = ((flags & PABLIO_READ) != 0);
doWrite = ((flags & PABLIO_WRITE) != 0);
@@ -271,17 +279,10 @@ PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
* audio drivers. */
err = Pa_OpenStream(
&aStream->stream,
- (doRead ? indeviceno : paNoDevice), /* MSP */
- (doRead ? aStream->samplesPerFrame : 0 ),
- format,
- NULL,
- (doWrite ? outdeviceno : paNoDevice), /* MSP */
- (doWrite ? aStream->samplesPerFrame : 0 ),
- format,
- NULL,
+ (doRead ? &instreamparams : 0), /* MSP */
+ (doWrite ? &outstreamparams : 0), /* MSP */
sampleRate,
framesperbuf, /* MSP */
- nbuffers, /* MSP */
paNoFlag, /* MSP -- portaudio will clip for us */
blockingIOCallback,
aStream );
diff --git a/pd/portaudio/pablio/pablio_pd.h b/pd/portaudio/pablio/pablio_pd.h
index b87b9f5a..8f8a688a 100644
--- a/pd/portaudio/pablio/pablio_pd.h
+++ b/pd/portaudio/pablio/pablio_pd.h
@@ -7,7 +7,7 @@ extern "C"
#endif /* __cplusplus */
/*
- * $Id: pablio_pd.h,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * $Id: pablio_pd.h,v 1.1.1.2 2003-05-09 16:03:59 ggeiger Exp $
* PABLIO.h
* Portable Audio Blocking read/write utility.
*
@@ -53,7 +53,7 @@ typedef struct
{
RingBuffer inFIFO;
RingBuffer outFIFO;
- PortAudioStream *stream;
+ PaStream *stream; /* MSP -- was PortAudioStream; probably an error */
int bytesPerFrame;
int samplesPerFrame;
}
diff --git a/pd/portaudio/pablio/pablio_pd.o b/pd/portaudio/pablio/pablio_pd.o
new file mode 100644
index 00000000..359a8c49
--- /dev/null
+++ b/pd/portaudio/pablio/pablio_pd.o
Binary files differ
diff --git a/pd/portaudio/pablio/ringbuffer_pd.o b/pd/portaudio/pablio/ringbuffer_pd.o
new file mode 100644
index 00000000..a348b1ed
--- /dev/null
+++ b/pd/portaudio/pablio/ringbuffer_pd.o
Binary files differ
diff --git a/pd/portaudio/testcvs/changeme.txt b/pd/portaudio/testcvs/changeme.txt
new file mode 100644
index 00000000..2866c3b7
--- /dev/null
+++ b/pd/portaudio/testcvs/changeme.txt
@@ -0,0 +1,8 @@
+This is just a dopy little file used to test the CVS repository.
+Feel free to trash this file.
+Minor change.
+Another tweak.
+philburk tweak
+stephane test
+Phil changed this again on 2/21/02. Yawn...
+