mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-05-24 10:22:26 -04:00
- Updated portaudio
git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/trunk@247 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
9471e22ff2
commit
d8934b4f71
@ -1,40 +1,58 @@
|
|||||||
# Generated automatically from Makefile.in by configure.
|
|
||||||
#
|
#
|
||||||
# PortAudio V19 Makefile.in
|
# PortAudio V19 Makefile.in
|
||||||
#
|
#
|
||||||
# Dominic Mazzoni
|
# Dominic Mazzoni
|
||||||
|
# Modifications by Mikael Magnusson
|
||||||
#
|
#
|
||||||
|
|
||||||
|
top_srcdir = .
|
||||||
|
srcdir = .
|
||||||
|
|
||||||
|
top_builddir = .
|
||||||
PREFIX = /usr/local
|
PREFIX = /usr/local
|
||||||
CC = cc
|
prefix = $(PREFIX)
|
||||||
CFLAGS = -Ipa_common -g -O2 -Wall -pedantic -pipe -fPIC -DPA_LITTLE_ENDIAN -DSIZEOF_SHORT=2 -DSIZEOF_INT=4 -DSIZEOF_LONG=4 -DHAVE_LIBPTHREAD=1 -DPA_USE_OSS=1
|
exec_prefix = ${prefix}
|
||||||
LIBS = -lpthread -lm -lpthread
|
bindir = ${exec_prefix}/bin
|
||||||
|
libdir = ${exec_prefix}/lib
|
||||||
|
includedir = ${prefix}/include
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -g -O2 -DPA_LITTLE_ENDIAN -pthread -I$(top_srcdir)/include -I$(top_srcdir)/src/common -I$(top_srcdir)/src/os/unix -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_DLFCN_H=1 -DSIZEOF_SHORT=2 -DSIZEOF_INT=4 -DSIZEOF_LONG=4 -DHAVE_CLOCK_GETTIME=1 -DHAVE_NANOSLEEP=1 -DPA_USE_OSS=1
|
||||||
|
LIBS = -lm -lpthread
|
||||||
AR = /usr/bin/ar
|
AR = /usr/bin/ar
|
||||||
RANLIB = ranlib
|
RANLIB = ranlib
|
||||||
|
LIBTOOL = $(SHELL) $(top_builddir)/libtool
|
||||||
INSTALL = /usr/bin/install -c
|
INSTALL = /usr/bin/install -c
|
||||||
|
INSTALL_DATA = ${INSTALL} -m 644
|
||||||
SHARED_FLAGS = -shared -fPIC
|
SHARED_FLAGS = -shared -fPIC
|
||||||
DLL_LIBS =
|
LDFLAGS =
|
||||||
CXXFLAGS =
|
DLL_LIBS = -lrt -lm -lpthread
|
||||||
|
CXXFLAGS = -g -O2
|
||||||
NASM =
|
NASM =
|
||||||
NASMOPT =
|
NASMOPT =
|
||||||
|
LN_S = ln -s
|
||||||
|
LT_RELEASE=@LT_RELEASE@
|
||||||
|
LT_CURRENT=2
|
||||||
|
LT_REVISION=0
|
||||||
|
LT_AGE=0
|
||||||
|
|
||||||
OTHER_OBJS = pa_unix_oss/pa_unix_oss.o pa_unix/pa_unix_hostapis.o pa_unix/pa_unix_util.o
|
OTHER_OBJS = src/hostapi/oss/pa_unix_oss.o src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o
|
||||||
|
|
||||||
PALIB = libportaudio.a
|
PALIB = libportaudio.la
|
||||||
PADLL = libportaudio.so
|
PAINC = include/portaudio.h
|
||||||
PADLLV = $(PADLL).0.0.19
|
|
||||||
PAINC = pa_common/portaudio.h
|
PA_LDFLAGS = $(LDFLAGS) $(SHARED_FLAGS) -rpath $(libdir) -no-undefined -export-symbols-regex "Pa_.*" -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
||||||
|
#MAKEFILE = Makefile
|
||||||
|
|
||||||
COMMON_OBJS = \
|
COMMON_OBJS = \
|
||||||
pa_common/pa_allocation.o \
|
src/common/pa_allocation.o \
|
||||||
pa_common/pa_converters.o \
|
src/common/pa_converters.o \
|
||||||
pa_common/pa_cpuload.o \
|
src/common/pa_cpuload.o \
|
||||||
pa_common/pa_dither.o \
|
src/common/pa_dither.o \
|
||||||
pa_common/pa_front.o \
|
src/common/pa_front.o \
|
||||||
pa_common/pa_process.o \
|
src/common/pa_process.o \
|
||||||
pa_common/pa_skeleton.o \
|
src/common/pa_skeleton.o \
|
||||||
pa_common/pa_stream.o \
|
src/common/pa_stream.o \
|
||||||
pa_common/pa_trace.o
|
src/common/pa_trace.o
|
||||||
|
|
||||||
TESTS = \
|
TESTS = \
|
||||||
bin/paqa_devs \
|
bin/paqa_devs \
|
||||||
@ -56,6 +74,7 @@ TESTS = \
|
|||||||
bin/patest_pink \
|
bin/patest_pink \
|
||||||
bin/patest_prime \
|
bin/patest_prime \
|
||||||
bin/patest_read_record \
|
bin/patest_read_record \
|
||||||
|
bin/patest_read_write_wire \
|
||||||
bin/patest_record \
|
bin/patest_record \
|
||||||
bin/patest_ringmix \
|
bin/patest_ringmix \
|
||||||
bin/patest_saw \
|
bin/patest_saw \
|
||||||
@ -65,7 +84,6 @@ TESTS = \
|
|||||||
bin/patest_sine_time \
|
bin/patest_sine_time \
|
||||||
bin/patest_start_stop \
|
bin/patest_start_stop \
|
||||||
bin/patest_stop \
|
bin/patest_stop \
|
||||||
bin/patest_sync \
|
|
||||||
bin/patest_toomanysines \
|
bin/patest_toomanysines \
|
||||||
bin/patest_underflow \
|
bin/patest_underflow \
|
||||||
bin/patest_wire \
|
bin/patest_wire \
|
||||||
@ -77,6 +95,8 @@ TESTS = \
|
|||||||
# Most of these don't compile yet. Put them in TESTS, above, if
|
# Most of these don't compile yet. Put them in TESTS, above, if
|
||||||
# you want to try to compile them...
|
# you want to try to compile them...
|
||||||
ALL_TESTS = \
|
ALL_TESTS = \
|
||||||
|
$(TESTS) \
|
||||||
|
bin/patest_sync \
|
||||||
bin/debug_convert \
|
bin/debug_convert \
|
||||||
bin/debug_dither_calc \
|
bin/debug_dither_calc \
|
||||||
bin/debug_dual \
|
bin/debug_dual \
|
||||||
@ -88,65 +108,34 @@ ALL_TESTS = \
|
|||||||
bin/debug_sine \
|
bin/debug_sine \
|
||||||
bin/debug_sine_formats \
|
bin/debug_sine_formats \
|
||||||
bin/debug_srate \
|
bin/debug_srate \
|
||||||
bin/debug_test1 \
|
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_in_overflow \
|
|
||||||
bin/patest_latency \
|
|
||||||
bin/patest_leftright \
|
|
||||||
bin/patest_longsine \
|
|
||||||
bin/patest_many \
|
|
||||||
bin/patest_maxsines \
|
|
||||||
bin/patest_multi_sine \
|
|
||||||
bin/patest_out_underflow \
|
|
||||||
bin/patest_pink \
|
|
||||||
bin/patest_read_record \
|
|
||||||
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 \
|
|
||||||
bin/patest_write_sine
|
|
||||||
|
|
||||||
OBJS = $(COMMON_OBJS) $(OTHER_OBJS)
|
OBJS = $(COMMON_OBJS) $(OTHER_OBJS)
|
||||||
|
|
||||||
all: lib/$(PALIB) lib/$(PADLLV) tests
|
LTOBJS:= $(OBJS:.o=.lo)
|
||||||
|
|
||||||
tests: bin/ $(TESTS)
|
SUBDIRS =
|
||||||
|
#SUBDIRS += bindings/cpp
|
||||||
|
|
||||||
lib/$(PALIB): lib/ $(OBJS) Makefile $(PAINC)
|
all: lib/$(PALIB) all-recursive tests
|
||||||
$(AR) ruv lib/$(PALIB) $(OBJS)
|
|
||||||
$(RANLIB) lib/$(PALIB)
|
|
||||||
|
|
||||||
lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC)
|
tests: bin-stamp $(TESTS)
|
||||||
$(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)
|
lib/$(PALIB): lib-stamp $(LTOBJS) $(MAKEFILE) $(PAINC)
|
||||||
$(INSTALL) -d $(PREFIX)/lib
|
$(LIBTOOL) --mode=link $(CC) $(PA_LDFLAGS) -o lib/$(PALIB) $(LTOBJS) $(DLL_LIBS)
|
||||||
$(INSTALL) -m 644 lib/$(PADLLV) $(PREFIX)/lib/$(PADLLV)
|
|
||||||
$(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB)
|
$(ALL_TESTS): bin/%: lib/$(PALIB) $(MAKEFILE) $(PAINC) test/%.c
|
||||||
cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL)
|
$(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(top_srcdir)/test/$*.c lib/$(PALIB) $(LIBS)
|
||||||
$(INSTALL) -d $(PREFIX)/include
|
|
||||||
$(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h
|
|
||||||
|
install: lib/$(PALIB) portaudio-2.0.pc
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(libdir)
|
||||||
|
$(LIBTOOL) --mode=install $(INSTALL) lib/$(PALIB) $(DESTDIR)$(libdir)
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(includedir)
|
||||||
|
$(INSTALL_DATA) -m 644 $(top_srcdir)/$(PAINC) $(DESTDIR)$(includedir)/portaudio.h
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig
|
||||||
|
$(INSTALL) -m 644 portaudio-2.0.pc $(DESTDIR)$(libdir)/pkgconfig/portaudio-2.0.pc
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "------------------------------------------------------------"
|
@echo "------------------------------------------------------------"
|
||||||
@echo "PortAudio was successfully installed."
|
@echo "PortAudio was successfully installed."
|
||||||
@ -154,33 +143,55 @@ install: lib/$(PALIB) lib/$(PADLLV)
|
|||||||
@echo "On some systems (e.g. Linux) you should run 'ldconfig' now"
|
@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 "to make the shared object available. You may also need to"
|
||||||
@echo "modify your LD_LIBRARY_PATH environment variable to include"
|
@echo "modify your LD_LIBRARY_PATH environment variable to include"
|
||||||
@echo "the directory $(PREFIX)/lib"
|
@echo "the directory $(libdir)"
|
||||||
@echo "------------------------------------------------------------"
|
@echo "------------------------------------------------------------"
|
||||||
@echo ""
|
@echo ""
|
||||||
|
$(MAKE) install-recursive
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(PREFIX)/lib/$(PADLLV)
|
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$(PALIB)
|
||||||
rm -f $(PREFIX)/lib/$(PALIB)
|
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(includedir)/portaudio.h
|
||||||
rm -f $(PREFIX)/lib/$(PADLL)
|
$(MAKE) uninstall-recursive
|
||||||
rm -f $(PREFIX)/include/portaudio.h
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJS) $(TESTS) lib/$(PALIB) lib/$(PADLLV)
|
$(LIBTOOL) --mode=clean rm -f $(LTOBJS) $(ALL_TESTS) lib/$(PALIB)
|
||||||
|
rm -f bin-stamp lib-stamp
|
||||||
|
-rm -rf bin lib
|
||||||
|
|
||||||
%.o: %.c Makefile $(PAINC)
|
distclean: clean
|
||||||
|
rm -f config.log config.status Makefile libtool portaudio-2.0.pc
|
||||||
|
|
||||||
|
%.o: %.c $(MAKEFILE) $(PAINC)
|
||||||
$(CC) -c $(CFLAGS) $< -o $@
|
$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
%.o: %.cpp Makefile $(PAINC)
|
%.lo: %.c $(MAKEFILE) $(PAINC)
|
||||||
|
$(LIBTOOL) --mode=compile $(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(MAKEFILE) $(PAINC)
|
||||||
$(CXX) -c $(CXXFLAGS) $< -o $@
|
$(CXX) -c $(CXXFLAGS) $< -o $@
|
||||||
|
|
||||||
%.o: %.asm
|
%.o: %.asm
|
||||||
$(NASM) $(NASMOPT) -o $@ $<
|
$(NASM) $(NASMOPT) -o $@ $<
|
||||||
|
|
||||||
bin:
|
bin-stamp:
|
||||||
mkdir bin
|
-mkdir bin
|
||||||
|
touch $@
|
||||||
|
|
||||||
lib:
|
lib-stamp:
|
||||||
mkdir lib
|
-mkdir lib
|
||||||
|
-mkdir -p src/os/win src/os/unix src/os/mac_osx src/common \
|
||||||
|
src/hostapi/oss src/hostapi/alsa src/hostapi/jack src/hostapi/asihpi \
|
||||||
|
src/hostapi/wmme src/hostapi/wdmks src/hostapi/dsound src/hostapi/wasapi
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
Makefile: Makefile.in config.status
|
||||||
|
$(SHELL) config.status
|
||||||
|
|
||||||
|
all-recursive:
|
||||||
|
for dir in $(SUBDIRS); do make -C $$dir all; done
|
||||||
|
|
||||||
|
install-recursive:
|
||||||
|
for dir in $(SUBDIRS); do make -C $$dir install; done
|
||||||
|
|
||||||
|
uninstall-recursive:
|
||||||
|
for dir in $(SUBDIRS); do make -C $$dir uninstall; done
|
||||||
|
@ -2,38 +2,57 @@
|
|||||||
# PortAudio V19 Makefile.in
|
# PortAudio V19 Makefile.in
|
||||||
#
|
#
|
||||||
# Dominic Mazzoni
|
# Dominic Mazzoni
|
||||||
|
# Modifications by Mikael Magnusson
|
||||||
#
|
#
|
||||||
|
|
||||||
|
top_srcdir = @top_srcdir@
|
||||||
|
srcdir = @srcdir@
|
||||||
|
VPATH = @srcdir@
|
||||||
|
top_builddir = .
|
||||||
PREFIX = @prefix@
|
PREFIX = @prefix@
|
||||||
|
prefix = $(PREFIX)
|
||||||
|
exec_prefix = @exec_prefix@
|
||||||
|
bindir = @bindir@
|
||||||
|
libdir = @libdir@
|
||||||
|
includedir = @includedir@
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
CFLAGS = -Ipa_common @CFLAGS@ @DEFS@
|
CFLAGS = @CFLAGS@ -I$(top_srcdir)/include -I$(top_srcdir)/src/common -I$(top_srcdir)/src/os/unix @DEFS@
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
AR = @AR@
|
AR = @AR@
|
||||||
RANLIB = @RANLIB@
|
RANLIB = @RANLIB@
|
||||||
|
LIBTOOL = @LIBTOOL@
|
||||||
INSTALL = @INSTALL@
|
INSTALL = @INSTALL@
|
||||||
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
SHARED_FLAGS = @SHARED_FLAGS@
|
SHARED_FLAGS = @SHARED_FLAGS@
|
||||||
|
LDFLAGS = @LDFLAGS@
|
||||||
DLL_LIBS = @DLL_LIBS@
|
DLL_LIBS = @DLL_LIBS@
|
||||||
CXXFLAGS = @CXXFLAGS@
|
CXXFLAGS = @CXXFLAGS@
|
||||||
NASM = @NASM@
|
NASM = @NASM@
|
||||||
NASMOPT = @NASMOPT@
|
NASMOPT = @NASMOPT@
|
||||||
|
LN_S = @LN_S@
|
||||||
|
LT_RELEASE=@LT_RELEASE@
|
||||||
|
LT_CURRENT=@LT_CURRENT@
|
||||||
|
LT_REVISION=@LT_REVISION@
|
||||||
|
LT_AGE=@LT_AGE@
|
||||||
|
|
||||||
OTHER_OBJS = @OTHER_OBJS@
|
OTHER_OBJS = @OTHER_OBJS@
|
||||||
|
|
||||||
PALIB = libportaudio.a
|
PALIB = libportaudio.la
|
||||||
PADLL = @PADLL@
|
PAINC = include/portaudio.h
|
||||||
PADLLV = $(PADLL).0.0.19
|
|
||||||
PAINC = pa_common/portaudio.h
|
PA_LDFLAGS = $(LDFLAGS) $(SHARED_FLAGS) -rpath $(libdir) -no-undefined -export-symbols-regex "Pa_.*" -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
||||||
|
#MAKEFILE = Makefile
|
||||||
|
|
||||||
COMMON_OBJS = \
|
COMMON_OBJS = \
|
||||||
pa_common/pa_allocation.o \
|
src/common/pa_allocation.o \
|
||||||
pa_common/pa_converters.o \
|
src/common/pa_converters.o \
|
||||||
pa_common/pa_cpuload.o \
|
src/common/pa_cpuload.o \
|
||||||
pa_common/pa_dither.o \
|
src/common/pa_dither.o \
|
||||||
pa_common/pa_front.o \
|
src/common/pa_front.o \
|
||||||
pa_common/pa_process.o \
|
src/common/pa_process.o \
|
||||||
pa_common/pa_skeleton.o \
|
src/common/pa_skeleton.o \
|
||||||
pa_common/pa_stream.o \
|
src/common/pa_stream.o \
|
||||||
pa_common/pa_trace.o
|
src/common/pa_trace.o
|
||||||
|
|
||||||
TESTS = \
|
TESTS = \
|
||||||
bin/paqa_devs \
|
bin/paqa_devs \
|
||||||
@ -55,6 +74,7 @@ TESTS = \
|
|||||||
bin/patest_pink \
|
bin/patest_pink \
|
||||||
bin/patest_prime \
|
bin/patest_prime \
|
||||||
bin/patest_read_record \
|
bin/patest_read_record \
|
||||||
|
bin/patest_read_write_wire \
|
||||||
bin/patest_record \
|
bin/patest_record \
|
||||||
bin/patest_ringmix \
|
bin/patest_ringmix \
|
||||||
bin/patest_saw \
|
bin/patest_saw \
|
||||||
@ -64,7 +84,6 @@ TESTS = \
|
|||||||
bin/patest_sine_time \
|
bin/patest_sine_time \
|
||||||
bin/patest_start_stop \
|
bin/patest_start_stop \
|
||||||
bin/patest_stop \
|
bin/patest_stop \
|
||||||
bin/patest_sync \
|
|
||||||
bin/patest_toomanysines \
|
bin/patest_toomanysines \
|
||||||
bin/patest_underflow \
|
bin/patest_underflow \
|
||||||
bin/patest_wire \
|
bin/patest_wire \
|
||||||
@ -76,6 +95,8 @@ TESTS = \
|
|||||||
# Most of these don't compile yet. Put them in TESTS, above, if
|
# Most of these don't compile yet. Put them in TESTS, above, if
|
||||||
# you want to try to compile them...
|
# you want to try to compile them...
|
||||||
ALL_TESTS = \
|
ALL_TESTS = \
|
||||||
|
$(TESTS) \
|
||||||
|
bin/patest_sync \
|
||||||
bin/debug_convert \
|
bin/debug_convert \
|
||||||
bin/debug_dither_calc \
|
bin/debug_dither_calc \
|
||||||
bin/debug_dual \
|
bin/debug_dual \
|
||||||
@ -87,65 +108,34 @@ ALL_TESTS = \
|
|||||||
bin/debug_sine \
|
bin/debug_sine \
|
||||||
bin/debug_sine_formats \
|
bin/debug_sine_formats \
|
||||||
bin/debug_srate \
|
bin/debug_srate \
|
||||||
bin/debug_test1 \
|
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_in_overflow \
|
|
||||||
bin/patest_latency \
|
|
||||||
bin/patest_leftright \
|
|
||||||
bin/patest_longsine \
|
|
||||||
bin/patest_many \
|
|
||||||
bin/patest_maxsines \
|
|
||||||
bin/patest_multi_sine \
|
|
||||||
bin/patest_out_underflow \
|
|
||||||
bin/patest_pink \
|
|
||||||
bin/patest_read_record \
|
|
||||||
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 \
|
|
||||||
bin/patest_write_sine
|
|
||||||
|
|
||||||
OBJS = $(COMMON_OBJS) $(OTHER_OBJS)
|
OBJS = $(COMMON_OBJS) $(OTHER_OBJS)
|
||||||
|
|
||||||
all: lib/$(PALIB) lib/$(PADLLV) tests
|
LTOBJS:= $(OBJS:.o=.lo)
|
||||||
|
|
||||||
tests: bin/ $(TESTS)
|
SUBDIRS =
|
||||||
|
@ENABLE_CXX_TRUE@SUBDIRS += bindings/cpp
|
||||||
|
|
||||||
lib/$(PALIB): lib/ $(OBJS) Makefile $(PAINC)
|
all: lib/$(PALIB) all-recursive tests
|
||||||
$(AR) ruv lib/$(PALIB) $(OBJS)
|
|
||||||
$(RANLIB) lib/$(PALIB)
|
|
||||||
|
|
||||||
lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC)
|
tests: bin-stamp $(TESTS)
|
||||||
$(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)
|
lib/$(PALIB): lib-stamp $(LTOBJS) $(MAKEFILE) $(PAINC)
|
||||||
$(INSTALL) -d $(PREFIX)/lib
|
$(LIBTOOL) --mode=link $(CC) $(PA_LDFLAGS) -o lib/$(PALIB) $(LTOBJS) $(DLL_LIBS)
|
||||||
$(INSTALL) -m 644 lib/$(PADLLV) $(PREFIX)/lib/$(PADLLV)
|
|
||||||
$(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB)
|
$(ALL_TESTS): bin/%: lib/$(PALIB) $(MAKEFILE) $(PAINC) test/%.c
|
||||||
cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL)
|
$(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(top_srcdir)/test/$*.c lib/$(PALIB) $(LIBS)
|
||||||
$(INSTALL) -d $(PREFIX)/include
|
|
||||||
$(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h
|
|
||||||
|
install: lib/$(PALIB) portaudio-2.0.pc
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(libdir)
|
||||||
|
$(LIBTOOL) --mode=install $(INSTALL) lib/$(PALIB) $(DESTDIR)$(libdir)
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(includedir)
|
||||||
|
$(INSTALL_DATA) -m 644 $(top_srcdir)/$(PAINC) $(DESTDIR)$(includedir)/portaudio.h
|
||||||
|
$(INSTALL) -d $(DESTDIR)$(libdir)/pkgconfig
|
||||||
|
$(INSTALL) -m 644 portaudio-2.0.pc $(DESTDIR)$(libdir)/pkgconfig/portaudio-2.0.pc
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "------------------------------------------------------------"
|
@echo "------------------------------------------------------------"
|
||||||
@echo "PortAudio was successfully installed."
|
@echo "PortAudio was successfully installed."
|
||||||
@ -153,33 +143,55 @@ install: lib/$(PALIB) lib/$(PADLLV)
|
|||||||
@echo "On some systems (e.g. Linux) you should run 'ldconfig' now"
|
@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 "to make the shared object available. You may also need to"
|
||||||
@echo "modify your LD_LIBRARY_PATH environment variable to include"
|
@echo "modify your LD_LIBRARY_PATH environment variable to include"
|
||||||
@echo "the directory $(PREFIX)/lib"
|
@echo "the directory $(libdir)"
|
||||||
@echo "------------------------------------------------------------"
|
@echo "------------------------------------------------------------"
|
||||||
@echo ""
|
@echo ""
|
||||||
|
$(MAKE) install-recursive
|
||||||
|
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(PREFIX)/lib/$(PADLLV)
|
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$(PALIB)
|
||||||
rm -f $(PREFIX)/lib/$(PALIB)
|
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(includedir)/portaudio.h
|
||||||
rm -f $(PREFIX)/lib/$(PADLL)
|
$(MAKE) uninstall-recursive
|
||||||
rm -f $(PREFIX)/include/portaudio.h
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(OBJS) $(TESTS) lib/$(PALIB) lib/$(PADLLV)
|
$(LIBTOOL) --mode=clean rm -f $(LTOBJS) $(ALL_TESTS) lib/$(PALIB)
|
||||||
|
rm -f bin-stamp lib-stamp
|
||||||
|
-rm -rf bin lib
|
||||||
|
|
||||||
%.o: %.c Makefile $(PAINC)
|
distclean: clean
|
||||||
|
rm -f config.log config.status Makefile libtool portaudio-2.0.pc
|
||||||
|
|
||||||
|
%.o: %.c $(MAKEFILE) $(PAINC)
|
||||||
$(CC) -c $(CFLAGS) $< -o $@
|
$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
%.o: %.cpp Makefile $(PAINC)
|
%.lo: %.c $(MAKEFILE) $(PAINC)
|
||||||
|
$(LIBTOOL) --mode=compile $(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(MAKEFILE) $(PAINC)
|
||||||
$(CXX) -c $(CXXFLAGS) $< -o $@
|
$(CXX) -c $(CXXFLAGS) $< -o $@
|
||||||
|
|
||||||
%.o: %.asm
|
%.o: %.asm
|
||||||
$(NASM) $(NASMOPT) -o $@ $<
|
$(NASM) $(NASMOPT) -o $@ $<
|
||||||
|
|
||||||
bin:
|
bin-stamp:
|
||||||
mkdir bin
|
-mkdir bin
|
||||||
|
touch $@
|
||||||
|
|
||||||
lib:
|
lib-stamp:
|
||||||
mkdir lib
|
-mkdir lib
|
||||||
|
-mkdir -p src/os/win src/os/unix src/os/mac_osx src/common \
|
||||||
|
src/hostapi/oss src/hostapi/alsa src/hostapi/jack src/hostapi/asihpi \
|
||||||
|
src/hostapi/wmme src/hostapi/wdmks src/hostapi/dsound src/hostapi/wasapi
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
Makefile: Makefile.in config.status
|
||||||
|
$(SHELL) config.status
|
||||||
|
|
||||||
|
all-recursive:
|
||||||
|
for dir in $(SUBDIRS); do make -C $$dir all; done
|
||||||
|
|
||||||
|
install-recursive:
|
||||||
|
for dir in $(SUBDIRS); do make -C $$dir install; done
|
||||||
|
|
||||||
|
uninstall-recursive:
|
||||||
|
for dir in $(SUBDIRS); do make -C $$dir uninstall; done
|
||||||
|
@ -46,7 +46,7 @@ Documentation:
|
|||||||
For information on compiling programs with PortAudio, please see the
|
For information on compiling programs with PortAudio, please see the
|
||||||
tutorial at:
|
tutorial at:
|
||||||
|
|
||||||
http://www.portaudio.com/docs/pa_tutorial.html
|
http://portaudio.com/trac/wiki/TutorialDir/TutorialStart
|
||||||
|
|
||||||
Important Files and Folders:
|
Important Files and Folders:
|
||||||
pa_common/ = platform independant code
|
pa_common/ = platform independant code
|
||||||
|
@ -1,78 +1,147 @@
|
|||||||
import sys, os.path
|
import sys, os.path
|
||||||
|
|
||||||
class ConfigurationError(Exception):
|
def rsplit(toSplit, sub, max=-1):
|
||||||
def __init__(self, reason):
|
""" str.rsplit seems to have been introduced in 2.4 :( """
|
||||||
Exception.__init__(self, "Configuration failed: %s" % reason)
|
l = []
|
||||||
|
i = 0
|
||||||
|
while i != max:
|
||||||
|
try: idx = toSplit.rindex(sub)
|
||||||
|
except ValueError: break
|
||||||
|
|
||||||
def _PackageOption(pkgName, default="yes"):
|
toSplit, splitOff = toSplit[:idx], toSplit[idx + len(sub):]
|
||||||
return BoolOption("use%s" % pkgName[0].upper() + pkgName[1:], "use %s if available" % (pkgName), default)
|
l.insert(0, splitOff)
|
||||||
|
i += 1
|
||||||
|
|
||||||
def _BoolOption(opt, explanation, default="yes"):
|
l.insert(0, toSplit)
|
||||||
return BoolOption("enable%s" % opt[0].upper() + opt[1:], explanation, default)
|
return l
|
||||||
|
|
||||||
def _DirectoryOption(path, help, default):
|
sconsDir = os.path.join("build", "scons")
|
||||||
return PathOption(path, help, default)
|
SConscript(os.path.join(sconsDir, "SConscript_common"))
|
||||||
# Incompatible with the latest stable SCons
|
Import("Platform", "Posix", "ApiVer")
|
||||||
# return PathOption(path, help, default, PathOption.PathIsDir)
|
|
||||||
|
|
||||||
def _EnumOption(opt, explanation, allowedValues, default):
|
# SConscript_opts exports PortAudio options
|
||||||
assert default in allowedValues
|
optsDict = SConscript(os.path.join(sconsDir, "SConscript_opts"))
|
||||||
return EnumOption("with%s" % opt[0].upper() + opt[1:], explanation, default, allowed_values=allowedValues)
|
optionsCache = os.path.join(sconsDir, "options.cache") # Save options between runs in this cache
|
||||||
|
options = Options(optionsCache, args=ARGUMENTS)
|
||||||
|
for k in ("Installation Dirs", "Build Targets", "Host APIs", "Build Parameters", "Bindings"):
|
||||||
|
options.AddOptions(*optsDict[k])
|
||||||
|
# Propagate options into environment
|
||||||
|
env = Environment(options=options)
|
||||||
|
# Save options for next run
|
||||||
|
options.Save(optionsCache, env)
|
||||||
|
# Generate help text for options
|
||||||
|
env.Help(options.GenerateHelpText(env))
|
||||||
|
|
||||||
def getPlatform():
|
buildDir = os.path.join("#", sconsDir, env["PLATFORM"])
|
||||||
global __platform
|
|
||||||
try: return __platform
|
|
||||||
except NameError:
|
|
||||||
env = Environment()
|
|
||||||
if env["PLATFORM"] == "posix":
|
|
||||||
if sys.platform[:5] == "linux":
|
|
||||||
__platform = "linux"
|
|
||||||
else:
|
|
||||||
raise ConfigurationError("Unknown platform %s" % sys.platform)
|
|
||||||
else:
|
|
||||||
if not env["PLATFORM"] in ("win32", "cygwin") + Posix:
|
|
||||||
raise ConfigurationError("Unknown platform %s" % env["PLATFORM"])
|
|
||||||
__platform = env["PLATFORM"]
|
|
||||||
|
|
||||||
return __platform
|
# Determine parameters to build tools
|
||||||
|
|
||||||
# sunos, aix, hpux, irix, sunos appear to be platforms known by SCons, assuming they're POSIX compliant
|
|
||||||
Posix = ("linux", "darwin", "sunos", "aix", "hpux", "irix", "sunos")
|
|
||||||
Windows = ("win32", "cygwin")
|
|
||||||
env = Environment(CPPPATH="pa_common")
|
|
||||||
|
|
||||||
Platform = getPlatform()
|
|
||||||
|
|
||||||
opts = Options("options.cache", args=ARGUMENTS)
|
|
||||||
if Platform in Posix:
|
if Platform in Posix:
|
||||||
opts.AddOptions(
|
baseLinkFlags = threadCFlags = "-pthread"
|
||||||
_DirectoryOption("prefix", "installation prefix", "/usr/local"),
|
baseCxxFlags = baseCFlags = "-Wall -pedantic -pipe " + threadCFlags
|
||||||
_PackageOption("ALSA"),
|
debugCxxFlags = debugCFlags = "-g"
|
||||||
_PackageOption("OSS"),
|
optCxxFlags = optCFlags = "-O2"
|
||||||
_PackageOption("JACK"),
|
env["CCFLAGS"] = baseCFlags.split()
|
||||||
)
|
env["CXXFLAGS"] = baseCxxFlags.split()
|
||||||
elif Platform in Windows:
|
env["LINKFLAGS"] = baseLinkFlags.split()
|
||||||
if Platform == "cygwin":
|
if env["enableDebug"]:
|
||||||
opts.AddOptions(_DirectoryOption("prefix", "installation prefix", "/usr/local"))
|
env.AppendUnique(CCFLAGS=debugCFlags.split())
|
||||||
opts.AddOptions(_EnumOption("winAPI", "Windows API to use", ("wmme", "directx", "asio"), "wmme"))
|
env.AppendUnique(CXXFLAGS=debugCxxFlags.split())
|
||||||
|
if env["enableOptimize"]:
|
||||||
|
env.AppendUnique(CCFLAGS=optCFlags.split())
|
||||||
|
env.AppendUnique(CXXFLAGS=optCxxFlags.split())
|
||||||
|
if not env["enableAsserts"]:
|
||||||
|
env.AppendUnique(CPPDEFINES=["-DNDEBUG"])
|
||||||
|
if env["customCFlags"]:
|
||||||
|
env.Append(CCFLAGS=env["customCFlags"])
|
||||||
|
if env["customCxxFlags"]:
|
||||||
|
env.Append(CXXFLAGS=env["customCxxFlags"])
|
||||||
|
if env["customLinkFlags"]:
|
||||||
|
env.Append(LINKFLAGS=env["customLinkFlags"])
|
||||||
|
|
||||||
if Platform == "darwin":
|
env.Append(CPPPATH=[os.path.join("#", "include"), "common"])
|
||||||
opts.AddOptions(_EnumOption("macAPI", "Mac API to use", ("asio", "core", "sm"), "core"))
|
|
||||||
|
|
||||||
opts.AddOptions(
|
# Store all signatures in one file, otherwise .sconsign files will get installed along with our own files
|
||||||
_BoolOption("shared", "create shared library"),
|
env.SConsignFile(os.path.join(sconsDir, ".sconsign"))
|
||||||
_BoolOption("static", "create static library"),
|
|
||||||
_BoolOption("debug", "compile with debug symbols"),
|
|
||||||
_BoolOption("optimize", "compile with optimization", default="no"),
|
|
||||||
_BoolOption("asserts", "runtime assertions are helpful for debugging, but can be detrimental to performance", default="yes"),
|
|
||||||
_BoolOption("debugOutput", "enable debug output", default="no"),
|
|
||||||
("customCFlags", "customize compilation of C code", ""),
|
|
||||||
)
|
|
||||||
|
|
||||||
opts.Update(env)
|
|
||||||
opts.Save("options.cache", env)
|
|
||||||
|
|
||||||
Help(opts.GenerateHelpText(env))
|
|
||||||
|
|
||||||
env.SConscriptChdir(False)
|
env.SConscriptChdir(False)
|
||||||
SConscript("SConscript", build_dir=".build_scons", exports=["env", "Platform", "Posix", "ConfigurationError"], duplicate=False)
|
sources, sharedLib, staticLib, tests, portEnv = env.SConscript(os.path.join("src", "SConscript"),
|
||||||
|
build_dir=buildDir, duplicate=False, exports=["env"])
|
||||||
|
|
||||||
|
if Platform in Posix:
|
||||||
|
prefix = env["prefix"]
|
||||||
|
includeDir = os.path.join(prefix, "include")
|
||||||
|
libDir = os.path.join(prefix, "lib")
|
||||||
|
env.Alias("install", includeDir)
|
||||||
|
env.Alias("install", libDir)
|
||||||
|
|
||||||
|
# pkg-config
|
||||||
|
|
||||||
|
def installPkgconfig(env, target, source):
|
||||||
|
tgt = str(target[0])
|
||||||
|
src = str(source[0])
|
||||||
|
f = open(src)
|
||||||
|
try: txt = f.read()
|
||||||
|
finally: f.close()
|
||||||
|
txt = txt.replace("@prefix@", prefix)
|
||||||
|
txt = txt.replace("@exec_prefix@", prefix)
|
||||||
|
txt = txt.replace("@libdir@", libDir)
|
||||||
|
txt = txt.replace("@includedir@", includeDir)
|
||||||
|
txt = txt.replace("@LIBS@", " ".join(["-l%s" % l for l in portEnv["LIBS"]]))
|
||||||
|
txt = txt.replace("@THREAD_CFLAGS@", threadCFlags)
|
||||||
|
|
||||||
|
f = open(tgt, "w")
|
||||||
|
try: f.write(txt)
|
||||||
|
finally: f.close()
|
||||||
|
|
||||||
|
pkgconfigTgt = "portaudio-%d.0.pc" % int(ApiVer.split(".", 1)[0])
|
||||||
|
env.Command(os.path.join(libDir, "pkgconfig", pkgconfigTgt),
|
||||||
|
os.path.join("#", pkgconfigTgt + ".in"), installPkgconfig)
|
||||||
|
|
||||||
|
# Default to None, since if the user disables all targets and no Default is set, all targets
|
||||||
|
# are built by default
|
||||||
|
env.Default(None)
|
||||||
|
if env["enableTests"]:
|
||||||
|
env.Default(tests)
|
||||||
|
if env["enableShared"]:
|
||||||
|
env.Default(sharedLib)
|
||||||
|
|
||||||
|
if Platform in Posix:
|
||||||
|
def symlink(env, target, source):
|
||||||
|
trgt = str(target[0])
|
||||||
|
src = str(source[0])
|
||||||
|
|
||||||
|
if os.path.islink(trgt) or os.path.exists(trgt):
|
||||||
|
os.remove(trgt)
|
||||||
|
os.symlink(os.path.basename(src), trgt)
|
||||||
|
|
||||||
|
major, minor, micro = [int(c) for c in ApiVer.split(".")]
|
||||||
|
|
||||||
|
soFile = "%s.%s" % (os.path.basename(str(sharedLib[0])), ApiVer)
|
||||||
|
env.InstallAs(target=os.path.join(libDir, soFile), source=sharedLib)
|
||||||
|
# Install symlinks
|
||||||
|
symTrgt = os.path.join(libDir, soFile)
|
||||||
|
env.Command(os.path.join(libDir, "libportaudio.so.%d.%d" % (major, minor)),
|
||||||
|
symTrgt, symlink)
|
||||||
|
symTrgt = rsplit(symTrgt, ".", 1)[0]
|
||||||
|
env.Command(os.path.join(libDir, "libportaudio.so.%d" % major), symTrgt, symlink)
|
||||||
|
symTrgt = rsplit(symTrgt, ".", 1)[0]
|
||||||
|
env.Command(os.path.join(libDir, "libportaudio.so"), symTrgt, symlink)
|
||||||
|
|
||||||
|
if env["enableStatic"]:
|
||||||
|
env.Default(staticLib)
|
||||||
|
env.Install(libDir, staticLib)
|
||||||
|
|
||||||
|
env.Install(includeDir, os.path.join("include", "portaudio.h"))
|
||||||
|
|
||||||
|
if env["enableCxx"]:
|
||||||
|
env.SConscriptChdir(True)
|
||||||
|
cxxEnv = env.Copy()
|
||||||
|
sharedLibs, staticLibs, headers = env.SConscript(os.path.join("bindings", "cpp", "SConscript"),
|
||||||
|
exports={"env": cxxEnv, "buildDir": buildDir}, build_dir=os.path.join(buildDir, "portaudiocpp"), duplicate=False)
|
||||||
|
if env["enableStatic"]:
|
||||||
|
env.Default(staticLibs)
|
||||||
|
env.Install(libDir, staticLibs)
|
||||||
|
if env["enableShared"]:
|
||||||
|
env.Default(sharedLibs)
|
||||||
|
env.Install(libDir, sharedLibs)
|
||||||
|
env.Install(os.path.join(includeDir, "portaudiocpp"), headers)
|
||||||
|
6658
portaudio-v19/aclocal.m4
vendored
6658
portaudio-v19/aclocal.m4
vendored
File diff suppressed because it is too large
Load Diff
@ -1,60 +1,93 @@
|
|||||||
# Doxyfile 1.2.13-20020210
|
# Doxyfile 1.4.6
|
||||||
|
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# General configuration options
|
# Project related configuration options
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
PROJECT_NAME = PortAudio
|
PROJECT_NAME = PortAudio
|
||||||
PROJECT_NUMBER = 2.0
|
PROJECT_NUMBER = 2.0
|
||||||
OUTPUT_DIRECTORY = "./docs/"
|
OUTPUT_DIRECTORY = ./doc/
|
||||||
|
CREATE_SUBDIRS = NO
|
||||||
OUTPUT_LANGUAGE = English
|
OUTPUT_LANGUAGE = English
|
||||||
EXTRACT_ALL = YES
|
USE_WINDOWS_ENCODING = NO
|
||||||
EXTRACT_PRIVATE = NO
|
|
||||||
EXTRACT_STATIC = NO
|
|
||||||
EXTRACT_LOCAL_CLASSES = YES
|
|
||||||
HIDE_UNDOC_MEMBERS = NO
|
|
||||||
HIDE_UNDOC_CLASSES = NO
|
|
||||||
BRIEF_MEMBER_DESC = YES
|
BRIEF_MEMBER_DESC = YES
|
||||||
REPEAT_BRIEF = YES
|
REPEAT_BRIEF = YES
|
||||||
|
ABBREVIATE_BRIEF = "The $name class" \
|
||||||
|
"The $name widget" \
|
||||||
|
"The $name file" \
|
||||||
|
is \
|
||||||
|
provides \
|
||||||
|
specifies \
|
||||||
|
contains \
|
||||||
|
represents \
|
||||||
|
a \
|
||||||
|
an \
|
||||||
|
the
|
||||||
ALWAYS_DETAILED_SEC = NO
|
ALWAYS_DETAILED_SEC = NO
|
||||||
INLINE_INHERITED_MEMB = NO
|
INLINE_INHERITED_MEMB = NO
|
||||||
FULL_PATH_NAMES = NO
|
FULL_PATH_NAMES = NO
|
||||||
STRIP_FROM_PATH =
|
STRIP_FROM_PATH =
|
||||||
INTERNAL_DOCS = NO
|
STRIP_FROM_INC_PATH =
|
||||||
STRIP_CODE_COMMENTS = YES
|
|
||||||
CASE_SENSE_NAMES = YES
|
|
||||||
SHORT_NAMES = NO
|
SHORT_NAMES = NO
|
||||||
HIDE_SCOPE_NAMES = NO
|
|
||||||
VERBATIM_HEADERS = YES
|
|
||||||
SHOW_INCLUDE_FILES = YES
|
|
||||||
JAVADOC_AUTOBRIEF = NO
|
JAVADOC_AUTOBRIEF = NO
|
||||||
|
MULTILINE_CPP_IS_BRIEF = NO
|
||||||
DETAILS_AT_TOP = NO
|
DETAILS_AT_TOP = NO
|
||||||
INHERIT_DOCS = YES
|
INHERIT_DOCS = YES
|
||||||
|
SEPARATE_MEMBER_PAGES = NO
|
||||||
|
TAB_SIZE = 8
|
||||||
|
ALIASES =
|
||||||
|
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||||
|
OPTIMIZE_OUTPUT_JAVA = NO
|
||||||
|
BUILTIN_STL_SUPPORT = NO
|
||||||
|
DISTRIBUTE_GROUP_DOC = NO
|
||||||
|
SUBGROUPING = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Build related configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
EXTRACT_ALL = YES
|
||||||
|
EXTRACT_PRIVATE = NO
|
||||||
|
EXTRACT_STATIC = NO
|
||||||
|
EXTRACT_LOCAL_CLASSES = YES
|
||||||
|
EXTRACT_LOCAL_METHODS = NO
|
||||||
|
HIDE_UNDOC_MEMBERS = NO
|
||||||
|
HIDE_UNDOC_CLASSES = NO
|
||||||
|
HIDE_FRIEND_COMPOUNDS = NO
|
||||||
|
HIDE_IN_BODY_DOCS = NO
|
||||||
|
INTERNAL_DOCS = NO
|
||||||
|
CASE_SENSE_NAMES = YES
|
||||||
|
HIDE_SCOPE_NAMES = NO
|
||||||
|
SHOW_INCLUDE_FILES = YES
|
||||||
INLINE_INFO = YES
|
INLINE_INFO = YES
|
||||||
SORT_MEMBER_DOCS = YES
|
SORT_MEMBER_DOCS = YES
|
||||||
DISTRIBUTE_GROUP_DOC = NO
|
SORT_BRIEF_DOCS = NO
|
||||||
TAB_SIZE = 8
|
SORT_BY_SCOPE_NAME = NO
|
||||||
GENERATE_TODOLIST = YES
|
GENERATE_TODOLIST = YES
|
||||||
GENERATE_TESTLIST = YES
|
GENERATE_TESTLIST = YES
|
||||||
GENERATE_BUGLIST = YES
|
GENERATE_BUGLIST = YES
|
||||||
ALIASES =
|
GENERATE_DEPRECATEDLIST= YES
|
||||||
ENABLED_SECTIONS =
|
ENABLED_SECTIONS =
|
||||||
MAX_INITIALIZER_LINES = 30
|
MAX_INITIALIZER_LINES = 30
|
||||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
|
||||||
OPTIMIZE_OUTPUT_JAVA = NO
|
|
||||||
SHOW_USED_FILES = YES
|
SHOW_USED_FILES = YES
|
||||||
|
SHOW_DIRECTORIES = NO
|
||||||
|
FILE_VERSION_FILTER =
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# configuration options related to warning and progress messages
|
# configuration options related to warning and progress messages
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
QUIET = NO
|
QUIET = NO
|
||||||
WARNINGS = YES
|
WARNINGS = YES
|
||||||
WARN_IF_UNDOCUMENTED = YES
|
WARN_IF_UNDOCUMENTED = YES
|
||||||
|
WARN_IF_DOC_ERROR = YES
|
||||||
|
WARN_NO_PARAMDOC = NO
|
||||||
WARN_FORMAT = "$file:$line: $text"
|
WARN_FORMAT = "$file:$line: $text"
|
||||||
WARN_LOGFILE =
|
WARN_LOGFILE =
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# configuration options related to the input files
|
# configuration options related to the input files
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
INPUT = ./pa_common ./pa_win_wmme ./pa_asio ./pa_win_ds ./pa_linux_alsa ./pa_unix_oss ./pa_jack ./pa_tests
|
INPUT = src \
|
||||||
FILE_PATTERNS = *.h *.c *.cpp
|
include \
|
||||||
|
test
|
||||||
|
FILE_PATTERNS = *.h \
|
||||||
|
*.c \
|
||||||
|
*.cpp
|
||||||
RECURSIVE = YES
|
RECURSIVE = YES
|
||||||
EXCLUDE =
|
EXCLUDE =
|
||||||
EXCLUDE_SYMLINKS = NO
|
EXCLUDE_SYMLINKS = NO
|
||||||
@ -64,14 +97,18 @@ EXAMPLE_PATTERNS =
|
|||||||
EXAMPLE_RECURSIVE = NO
|
EXAMPLE_RECURSIVE = NO
|
||||||
IMAGE_PATH =
|
IMAGE_PATH =
|
||||||
INPUT_FILTER =
|
INPUT_FILTER =
|
||||||
|
FILTER_PATTERNS =
|
||||||
FILTER_SOURCE_FILES = NO
|
FILTER_SOURCE_FILES = NO
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# configuration options related to source browsing
|
# configuration options related to source browsing
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
SOURCE_BROWSER = NO
|
SOURCE_BROWSER = NO
|
||||||
INLINE_SOURCES = NO
|
INLINE_SOURCES = NO
|
||||||
|
STRIP_CODE_COMMENTS = YES
|
||||||
REFERENCED_BY_RELATION = YES
|
REFERENCED_BY_RELATION = YES
|
||||||
REFERENCES_RELATION = YES
|
REFERENCES_RELATION = YES
|
||||||
|
USE_HTAGS = NO
|
||||||
|
VERBATIM_HEADERS = YES
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# configuration options related to the alphabetical class index
|
# configuration options related to the alphabetical class index
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@ -82,13 +119,15 @@ IGNORE_PREFIX =
|
|||||||
# configuration options related to the HTML output
|
# configuration options related to the HTML output
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
GENERATE_HTML = YES
|
GENERATE_HTML = YES
|
||||||
HTML_OUTPUT = doxygen_html
|
HTML_OUTPUT = html
|
||||||
HTML_FILE_EXTENSION = .html
|
HTML_FILE_EXTENSION = .html
|
||||||
HTML_HEADER =
|
HTML_HEADER =
|
||||||
HTML_FOOTER =
|
HTML_FOOTER =
|
||||||
HTML_STYLESHEET =
|
HTML_STYLESHEET =
|
||||||
HTML_ALIGN_MEMBERS = YES
|
HTML_ALIGN_MEMBERS = YES
|
||||||
GENERATE_HTMLHELP = NO
|
GENERATE_HTMLHELP = NO
|
||||||
|
CHM_FILE =
|
||||||
|
HHC_LOCATION =
|
||||||
GENERATE_CHI = NO
|
GENERATE_CHI = NO
|
||||||
BINARY_TOC = NO
|
BINARY_TOC = NO
|
||||||
TOC_EXPAND = NO
|
TOC_EXPAND = NO
|
||||||
@ -110,6 +149,7 @@ LATEX_HEADER =
|
|||||||
PDF_HYPERLINKS = NO
|
PDF_HYPERLINKS = NO
|
||||||
USE_PDFLATEX = NO
|
USE_PDFLATEX = NO
|
||||||
LATEX_BATCHMODE = NO
|
LATEX_BATCHMODE = NO
|
||||||
|
LATEX_HIDE_INDICES = NO
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# configuration options related to the RTF output
|
# configuration options related to the RTF output
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
@ -130,11 +170,22 @@ MAN_LINKS = NO
|
|||||||
# configuration options related to the XML output
|
# configuration options related to the XML output
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
GENERATE_XML = NO
|
GENERATE_XML = NO
|
||||||
|
XML_OUTPUT = xml
|
||||||
|
XML_SCHEMA =
|
||||||
|
XML_DTD =
|
||||||
|
XML_PROGRAMLISTING = YES
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# configuration options for the AutoGen Definitions output
|
# configuration options for the AutoGen Definitions output
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
GENERATE_AUTOGEN_DEF = NO
|
GENERATE_AUTOGEN_DEF = NO
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the Perl module output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_PERLMOD = NO
|
||||||
|
PERLMOD_LATEX = NO
|
||||||
|
PERLMOD_PRETTY = YES
|
||||||
|
PERLMOD_MAKEVAR_PREFIX =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
# Configuration options related to the preprocessor
|
# Configuration options related to the preprocessor
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
ENABLE_PREPROCESSING = YES
|
ENABLE_PREPROCESSING = YES
|
||||||
@ -147,7 +198,7 @@ PREDEFINED =
|
|||||||
EXPAND_AS_DEFINED =
|
EXPAND_AS_DEFINED =
|
||||||
SKIP_FUNCTION_MACROS = YES
|
SKIP_FUNCTION_MACROS = YES
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration::addtions related to external references
|
# Configuration::additions related to external references
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
TAGFILES =
|
TAGFILES =
|
||||||
GENERATE_TAGFILE =
|
GENERATE_TAGFILE =
|
||||||
@ -162,24 +213,25 @@ HIDE_UNDOC_RELATIONS = NO
|
|||||||
HAVE_DOT = NO
|
HAVE_DOT = NO
|
||||||
CLASS_GRAPH = YES
|
CLASS_GRAPH = YES
|
||||||
COLLABORATION_GRAPH = YES
|
COLLABORATION_GRAPH = YES
|
||||||
|
GROUP_GRAPHS = YES
|
||||||
|
UML_LOOK = NO
|
||||||
TEMPLATE_RELATIONS = YES
|
TEMPLATE_RELATIONS = YES
|
||||||
INCLUDE_GRAPH = YES
|
INCLUDE_GRAPH = YES
|
||||||
INCLUDED_BY_GRAPH = YES
|
INCLUDED_BY_GRAPH = YES
|
||||||
|
CALL_GRAPH = NO
|
||||||
GRAPHICAL_HIERARCHY = YES
|
GRAPHICAL_HIERARCHY = YES
|
||||||
|
DIRECTORY_GRAPH = YES
|
||||||
DOT_IMAGE_FORMAT = png
|
DOT_IMAGE_FORMAT = png
|
||||||
DOT_PATH =
|
DOT_PATH =
|
||||||
DOTFILE_DIRS =
|
DOTFILE_DIRS =
|
||||||
MAX_DOT_GRAPH_WIDTH = 1024
|
MAX_DOT_GRAPH_WIDTH = 1024
|
||||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||||
|
MAX_DOT_GRAPH_DEPTH = 1000
|
||||||
|
DOT_TRANSPARENT = NO
|
||||||
|
DOT_MULTI_TARGETS = NO
|
||||||
GENERATE_LEGEND = YES
|
GENERATE_LEGEND = YES
|
||||||
DOT_CLEANUP = YES
|
DOT_CLEANUP = YES
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
# Configuration::addtions related to the search engine
|
# Configuration::additions related to the search engine
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
SEARCHENGINE = NO
|
SEARCHENGINE = NO
|
||||||
CGI_NAME = search.cgi
|
|
||||||
CGI_URL =
|
|
||||||
DOC_URL =
|
|
||||||
DOC_ABSPATH =
|
|
||||||
BIN_ABSPATH = /usr/local/bin/
|
|
||||||
EXT_DOC_PATHS =
|
|
||||||
|
31
portaudio-v19/config.guess
vendored
31
portaudio-v19/config.guess
vendored
@ -3,7 +3,7 @@
|
|||||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||||
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||||
|
|
||||||
timestamp='2003-07-02'
|
timestamp='2003-02-22'
|
||||||
|
|
||||||
# This file is free software; you can redistribute it and/or modify it
|
# 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
|
# under the terms of the GNU General Public License as published by
|
||||||
@ -106,7 +106,6 @@ trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
|
|||||||
: ${TMPDIR=/tmp} ;
|
: ${TMPDIR=/tmp} ;
|
||||||
{ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
|
{ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
|
||||||
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
|
{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
|
||||||
{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
|
|
||||||
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
|
{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
|
||||||
dummy=$tmp/dummy ;
|
dummy=$tmp/dummy ;
|
||||||
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
|
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
|
||||||
@ -283,9 +282,6 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
|||||||
# 1.2 uses "1.2" for uname -r.
|
# 1.2 uses "1.2" for uname -r.
|
||||||
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
Alpha*:OpenVMS:*:*)
|
|
||||||
echo alpha-hp-vms
|
|
||||||
exit 0 ;;
|
|
||||||
Alpha\ *:Windows_NT*:*)
|
Alpha\ *:Windows_NT*:*)
|
||||||
# How do we know it's Interix rather than the generic POSIX subsystem?
|
# 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
|
# Should we change UNAME_MACHINE based on the output of uname instead
|
||||||
@ -324,9 +320,6 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
|||||||
NILE*:*:*:dcosx)
|
NILE*:*:*:dcosx)
|
||||||
echo pyramid-pyramid-svr4
|
echo pyramid-pyramid-svr4
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
DRS?6000:unix:4.0:6*)
|
|
||||||
echo sparc-icl-nx6
|
|
||||||
exit 0 ;;
|
|
||||||
DRS?6000:UNIX_SV:4.2*:7*)
|
DRS?6000:UNIX_SV:4.2*:7*)
|
||||||
case `/usr/bin/uname -p` in
|
case `/usr/bin/uname -p` in
|
||||||
sparc) echo sparc-icl-nx7 && exit 0 ;;
|
sparc) echo sparc-icl-nx7 && exit 0 ;;
|
||||||
@ -751,7 +744,7 @@ EOF
|
|||||||
*:BSD/OS:*:*)
|
*:BSD/OS:*:*)
|
||||||
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
|
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
*:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
|
*:FreeBSD:*:*)
|
||||||
# Determine whether the default compiler uses glibc.
|
# Determine whether the default compiler uses glibc.
|
||||||
eval $set_cc_for_build
|
eval $set_cc_for_build
|
||||||
sed 's/^ //' << EOF >$dummy.c
|
sed 's/^ //' << EOF >$dummy.c
|
||||||
@ -763,10 +756,7 @@ EOF
|
|||||||
#endif
|
#endif
|
||||||
EOF
|
EOF
|
||||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
|
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
|
||||||
# GNU/FreeBSD systems have a "k" prefix to indicate we are using
|
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
|
||||||
# FreeBSD's kernel, but not the complete OS.
|
|
||||||
case ${LIBC} in gnu) kernel_only='k' ;; esac
|
|
||||||
echo ${UNAME_MACHINE}-unknown-${kernel_only}freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
|
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
i*:CYGWIN*:*)
|
i*:CYGWIN*:*)
|
||||||
echo ${UNAME_MACHINE}-pc-cygwin
|
echo ${UNAME_MACHINE}-pc-cygwin
|
||||||
@ -777,8 +767,8 @@ EOF
|
|||||||
i*:PW*:*)
|
i*:PW*:*)
|
||||||
echo ${UNAME_MACHINE}-pc-pw32
|
echo ${UNAME_MACHINE}-pc-pw32
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
x86:Interix*:[34]*)
|
x86:Interix*:3*)
|
||||||
echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
|
echo i586-pc-interix3
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
|
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
|
||||||
echo i${UNAME_MACHINE}-pc-mks
|
echo i${UNAME_MACHINE}-pc-mks
|
||||||
@ -807,9 +797,6 @@ EOF
|
|||||||
arm*:Linux:*:*)
|
arm*:Linux:*:*)
|
||||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
cris:Linux:*:*)
|
|
||||||
echo cris-axis-linux-gnu
|
|
||||||
exit 0 ;;
|
|
||||||
ia64:Linux:*:*)
|
ia64:Linux:*:*)
|
||||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
@ -888,9 +875,6 @@ EOF
|
|||||||
s390:Linux:*:* | s390x:Linux:*:*)
|
s390:Linux:*:* | s390x:Linux:*:*)
|
||||||
echo ${UNAME_MACHINE}-ibm-linux
|
echo ${UNAME_MACHINE}-ibm-linux
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
sh64*:Linux:*:*)
|
|
||||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
|
||||||
exit 0 ;;
|
|
||||||
sh*:Linux:*:*)
|
sh*:Linux:*:*)
|
||||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
@ -1049,7 +1033,7 @@ EOF
|
|||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
M68*:*:R3V[567]*:*)
|
M68*:*:R3V[567]*:*)
|
||||||
test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
|
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 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0)
|
3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0)
|
||||||
OS_REL=''
|
OS_REL=''
|
||||||
test -r /etc/.relid \
|
test -r /etc/.relid \
|
||||||
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
|
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
|
||||||
@ -1205,9 +1189,6 @@ EOF
|
|||||||
*:ITS:*:*)
|
*:ITS:*:*)
|
||||||
echo pdp10-unknown-its
|
echo pdp10-unknown-its
|
||||||
exit 0 ;;
|
exit 0 ;;
|
||||||
SEI:*:*:SEIUX)
|
|
||||||
echo mips-sei-seiux${UNAME_RELEASE}
|
|
||||||
exit 0 ;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
#echo '(No uname command or uname output not recognized.)' 1>&2
|
#echo '(No uname command or uname output not recognized.)' 1>&2
|
||||||
|
41
portaudio-v19/config.sub
vendored
41
portaudio-v19/config.sub
vendored
@ -3,7 +3,7 @@
|
|||||||
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
|
||||||
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
||||||
|
|
||||||
timestamp='2003-07-04'
|
timestamp='2003-02-22'
|
||||||
|
|
||||||
# This file is (in principle) common to ALL GNU software.
|
# This file is (in principle) common to ALL GNU software.
|
||||||
# The presence of a machine in this file suggests that SOME GNU software
|
# The presence of a machine in this file suggests that SOME GNU software
|
||||||
@ -118,7 +118,7 @@ esac
|
|||||||
# Here we must recognize all the valid KERNEL-OS combinations.
|
# Here we must recognize all the valid KERNEL-OS combinations.
|
||||||
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
||||||
case $maybe_os in
|
case $maybe_os in
|
||||||
nto-qnx* | linux-gnu* | kfreebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
|
nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
|
||||||
os=-$maybe_os
|
os=-$maybe_os
|
||||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
||||||
;;
|
;;
|
||||||
@ -229,7 +229,7 @@ case $basic_machine in
|
|||||||
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||||
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||||
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
|
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
|
||||||
| c4x | clipper \
|
| clipper \
|
||||||
| d10v | d30v | dlx | dsp16xx \
|
| d10v | d30v | dlx | dsp16xx \
|
||||||
| fr30 | frv \
|
| fr30 | frv \
|
||||||
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||||
@ -261,7 +261,7 @@ case $basic_machine in
|
|||||||
| sh64 | sh64le \
|
| sh64 | sh64le \
|
||||||
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
|
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
|
||||||
| strongarm \
|
| strongarm \
|
||||||
| tahoe | thumb | tic4x | tic80 | tron \
|
| tahoe | thumb | tic80 | tron \
|
||||||
| v850 | v850e \
|
| v850 | v850e \
|
||||||
| we32k \
|
| we32k \
|
||||||
| x86 | xscale | xstormy16 | xtensa \
|
| x86 | xscale | xstormy16 | xtensa \
|
||||||
@ -292,7 +292,7 @@ case $basic_machine in
|
|||||||
| a29k-* \
|
| a29k-* \
|
||||||
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
|
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
|
||||||
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
|
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
|
||||||
| alphapca5[67]-* | alpha64pca5[67]-* | amd64-* | arc-* \
|
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
|
||||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||||
| avr-* \
|
| avr-* \
|
||||||
| bs2000-* \
|
| bs2000-* \
|
||||||
@ -373,9 +373,6 @@ case $basic_machine in
|
|||||||
basic_machine=a29k-none
|
basic_machine=a29k-none
|
||||||
os=-bsd
|
os=-bsd
|
||||||
;;
|
;;
|
||||||
amd64)
|
|
||||||
basic_machine=x86_64-pc
|
|
||||||
;;
|
|
||||||
amdahl)
|
amdahl)
|
||||||
basic_machine=580-amdahl
|
basic_machine=580-amdahl
|
||||||
os=-sysv
|
os=-sysv
|
||||||
@ -771,24 +768,18 @@ case $basic_machine in
|
|||||||
pentiumpro | p6 | 6x86 | athlon | athlon_*)
|
pentiumpro | p6 | 6x86 | athlon | athlon_*)
|
||||||
basic_machine=i686-pc
|
basic_machine=i686-pc
|
||||||
;;
|
;;
|
||||||
pentiumii | pentium2 | pentiumiii | pentium3)
|
pentiumii | pentium2)
|
||||||
basic_machine=i686-pc
|
basic_machine=i686-pc
|
||||||
;;
|
;;
|
||||||
pentium4)
|
|
||||||
basic_machine=i786-pc
|
|
||||||
;;
|
|
||||||
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
|
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
|
||||||
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
|
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
;;
|
;;
|
||||||
pentiumpro-* | p6-* | 6x86-* | athlon-*)
|
pentiumpro-* | p6-* | 6x86-* | athlon-*)
|
||||||
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
;;
|
;;
|
||||||
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
|
pentiumii-* | pentium2-*)
|
||||||
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||||
;;
|
;;
|
||||||
pentium4-*)
|
|
||||||
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
|
|
||||||
;;
|
|
||||||
pn)
|
pn)
|
||||||
basic_machine=pn-gould
|
basic_machine=pn-gould
|
||||||
;;
|
;;
|
||||||
@ -847,10 +838,6 @@ case $basic_machine in
|
|||||||
sb1el)
|
sb1el)
|
||||||
basic_machine=mipsisa64sb1el-unknown
|
basic_machine=mipsisa64sb1el-unknown
|
||||||
;;
|
;;
|
||||||
sei)
|
|
||||||
basic_machine=mips-sei
|
|
||||||
os=-seiux
|
|
||||||
;;
|
|
||||||
sequent)
|
sequent)
|
||||||
basic_machine=i386-sequent
|
basic_machine=i386-sequent
|
||||||
;;
|
;;
|
||||||
@ -858,9 +845,6 @@ case $basic_machine in
|
|||||||
basic_machine=sh-hitachi
|
basic_machine=sh-hitachi
|
||||||
os=-hms
|
os=-hms
|
||||||
;;
|
;;
|
||||||
sh64)
|
|
||||||
basic_machine=sh64-unknown
|
|
||||||
;;
|
|
||||||
sparclite-wrs | simso-wrs)
|
sparclite-wrs | simso-wrs)
|
||||||
basic_machine=sparclite-wrs
|
basic_machine=sparclite-wrs
|
||||||
os=-vxworks
|
os=-vxworks
|
||||||
@ -935,6 +919,10 @@ case $basic_machine in
|
|||||||
basic_machine=t90-cray
|
basic_machine=t90-cray
|
||||||
os=-unicos
|
os=-unicos
|
||||||
;;
|
;;
|
||||||
|
tic4x | c4x*)
|
||||||
|
basic_machine=tic4x-unknown
|
||||||
|
os=-coff
|
||||||
|
;;
|
||||||
tic54x | c54x*)
|
tic54x | c54x*)
|
||||||
basic_machine=tic54x-unknown
|
basic_machine=tic54x-unknown
|
||||||
os=-coff
|
os=-coff
|
||||||
@ -1128,7 +1116,7 @@ case $os in
|
|||||||
| -aos* \
|
| -aos* \
|
||||||
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
|
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
|
||||||
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
|
| -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
|
||||||
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -kfreebsd* | -freebsd* | -riscix* \
|
| -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \
|
||||||
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
| -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
|
||||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||||
@ -1140,7 +1128,7 @@ case $os in
|
|||||||
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
|
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
|
||||||
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
|
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
|
||||||
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
|
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
|
||||||
| -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
|
| -powermax* | -dnix*)
|
||||||
# Remember, each alternative MUST END IN *, to match a version number.
|
# Remember, each alternative MUST END IN *, to match a version number.
|
||||||
;;
|
;;
|
||||||
-qnx*)
|
-qnx*)
|
||||||
@ -1286,9 +1274,6 @@ case $basic_machine in
|
|||||||
arm*-semi)
|
arm*-semi)
|
||||||
os=-aout
|
os=-aout
|
||||||
;;
|
;;
|
||||||
c4x-* | tic4x-*)
|
|
||||||
os=-coff
|
|
||||||
;;
|
|
||||||
# This must come before the *-dec entry.
|
# This must come before the *-dec entry.
|
||||||
pdp10-*)
|
pdp10-*)
|
||||||
os=-tops20
|
os=-tops20
|
||||||
|
22347
portaudio-v19/configure
vendored
22347
portaudio-v19/configure
vendored
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@ AC_PREREQ(2.13)
|
|||||||
|
|
||||||
dnl Init autoconf and make sure configure is being called
|
dnl Init autoconf and make sure configure is being called
|
||||||
dnl from the right directory
|
dnl from the right directory
|
||||||
AC_INIT([pa_common/portaudio.h])
|
AC_INIT([include/portaudio.h])
|
||||||
|
|
||||||
dnl Specify options
|
dnl Specify options
|
||||||
|
|
||||||
@ -25,6 +25,10 @@ AC_ARG_WITH(oss,
|
|||||||
[ --with-oss (default=yes)],
|
[ --with-oss (default=yes)],
|
||||||
with_oss=$withval, with_oss="yes")
|
with_oss=$withval, with_oss="yes")
|
||||||
|
|
||||||
|
AC_ARG_WITH(asihpi,
|
||||||
|
[ --with-asihpi (default=auto)],
|
||||||
|
with_asihpi=$withval, with_asihpi="yes")
|
||||||
|
|
||||||
AC_ARG_WITH(host_os,
|
AC_ARG_WITH(host_os,
|
||||||
[ --with-host_os (no default)],
|
[ --with-host_os (no default)],
|
||||||
host_os=$withval)
|
host_os=$withval)
|
||||||
@ -45,13 +49,25 @@ AC_ARG_WITH(asiodir,
|
|||||||
AC_ARG_WITH(dxdir,
|
AC_ARG_WITH(dxdir,
|
||||||
[ --with-dxdir (default=/usr/local/dx7sdk)],
|
[ --with-dxdir (default=/usr/local/dx7sdk)],
|
||||||
with_dxdir=$withval, with_dxdir="/usr/local/dx7sdk")
|
with_dxdir=$withval, with_dxdir="/usr/local/dx7sdk")
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(debug-output,
|
||||||
|
[ --enable-debug-output],
|
||||||
|
[if test x$enableval != xno ; then
|
||||||
|
AC_DEFINE(PA_ENABLE_DEBUG_OUTPUT,,[Enable debugging messages])
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(cxx,
|
||||||
|
[ --enable-cxx (default=no)],
|
||||||
|
enable_cxx=$enableval, enable_cxx="no")
|
||||||
|
|
||||||
dnl Checks for programs.
|
dnl Checks for programs.
|
||||||
|
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
AC_PROG_RANLIB
|
AC_LIBTOOL_WIN32_DLL
|
||||||
|
AC_PROG_LIBTOOL
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
|
AC_PROG_LN_S
|
||||||
AC_PATH_PROG(AR, ar, no)
|
AC_PATH_PROG(AR, ar, no)
|
||||||
if [[ $AR = "no" ]] ; then
|
if [[ $AR = "no" ]] ; then
|
||||||
AC_MSG_ERROR("Could not find ar - needed to create a library");
|
AC_MSG_ERROR("Could not find ar - needed to create a library");
|
||||||
@ -64,12 +80,13 @@ dnl checks for various host APIs and arguments to configure that
|
|||||||
dnl turn them on or off
|
dnl turn them on or off
|
||||||
|
|
||||||
AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no)
|
AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no)
|
||||||
|
AC_CHECK_LIB(hpi, HPI_SubSysCreate, have_asihpi=yes, have_asihpi=no, -lm)
|
||||||
|
|
||||||
dnl Determine the host description for the subsequent test.
|
dnl Determine the host description for the subsequent test.
|
||||||
dnl PKG_CHECK_MODULES seems to check and set the host variable also, but
|
dnl PKG_CHECK_MODULES seems to check and set the host variable also, but
|
||||||
dnl that then requires pkg-config availability which is not standard on
|
dnl that then requires pkg-config availability which is not standard on
|
||||||
dnl MinGW systems and can be a pain to install.
|
dnl MinGW systems and can be a pain to install.
|
||||||
AC_CANONICAL_HOST
|
dnl AC_CANONICAL_HOST
|
||||||
|
|
||||||
PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no)
|
PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no)
|
||||||
|
|
||||||
@ -79,16 +96,34 @@ AC_CHECK_SIZEOF(short)
|
|||||||
AC_CHECK_SIZEOF(int)
|
AC_CHECK_SIZEOF(int)
|
||||||
AC_CHECK_SIZEOF(long)
|
AC_CHECK_SIZEOF(long)
|
||||||
|
|
||||||
|
save_LIBS="${LIBS}"
|
||||||
|
AC_CHECK_LIB(rt, clock_gettime, [rt_libs=" -lrt"])
|
||||||
|
LIBS="${LIBS}${rt_libs}"
|
||||||
|
DLL_LIBS="${DLL_LIBS}${rt_libs}"
|
||||||
|
AC_CHECK_FUNCS([clock_gettime nanosleep])
|
||||||
|
LIBS="${save_LIBS}"
|
||||||
|
|
||||||
|
dnl LT_RELEASE=19
|
||||||
|
LT_CURRENT=2
|
||||||
|
LT_REVISION=0
|
||||||
|
LT_AGE=0
|
||||||
|
|
||||||
|
dnl AC_SUBST(LT_RELEASE)
|
||||||
|
AC_SUBST(LT_CURRENT)
|
||||||
|
AC_SUBST(LT_REVISION)
|
||||||
|
AC_SUBST(LT_AGE)
|
||||||
|
|
||||||
dnl extra variables
|
dnl extra variables
|
||||||
AC_SUBST(OTHER_OBJS)
|
AC_SUBST(OTHER_OBJS)
|
||||||
AC_SUBST(PADLL)
|
AC_SUBST(PADLL)
|
||||||
AC_SUBST(SHARED_FLAGS)
|
AC_SUBST(SHARED_FLAGS)
|
||||||
|
AC_SUBST(THREAD_CFLAGS)
|
||||||
AC_SUBST(DLL_LIBS)
|
AC_SUBST(DLL_LIBS)
|
||||||
AC_SUBST(CXXFLAGS)
|
AC_SUBST(CXXFLAGS)
|
||||||
AC_SUBST(NASM)
|
AC_SUBST(NASM)
|
||||||
AC_SUBST(NASMOPT)
|
AC_SUBST(NASMOPT)
|
||||||
|
|
||||||
CFLAGS="-g -O2 -Wall -pedantic -pipe -fPIC"
|
CFLAGS=${CFLAGS:-"-g -O2 -Wall -pedantic -pipe -fPIC"}
|
||||||
|
|
||||||
if [[ $ac_cv_c_bigendian = "yes" ]] ; then
|
if [[ $ac_cv_c_bigendian = "yes" ]] ; then
|
||||||
CFLAGS="$CFLAGS -DPA_BIG_ENDIAN"
|
CFLAGS="$CFLAGS -DPA_BIG_ENDIAN"
|
||||||
@ -101,10 +136,10 @@ case "${host_os}" in
|
|||||||
dnl Mac OS X configuration
|
dnl Mac OS X configuration
|
||||||
|
|
||||||
AC_DEFINE(PA_USE_COREAUDIO)
|
AC_DEFINE(PA_USE_COREAUDIO)
|
||||||
OTHER_OBJS="pa_mac/pa_mac_hostapis.o pa_unix/pa_unix_util.o pa_mac_core/pa_mac_core.o";
|
OTHER_OBJS="src/os/mac_osx/pa_mac_hostapis.o src/os/unix/pa_unix_util.o src/hostapi/coreaudio/pa_mac_core.o";
|
||||||
LIBS="-framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon";
|
LIBS="-framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon";
|
||||||
PADLL="libportaudio.dylib";
|
PADLL="libportaudio.dylib";
|
||||||
SHARED_FLAGS="-framework CoreAudio -framework AudioToolbox -framework -framework AudioUnit -framework Carbon -dynamiclib";
|
SHARED_FLAGS="-framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon -dynamiclib";
|
||||||
if [[ $with_macapi = "asio" ]] ; then
|
if [[ $with_macapi = "asio" ]] ; then
|
||||||
if [[ $with_asiodir ]] ; then
|
if [[ $with_asiodir ]] ; then
|
||||||
ASIODIR="$with_asiodir";
|
ASIODIR="$with_asiodir";
|
||||||
@ -114,7 +149,7 @@ case "${host_os}" in
|
|||||||
echo "ASIODIR: $ASIODIR";
|
echo "ASIODIR: $ASIODIR";
|
||||||
|
|
||||||
OTHER_OBJS="$CFLAGS pa_asio/iasiothiscallresolver.o $ASIODIR/host/asiodrivers.o $ASIODIR/common/asio.o $ASIODIR/host/mac/asioshlib.o";
|
OTHER_OBJS="$CFLAGS pa_asio/iasiothiscallresolver.o $ASIODIR/host/asiodrivers.o $ASIODIR/common/asio.o $ASIODIR/host/mac/asioshlib.o";
|
||||||
CFLAGS="$CFLAGS -Ipa_asio -I$ASIDIR/host/mac -I$ASIODIR/common";
|
CFLAGS="$CFLAGS -I\$(top_srcdir)/pa_asio -I$ASIDIR/host/mac -I$ASIODIR/common";
|
||||||
CXXFLAGS="$CFLAGS";
|
CXXFLAGS="$CFLAGS";
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
@ -130,14 +165,15 @@ case "${host_os}" in
|
|||||||
DXDIR="/usr/local/dx7sdk";
|
DXDIR="/usr/local/dx7sdk";
|
||||||
fi
|
fi
|
||||||
echo "DXDIR: $DXDIR"
|
echo "DXDIR: $DXDIR"
|
||||||
OTHER_OBJS="pa_win_ds/pa_win_ds.o pa_win_ds/dsound_wrapper.o pa_win/pa_win_hostapis.o pa_win/pa_win_util.o";
|
OTHER_OBJS="src/hostapi/dsound/pa_win_ds.o src/hostapi/dsound/dsound_wrapper.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o";
|
||||||
LIBS="-lwinmm -lm -ldsound -lole32";
|
LIBS="-lwinmm -lm -ldsound -lole32";
|
||||||
PADLL="portaudio.dll";
|
PADLL="portaudio.dll";
|
||||||
SHARED_FLAGS="-shared -mthreads";
|
THREAD_CFLAGS="-mthreads"
|
||||||
DLL_LIBS="-lwinmm -lm -L./dx7sdk/lib -ldsound -lole32";
|
SHARED_FLAGS="-shared";
|
||||||
|
DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L./dx7sdk/lib -ldsound -lole32";
|
||||||
#VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"";
|
#VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"";
|
||||||
#CFLAGS="$CFLAGS -I$VC98 -DPA_NO_WMME -DPA_NO_ASIO";
|
#CFLAGS="$CFLAGS -I$VC98 -DPA_NO_WMME -DPA_NO_ASIO";
|
||||||
CFLAGS="$CFLAGS -Ipa_common -I$DXDIR/include -DPA_NO_WMME -DPA_NO_ASIO" -DPA_NO_WDMKS;
|
CFLAGS="$CFLAGS -I\$(top_srcdir)/include -I$DXDIR/include -DPA_NO_WMME -DPA_NO_ASIO" -DPA_NO_WDMKS;
|
||||||
elif [[ $with_winapi = "asio" ]] ; then
|
elif [[ $with_winapi = "asio" ]] ; then
|
||||||
if [[ $with_asiodir ]] ; then
|
if [[ $with_asiodir ]] ; then
|
||||||
ASIODIR="$with_asiodir";
|
ASIODIR="$with_asiodir";
|
||||||
@ -146,12 +182,13 @@ case "${host_os}" in
|
|||||||
fi
|
fi
|
||||||
echo "ASIODIR: $ASIODIR"
|
echo "ASIODIR: $ASIODIR"
|
||||||
|
|
||||||
OTHER_OBJS="pa_asio/pa_asio.o pa_win/pa_win_hostapis.o pa_win/pa_win_util.o pa_asio/iasiothiscallresolver.o $ASIODIR/common/asio.o $ASIODIR/host/asiodrivers.o $ASIODIR/host/pc/asiolist.o";
|
OTHER_OBJS="pa_asio/pa_asio.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o pa_asio/iasiothiscallresolver.o $ASIODIR/common/asio.o $ASIODIR/host/asiodrivers.o $ASIODIR/host/pc/asiolist.o";
|
||||||
LIBS="-lwinmm -lm -lstdc++ -lole32 -luuid";
|
LIBS="-lwinmm -lm -lstdc++ -lole32 -luuid";
|
||||||
PADLL="portaudio.dll";
|
PADLL="portaudio.dll";
|
||||||
SHARED_FLAGS="-shared -mthreads";
|
THREAD_CFLAGS="-mthreads"
|
||||||
DLL_LIBS="-lwinmm -lm -lstdc++ -lole32 -luuid";
|
SHARED_FLAGS="-shared";
|
||||||
CFLAGS="$CFLAGS -ffast-math -fomit-frame-pointer -Ipa_common -Ipa_asio -I$ASIODIR/host/pc -I$ASIODIR/common -I$ASIODIR/host -DPA_NO_WMME -DPA_NO_DS -DPA_NO_WDMKS -DWINDOWS";
|
DLL_LIBS="${DLL_LIBS} -lwinmm -lm -lstdc++ -lole32 -luuid";
|
||||||
|
CFLAGS="$CFLAGS -ffast-math -fomit-frame-pointer -I\$(top_srcdir)/src/common -I\$(top_srcdir)/pa_asio -I$ASIODIR/host/pc -I$ASIODIR/common -I$ASIODIR/host -DPA_NO_WMME -DPA_NO_DS -DPA_NO_WDMKS -DWINDOWS";
|
||||||
CXXFLAGS="$CFLAGS";
|
CXXFLAGS="$CFLAGS";
|
||||||
elif [[ $with_winapi = "wdmks" ]] ; then
|
elif [[ $with_winapi = "wdmks" ]] ; then
|
||||||
if [[ $with_dxdir ]] ; then
|
if [[ $with_dxdir ]] ; then
|
||||||
@ -160,32 +197,35 @@ case "${host_os}" in
|
|||||||
DXDIR="/usr/local/dx7sdk";
|
DXDIR="/usr/local/dx7sdk";
|
||||||
fi
|
fi
|
||||||
echo "DXDIR: $DXDIR"
|
echo "DXDIR: $DXDIR"
|
||||||
OTHER_OBJS="pa_win_wdmks/pa_win_wdmks.o pa_win/pa_win_hostapis.o pa_win/pa_win_util.o";
|
OTHER_OBJS="src/hostapi/wdmks/pa_win_wdmks.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o";
|
||||||
LIBS="-lwinmm -lm -luuid -lsetupapi -lole32";
|
LIBS="-lwinmm -lm -luuid -lsetupapi -lole32";
|
||||||
PADLL="portaudio.dll";
|
PADLL="portaudio.dll";
|
||||||
SHARED_FLAGS="-shared -mthreads";
|
THREAD_CFLAGS="-mthreads"
|
||||||
DLL_LIBS="-lwinmm -lm -L./dx7sdk/lib -luuid -lsetupapi -lole32";
|
SHARED_FLAGS="-shared";
|
||||||
|
DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L./dx7sdk/lib -luuid -lsetupapi -lole32";
|
||||||
#VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"";
|
#VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"";
|
||||||
#CFLAGS="$CFLAGS -I$VC98 -DPA_NO_WMME -DPA_NO_ASIO";
|
#CFLAGS="$CFLAGS -I$VC98 -DPA_NO_WMME -DPA_NO_ASIO";
|
||||||
CFLAGS="$CFLAGS -Ipa_common -I$DXDIR/include -DPA_NO_WMME -DPA_NO_DS -DPA_NO_ASIO";
|
CFLAGS="$CFLAGS -I\$(top_srcdir)/src/common -I$DXDIR/include -DPA_NO_WMME -DPA_NO_DS -DPA_NO_ASIO";
|
||||||
else # WMME default
|
else # WMME default
|
||||||
OTHER_OBJS="pa_win_wmme/pa_win_wmme.o pa_win/pa_win_hostapis.o pa_win/pa_win_util.o";
|
OTHER_OBJS="src/hostapi/wmme/pa_win_wmme.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o";
|
||||||
LIBS="-lwinmm -lm -lstdc++ -lole32 -luuid";
|
LIBS="-lwinmm -lm -lstdc++ -lole32 -luuid";
|
||||||
PADLL="portaudio.dll";
|
PADLL="portaudio.dll";
|
||||||
SHARED_FLAGS="-shared -mthreads";
|
THREAD_CFLAGS="-mthreads"
|
||||||
DLL_LIBS="-lwinmm";
|
SHARED_FLAGS="-shared";
|
||||||
CFLAGS="$CFLAGS -Ipa_common -DPA_NO_DS -DPA_NO_ASIO -DPA_NO_WDMKS";
|
DLL_LIBS="${DLL_LIBS} -lwinmm";
|
||||||
|
CFLAGS="$CFLAGS -I\$(top_srcdir)/src/common -DPA_NO_DS -DPA_NO_ASIO -DPA_NO_WDMKS";
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
cygwin* )
|
cygwin* )
|
||||||
dnl Cygwin configuration
|
dnl Cygwin configuration
|
||||||
|
|
||||||
OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
|
OTHER_OBJS="src/hostapi/wmme/pa_win_wmme.o";
|
||||||
LIBS="-lwinmm -lm";
|
LIBS="-lwinmm -lm";
|
||||||
PADLL="portaudio.dll";
|
PADLL="portaudio.dll";
|
||||||
SHARED_FLAGS="-shared -mthreads";
|
THREAD_CFLAGS="-mthreads"
|
||||||
DLL_LIBS="-lwinmm";
|
SHARED_FLAGS="-shared";
|
||||||
|
DLL_LIBS="${DLL_LIBS} -lwinmm";
|
||||||
;;
|
;;
|
||||||
|
|
||||||
irix* )
|
irix* )
|
||||||
@ -203,48 +243,68 @@ case "${host_os}" in
|
|||||||
|
|
||||||
dnl The _REENTRANT option for pthread safety. Perhaps not necessary but it 'll do no harm.
|
dnl The _REENTRANT option for pthread safety. Perhaps not necessary but it 'll do no harm.
|
||||||
dnl
|
dnl
|
||||||
CFLAGS="$CFLAGS -D_REENTRANT"
|
THREAD_CFLAGS="-D_REENTRANT"
|
||||||
|
|
||||||
OTHER_OBJS="pa_sgi/pa_sgi.o pa_unix/pa_unix_hostapis.o pa_unix/pa_unix_util.o";
|
OTHER_OBJS="pa_sgi/pa_sgi.o src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o";
|
||||||
|
|
||||||
dnl SGI books say -lpthread should be the last of the libs mentioned.
|
dnl SGI books say -lpthread should be the last of the libs mentioned.
|
||||||
dnl
|
dnl
|
||||||
LIBS="-lm -ldmedia -laudio -lpthread";
|
LIBS="-lm -ldmedia -laudio -lpthread";
|
||||||
PADLL="libportaudio.so";
|
PADLL="libportaudio.so";
|
||||||
SHARED_FLAGS="-shared";
|
SHARED_FLAGS="";
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
dnl Unix configuration
|
dnl Unix configuration
|
||||||
|
|
||||||
AC_CHECK_LIB(pthread, pthread_create,
|
AC_CHECK_LIB(pthread, pthread_create,[have_pthread="yes"]
|
||||||
,
|
,
|
||||||
AC_MSG_ERROR([libpthread not found!]))
|
AC_MSG_ERROR([libpthread not found!]))
|
||||||
|
|
||||||
if [[ $have_alsa = "yes" ] && [ $with_alsa != "no" ]] ; then
|
if [[ $have_alsa = "yes" ] && [ $with_alsa != "no" ]] ; then
|
||||||
LIBS="$LIBS -lasound"
|
|
||||||
DLL_LIBS="$DLL_LIBS -lasound"
|
DLL_LIBS="$DLL_LIBS -lasound"
|
||||||
OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/pa_linux_alsa.o"
|
OTHER_OBJS="$OTHER_OBJS src/hostapi/alsa/pa_linux_alsa.o"
|
||||||
AC_DEFINE(PA_USE_ALSA)
|
AC_DEFINE(PA_USE_ALSA)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $have_jack = "yes" ] && [ $with_jack != "no" ]] ; then
|
if [[ $have_jack = "yes" ] && [ $with_jack != "no" ]] ; then
|
||||||
LIBS="$LIBS $JACK_LIBS"
|
|
||||||
DLL_LIBS="$DLL_LIBS $JACK_LIBS"
|
DLL_LIBS="$DLL_LIBS $JACK_LIBS"
|
||||||
CFLAGS="$CFLAGS $JACK_CFLAGS"
|
CFLAGS="$CFLAGS $JACK_CFLAGS"
|
||||||
OTHER_OBJS="$OTHER_OBJS pa_jack/pa_jack.o"
|
OTHER_OBJS="$OTHER_OBJS src/hostapi/jack/pa_jack.o"
|
||||||
AC_DEFINE(PA_USE_JACK)
|
AC_DEFINE(PA_USE_JACK)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $with_oss != "no" ]] ; then
|
if [[ $with_oss != "no" ]] ; then
|
||||||
OTHER_OBJS="$OTHER_OBJS pa_unix_oss/pa_unix_oss.o"
|
OTHER_OBJS="$OTHER_OBJS src/hostapi/oss/pa_unix_oss.o"
|
||||||
AC_DEFINE(PA_USE_OSS)
|
AC_DEFINE(PA_USE_OSS)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ $have_asihpi = "yes" ] && [ $with_asihpi != "no" ]] ; then
|
||||||
|
LIBS="$LIBS -lhpi"
|
||||||
|
DLL_LIBS="$DLL_LIBS -lhpi"
|
||||||
|
OTHER_OBJS="$OTHER_OBJS src/hostapi/asihpi/pa_linux_asihpi.o"
|
||||||
|
AC_DEFINE(PA_USE_ASIHPI)
|
||||||
|
fi
|
||||||
|
|
||||||
|
THREAD_CFLAGS="-pthread"
|
||||||
|
DLL_LIBS="$DLL_LIBS -lm -lpthread";
|
||||||
LIBS="$LIBS -lm -lpthread";
|
LIBS="$LIBS -lm -lpthread";
|
||||||
PADLL="libportaudio.so";
|
PADLL="libportaudio.so";
|
||||||
SHARED_FLAGS="-shared -fPIC";
|
SHARED_FLAGS="-shared -fPIC";
|
||||||
|
|
||||||
OTHER_OBJS="$OTHER_OBJS pa_unix/pa_unix_hostapis.o pa_unix/pa_unix_util.o"
|
OTHER_OBJS="$OTHER_OBJS src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o"
|
||||||
esac
|
esac
|
||||||
|
CFLAGS="$CFLAGS $THREAD_CFLAGS"
|
||||||
|
|
||||||
AC_OUTPUT([Makefile])
|
if test "$enable_cxx" = "yes"; then
|
||||||
|
AC_CONFIG_SUBDIRS([bindings/cpp])
|
||||||
|
ENABLE_CXX_TRUE=""
|
||||||
|
ENABLE_CXX_FALE="#"
|
||||||
|
else
|
||||||
|
ENABLE_CXX_TRUE="#"
|
||||||
|
ENABLE_CXX_FALE=""
|
||||||
|
fi
|
||||||
|
AC_SUBST(ENABLE_CXX_TRUE)
|
||||||
|
AC_SUBST(ENABLE_CXX_FALSE)
|
||||||
|
|
||||||
|
AC_OUTPUT([Makefile portaudio-2.0.pc])
|
||||||
|
122
portaudio-v19/include/pa_asio.h
Normal file
122
portaudio-v19/include/pa_asio.h
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
#ifndef PA_ASIO_H
|
||||||
|
#define PA_ASIO_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief ASIO-specific PortAudio API extension header file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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 preferredLatency 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 );
|
||||||
|
|
||||||
|
|
||||||
|
/** Display the ASIO control panel for the specified device.
|
||||||
|
|
||||||
|
@param device The global index of the device whose control panel is to be displayed.
|
||||||
|
@param systemSpecific On Windows, the calling application's main window handle,
|
||||||
|
on Macintosh this value should be zero.
|
||||||
|
*/
|
||||||
|
PaError PaAsio_ShowControlPanel( PaDeviceIndex device, void* systemSpecific );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Retrieve a pointer to a string containing the name of the specified
|
||||||
|
input channel. The string is valid until Pa_Terminate is called.
|
||||||
|
|
||||||
|
The string will be no longer than 32 characters including the null terminator.
|
||||||
|
*/
|
||||||
|
PaError PaAsio_GetInputChannelName( PaDeviceIndex device, int channelIndex,
|
||||||
|
const char** channelName );
|
||||||
|
|
||||||
|
|
||||||
|
/** Retrieve a pointer to a string containing the name of the specified
|
||||||
|
input channel. The string is valid until Pa_Terminate is called.
|
||||||
|
|
||||||
|
The string will be no longer than 32 characters including the null terminator.
|
||||||
|
*/
|
||||||
|
PaError PaAsio_GetOutputChannelName( PaDeviceIndex device, int channelIndex,
|
||||||
|
const char** channelName );
|
||||||
|
|
||||||
|
|
||||||
|
#define paAsioUseChannelSelectors (0x01)
|
||||||
|
|
||||||
|
typedef struct PaAsioStreamInfo{
|
||||||
|
unsigned long size; /**< sizeof(PaAsioStreamInfo) */
|
||||||
|
PaHostApiTypeId hostApiType; /**< paASIO */
|
||||||
|
unsigned long version; /**< 1 */
|
||||||
|
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
/* Support for opening only specific channels of an ASIO device.
|
||||||
|
If the paAsioUseChannelSelectors flag is set, channelSelectors is a
|
||||||
|
pointer to an array of integers specifying the device channels to use.
|
||||||
|
When used, the length of the channelSelectors array must match the
|
||||||
|
corresponding channelCount parameter to Pa_OpenStream() otherwise a
|
||||||
|
crash may result.
|
||||||
|
The values in the selectors array must specify channels within the
|
||||||
|
range of supported channels for the device or paInvalidChannelCount will
|
||||||
|
result.
|
||||||
|
*/
|
||||||
|
int *channelSelectors;
|
||||||
|
}PaAsioStreamInfo;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif /* PA_ASIO_H */
|
64
portaudio-v19/include/pa_linux_alsa.h
Normal file
64
portaudio-v19/include/pa_linux_alsa.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#ifndef PA_LINUX_ALSA_H
|
||||||
|
#define PA_LINUX_ALSA_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* PortAudio Portable Real-Time Audio Library
|
||||||
|
* ALSA-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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
* ALSA-specific PortAudio API extension header file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct PaAlsaStreamInfo
|
||||||
|
{
|
||||||
|
unsigned long size;
|
||||||
|
PaHostApiTypeId hostApiType;
|
||||||
|
unsigned long version;
|
||||||
|
|
||||||
|
const char *deviceString;
|
||||||
|
}
|
||||||
|
PaAlsaStreamInfo;
|
||||||
|
|
||||||
|
void PaAlsa_InitializeStreamInfo( PaAlsaStreamInfo *info );
|
||||||
|
|
||||||
|
void PaAlsa_EnableRealtimeScheduling( PaStream *s, int enable );
|
||||||
|
|
||||||
|
void PaAlsa_EnableWatchdog( PaStream *s, int enable );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
70
portaudio-v19/include/pa_mac_core.h
Normal file
70
portaudio-v19/include/pa_mac_core.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Mac spcific flags for PA.
|
||||||
|
* portaudio.h should be included before this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A pointer to a paMacCoreStreamInfo may be passed as
|
||||||
|
* the hostApiSpecificStreamInfo in the PaStreamParameters struct
|
||||||
|
* when opening a stream or querying the format. Use NULL, for the
|
||||||
|
* defaults. Note that for duplex streams, both infos should be the
|
||||||
|
* same or behaviour is undefined.
|
||||||
|
*/
|
||||||
|
typedef struct paMacCoreStreamInfo
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
unsigned long flags; /* flags to modify behaviour */
|
||||||
|
} paMacCoreStreamInfo;
|
||||||
|
|
||||||
|
/* Use this function to initialize a paMacCoreStreamInfo struct
|
||||||
|
using the requested flags. */
|
||||||
|
void paSetupMacCoreStreamInfo( paMacCoreStreamInfo *data, unsigned long flags )
|
||||||
|
{
|
||||||
|
bzero( data, sizeof( paMacCoreStreamInfo ) );
|
||||||
|
data->size = sizeof( paMacCoreStreamInfo );
|
||||||
|
data->hostApiType = paCoreAudio;
|
||||||
|
data->version = 0x01;
|
||||||
|
data->flags = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following flags alter the behaviour of PA on the mac platform.
|
||||||
|
* they can be ORed together. These should work both for opening and
|
||||||
|
* checking a device.
|
||||||
|
*/
|
||||||
|
/* Allows PortAudio to change things like the device's frame size,
|
||||||
|
* which allows for much lower latency, but might disrupt the device
|
||||||
|
* if other programs are using it, even when you are just Querying
|
||||||
|
* the device. */
|
||||||
|
const unsigned long paMacCore_ChangeDeviceParameters = 0x01;
|
||||||
|
|
||||||
|
/* In combination with the above flag,
|
||||||
|
* causes the stream opening to fail, unless the exact sample rates
|
||||||
|
* are supported by the device. */
|
||||||
|
const unsigned long paMacCore_FailIfConversionRequired = 0x02;
|
||||||
|
|
||||||
|
/* These flags set the SR conversion quality, if required. The wierd ordering
|
||||||
|
* allows Maximum Quality to be the default.*/
|
||||||
|
const unsigned long paMacCore_ConversionQualityMin = 0x0100;
|
||||||
|
const unsigned long paMacCore_ConversionQualityMedium = 0x0200;
|
||||||
|
const unsigned long paMacCore_ConversionQualityLow = 0x0300;
|
||||||
|
const unsigned long paMacCore_ConversionQualityHigh = 0x0400;
|
||||||
|
const unsigned long paMacCore_ConversionQualityMax = 0x0000;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Here are some "preset" combinations of flags (above) to get to some
|
||||||
|
* common configurations. THIS IS OVERKILL, but if more flags are added
|
||||||
|
* it won't be.
|
||||||
|
*/
|
||||||
|
/*This is the default setting: do as much sample rate conversion as possible
|
||||||
|
* and as little mucking with the device as possible. */
|
||||||
|
const unsigned long paMacCorePlayNice = 0x00;
|
||||||
|
/*This setting is tuned for pro audio apps. It allows SR conversion on input
|
||||||
|
and output, but it tries to set the appropriate SR on the device.*/
|
||||||
|
const unsigned long paMacCorePro = 0x01;
|
||||||
|
/*This is a setting to minimize CPU usage and still play nice.*/
|
||||||
|
const unsigned long paMacCoreMinimizeCPUButPlayNice = 0x0100;
|
||||||
|
/*This is a setting to minimize CPU usage, even if that means interrupting the device. */
|
||||||
|
const unsigned long paMacCoreMinimizeCPU = 0x0101;
|
160
portaudio-v19/include/pa_win_wmme.h
Normal file
160
portaudio-v19/include/pa_win_wmme.h
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
#ifndef PA_WIN_WMME_H
|
||||||
|
#define PA_WIN_WMME_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief WMME-specific PortAudio API extension header file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "portaudio.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#define paWinMmeUseLowLevelLatencyParameters (0x01)
|
||||||
|
#define paWinMmeUseMultipleDevices (0x02) /* use mme specific multiple device feature */
|
||||||
|
|
||||||
|
|
||||||
|
/* 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%
|
||||||
|
This flag disables any priority throttling. The processing thread will always
|
||||||
|
run at THREAD_PRIORITY_TIME_CRITICAL.
|
||||||
|
*/
|
||||||
|
#define paWinMmeDontThrottleOverloadedProcessingThread (0x08)
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
If PaWinMmeStreamInfo structures with PaWinMmeUseLowLevelLatencyParameters
|
||||||
|
are supplied for both input and output in a full duplex stream, then the
|
||||||
|
input and output framesPerBuffer must be the same, or the larger of the
|
||||||
|
two must be a multiple of the smaller, otherwise a
|
||||||
|
paIncompatibleHostApiSpecificStreamInfo error will be returned from
|
||||||
|
Pa_OpenStream().
|
||||||
|
*/
|
||||||
|
unsigned long framesPerBuffer;
|
||||||
|
unsigned long bufferCount; /* formerly 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;
|
||||||
|
|
||||||
|
|
||||||
|
/** Retrieve the number of wave in handles used by a PortAudio WinMME stream.
|
||||||
|
Returns zero if the stream is output only.
|
||||||
|
|
||||||
|
@return A non-negative value indicating the number of wave in handles
|
||||||
|
or, a PaErrorCode (which are always negative) if PortAudio is not initialized
|
||||||
|
or an error is encountered.
|
||||||
|
|
||||||
|
@see PaWinMME_GetStreamInputHandle
|
||||||
|
*/
|
||||||
|
int PaWinMME_GetStreamInputHandleCount( PaStream* stream );
|
||||||
|
|
||||||
|
|
||||||
|
/** Retrieve a wave in handle used by a PortAudio WinMME stream.
|
||||||
|
|
||||||
|
@param stream The stream to query.
|
||||||
|
@param handleIndex The zero based index of the wave in handle to retrieve. This
|
||||||
|
should be in the range [0, PaWinMME_GetStreamInputHandle(stream)-1].
|
||||||
|
|
||||||
|
@return A valid wave in handle, or NULL if an error occurred.
|
||||||
|
|
||||||
|
@see PaWinMME_GetStreamInputHandle
|
||||||
|
*/
|
||||||
|
HWAVEIN PaWinMME_GetStreamInputHandle( PaStream* stream, int handleIndex );
|
||||||
|
|
||||||
|
|
||||||
|
/** Retrieve the number of wave out handles used by a PortAudio WinMME stream.
|
||||||
|
Returns zero if the stream is input only.
|
||||||
|
|
||||||
|
@return A non-negative value indicating the number of wave out handles
|
||||||
|
or, a PaErrorCode (which are always negative) if PortAudio is not initialized
|
||||||
|
or an error is encountered.
|
||||||
|
|
||||||
|
@see PaWinMME_GetStreamOutputHandle
|
||||||
|
*/
|
||||||
|
int PaWinMME_GetStreamOutputHandleCount( PaStream* stream );
|
||||||
|
|
||||||
|
|
||||||
|
/** Retrieve a wave out handle used by a PortAudio WinMME stream.
|
||||||
|
|
||||||
|
@param stream The stream to query.
|
||||||
|
@param handleIndex The zero based index of the wave out handle to retrieve.
|
||||||
|
This should be in the range [0, PaWinMME_GetStreamOutputHandleCount(stream)-1].
|
||||||
|
|
||||||
|
@return A valid wave out handle, or NULL if an error occurred.
|
||||||
|
|
||||||
|
@see PaWinMME_GetStreamOutputHandleCount
|
||||||
|
*/
|
||||||
|
HWAVEOUT PaWinMME_GetStreamOutputHandle( PaStream* stream, int handleIndex );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif /* PA_WIN_WMME_H */
|
1126
portaudio-v19/include/portaudio.h
Normal file
1126
portaudio-v19/include/portaudio.h
Normal file
File diff suppressed because it is too large
Load Diff
198
portaudio-v19/src/SConscript
Normal file
198
portaudio-v19/src/SConscript
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
import os.path, copy, sys
|
||||||
|
|
||||||
|
def checkSymbol(conf, header, library=None, symbol=None, autoAdd=True, critical=False, pkgName=None):
|
||||||
|
""" Check for symbol in library, optionally look only for header.
|
||||||
|
@param conf: Configure instance.
|
||||||
|
@param header: The header file where the symbol is declared.
|
||||||
|
@param library: The library in which the symbol exists, if None it is taken to be the standard C library.
|
||||||
|
@param symbol: The symbol to look for, if None only the header will be looked up.
|
||||||
|
@param autoAdd: Automatically link with this library if check is positive.
|
||||||
|
@param critical: Raise on error?
|
||||||
|
@param pkgName: Optional name of pkg-config entry for library, to determine build parameters.
|
||||||
|
@return: True/False
|
||||||
|
"""
|
||||||
|
origEnv = conf.env.Copy() # Copy unmodified environment so we can restore it upon error
|
||||||
|
env = conf.env
|
||||||
|
if library is None:
|
||||||
|
library = "c" # Standard library
|
||||||
|
autoAdd = False
|
||||||
|
|
||||||
|
if pkgName is not None:
|
||||||
|
origLibs = copy.copy(env.get("LIBS", None))
|
||||||
|
|
||||||
|
try: env.ParseConfig("pkg-config --silence-errors %s --cflags --libs" % pkgName)
|
||||||
|
except: pass
|
||||||
|
else:
|
||||||
|
# I see no other way of checking that the parsing succeeded, if it did add no more linking parameters
|
||||||
|
if env.get("LIBS", None) != origLibs:
|
||||||
|
autoAdd = False
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not conf.CheckCHeader(header, include_quotes="<>"):
|
||||||
|
raise ConfigurationError("missing header %s" % header)
|
||||||
|
if symbol is not None and not conf.CheckLib(library, symbol, language="C", autoadd=autoAdd):
|
||||||
|
raise ConfigurationError("missing symbol %s in library %s" % (symbol, library))
|
||||||
|
except ConfigurationError:
|
||||||
|
conf.env = origEnv
|
||||||
|
if not critical:
|
||||||
|
return False
|
||||||
|
raise
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
import SCons.Errors
|
||||||
|
|
||||||
|
# Import common variables
|
||||||
|
|
||||||
|
# Could use '#' to refer to top-level SConstruct directory, but looks like env.SConsignFile doesn't interpret this at least :(
|
||||||
|
sconsDir = os.path.abspath(os.path.join("build", "scons"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
Import("Platform", "Posix", "ConfigurationError", "ApiVer")
|
||||||
|
except SCons.Errors.UserError:
|
||||||
|
# The common objects must be exported first
|
||||||
|
SConscript(os.path.join(sconsDir, "SConscript_common"))
|
||||||
|
Import("Platform", "Posix", "ConfigurationError", "ApiVer")
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
# This will be manipulated
|
||||||
|
env = env.Copy()
|
||||||
|
|
||||||
|
# We operate with a set of needed libraries and optional libraries, the latter stemming from host API implementations.
|
||||||
|
# For libraries of both types we record a set of values that is used to look for the library in question, during
|
||||||
|
# configuration. If the corresponding library for a host API implementation isn't found, the implementation is left out.
|
||||||
|
neededLibs = []
|
||||||
|
optionalImpls = {}
|
||||||
|
if Platform in Posix:
|
||||||
|
env.Append(CPPPATH=os.path.join("os", "unix"))
|
||||||
|
neededLibs += [("pthread", "pthread.h", "pthread_create"), ("m", "math.h", "sin")]
|
||||||
|
if env["useALSA"]:
|
||||||
|
optionalImpls["ALSA"] = ("asound", "alsa/asoundlib.h", "snd_pcm_open")
|
||||||
|
if env["useJACK"]:
|
||||||
|
optionalImpls["JACK"] = ("jack", "jack/jack.h", "jack_client_new")
|
||||||
|
if env["useOSS"]:
|
||||||
|
# TODO: It looks like the prefix for soundcard.h depends on the platform
|
||||||
|
optionalImpls["OSS"] = ("oss", "sys/soundcard.h", None)
|
||||||
|
if env["useASIHPI"]:
|
||||||
|
optionalImpls["ASIHPI"] = ("hpi", "asihpi/hpi.h", "HPI_SubSysCreate")
|
||||||
|
else:
|
||||||
|
raise ConfigurationError("unknown platform %s" % Platform)
|
||||||
|
|
||||||
|
if Platform == "darwin":
|
||||||
|
env.Append(LINKFLAGS=["-framework CoreAudio", "-framework AudioToolBox"])
|
||||||
|
env.Append(CPPDEFINES=["PA_USE_COREAUDIO"])
|
||||||
|
elif Platform == "cygwin":
|
||||||
|
env.Append(LIBS=["winmm"])
|
||||||
|
elif Platform == "irix":
|
||||||
|
neededLibs += [("audio", "dmedia/audio.h", "alOpenPort"), ("dmedia", "dmedia/dmedia.h", "dmGetUST")]
|
||||||
|
env.Append(CPPDEFINES=["PA_USE_SGI"])
|
||||||
|
|
||||||
|
def CheckCTypeSize(context, tp):
|
||||||
|
""" Check size of C type.
|
||||||
|
@param context: A configuration context.
|
||||||
|
@param tp: The type to check.
|
||||||
|
@return: Size of type, in bytes.
|
||||||
|
"""
|
||||||
|
context.Message("Checking the size of C type %s..." % tp)
|
||||||
|
ret = context.TryRun("""
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
printf("%%d", sizeof(%s));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
""" % tp, ".c")
|
||||||
|
if not ret[0]:
|
||||||
|
context.Result(" Couldn't obtain size of type %s!" % tp)
|
||||||
|
return None
|
||||||
|
|
||||||
|
assert ret[1]
|
||||||
|
sz = int(ret[1])
|
||||||
|
context.Result("%d" % sz)
|
||||||
|
return sz
|
||||||
|
|
||||||
|
"""
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
env.Append(CPPDEFINES=["PA_LITTLE_ENDIAN"])
|
||||||
|
elif sys.byteorder == "big":
|
||||||
|
env.Append(CPPDEFINES=["PA_BIG_ENDIAN"])
|
||||||
|
else:
|
||||||
|
raise ConfigurationError("unknown byte order: %s" % sys.byteorder)
|
||||||
|
"""
|
||||||
|
if env["enableDebugOutput"]:
|
||||||
|
env.Append(CPPDEFINES=["PA_ENABLE_DEBUG_OUTPUT"])
|
||||||
|
|
||||||
|
# Start configuration
|
||||||
|
|
||||||
|
# Use an absolute path for conf_dir, otherwise it gets created both relative to current directory and build directory
|
||||||
|
conf = env.Configure(log_file=os.path.join(sconsDir, "sconf.log"), custom_tests={"CheckCTypeSize": CheckCTypeSize},
|
||||||
|
conf_dir=os.path.join(sconsDir, ".sconf_temp"))
|
||||||
|
conf.env.Append(CPPDEFINES=["SIZEOF_SHORT=%d" % conf.CheckCTypeSize("short")])
|
||||||
|
conf.env.Append(CPPDEFINES=["SIZEOF_INT=%d" % conf.CheckCTypeSize("int")])
|
||||||
|
conf.env.Append(CPPDEFINES=["SIZEOF_LONG=%d" % conf.CheckCTypeSize("long")])
|
||||||
|
if checkSymbol(conf, "time.h", "rt", "clock_gettime"):
|
||||||
|
conf.env.Append(CPPDEFINES=["HAVE_CLOCK_GETTIME"])
|
||||||
|
if checkSymbol(conf, "time.h", symbol="nanosleep"):
|
||||||
|
conf.env.Append(CPPDEFINES=["HAVE_NANOSLEEP"])
|
||||||
|
|
||||||
|
# Look for needed libraries and link with them
|
||||||
|
for lib, hdr, sym in neededLibs:
|
||||||
|
checkSymbol(conf, hdr, lib, sym, critical=True)
|
||||||
|
# Look for host API libraries, if a library isn't found disable corresponding host API implementation.
|
||||||
|
for name, val in optionalImpls.items():
|
||||||
|
lib, hdr, sym = val
|
||||||
|
if checkSymbol(conf, hdr, lib, sym, critical=False, pkgName=name.lower()):
|
||||||
|
conf.env.Append(CPPDEFINES=["PA_USE_%s=1" % name.upper()])
|
||||||
|
else:
|
||||||
|
del optionalImpls[name]
|
||||||
|
|
||||||
|
# Configuration finished
|
||||||
|
env = conf.Finish()
|
||||||
|
|
||||||
|
# PA infrastructure
|
||||||
|
CommonSources = [os.path.join("common", f) for f in "pa_allocation.c pa_converters.c pa_cpuload.c pa_dither.c pa_front.c \
|
||||||
|
pa_process.c pa_skeleton.c pa_stream.c pa_trace.c".split()]
|
||||||
|
|
||||||
|
# Host API implementations
|
||||||
|
ImplSources = []
|
||||||
|
if Platform in Posix:
|
||||||
|
ImplSources += [os.path.join("os", "unix", f) for f in "pa_unix_hostapis.c pa_unix_util.c".split()]
|
||||||
|
|
||||||
|
if "ALSA" in optionalImpls:
|
||||||
|
ImplSources.append(os.path.join("hostapi", "alsa", "pa_linux_alsa.c"))
|
||||||
|
if "JACK" in optionalImpls:
|
||||||
|
ImplSources.append(os.path.join("hostapi", "jack", "pa_jack.c"))
|
||||||
|
if "OSS" in optionalImpls:
|
||||||
|
ImplSources.append(os.path.join("hostapi", "oss", "pa_unix_oss.c"))
|
||||||
|
if "ASIHPI" in optionalImpls:
|
||||||
|
ImplSources.append(os.path.join("hostapi", "asihpi", "pa_linux_asihpi.c"))
|
||||||
|
|
||||||
|
|
||||||
|
sources = CommonSources + ImplSources
|
||||||
|
|
||||||
|
sharedLibEnv = env.Copy()
|
||||||
|
if Platform in Posix:
|
||||||
|
# Add soname to library, this is so a reference is made to the versioned library in programs linking against libportaudio.so
|
||||||
|
sharedLibEnv.AppendUnique(SHLINKFLAGS="-Wl,-soname=libportaudio.so.%d" % int(ApiVer.split(".")[0]))
|
||||||
|
sharedLib = sharedLibEnv.SharedLibrary(target="portaudio", source=sources)
|
||||||
|
|
||||||
|
staticLib = env.StaticLibrary(target="portaudio", source=sources)
|
||||||
|
|
||||||
|
if Platform in Posix:
|
||||||
|
prefix = env["prefix"]
|
||||||
|
includeDir = os.path.join(prefix, "include")
|
||||||
|
libDir = os.path.join(prefix, "lib")
|
||||||
|
|
||||||
|
testNames = ["patest_sine", "paqa_devs", "paqa_errs", "patest1", "patest_buffer", "patest_callbackstop", "patest_clip", \
|
||||||
|
"patest_dither", "patest_hang", "patest_in_overflow", "patest_latency", "patest_leftright", "patest_longsine", \
|
||||||
|
"patest_many", "patest_maxsines", "patest_multi_sine", "patest_out_underflow", "patest_pink", "patest_prime", \
|
||||||
|
"patest_read_record", "patest_record", "patest_ringmix", "patest_saw", "patest_sine8", "patest_sine", \
|
||||||
|
"patest_sine_time", "patest_start_stop", "patest_stop", "patest_sync", \
|
||||||
|
"patest_toomanysines", "patest_underflow", "patest_wire", "patest_write_sine", "pa_devs", "pa_fuzz", "pa_minlat"]
|
||||||
|
|
||||||
|
# The test directory ("bin") should be in the top-level PA directory
|
||||||
|
tests = [env.Program(target=os.path.join("#", "bin", name), source=[os.path.join("#", "test", name + ".c"),
|
||||||
|
staticLib]) for name in testNames]
|
||||||
|
|
||||||
|
Return("sources", "sharedLib", "staticLib", "tests", "env")
|
234
portaudio-v19/src/common/pa_allocation.c
Normal file
234
portaudio-v19/src/common/pa_allocation.c
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* $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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Allocation Group implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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 = (struct PaUtilAllocationGroupLink *)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 )
|
||||||
|
{
|
||||||
|
if( previous )
|
||||||
|
{
|
||||||
|
previous->next = current->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
group->allocations = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
current->buffer = 0;
|
||||||
|
current->next = group->spareLinks;
|
||||||
|
group->spareLinks = current;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
95
portaudio-v19/src/common/pa_allocation.h
Normal file
95
portaudio-v19/src/common/pa_allocation.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
#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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Allocation Group prototypes. An Allocation Group makes it easy to
|
||||||
|
allocate multiple blocks of memory and free them all simultanously.
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
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 */
|
1926
portaudio-v19/src/common/pa_converters.c
Normal file
1926
portaudio-v19/src/common/pa_converters.c
Normal file
File diff suppressed because it is too large
Load Diff
254
portaudio-v19/src/common/pa_converters.h
Normal file
254
portaudio-v19/src/common/pa_converters.h
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
#ifndef PA_CONVERTERS_H
|
||||||
|
#define PA_CONVERTERS_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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
|
||||||
|
@brief Conversion functions used to convert buffers of samples from one
|
||||||
|
format to another.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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 PaUtilConverter 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 );
|
||||||
|
|
||||||
|
|
||||||
|
/** The generic buffer zeroer prototype. Buffer zeroers copy count zeros to
|
||||||
|
destinationBuffer. The actual type of the data pointed to varys for
|
||||||
|
different zeroer 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 count The number of samples to zero.
|
||||||
|
*/
|
||||||
|
typedef void PaUtilZeroer(
|
||||||
|
void *destinationBuffer, signed int destinationStride, unsigned int count );
|
||||||
|
|
||||||
|
|
||||||
|
/** Find a buffer zeroer function for the given destination format.
|
||||||
|
@return
|
||||||
|
A pointer to a PaUtilZeroer which will perform the requested
|
||||||
|
zeroing.
|
||||||
|
*/
|
||||||
|
PaUtilZeroer* PaUtil_SelectZeroer( PaSampleFormat destinationFormat );
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
/* low level functions and data structures which may be used for
|
||||||
|
substituting 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;
|
||||||
|
|
||||||
|
|
||||||
|
/** The type used to store all buffer zeroing functions.
|
||||||
|
@see paZeroers;
|
||||||
|
*/
|
||||||
|
typedef struct{
|
||||||
|
PaUtilZeroer *ZeroU8; /* unsigned 8 bit, zero == 128 */
|
||||||
|
PaUtilZeroer *Zero8;
|
||||||
|
PaUtilZeroer *Zero16;
|
||||||
|
PaUtilZeroer *Zero24;
|
||||||
|
PaUtilZeroer *Zero32;
|
||||||
|
} PaUtilZeroerTable;
|
||||||
|
|
||||||
|
|
||||||
|
/** A table of pointers to all required zeroer functions.
|
||||||
|
PaUtil_SelectZeroer() uses this table to lookup the appropriate
|
||||||
|
conversion functions. The fields of this structure are initialized
|
||||||
|
with default conversion functions. User code may substitue optimised
|
||||||
|
conversion functions by assigning different function pointers to
|
||||||
|
these fields.
|
||||||
|
|
||||||
|
@note
|
||||||
|
If the PA_NO_STANDARD_ZEROERS preprocessor variable is defined,
|
||||||
|
PortAudio's standard zeroers will not be compiled, and all fields
|
||||||
|
of this structure will be initialized to NULL. In such cases, users
|
||||||
|
should supply their own zeroing functions for the sample sizes which
|
||||||
|
they intend to use.
|
||||||
|
|
||||||
|
@see PaUtilZeroerTable, PaUtilZeroer, PaUtil_SelectZeroer
|
||||||
|
*/
|
||||||
|
extern PaUtilZeroerTable paZeroers;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_CONVERTERS_H */
|
96
portaudio-v19/src/common/pa_cpuload.c
Normal file
96
portaudio-v19/src/common/pa_cpuload.c
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Functions to assist in measuring the CPU utilization of a callback
|
||||||
|
stream. Used to implement the Pa_GetStreamCpuLoad() function.
|
||||||
|
|
||||||
|
@todo Dynamically calculate the coefficients used to smooth the CPU Load
|
||||||
|
Measurements over time to provide a uniform characterisation of CPU Load
|
||||||
|
independent of rate at which PaUtil_BeginCpuLoadMeasurement /
|
||||||
|
PaUtil_EndCpuLoadMeasurement are called.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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;
|
||||||
|
measurer->averageLoad = 0.;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer )
|
||||||
|
{
|
||||||
|
measurer->averageLoad = 0.;
|
||||||
|
}
|
||||||
|
|
||||||
|
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. */
|
||||||
|
/** FIXME @todo these coefficients shouldn't be hardwired */
|
||||||
|
#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;
|
||||||
|
}
|
63
portaudio-v19/src/common/pa_cpuload.h
Normal file
63
portaudio-v19/src/common/pa_cpuload.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#ifndef PA_CPULOAD_H
|
||||||
|
#define PA_CPULOAD_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Functions to assist in measuring the CPU utilization of a callback
|
||||||
|
stream. Used to implement the Pa_GetStreamCpuLoad() function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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 );
|
||||||
|
void PaUtil_ResetCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer );
|
||||||
|
double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_CPULOAD_H */
|
204
portaudio-v19/src/common/pa_dither.c
Normal file
204
portaudio-v19/src/common/pa_dither.c
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Functions for generating dither noise
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "pa_dither.h"
|
||||||
|
#include "pa_types.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_ ((SIZEOF_LONG*8 - 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_ ((SIZEOF_LONG*8 - 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_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following alternate dither algorithms (from musicdsp.org) could be
|
||||||
|
considered
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*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;
|
||||||
|
}
|
||||||
|
*/
|
91
portaudio-v19/src/common/pa_dither.h
Normal file
91
portaudio-v19/src/common/pa_dither.h
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#ifndef PA_DITHER_H
|
||||||
|
#define PA_DITHER_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Functions for generating dither noise
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief State needed to generate a dither signal */
|
||||||
|
typedef struct PaUtilTriangularDitherGenerator{
|
||||||
|
unsigned long previous;
|
||||||
|
unsigned long randSeed1;
|
||||||
|
unsigned long randSeed2;
|
||||||
|
} PaUtilTriangularDitherGenerator;
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Initialize dither state */
|
||||||
|
void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *ditherState );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief 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
|
||||||
|
*/
|
||||||
|
signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *ditherState );
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief 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.
|
||||||
|
*/
|
||||||
|
float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *ditherState );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_DITHER_H */
|
130
portaudio-v19/src/common/pa_endianness.h
Normal file
130
portaudio-v19/src/common/pa_endianness.h
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
#ifndef PA_ENDIANNESS_H
|
||||||
|
#define PA_ENDIANNESS_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Configure endianness symbols for the target processor.
|
||||||
|
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/* If this is an apple, we need to do detect endianness this way */
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
/* we need to do some endian detection that is sensitive to harware arch */
|
||||||
|
#if defined(__LITTLE_ENDIAN__)
|
||||||
|
#if !defined( PA_LITTLE_ENDIAN )
|
||||||
|
#define PA_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#if defined( PA_BIG_ENDIAN )
|
||||||
|
#undef PA_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if !defined( PA_BIG_ENDIAN )
|
||||||
|
#define PA_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
#if defined( PA_LITTLE_ENDIAN )
|
||||||
|
#undef PA_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
/* this is not an apple, so first check the existing defines, and, failing that,
|
||||||
|
detect well-known architechtures. */
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/* endianness define has not been set externally */
|
||||||
|
|
||||||
|
/* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */
|
||||||
|
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(LITTLE_ENDIAN) || defined(__i386) || defined(_M_IX86)
|
||||||
|
#define PA_LITTLE_ENDIAN /* win32, assume intel byte order */
|
||||||
|
#else
|
||||||
|
#define PA_BIG_ENDIAN
|
||||||
|
#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( "PortAudio: 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( "PortAudio: compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 0 ); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_ENDIANNESS_H */
|
1981
portaudio-v19/src/common/pa_front.c
Normal file
1981
portaudio-v19/src/common/pa_front.c
Normal file
File diff suppressed because it is too large
Load Diff
244
portaudio-v19/src/common/pa_hostapi.h
Normal file
244
portaudio-v19/src/common/pa_hostapi.h
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
#ifndef PA_HOSTAPI_H
|
||||||
|
#define PA_HOSTAPI_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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
|
||||||
|
@brief Interface used by pa_front to virtualize functions which operate on
|
||||||
|
host APIs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "portaudio.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
/** **FOR THE USE OF pa_front.c ONLY**
|
||||||
|
Do NOT 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.
|
||||||
|
*/
|
||||||
|
typedef struct PaUtilPrivatePaFrontHostApiInfo {
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** A structure representing the interface to a host API. Contains both
|
||||||
|
concrete data and pointers to functions which implement the interface.
|
||||||
|
*/
|
||||||
|
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 indices within the host api's own
|
||||||
|
device index range (0 to deviceCount). These values will be converted
|
||||||
|
to global device indices by pa_front 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
|
||||||
|
- paNeverDropInput is only used for full-duplex callback streams
|
||||||
|
with variable buffer size (paFramesPerBufferUnspecified)
|
||||||
|
|
||||||
|
[*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;
|
||||||
|
|
||||||
|
|
||||||
|
/** Prototype for the initialization function which must be implemented by every
|
||||||
|
host API.
|
||||||
|
|
||||||
|
@see paHostApiInitializers
|
||||||
|
*/
|
||||||
|
typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex );
|
||||||
|
|
||||||
|
|
||||||
|
/** paHostApiInitializers is a NULL-terminated array of host API initialization
|
||||||
|
functions. These functions are called by pa_front to initialize the host APIs
|
||||||
|
when the client calls Pa_Initialize().
|
||||||
|
|
||||||
|
There is a platform specific file which defines paHostApiInitializers for that
|
||||||
|
platform, pa_win/pa_win_hostapis.c contains the Win32 definitions for example.
|
||||||
|
*/
|
||||||
|
extern PaUtilHostApiInitializer *paHostApiInitializers[];
|
||||||
|
|
||||||
|
|
||||||
|
/** The index of the default host API in the paHostApiInitializers array.
|
||||||
|
|
||||||
|
There is a platform specific file which defines paDefaultHostApiIndex for that
|
||||||
|
platform, see pa_win/pa_win_hostapis.c for example.
|
||||||
|
*/
|
||||||
|
extern int paDefaultHostApiIndex;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_HOSTAPI_H */
|
1763
portaudio-v19/src/common/pa_process.c
Normal file
1763
portaudio-v19/src/common/pa_process.c
Normal file
File diff suppressed because it is too large
Load Diff
741
portaudio-v19/src/common/pa_process.h
Normal file
741
portaudio-v19/src/common/pa_process.h
Normal file
@ -0,0 +1,741 @@
|
|||||||
|
#ifndef PA_PROCESS_H
|
||||||
|
#define PA_PROCESS_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Buffer Processor prototypes. A Buffer Processor performs buffer length
|
||||||
|
adaption, coordinates sample format conversion, and interleaves/deinterleaves
|
||||||
|
channels.
|
||||||
|
|
||||||
|
<h3>Overview</h3>
|
||||||
|
|
||||||
|
The "Buffer Processor" (PaUtilBufferProcessor) manages conversion of audio
|
||||||
|
data from host buffers to user buffers and back again. Where required, the
|
||||||
|
buffer processor takes care of converting between host and user sample formats,
|
||||||
|
interleaving and deinterleaving multichannel buffers, and adapting between host
|
||||||
|
and user buffers with different lengths. The buffer processor may be used with
|
||||||
|
full and half duplex streams, for both callback streams and blocking read/write
|
||||||
|
streams.
|
||||||
|
|
||||||
|
One of the important capabilities provided by the buffer processor is
|
||||||
|
the ability to adapt between user and host buffer sizes of different lengths
|
||||||
|
with minimum latency. Although this task is relatively easy to perform when
|
||||||
|
the host buffer size is an integer multiple of the user buffer size, the
|
||||||
|
problem is more complicated when this is not the case - especially for
|
||||||
|
full-duplex callback streams. Where necessary the adaption is implemented by
|
||||||
|
internally buffering some input and/or output data. The buffer adation
|
||||||
|
algorithm used by the buffer processor was originally implemented by
|
||||||
|
Stephan Letz for the ASIO version of PortAudio, and is described in his
|
||||||
|
Callback_adaption_.pdf which is included in the distribution.
|
||||||
|
|
||||||
|
The buffer processor performs sample conversion using the functions provided
|
||||||
|
by pa_converters.c.
|
||||||
|
|
||||||
|
The following sections provide an overview of how to use the buffer processor.
|
||||||
|
Interested readers are advised to consult the host API implementations for
|
||||||
|
examples of buffer processor usage.
|
||||||
|
|
||||||
|
|
||||||
|
<h4>Initialization, resetting and termination</h4>
|
||||||
|
|
||||||
|
When a stream is opened, the buffer processor should be initialized using
|
||||||
|
PaUtil_InitializeBufferProcessor. This function initializes internal state
|
||||||
|
and allocates temporary buffers as neccesary according to the supplied
|
||||||
|
configuration parameters. Some of the parameters correspond to those requested
|
||||||
|
by the user in their call to Pa_OpenStream(), others reflect the requirements
|
||||||
|
of the host API implementation - they indicate host buffer sizes, formats,
|
||||||
|
and the type of buffering which the Host API uses. The buffer processor should
|
||||||
|
be initialized for callback streams and blocking read/write streams.
|
||||||
|
|
||||||
|
Call PaUtil_ResetBufferProcessor to clear any sample data which is present
|
||||||
|
in the buffer processor before starting to use it (for example when
|
||||||
|
Pa_StartStream is called).
|
||||||
|
|
||||||
|
When the buffer processor is no longer used call
|
||||||
|
PaUtil_TerminateBufferProcessor.
|
||||||
|
|
||||||
|
|
||||||
|
<h4>Using the buffer processor for a callback stream</h4>
|
||||||
|
|
||||||
|
The buffer processor's role in a callback stream is to take host input buffers
|
||||||
|
process them with the stream callback, and fill host output buffers. For a
|
||||||
|
full duplex stream, the buffer processor handles input and output simultaneously
|
||||||
|
due to the requirements of the minimum-latency buffer adation algorithm.
|
||||||
|
|
||||||
|
When a host buffer becomes available, the implementation should call
|
||||||
|
the buffer processor to process the buffer. The buffer processor calls the
|
||||||
|
stream callback to consume and/or produce audio data as necessary. The buffer
|
||||||
|
processor will convert sample formats, interleave/deinterleave channels,
|
||||||
|
and slice or chunk the data to the appropriate buffer lengths according to
|
||||||
|
the requirements of the stream callback and the host API.
|
||||||
|
|
||||||
|
To process a host buffer (or a pair of host buffers for a full-duplex stream)
|
||||||
|
use the following calling sequence:
|
||||||
|
|
||||||
|
-# Call PaUtil_BeginBufferProcessing
|
||||||
|
-# For a stream which takes input:
|
||||||
|
- Call PaUtil_SetInputFrameCount with the number of frames in the host input
|
||||||
|
buffer.
|
||||||
|
- Call one of the following functions one or more times to tell the
|
||||||
|
buffer processor about the host input buffer(s): PaUtil_SetInputChannel,
|
||||||
|
PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel.
|
||||||
|
Which function you call will depend on whether the host buffer(s) are
|
||||||
|
interleaved or not.
|
||||||
|
- If the available host data is split accross two buffers (for example a
|
||||||
|
data range at the end of a circular buffer and another range at the
|
||||||
|
beginning of the circular buffer), also call
|
||||||
|
PaUtil_Set2ndInputFrameCount, PaUtil_Set2ndInputChannel,
|
||||||
|
PaUtil_Set2ndInterleavedInputChannels,
|
||||||
|
PaUtil_Set2ndNonInterleavedInputChannel as necessary to tell the buffer
|
||||||
|
processor about the second buffer.
|
||||||
|
-# For a stream which generates output:
|
||||||
|
- Call PaUtil_SetOutputFrameCount with the number of frames in the host
|
||||||
|
output buffer.
|
||||||
|
- Call one of the following functions one or more times to tell the
|
||||||
|
buffer processor about the host output buffer(s): PaUtil_SetOutputChannel,
|
||||||
|
PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel.
|
||||||
|
Which function you call will depend on whether the host buffer(s) are
|
||||||
|
interleaved or not.
|
||||||
|
- If the available host output buffer space is split accross two buffers
|
||||||
|
(for example a data range at the end of a circular buffer and another
|
||||||
|
range at the beginning of the circular buffer), call
|
||||||
|
PaUtil_Set2ndOutputFrameCount, PaUtil_Set2ndOutputChannel,
|
||||||
|
PaUtil_Set2ndInterleavedOutputChannels,
|
||||||
|
PaUtil_Set2ndNonInterleavedOutputChannel as necessary to tell the buffer
|
||||||
|
processor about the second buffer.
|
||||||
|
-# Call PaUtil_EndBufferProcessing, this function performs the actual data
|
||||||
|
conversion and processing.
|
||||||
|
|
||||||
|
|
||||||
|
<h4>Using the buffer processor for a blocking read/write stream</h4>
|
||||||
|
|
||||||
|
Blocking read/write streams use the buffer processor to convert and copy user
|
||||||
|
output data to a host buffer, and to convert and copy host input data to
|
||||||
|
the user's buffer. The buffer processor does not perform any buffer adaption.
|
||||||
|
When using the buffer processor in a blocking read/write stream the input and
|
||||||
|
output conversion are performed separately by the PaUtil_CopyInput and
|
||||||
|
PaUtil_CopyOutput functions.
|
||||||
|
|
||||||
|
To copy data from a host input buffer to the buffer(s) which the user supplies
|
||||||
|
to Pa_ReadStream, use the following calling sequence.
|
||||||
|
|
||||||
|
- Repeat the following three steps until the user buffer(s) have been filled
|
||||||
|
with samples from the host input buffers:
|
||||||
|
-# Call PaUtil_SetInputFrameCount with the number of frames in the host
|
||||||
|
input buffer.
|
||||||
|
-# Call one of the following functions one or more times to tell the
|
||||||
|
buffer processor about the host input buffer(s): PaUtil_SetInputChannel,
|
||||||
|
PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel.
|
||||||
|
Which function you call will depend on whether the host buffer(s) are
|
||||||
|
interleaved or not.
|
||||||
|
-# Call PaUtil_CopyInput with the user buffer pointer (or a copy of the
|
||||||
|
array of buffer pointers for a non-interleaved stream) passed to
|
||||||
|
Pa_ReadStream, along with the number of frames in the user buffer(s).
|
||||||
|
Be careful to pass a <i>copy</i> of the user buffer pointers to
|
||||||
|
PaUtil_CopyInput because PaUtil_CopyInput advances the pointers to
|
||||||
|
the start of the next region to copy.
|
||||||
|
- PaUtil_CopyInput will not copy more data than is available in the
|
||||||
|
host buffer(s), so the above steps need to be repeated until the user
|
||||||
|
buffer(s) are full.
|
||||||
|
|
||||||
|
|
||||||
|
To copy data to the host output buffer from the user buffers(s) supplied
|
||||||
|
to Pa_WriteStream use the following calling sequence.
|
||||||
|
|
||||||
|
- Repeat the following three steps until all frames from the user buffer(s)
|
||||||
|
have been copied to the host API:
|
||||||
|
-# Call PaUtil_SetOutputFrameCount with the number of frames in the host
|
||||||
|
output buffer.
|
||||||
|
-# Call one of the following functions one or more times to tell the
|
||||||
|
buffer processor about the host output buffer(s): PaUtil_SetOutputChannel,
|
||||||
|
PaUtil_SetInterleavedOutputChannels, PaUtil_SetNonInterleavedOutputChannel.
|
||||||
|
Which function you call will depend on whether the host buffer(s) are
|
||||||
|
interleaved or not.
|
||||||
|
-# Call PaUtil_CopyOutput with the user buffer pointer (or a copy of the
|
||||||
|
array of buffer pointers for a non-interleaved stream) passed to
|
||||||
|
Pa_WriteStream, along with the number of frames in the user buffer(s).
|
||||||
|
Be careful to pass a <i>copy</i> of the user buffer pointers to
|
||||||
|
PaUtil_CopyOutput because PaUtil_CopyOutput advances the pointers to
|
||||||
|
the start of the next region to copy.
|
||||||
|
- PaUtil_CopyOutput will not copy more data than fits in the host buffer(s),
|
||||||
|
so the above steps need to be repeated until all user data is copied.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "portaudio.h"
|
||||||
|
#include "pa_converters.h"
|
||||||
|
#include "pa_dither.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief Mode flag passed to PaUtil_InitializeBufferProcessor indicating the type
|
||||||
|
of buffering that the host API uses.
|
||||||
|
|
||||||
|
The mode used depends on whether the host API or the implementation manages
|
||||||
|
the buffers, and how these buffers are used (scatter gather, circular buffer).
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/** The host buffer size is a fixed known size. */
|
||||||
|
paUtilFixedHostBufferSize,
|
||||||
|
|
||||||
|
/** The host buffer size may vary, but has a known maximum size. */
|
||||||
|
paUtilBoundedHostBufferSize,
|
||||||
|
|
||||||
|
/** Nothing is known about the host buffer size. */
|
||||||
|
paUtilUnknownHostBufferSize,
|
||||||
|
|
||||||
|
/** The host buffer size varies, and the client does not require the buffer
|
||||||
|
processor to consume all of the input and fill all of the output buffer. This
|
||||||
|
is useful when the implementation has access to the host API's circular buffer
|
||||||
|
and only needs to consume/fill some of it, not necessarily all of it, with each
|
||||||
|
call to the buffer processor. This is the only mode where
|
||||||
|
PaUtil_EndBufferProcessing() may not consume the whole buffer.
|
||||||
|
*/
|
||||||
|
paUtilVariableHostBufferSizePartialUsageAllowed
|
||||||
|
}PaUtilHostBufferSizeMode;
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief An auxilliary data structure used internally by the buffer processor
|
||||||
|
to represent host input and output buffers. */
|
||||||
|
typedef struct PaUtilChannelDescriptor{
|
||||||
|
void *data;
|
||||||
|
unsigned int stride; /**< stride in samples, not bytes */
|
||||||
|
}PaUtilChannelDescriptor;
|
||||||
|
|
||||||
|
|
||||||
|
/** @brief The main buffer processor data structure.
|
||||||
|
|
||||||
|
Allocate one of these, initialize it with PaUtil_InitializeBufferProcessor
|
||||||
|
and terminate it with PaUtil_TerminateBufferProcessor.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
PaUtilZeroer *inputZeroer;
|
||||||
|
|
||||||
|
unsigned int outputChannelCount;
|
||||||
|
unsigned int bytesPerHostOutputSample;
|
||||||
|
unsigned int bytesPerUserOutputSample;
|
||||||
|
int userOutputIsInterleaved;
|
||||||
|
PaUtilConverter *outputConverter;
|
||||||
|
PaUtilZeroer *outputZeroer;
|
||||||
|
|
||||||
|
unsigned long initialFramesInTempInputBuffer;
|
||||||
|
unsigned long initialFramesInTempOutputBuffer;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
PaStreamCallbackFlags callbackStatusFlags;
|
||||||
|
|
||||||
|
unsigned long hostInputFrameCount[2];
|
||||||
|
PaUtilChannelDescriptor *hostInputChannels[2]; /**< pointers to arrays of channel descriptors.
|
||||||
|
pointers are NULL for half-duplex output processing.
|
||||||
|
hostInputChannels[i].data is NULL when the caller
|
||||||
|
calls PaUtil_SetNoInput()
|
||||||
|
*/
|
||||||
|
unsigned long hostOutputFrameCount[2];
|
||||||
|
PaUtilChannelDescriptor *hostOutputChannels[2]; /**< pointers to arrays of channel descriptors.
|
||||||
|
pointers are NULL for half-duplex input processing.
|
||||||
|
hostOutputChannels[i].data is NULL when the caller
|
||||||
|
calls PaUtil_SetNoOutput()
|
||||||
|
*/
|
||||||
|
|
||||||
|
PaUtilTriangularDitherGenerator ditherGenerator;
|
||||||
|
|
||||||
|
double samplePeriod;
|
||||||
|
|
||||||
|
PaStreamCallback *streamCallback;
|
||||||
|
void *userData;
|
||||||
|
} PaUtilBufferProcessor;
|
||||||
|
|
||||||
|
|
||||||
|
/** @name Initialization, termination, resetting and info */
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
|
/** Initialize a buffer processor's representation stored in a
|
||||||
|
PaUtilBufferProcessor structure. Be sure to call
|
||||||
|
PaUtil_TerminateBufferProcessor after finishing with a buffer processor.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor structure to initialize.
|
||||||
|
|
||||||
|
@param inputChannelCount The number of input channels as passed to
|
||||||
|
Pa_OpenStream or 0 for an output-only stream.
|
||||||
|
|
||||||
|
@param userInputSampleFormat Format of user input samples, as passed to
|
||||||
|
Pa_OpenStream. This parameter is ignored for ouput-only streams.
|
||||||
|
|
||||||
|
@param hostInputSampleFormat Format of host input samples. This parameter is
|
||||||
|
ignored for output-only streams. See note about host buffer interleave below.
|
||||||
|
|
||||||
|
@param outputChannelCount The number of output channels as passed to
|
||||||
|
Pa_OpenStream or 0 for an input-only stream.
|
||||||
|
|
||||||
|
@param userOutputSampleFormat Format of user output samples, as passed to
|
||||||
|
Pa_OpenStream. This parameter is ignored for input-only streams.
|
||||||
|
|
||||||
|
@param hostOutputSampleFormat Format of host output samples. This parameter is
|
||||||
|
ignored for input-only streams. See note about host buffer interleave below.
|
||||||
|
|
||||||
|
@param sampleRate Sample rate of the stream. The more accurate this is the
|
||||||
|
better - it is used for updating time stamps when adapting buffers.
|
||||||
|
|
||||||
|
@param streamFlags Stream flags as passed to Pa_OpenStream, this parameter is
|
||||||
|
used for selecting special sample conversion options such as clipping and
|
||||||
|
dithering.
|
||||||
|
|
||||||
|
@param framesPerUserBuffer Number of frames per user buffer, as requested
|
||||||
|
by the framesPerBuffer parameter to Pa_OpenStream. This parameter may be
|
||||||
|
zero to indicate that the user will accept any (and varying) buffer sizes.
|
||||||
|
|
||||||
|
@param framesPerHostBuffer Specifies the number of frames per host buffer
|
||||||
|
for 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.
|
||||||
|
|
||||||
|
@param hostBufferSizeMode A mode flag indicating the size variability of
|
||||||
|
host buffers that will be passed to the buffer processor. See
|
||||||
|
PaUtilHostBufferSizeMode for further details.
|
||||||
|
|
||||||
|
@param streamCallback The user stream callback passed to Pa_OpenStream.
|
||||||
|
|
||||||
|
@param userData The user data field passed to Pa_OpenStream.
|
||||||
|
|
||||||
|
@note The interleave flag is ignored for host buffer formats. Host
|
||||||
|
interleave is determined by the use of different SetInput and SetOutput
|
||||||
|
functions.
|
||||||
|
|
||||||
|
@return An error code indicating whether the initialization was successful.
|
||||||
|
If the error code is not PaNoError, the buffer processor was not initialized
|
||||||
|
and should not be used.
|
||||||
|
|
||||||
|
@see Pa_OpenStream, PaUtilHostBufferSizeMode, PaUtil_TerminateBufferProcessor
|
||||||
|
*/
|
||||||
|
PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
int inputChannelCount, PaSampleFormat userInputSampleFormat,
|
||||||
|
PaSampleFormat hostInputSampleFormat,
|
||||||
|
int outputChannelCount, 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 );
|
||||||
|
|
||||||
|
|
||||||
|
/** Terminate a buffer processor's representation. Deallocates any temporary
|
||||||
|
buffers allocated by PaUtil_InitializeBufferProcessor.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor structure to terminate.
|
||||||
|
|
||||||
|
@see PaUtil_InitializeBufferProcessor.
|
||||||
|
*/
|
||||||
|
void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bufferProcessor );
|
||||||
|
|
||||||
|
|
||||||
|
/** Clear any internally buffered data. If you call
|
||||||
|
PaUtil_InitializeBufferProcessor in your OpenStream routine, make sure you
|
||||||
|
call PaUtil_ResetBufferProcessor in your StartStream call.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor to reset.
|
||||||
|
*/
|
||||||
|
void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bufferProcessor );
|
||||||
|
|
||||||
|
|
||||||
|
/** Retrieve the input latency of a buffer processor.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor examine.
|
||||||
|
|
||||||
|
@return The input latency introduced by the buffer processor, in frames.
|
||||||
|
|
||||||
|
@see PaUtil_GetBufferProcessorOutputLatency
|
||||||
|
*/
|
||||||
|
unsigned long PaUtil_GetBufferProcessorInputLatency( PaUtilBufferProcessor* bufferProcessor );
|
||||||
|
|
||||||
|
/** Retrieve the output latency of a buffer processor.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor examine.
|
||||||
|
|
||||||
|
@return The output latency introduced by the buffer processor, in frames.
|
||||||
|
|
||||||
|
@see PaUtil_GetBufferProcessorInputLatency
|
||||||
|
*/
|
||||||
|
unsigned long PaUtil_GetBufferProcessorOutputLatency( PaUtilBufferProcessor* bufferProcessor );
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
/** @name Host buffer pointer configuration
|
||||||
|
|
||||||
|
Functions to set host input and output buffers, used by both callback streams
|
||||||
|
and blocking read/write streams.
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
|
|
||||||
|
/** Set the number of frames in the input host buffer(s) specified by the
|
||||||
|
PaUtil_Set*InputChannel functions.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
|
||||||
|
@param frameCount The number of host input frames. A 0 frameCount indicates to
|
||||||
|
use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor.
|
||||||
|
|
||||||
|
@see PaUtil_SetNoInput, PaUtil_SetInputChannel,
|
||||||
|
PaUtil_SetInterleavedInputChannels, PaUtil_SetNonInterleavedInputChannel
|
||||||
|
*/
|
||||||
|
void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned long frameCount );
|
||||||
|
|
||||||
|
|
||||||
|
/** Indicate that no input is avalable. This function should be used when
|
||||||
|
priming the output of a full-duplex stream opened with the
|
||||||
|
paPrimeOutputBuffersUsingStreamCallback flag. Note that it is not necessary
|
||||||
|
to call this or any othe PaUtil_Set*Input* functions for ouput-only streams.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
*/
|
||||||
|
void PaUtil_SetNoInput( PaUtilBufferProcessor* bufferProcessor );
|
||||||
|
|
||||||
|
|
||||||
|
/** Provide the buffer processor with a pointer to a host input channel.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
@param channel The channel number.
|
||||||
|
@param data The buffer.
|
||||||
|
@param stride The stride from one sample to the next, in samples. For
|
||||||
|
interleaved host buffers, the stride will usually be the same as the number of
|
||||||
|
channels in the buffer.
|
||||||
|
*/
|
||||||
|
void PaUtil_SetInputChannel( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int channel, void *data, unsigned int stride );
|
||||||
|
|
||||||
|
|
||||||
|
/** Provide the buffer processor with a pointer to an number of interleaved
|
||||||
|
host input channels.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
@param firstChannel The first channel number.
|
||||||
|
@param data The buffer.
|
||||||
|
@param channelCount The number of interleaved channels in the buffer. If
|
||||||
|
channelCount is zero, the number of channels specified to
|
||||||
|
PaUtil_InitializeBufferProcessor will be used.
|
||||||
|
*/
|
||||||
|
void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int firstChannel, void *data, unsigned int channelCount );
|
||||||
|
|
||||||
|
|
||||||
|
/** Provide the buffer processor with a pointer to one non-interleaved host
|
||||||
|
output channel.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
@param channel The channel number.
|
||||||
|
@param data The buffer.
|
||||||
|
*/
|
||||||
|
void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int channel, void *data );
|
||||||
|
|
||||||
|
|
||||||
|
/** Use for the second buffer half when the input buffer is split in two halves.
|
||||||
|
@see PaUtil_SetInputFrameCount
|
||||||
|
*/
|
||||||
|
void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned long frameCount );
|
||||||
|
|
||||||
|
/** Use for the second buffer half when the input buffer is split in two halves.
|
||||||
|
@see PaUtil_SetInputChannel
|
||||||
|
*/
|
||||||
|
void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int channel, void *data, unsigned int stride );
|
||||||
|
|
||||||
|
/** Use for the second buffer half when the input buffer is split in two halves.
|
||||||
|
@see PaUtil_SetInterleavedInputChannels
|
||||||
|
*/
|
||||||
|
void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int firstChannel, void *data, unsigned int channelCount );
|
||||||
|
|
||||||
|
/** Use for the second buffer half when the input buffer is split in two halves.
|
||||||
|
@see PaUtil_SetNonInterleavedInputChannel
|
||||||
|
*/
|
||||||
|
void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int channel, void *data );
|
||||||
|
|
||||||
|
|
||||||
|
/** Set the number of frames in the output host buffer(s) specified by the
|
||||||
|
PaUtil_Set*OutputChannel functions.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
|
||||||
|
@param frameCount The number of host output frames. A 0 frameCount indicates to
|
||||||
|
use the framesPerHostBuffer value passed to PaUtil_InitializeBufferProcessor.
|
||||||
|
|
||||||
|
@see PaUtil_SetOutputChannel, PaUtil_SetInterleavedOutputChannels,
|
||||||
|
PaUtil_SetNonInterleavedOutputChannel
|
||||||
|
*/
|
||||||
|
void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned long frameCount );
|
||||||
|
|
||||||
|
|
||||||
|
/** Indicate that the output will be discarded. This function should be used
|
||||||
|
when implementing the paNeverDropInput mode for full duplex streams.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
*/
|
||||||
|
void PaUtil_SetNoOutput( PaUtilBufferProcessor* bufferProcessor );
|
||||||
|
|
||||||
|
|
||||||
|
/** Provide the buffer processor with a pointer to a host output channel.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
@param channel The channel number.
|
||||||
|
@param data The buffer.
|
||||||
|
@param stride The stride from one sample to the next, in samples. For
|
||||||
|
interleaved host buffers, the stride will usually be the same as the number of
|
||||||
|
channels in the buffer.
|
||||||
|
*/
|
||||||
|
void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int channel, void *data, unsigned int stride );
|
||||||
|
|
||||||
|
|
||||||
|
/** Provide the buffer processor with a pointer to a number of interleaved
|
||||||
|
host output channels.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
@param firstChannel The first channel number.
|
||||||
|
@param data The buffer.
|
||||||
|
@param channelCount The number of interleaved channels in the buffer. If
|
||||||
|
channelCount is zero, the number of channels specified to
|
||||||
|
PaUtil_InitializeBufferProcessor will be used.
|
||||||
|
*/
|
||||||
|
void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int firstChannel, void *data, unsigned int channelCount );
|
||||||
|
|
||||||
|
|
||||||
|
/** Provide the buffer processor with a pointer to one non-interleaved host
|
||||||
|
output channel.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
@param channel The channel number.
|
||||||
|
@param data The buffer.
|
||||||
|
*/
|
||||||
|
void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int channel, void *data );
|
||||||
|
|
||||||
|
|
||||||
|
/** Use for the second buffer half when the output buffer is split in two halves.
|
||||||
|
@see PaUtil_SetOutputFrameCount
|
||||||
|
*/
|
||||||
|
void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned long frameCount );
|
||||||
|
|
||||||
|
/** Use for the second buffer half when the output buffer is split in two halves.
|
||||||
|
@see PaUtil_SetOutputChannel
|
||||||
|
*/
|
||||||
|
void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int channel, void *data, unsigned int stride );
|
||||||
|
|
||||||
|
/** Use for the second buffer half when the output buffer is split in two halves.
|
||||||
|
@see PaUtil_SetInterleavedOutputChannels
|
||||||
|
*/
|
||||||
|
void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int firstChannel, void *data, unsigned int channelCount );
|
||||||
|
|
||||||
|
/** Use for the second buffer half when the output buffer is split in two halves.
|
||||||
|
@see PaUtil_SetNonInterleavedOutputChannel
|
||||||
|
*/
|
||||||
|
void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned int channel, void *data );
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
/** @name Buffer processing functions for callback streams
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
|
/** Commence processing a host buffer (or a pair of host buffers in the
|
||||||
|
full-duplex case) for a callback stream.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
|
||||||
|
@param timeInfo Timing information for the first sample of the host
|
||||||
|
buffer(s). This information may be adjusted when buffer adaption is being
|
||||||
|
performed.
|
||||||
|
|
||||||
|
@param callbackStatusFlags Flags indicating whether underruns and overruns
|
||||||
|
have occurred since the last time the buffer processor was called.
|
||||||
|
*/
|
||||||
|
void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags );
|
||||||
|
|
||||||
|
|
||||||
|
/** Finish processing a host buffer (or a pair of host buffers in the
|
||||||
|
full-duplex case) for a callback stream.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
|
||||||
|
@param callbackResult On input, indicates a previous callback result, and on
|
||||||
|
exit, the result of the user stream callback, if it is called.
|
||||||
|
On entry callbackResult should contain one of { paContinue, paComplete, or
|
||||||
|
paAbort}. If paComplete is passed, the stream callback will not be called
|
||||||
|
but any audio that was generated by previous stream callbacks will be copied
|
||||||
|
to the output buffer(s). You can check whether the buffer processor's internal
|
||||||
|
buffer is empty by calling PaUtil_IsBufferProcessorOutputEmpty.
|
||||||
|
|
||||||
|
If the stream callback is called its result is stored in *callbackResult. If
|
||||||
|
the stream callback returns paComplete or paAbort, all output buffers will be
|
||||||
|
full of valid data - some of which may be zeros to acount for data that
|
||||||
|
wasn't generated by the terminating callback.
|
||||||
|
|
||||||
|
@return The number of frames processed. This usually corresponds to the
|
||||||
|
number of frames specified by the PaUtil_Set*FrameCount functions, exept in
|
||||||
|
the paUtilVariableHostBufferSizePartialUsageAllowed buffer size mode when a
|
||||||
|
smaller value may be returned.
|
||||||
|
*/
|
||||||
|
unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
int *callbackResult );
|
||||||
|
|
||||||
|
|
||||||
|
/** Determine whether any callback generated output remains in the bufffer
|
||||||
|
processor's internal buffers. This method may be used to determine when to
|
||||||
|
continue calling PaUtil_EndBufferProcessing() after the callback has returned
|
||||||
|
a callbackResult of paComplete.
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
|
||||||
|
@return Returns non-zero when callback generated output remains in the internal
|
||||||
|
buffer and zero (0) when there internal buffer contains no callback generated
|
||||||
|
data.
|
||||||
|
*/
|
||||||
|
int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bufferProcessor );
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
/** @name Buffer processing functions for blocking read/write streams
|
||||||
|
*/
|
||||||
|
/*@{*/
|
||||||
|
|
||||||
|
/** Copy samples from host input channels set up by the PaUtil_Set*InputChannels
|
||||||
|
functions to a user supplied buffer. This function is intended for use with
|
||||||
|
blocking read/write streams. Copies the minimum of the number of
|
||||||
|
user frames (specified by the frameCount parameter) and the number of available
|
||||||
|
host frames (specified in a previous call to SetInputFrameCount()).
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
|
||||||
|
@param buffer A pointer to the user buffer pointer, or a pointer to a pointer
|
||||||
|
to an array of user buffer pointers for a non-interleaved stream. It is
|
||||||
|
important that this parameter points to a copy of the user buffer pointers,
|
||||||
|
not to the actual user buffer pointers, because this function updates the
|
||||||
|
pointers before returning.
|
||||||
|
|
||||||
|
@param frameCount The number of frames of data in the buffer(s) pointed to by
|
||||||
|
the buffer parameter.
|
||||||
|
|
||||||
|
@return The number of frames copied. The buffer pointer(s) pointed to by the
|
||||||
|
buffer parameter are advanced to point to the frame(s) following the last one
|
||||||
|
filled.
|
||||||
|
*/
|
||||||
|
unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
void **buffer, unsigned long frameCount );
|
||||||
|
|
||||||
|
|
||||||
|
/* Copy samples from a user supplied buffer to host output channels set up by
|
||||||
|
the PaUtil_Set*OutputChannels functions. This function is intended for use with
|
||||||
|
blocking read/write streams. Copies the minimum of the number of
|
||||||
|
user frames (specified by the frameCount parameter) and the number of
|
||||||
|
host frames (specified in a previous call to SetOutputFrameCount()).
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
|
||||||
|
@param buffer A pointer to the user buffer pointer, or a pointer to a pointer
|
||||||
|
to an array of user buffer pointers for a non-interleaved stream. It is
|
||||||
|
important that this parameter points to a copy of the user buffer pointers,
|
||||||
|
not to the actual user buffer pointers, because this function updates the
|
||||||
|
pointers before returning.
|
||||||
|
|
||||||
|
@param frameCount The number of frames of data in the buffer(s) pointed to by
|
||||||
|
the buffer parameter.
|
||||||
|
|
||||||
|
@return The number of frames copied. The buffer pointer(s) pointed to by the
|
||||||
|
buffer parameter are advanced to point to the frame(s) following the last one
|
||||||
|
copied.
|
||||||
|
*/
|
||||||
|
unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
const void ** buffer, unsigned long frameCount );
|
||||||
|
|
||||||
|
|
||||||
|
/* Zero samples in host output channels set up by the PaUtil_Set*OutputChannels
|
||||||
|
functions. This function is useful for flushing streams.
|
||||||
|
Zeros the minimum of frameCount and the number of host frames specified in a
|
||||||
|
previous call to SetOutputFrameCount().
|
||||||
|
|
||||||
|
@param bufferProcessor The buffer processor.
|
||||||
|
|
||||||
|
@param frameCount The maximum number of frames to zero.
|
||||||
|
|
||||||
|
@return The number of frames zeroed.
|
||||||
|
*/
|
||||||
|
unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bufferProcessor,
|
||||||
|
unsigned long frameCount );
|
||||||
|
|
||||||
|
|
||||||
|
/*@}*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_PROCESS_H */
|
807
portaudio-v19/src/common/pa_skeleton.c
Normal file
807
portaudio-v19/src/common/pa_skeleton.c
Normal file
@ -0,0 +1,807 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Skeleton implementation of support for a host API.
|
||||||
|
|
||||||
|
@note 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
|
|
||||||
|
/* prototypes for functions declared in this file */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
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, const 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_DummyRead, PaUtil_DummyWrite,
|
||||||
|
PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
|
||||||
|
|
||||||
|
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 resources 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;
|
||||||
|
|
||||||
|
/* all standard sample formats are supported by the buffer adapter,
|
||||||
|
this implementation doesn't support any custom sample formats */
|
||||||
|
if( inputSampleFormat & paCustomFormat )
|
||||||
|
return paSampleFormatNotSupported;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* all standard sample formats are supported by the buffer adapter,
|
||||||
|
this implementation doesn't support any custom sample formats */
|
||||||
|
if( outputSampleFormat & paCustomFormat )
|
||||||
|
return paSampleFormatNotSupported;
|
||||||
|
|
||||||
|
/* unless alternate device specification is supported, reject the use of
|
||||||
|
paUseHostApiSpecificDeviceSpecification */
|
||||||
|
|
||||||
|
if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
|
||||||
|
return paInvalidDevice;
|
||||||
|
|
||||||
|
/* check that output device can support outputChannelCount */
|
||||||
|
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:
|
||||||
|
|
||||||
|
- if a full duplex stream is requested, check that the combination
|
||||||
|
of input and output parameters is supported if necessary
|
||||||
|
|
||||||
|
- check that the device supports sampleRate
|
||||||
|
|
||||||
|
Because the buffer adapter handles conversion between all standard
|
||||||
|
sample formats, the following checks are only required if paCustomFormat
|
||||||
|
is implemented, or under some other unusual conditions.
|
||||||
|
|
||||||
|
- check that input device can support inputSampleFormat, or that
|
||||||
|
we have the capability to convert from inputSampleFormat 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* suppress unused variable warnings */
|
||||||
|
(void) 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, outputSampleFormat;
|
||||||
|
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialized var' warnings. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
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: initialise the following fields with estimated or actual
|
||||||
|
values.
|
||||||
|
*/
|
||||||
|
stream->streamRepresentation.streamInfo.inputLatency =
|
||||||
|
PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor);
|
||||||
|
stream->streamRepresentation.streamInfo.outputLatency =
|
||||||
|
PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor);
|
||||||
|
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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, 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */ );
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 */
|
||||||
|
|
||||||
|
/* you must pass a valid value of callback result to PaUtil_EndBufferProcessing()
|
||||||
|
in general you would pass paContinue for normal operation, and
|
||||||
|
paComplete to drain the buffer processor's internal output buffer.
|
||||||
|
You can check whether the buffer processor's output buffer is empty
|
||||||
|
using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
|
||||||
|
*/
|
||||||
|
callbackResult = paContinue;
|
||||||
|
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;
|
||||||
|
|
||||||
|
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
|
||||||
|
|
||||||
|
/* IMPLEMENT ME, see portaudio.h for required behavior */
|
||||||
|
|
||||||
|
/* suppress unused function warning. the code in ExampleHostProcessingLoop or
|
||||||
|
something similar should be implemented to feed samples to and from the
|
||||||
|
host after StartStream() is called.
|
||||||
|
*/
|
||||||
|
(void) ExampleHostProcessingLoop;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PaError StopStream( PaStream *s )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
PaSkeletonStream *stream = (PaSkeletonStream*)s;
|
||||||
|
|
||||||
|
/* suppress unused variable warnings */
|
||||||
|
(void) stream;
|
||||||
|
|
||||||
|
/* IMPLEMENT ME, see portaudio.h for required behavior */
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PaError AbortStream( PaStream *s )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
PaSkeletonStream *stream = (PaSkeletonStream*)s;
|
||||||
|
|
||||||
|
/* suppress unused variable warnings */
|
||||||
|
(void) stream;
|
||||||
|
|
||||||
|
/* IMPLEMENT ME, see portaudio.h for required behavior */
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PaError IsStreamStopped( PaStream *s )
|
||||||
|
{
|
||||||
|
PaSkeletonStream *stream = (PaSkeletonStream*)s;
|
||||||
|
|
||||||
|
/* suppress unused variable warnings */
|
||||||
|
(void) stream;
|
||||||
|
|
||||||
|
/* IMPLEMENT ME, see portaudio.h for required behavior */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PaError IsStreamActive( PaStream *s )
|
||||||
|
{
|
||||||
|
PaSkeletonStream *stream = (PaSkeletonStream*)s;
|
||||||
|
|
||||||
|
/* suppress unused variable warnings */
|
||||||
|
(void) stream;
|
||||||
|
|
||||||
|
/* IMPLEMENT ME, see portaudio.h for required behavior */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PaTime GetStreamTime( PaStream *s )
|
||||||
|
{
|
||||||
|
PaSkeletonStream *stream = (PaSkeletonStream*)s;
|
||||||
|
|
||||||
|
/* suppress unused variable warnings */
|
||||||
|
(void) stream;
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* suppress unused variable warnings */
|
||||||
|
(void) buffer;
|
||||||
|
(void) frames;
|
||||||
|
(void) stream;
|
||||||
|
|
||||||
|
/* IMPLEMENT ME, see portaudio.h for required behavior*/
|
||||||
|
|
||||||
|
return paNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PaError WriteStream( PaStream* s,
|
||||||
|
const void *buffer,
|
||||||
|
unsigned long frames )
|
||||||
|
{
|
||||||
|
PaSkeletonStream *stream = (PaSkeletonStream*)s;
|
||||||
|
|
||||||
|
/* suppress unused variable warnings */
|
||||||
|
(void) buffer;
|
||||||
|
(void) frames;
|
||||||
|
(void) stream;
|
||||||
|
|
||||||
|
/* IMPLEMENT ME, see portaudio.h for required behavior*/
|
||||||
|
|
||||||
|
return paNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static signed long GetStreamReadAvailable( PaStream* s )
|
||||||
|
{
|
||||||
|
PaSkeletonStream *stream = (PaSkeletonStream*)s;
|
||||||
|
|
||||||
|
/* suppress unused variable warnings */
|
||||||
|
(void) stream;
|
||||||
|
|
||||||
|
/* IMPLEMENT ME, see portaudio.h for required behavior*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static signed long GetStreamWriteAvailable( PaStream* s )
|
||||||
|
{
|
||||||
|
PaSkeletonStream *stream = (PaSkeletonStream*)s;
|
||||||
|
|
||||||
|
/* suppress unused variable warnings */
|
||||||
|
(void) stream;
|
||||||
|
|
||||||
|
/* IMPLEMENT ME, see portaudio.h for required behavior*/
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
141
portaudio-v19/src/common/pa_stream.c
Normal file
141
portaudio-v19/src/common/pa_stream.c
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Interface used by pa_front to virtualize functions which operate on
|
||||||
|
streams.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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*, const 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_DummyRead( PaStream* stream,
|
||||||
|
void *buffer,
|
||||||
|
unsigned long frames )
|
||||||
|
{
|
||||||
|
(void)stream; /* unused parameter */
|
||||||
|
(void)buffer; /* unused parameter */
|
||||||
|
(void)frames; /* unused parameter */
|
||||||
|
|
||||||
|
return paCanNotReadFromACallbackStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PaError PaUtil_DummyWrite( PaStream* stream,
|
||||||
|
const void *buffer,
|
||||||
|
unsigned long frames )
|
||||||
|
{
|
||||||
|
(void)stream; /* unused parameter */
|
||||||
|
(void)buffer; /* unused parameter */
|
||||||
|
(void)frames; /* unused parameter */
|
||||||
|
|
||||||
|
return paCanNotWriteToACallbackStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
signed long PaUtil_DummyGetReadAvailable( PaStream* stream )
|
||||||
|
{
|
||||||
|
(void)stream; /* unused parameter */
|
||||||
|
|
||||||
|
return paCanNotReadFromACallbackStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
signed long PaUtil_DummyGetWriteAvailable( PaStream* stream )
|
||||||
|
{
|
||||||
|
(void)stream; /* unused parameter */
|
||||||
|
|
||||||
|
return paCanNotWriteToACallbackStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double PaUtil_DummyGetCpuLoad( PaStream* stream )
|
||||||
|
{
|
||||||
|
(void)stream; /* unused parameter */
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
196
portaudio-v19/src/common/pa_stream.h
Normal file
196
portaudio-v19/src/common/pa_stream.h
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
#ifndef PA_STREAM_H
|
||||||
|
#define PA_STREAM_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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
|
||||||
|
@brief Interface used by pa_front to virtualize functions which operate on
|
||||||
|
streams.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "portaudio.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#define PA_STREAM_MAGIC (0x18273645)
|
||||||
|
|
||||||
|
|
||||||
|
/** A structure representing an (abstract) interface to a host API. Contains
|
||||||
|
pointers to functions which implement the interface.
|
||||||
|
|
||||||
|
All PaStreamInterface functions are guaranteed to be called with a non-null,
|
||||||
|
valid stream parameter.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
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, const void *buffer, unsigned long frames );
|
||||||
|
signed long (*GetReadAvailable)( PaStream* stream );
|
||||||
|
signed long (*GetWriteAvailable)( PaStream* stream );
|
||||||
|
} PaUtilStreamInterface;
|
||||||
|
|
||||||
|
|
||||||
|
/** Initialize the fields of a PaUtilStreamInterface structure.
|
||||||
|
*/
|
||||||
|
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, const void *buffer, unsigned long frames ),
|
||||||
|
signed long (*GetReadAvailable)( PaStream* stream ),
|
||||||
|
signed long (*GetWriteAvailable)( PaStream* stream ) );
|
||||||
|
|
||||||
|
|
||||||
|
/** Dummy Read function for use in interfaces to a callback based streams.
|
||||||
|
Pass to the Read parameter of PaUtil_InitializeStreamInterface.
|
||||||
|
@return An error code indicating that the function has no effect
|
||||||
|
because the stream is a callback stream.
|
||||||
|
*/
|
||||||
|
PaError PaUtil_DummyRead( PaStream* stream,
|
||||||
|
void *buffer,
|
||||||
|
unsigned long frames );
|
||||||
|
|
||||||
|
|
||||||
|
/** Dummy Write function for use in an interfaces to callback based streams.
|
||||||
|
Pass to the Write parameter of PaUtil_InitializeStreamInterface.
|
||||||
|
@return An error code indicating that the function has no effect
|
||||||
|
because the stream is a callback stream.
|
||||||
|
*/
|
||||||
|
PaError PaUtil_DummyWrite( PaStream* stream,
|
||||||
|
const void *buffer,
|
||||||
|
unsigned long frames );
|
||||||
|
|
||||||
|
|
||||||
|
/** Dummy GetReadAvailable function for use in interfaces to callback based
|
||||||
|
streams. Pass to the GetReadAvailable parameter of PaUtil_InitializeStreamInterface.
|
||||||
|
@return An error code indicating that the function has no effect
|
||||||
|
because the stream is a callback stream.
|
||||||
|
*/
|
||||||
|
signed long PaUtil_DummyGetReadAvailable( PaStream* stream );
|
||||||
|
|
||||||
|
|
||||||
|
/** Dummy GetWriteAvailable function for use in interfaces to callback based
|
||||||
|
streams. Pass to the GetWriteAvailable parameter of PaUtil_InitializeStreamInterface.
|
||||||
|
@return An error code indicating that the function has no effect
|
||||||
|
because the stream is a callback stream.
|
||||||
|
*/
|
||||||
|
signed long PaUtil_DummyGetWriteAvailable( PaStream* stream );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Dummy GetCpuLoad function for use in an interface to a read/write stream.
|
||||||
|
Pass to the GetCpuLoad parameter of PaUtil_InitializeStreamInterface.
|
||||||
|
@return Returns 0.
|
||||||
|
*/
|
||||||
|
double PaUtil_DummyGetCpuLoad( PaStream* stream );
|
||||||
|
|
||||||
|
|
||||||
|
/** Non host specific data for a stream. This data is used by pa_front to
|
||||||
|
forward to the appropriate functions in the streamInterface structure.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
/** Initialize a PaUtilStreamRepresentation structure.
|
||||||
|
|
||||||
|
@see PaUtil_InitializeStreamRepresentation
|
||||||
|
*/
|
||||||
|
void PaUtil_InitializeStreamRepresentation(
|
||||||
|
PaUtilStreamRepresentation *streamRepresentation,
|
||||||
|
PaUtilStreamInterface *streamInterface,
|
||||||
|
PaStreamCallback *streamCallback,
|
||||||
|
void *userData );
|
||||||
|
|
||||||
|
|
||||||
|
/** Clean up a PaUtilStreamRepresentation structure previously initialized
|
||||||
|
by a call to PaUtil_InitializeStreamRepresentation.
|
||||||
|
|
||||||
|
@see PaUtil_InitializeStreamRepresentation
|
||||||
|
*/
|
||||||
|
void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation );
|
||||||
|
|
||||||
|
|
||||||
|
/** Check that the stream pointer is valid.
|
||||||
|
|
||||||
|
@return Returns paNoError if the stream pointer appears to be OK, otherwise
|
||||||
|
returns an error indicating the cause of failure.
|
||||||
|
*/
|
||||||
|
PaError PaUtil_ValidateStreamPointer( PaStream *stream );
|
||||||
|
|
||||||
|
|
||||||
|
/** Cast an opaque stream pointer into a pointer to a PaUtilStreamRepresentation.
|
||||||
|
|
||||||
|
@see PaUtilStreamRepresentation
|
||||||
|
*/
|
||||||
|
#define PA_STREAM_REP( stream )\
|
||||||
|
((PaUtilStreamRepresentation*) (stream) )
|
||||||
|
|
||||||
|
|
||||||
|
/** Cast an opaque stream pointer into a pointer to a PaUtilStreamInterface.
|
||||||
|
|
||||||
|
@see PaUtilStreamRepresentation, PaUtilStreamInterface
|
||||||
|
*/
|
||||||
|
#define PA_STREAM_INTERFACE( stream )\
|
||||||
|
PA_STREAM_REP( (stream) )->streamInterface
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_STREAM_H */
|
88
portaudio-v19/src/common/pa_trace.c
Normal file
88
portaudio-v19/src/common/pa_trace.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* Portable Audio I/O Library Trace Facility
|
||||||
|
* Store trace information in real-time for later printing.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Event trace mechanism for debugging.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "pa_trace.h"
|
||||||
|
|
||||||
|
#if PA_TRACE_REALTIME_EVENTS
|
||||||
|
|
||||||
|
static char *traceTextArray[PA_MAX_TRACE_RECORDS];
|
||||||
|
static int traceIntArray[PA_MAX_TRACE_RECORDS];
|
||||||
|
static int traceIndex = 0;
|
||||||
|
static int traceBlock = 0;
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
void PaUtil_ResetTraceMessages()
|
||||||
|
{
|
||||||
|
traceIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
void PaUtil_DumpTraceMessages()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int messageCount = (traceIndex < PA_MAX_TRACE_RECORDS) ? traceIndex : PA_MAX_TRACE_RECORDS;
|
||||||
|
|
||||||
|
printf("DumpTraceMessages: traceIndex = %d\n", traceIndex );
|
||||||
|
for( i=0; i<messageCount; i++ )
|
||||||
|
{
|
||||||
|
printf("%3d: %s = 0x%08X\n",
|
||||||
|
i, traceTextArray[i], traceIntArray[i] );
|
||||||
|
}
|
||||||
|
PaUtil_ResetTraceMessages();
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************/
|
||||||
|
void PaUtil_AddTraceMessage( const char *msg, int data )
|
||||||
|
{
|
||||||
|
if( (traceIndex == PA_MAX_TRACE_RECORDS) && (traceBlock == 0) )
|
||||||
|
{
|
||||||
|
traceBlock = 1;
|
||||||
|
/* PaUtil_DumpTraceMessages(); */
|
||||||
|
}
|
||||||
|
else if( traceIndex < PA_MAX_TRACE_RECORDS )
|
||||||
|
{
|
||||||
|
traceTextArray[traceIndex] = msg;
|
||||||
|
traceIntArray[traceIndex] = data;
|
||||||
|
traceIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TRACE_REALTIME_EVENTS */
|
70
portaudio-v19/src/common/pa_trace.h
Normal file
70
portaudio-v19/src/common/pa_trace.h
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#ifndef PA_TRACE_H
|
||||||
|
#define PA_TRACE_H
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* Portable Audio I/O Library Trace Facility
|
||||||
|
* Store trace information in real-time for later printing.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Event trace mechanism for debugging.
|
||||||
|
|
||||||
|
Allows data to be written to the buffer at interrupt time and dumped later.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define PA_TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */
|
||||||
|
#define PA_MAX_TRACE_RECORDS (2048)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
#if PA_TRACE_REALTIME_EVENTS
|
||||||
|
|
||||||
|
void PaUtil_ResetTraceMessages();
|
||||||
|
void PaUtil_AddTraceMessage( const char *msg, int data );
|
||||||
|
void PaUtil_DumpTraceMessages();
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define PaUtil_ResetTraceMessages() /* noop */
|
||||||
|
#define PaUtil_AddTraceMessage(msg,data) /* noop */
|
||||||
|
#define PaUtil_DumpTraceMessages() /* noop */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif /* PA_TRACE_H */
|
65
portaudio-v19/src/common/pa_types.h
Normal file
65
portaudio-v19/src/common/pa_types.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#ifndef PA_TYPES_H
|
||||||
|
#define PA_TYPES_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
SIZEOF_SHORT, SIZEOF_INT and SIZEOF_LONG are set by the configure script
|
||||||
|
when it is used. Otherwise we default to the common 32 bit values, if your
|
||||||
|
platform doesn't use configure, and doesn't use the default values below
|
||||||
|
you will need to explicitly define these symbols in your make file.
|
||||||
|
|
||||||
|
A PA_VALIDATE_SIZES macro is provided to assert that the values set in this
|
||||||
|
file are correct.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SIZEOF_SHORT
|
||||||
|
#define SIZEOF_SHORT 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SIZEOF_INT
|
||||||
|
#define SIZEOF_INT 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SIZEOF_LONG
|
||||||
|
#define SIZEOF_LONG 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if SIZEOF_SHORT == 2
|
||||||
|
typedef signed short PaInt16;
|
||||||
|
typedef unsigned short PaUint16;
|
||||||
|
#elif SIZEOF_INT == 2
|
||||||
|
typedef signed int PaInt16;
|
||||||
|
typedef unsigned int PaUint16;
|
||||||
|
#else
|
||||||
|
#error pa_types.h was unable to determine which type to use for 16bit integers on the target platform
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SIZEOF_SHORT == 4
|
||||||
|
typedef signed short PaInt32;
|
||||||
|
typedef unsigned short PaUint32;
|
||||||
|
#elif SIZEOF_INT == 4
|
||||||
|
typedef signed int PaInt32;
|
||||||
|
typedef unsigned int PaUint32;
|
||||||
|
#elif SIZEOF_LONG == 4
|
||||||
|
typedef signed long PaInt32;
|
||||||
|
typedef unsigned long PaUint32;
|
||||||
|
#else
|
||||||
|
#error pa_types.h was unable to determine which type to use for 32bit integers on the target platform
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* PA_VALIDATE_TYPE_SIZES compares the size of the integer types at runtime to
|
||||||
|
ensure that PortAudio was configured correctly, and raises an assertion if
|
||||||
|
they don't match the expected values. <assert.h> must be included in the
|
||||||
|
context in which this macro is used.
|
||||||
|
*/
|
||||||
|
#define PA_VALIDATE_TYPE_SIZES \
|
||||||
|
{ \
|
||||||
|
assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint16 ) == 2 ); \
|
||||||
|
assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt16 ) == 2 ); \
|
||||||
|
assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaUint32 ) == 4 ); \
|
||||||
|
assert( "PortAudio: type sizes are not correct in pa_types.h" && sizeof( PaInt32 ) == 4 ); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* PA_TYPES_H */
|
167
portaudio-v19/src/common/pa_util.h
Normal file
167
portaudio-v19/src/common/pa_util.h
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@brief Prototypes for utility functions used by PortAudio implementations.
|
||||||
|
|
||||||
|
@todo Document and adhere to the alignment guarantees provided by
|
||||||
|
PaUtil_AllocateMemory().
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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. If the host API
|
||||||
|
specified by type is not found, this function returns paHostApiNotFound.
|
||||||
|
*/
|
||||||
|
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, ... );
|
||||||
|
|
||||||
|
#ifdef PA_ENABLE_DEBUG_OUTPUT
|
||||||
|
#define PA_DEBUG(x) PaUtil_DebugPrint x ;
|
||||||
|
#else
|
||||||
|
#define PA_DEBUG(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* the following functions are implemented in a platform platform specific
|
||||||
|
.c file
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Allocate size bytes, guaranteed to be aligned to a FIXME byte boundary */
|
||||||
|
void *PaUtil_AllocateMemory( long size );
|
||||||
|
|
||||||
|
|
||||||
|
/** Realease block if non-NULL. block may be NULL */
|
||||||
|
void PaUtil_FreeMemory( void *block );
|
||||||
|
|
||||||
|
|
||||||
|
/** 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.
|
||||||
|
*/
|
||||||
|
int PaUtil_CountCurrentlyAllocatedBlocks( void );
|
||||||
|
|
||||||
|
|
||||||
|
/** Initialize the clock used by PaUtil_GetTime(). Call this before calling
|
||||||
|
PaUtil_GetTime.
|
||||||
|
|
||||||
|
@see PaUtil_GetTime
|
||||||
|
*/
|
||||||
|
void PaUtil_InitializeClock( void );
|
||||||
|
|
||||||
|
|
||||||
|
/** Return the system time in seconds. Used to implement CPU load functions
|
||||||
|
|
||||||
|
@see PaUtil_InitializeClock
|
||||||
|
*/
|
||||||
|
double PaUtil_GetTime( void );
|
||||||
|
|
||||||
|
|
||||||
|
/* void Pa_Sleep( long msec ); must also be implemented in per-platform .c file */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_UTIL_H */
|
3310
portaudio-v19/src/hostapi/alsa/pa_linux_alsa.c
Normal file
3310
portaudio-v19/src/hostapi/alsa/pa_linux_alsa.c
Normal file
File diff suppressed because it is too large
Load Diff
2900
portaudio-v19/src/hostapi/asihpi/pa_linux_asihpi.c
Normal file
2900
portaudio-v19/src/hostapi/asihpi/pa_linux_asihpi.c
Normal file
File diff suppressed because it is too large
Load Diff
137
portaudio-v19/src/hostapi/asio/ASIO-README.txt
Normal file
137
portaudio-v19/src/hostapi/asio/ASIO-README.txt
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
ASIO-README.txt
|
||||||
|
|
||||||
|
This document contains information to help you compile PortAudio with
|
||||||
|
ASIO support. If you find any omissions or errors in this document
|
||||||
|
please notify Ross Bencina <rossb@audiomulch.com>.
|
||||||
|
|
||||||
|
|
||||||
|
Building PortAudio with ASIO support
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
To build PortAudio with ASIO support you need to compile and link with
|
||||||
|
pa_asio.c, and files from the ASIO SDK (see below), along with the common
|
||||||
|
files from pa_common/ and platform specific files from pa_win/ (for Win32)
|
||||||
|
or pa_mac/ (for Macintosh).
|
||||||
|
|
||||||
|
If you are compiling with a non-Microsoft compiler on windows, also
|
||||||
|
compile and link with iasiothiscallresolver.cpp (see below for
|
||||||
|
an explanation).
|
||||||
|
|
||||||
|
For some platforms (MingW, possibly Mac), you may simply
|
||||||
|
be able to type:
|
||||||
|
|
||||||
|
./configure --with-host_os=mingw --with-winapi=asio [--with-asiodir=/usr/local/asiosdk2]
|
||||||
|
make
|
||||||
|
|
||||||
|
./configure --with-host_os=darwin --with-winapi=asio [--with-asiodir=/usr/local/asiosdk2]
|
||||||
|
make
|
||||||
|
|
||||||
|
and life will be good.
|
||||||
|
|
||||||
|
|
||||||
|
Obtaining the ASIO SDK
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
In order to build PortAudio with ASIO support, you need to download
|
||||||
|
the ASIO SDK (version 2.0) from Steinberg. Steinberg makes the ASIO
|
||||||
|
SDK available to anyone free of charge, however they do not permit its
|
||||||
|
source code to be distributed.
|
||||||
|
|
||||||
|
NOTE: In some cases the ASIO SDK may require patching, see below
|
||||||
|
for further details.
|
||||||
|
|
||||||
|
http://www.steinberg.net/en/ps/support/3rdparty/asio_sdk/
|
||||||
|
|
||||||
|
If the above link is broken search Google for:
|
||||||
|
"download steinberg ASIO SDK"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Building the ASIO SDK on Macintosh
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
To build the ASIO SDK on Macintosh you need to compile and link with the
|
||||||
|
following files from the ASIO SDK:
|
||||||
|
|
||||||
|
host/asiodrivers.cpp
|
||||||
|
host/mac/asioshlib.cpp
|
||||||
|
host/mac/codefragements.cpp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Building the ASIO SDK on Windows
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
To build the ASIO SDK on Windows you need to compile and link with the
|
||||||
|
following files from the ASIO SDK:
|
||||||
|
|
||||||
|
asio_sdk\common\asio.cpp
|
||||||
|
asio_sdk\host\asiodrivers.cpp
|
||||||
|
asio_sdk\host\pc\asiolist.cpp
|
||||||
|
|
||||||
|
You may also need to adjust your include paths to support inclusion of
|
||||||
|
header files from the above directories.
|
||||||
|
|
||||||
|
The ASIO SDK depends on the following COM API functions:
|
||||||
|
CoInitialize, CoUninitialize, CoCreateInstance, CLSIDFromString
|
||||||
|
For compilation with MinGW you will need to link with -lole32, for
|
||||||
|
Borland link with Import32.lib.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Non-Microsoft (MSVC) Compilers on Windows including Borland and GCC
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
|
||||||
|
Steinberg did not specify a calling convention in the IASIO interface
|
||||||
|
definition. This causes the Microsoft compiler to use the proprietary
|
||||||
|
thiscall convention which is not compatible with other compilers, such
|
||||||
|
as compilers from Borland (BCC and C++Builder) and GNU (gcc).
|
||||||
|
Steinberg's ASIO SDK will compile but crash on initialization if
|
||||||
|
compiled with a non-Microsoft compiler on Windows.
|
||||||
|
|
||||||
|
PortAudio solves this problem using the iasiothiscallresolver library
|
||||||
|
which is included in the distribution. When building ASIO support for
|
||||||
|
non-Microsoft compilers, be sure to compile and link with
|
||||||
|
iasiothiscallresolver.cpp. Note that iasiothiscallresolver includes
|
||||||
|
conditional directives which cause it to have no effect if it is
|
||||||
|
compiled with a Microsoft compiler, or on the Macintosh.
|
||||||
|
|
||||||
|
If you use configure and make (see above), this should be handled
|
||||||
|
automatically for you.
|
||||||
|
|
||||||
|
For further information about the IASIO thiscall problem see this page:
|
||||||
|
http://www.audiomulch.com/~rossb/code/calliasio
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Macintosh ASIO SDK Bug Patch
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
There is a bug in the ASIO SDK that causes the Macintosh version to
|
||||||
|
often fail during initialization. Below 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
---
|
BIN
portaudio-v19/src/hostapi/asio/Callback_adaptation_.pdf
Normal file
BIN
portaudio-v19/src/hostapi/asio/Callback_adaptation_.pdf
Normal file
Binary file not shown.
BIN
portaudio-v19/src/hostapi/asio/Pa_ASIO.pdf
Normal file
BIN
portaudio-v19/src/hostapi/asio/Pa_ASIO.pdf
Normal file
Binary file not shown.
563
portaudio-v19/src/hostapi/asio/iasiothiscallresolver.cpp
Normal file
563
portaudio-v19/src/hostapi/asio/iasiothiscallresolver.cpp
Normal file
@ -0,0 +1,563 @@
|
|||||||
|
/*
|
||||||
|
IASIOThiscallResolver.cpp see the comments in iasiothiscallresolver.h for
|
||||||
|
the top level description - this comment describes the technical details of
|
||||||
|
the implementation.
|
||||||
|
|
||||||
|
The latest version of this file is available from:
|
||||||
|
http://www.audiomulch.com/~rossb/code/calliasio
|
||||||
|
|
||||||
|
please email comments to Ross Bencina <rossb@audiomulch.com>
|
||||||
|
|
||||||
|
BACKGROUND
|
||||||
|
|
||||||
|
The IASIO interface declared in the Steinberg ASIO 2 SDK declares
|
||||||
|
functions with no explicit calling convention. This causes MSVC++ to default
|
||||||
|
to using the thiscall convention, which is a proprietary convention not
|
||||||
|
implemented by some non-microsoft compilers - notably borland BCC,
|
||||||
|
C++Builder, and gcc. MSVC++ is the defacto standard compiler used by
|
||||||
|
Steinberg. As a result of this situation, the ASIO sdk will compile with
|
||||||
|
any compiler, however attempting to execute the compiled code will cause a
|
||||||
|
crash due to different default calling conventions on non-Microsoft
|
||||||
|
compilers.
|
||||||
|
|
||||||
|
IASIOThiscallResolver solves the problem by providing an adapter class that
|
||||||
|
delegates to the IASIO interface using the correct calling convention
|
||||||
|
(thiscall). Due to the lack of support for thiscall in the Borland and GCC
|
||||||
|
compilers, the calls have been implemented in assembly language.
|
||||||
|
|
||||||
|
A number of macros are defined for thiscall function calls with different
|
||||||
|
numbers of parameters, with and without return values - it may be possible
|
||||||
|
to modify the format of these macros to make them work with other inline
|
||||||
|
assemblers.
|
||||||
|
|
||||||
|
|
||||||
|
THISCALL DEFINITION
|
||||||
|
|
||||||
|
A number of definitions of the thiscall calling convention are floating
|
||||||
|
around the internet. The following definition has been validated against
|
||||||
|
output from the MSVC++ compiler:
|
||||||
|
|
||||||
|
For non-vararg functions, thiscall works as follows: the object (this)
|
||||||
|
pointer is passed in ECX. All arguments are passed on the stack in
|
||||||
|
right to left order. The return value is placed in EAX. The callee
|
||||||
|
clears the passed arguments from the stack.
|
||||||
|
|
||||||
|
|
||||||
|
FINDING FUNCTION POINTERS FROM AN IASIO POINTER
|
||||||
|
|
||||||
|
The first field of a COM object is a pointer to its vtble. Thus a pointer
|
||||||
|
to an object implementing the IASIO interface also points to a pointer to
|
||||||
|
that object's vtbl. The vtble is a table of function pointers for all of
|
||||||
|
the virtual functions exposed by the implemented interfaces.
|
||||||
|
|
||||||
|
If we consider a variable declared as a pointer to IASO:
|
||||||
|
|
||||||
|
IASIO *theAsioDriver
|
||||||
|
|
||||||
|
theAsioDriver points to:
|
||||||
|
|
||||||
|
object implementing IASIO
|
||||||
|
{
|
||||||
|
IASIOvtbl *vtbl
|
||||||
|
other data
|
||||||
|
}
|
||||||
|
|
||||||
|
in other words, theAsioDriver points to a pointer to an IASIOvtbl
|
||||||
|
|
||||||
|
vtbl points to a table of function pointers:
|
||||||
|
|
||||||
|
IASIOvtbl ( interface IASIO : public IUnknown )
|
||||||
|
{
|
||||||
|
(IUnknown functions)
|
||||||
|
0 virtual HRESULT STDMETHODCALLTYPE (*QueryInterface)(REFIID riid, void **ppv) = 0;
|
||||||
|
4 virtual ULONG STDMETHODCALLTYPE (*AddRef)() = 0;
|
||||||
|
8 virtual ULONG STDMETHODCALLTYPE (*Release)() = 0;
|
||||||
|
|
||||||
|
(IASIO functions)
|
||||||
|
12 virtual ASIOBool (*init)(void *sysHandle) = 0;
|
||||||
|
16 virtual void (*getDriverName)(char *name) = 0;
|
||||||
|
20 virtual long (*getDriverVersion)() = 0;
|
||||||
|
24 virtual void (*getErrorMessage)(char *string) = 0;
|
||||||
|
28 virtual ASIOError (*start)() = 0;
|
||||||
|
32 virtual ASIOError (*stop)() = 0;
|
||||||
|
36 virtual ASIOError (*getChannels)(long *numInputChannels, long *numOutputChannels) = 0;
|
||||||
|
40 virtual ASIOError (*getLatencies)(long *inputLatency, long *outputLatency) = 0;
|
||||||
|
44 virtual ASIOError (*getBufferSize)(long *minSize, long *maxSize,
|
||||||
|
long *preferredSize, long *granularity) = 0;
|
||||||
|
48 virtual ASIOError (*canSampleRate)(ASIOSampleRate sampleRate) = 0;
|
||||||
|
52 virtual ASIOError (*getSampleRate)(ASIOSampleRate *sampleRate) = 0;
|
||||||
|
56 virtual ASIOError (*setSampleRate)(ASIOSampleRate sampleRate) = 0;
|
||||||
|
60 virtual ASIOError (*getClockSources)(ASIOClockSource *clocks, long *numSources) = 0;
|
||||||
|
64 virtual ASIOError (*setClockSource)(long reference) = 0;
|
||||||
|
68 virtual ASIOError (*getSamplePosition)(ASIOSamples *sPos, ASIOTimeStamp *tStamp) = 0;
|
||||||
|
72 virtual ASIOError (*getChannelInfo)(ASIOChannelInfo *info) = 0;
|
||||||
|
76 virtual ASIOError (*createBuffers)(ASIOBufferInfo *bufferInfos, long numChannels,
|
||||||
|
long bufferSize, ASIOCallbacks *callbacks) = 0;
|
||||||
|
80 virtual ASIOError (*disposeBuffers)() = 0;
|
||||||
|
84 virtual ASIOError (*controlPanel)() = 0;
|
||||||
|
88 virtual ASIOError (*future)(long selector,void *opt) = 0;
|
||||||
|
92 virtual ASIOError (*outputReady)() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
The numbers in the left column show the byte offset of each function ptr
|
||||||
|
from the beginning of the vtbl. These numbers are used in the code below
|
||||||
|
to select different functions.
|
||||||
|
|
||||||
|
In order to find the address of a particular function, theAsioDriver
|
||||||
|
must first be dereferenced to find the value of the vtbl pointer:
|
||||||
|
|
||||||
|
mov eax, theAsioDriver
|
||||||
|
mov edx, [theAsioDriver] // edx now points to vtbl[0]
|
||||||
|
|
||||||
|
Then an offset must be added to the vtbl pointer to select a
|
||||||
|
particular function, for example vtbl+44 points to the slot containing
|
||||||
|
a pointer to the getBufferSize function.
|
||||||
|
|
||||||
|
Finally vtbl+x must be dereferenced to obtain the value of the function
|
||||||
|
pointer stored in that address:
|
||||||
|
|
||||||
|
call [edx+44] // call the function pointed to by
|
||||||
|
// the value in the getBufferSize field of the vtbl
|
||||||
|
|
||||||
|
|
||||||
|
SEE ALSO
|
||||||
|
|
||||||
|
Martin Fay's OpenASIO DLL at http://www.martinfay.com solves the same
|
||||||
|
problem by providing a new COM interface which wraps IASIO with an
|
||||||
|
interface that uses portable calling conventions. OpenASIO must be compiled
|
||||||
|
with MSVC, and requires that you ship the OpenASIO DLL with your
|
||||||
|
application.
|
||||||
|
|
||||||
|
|
||||||
|
ACKNOWLEDGEMENTS
|
||||||
|
|
||||||
|
Ross Bencina: worked out the thiscall details above, wrote the original
|
||||||
|
Borland asm macros, and a patch for asio.cpp (which is no longer needed).
|
||||||
|
Thanks to Martin Fay for introducing me to the issues discussed here,
|
||||||
|
and to Rene G. Ceballos for assisting with asm dumps from MSVC++.
|
||||||
|
|
||||||
|
Antti Silvast: converted the original calliasio to work with gcc and NASM
|
||||||
|
by implementing the asm code in a separate file.
|
||||||
|
|
||||||
|
Fraser Adams: modified the original calliasio containing the Borland inline
|
||||||
|
asm to add inline asm for gcc i.e. Intel syntax for Borland and AT&T syntax
|
||||||
|
for gcc. This seems a neater approach for gcc than to have a separate .asm
|
||||||
|
file and it means that we only need one version of the thiscall patch.
|
||||||
|
|
||||||
|
Fraser Adams: rewrote the original calliasio patch in the form of the
|
||||||
|
IASIOThiscallResolver class in order to avoid modifications to files from
|
||||||
|
the Steinberg SDK, which may have had potential licence issues.
|
||||||
|
|
||||||
|
Andrew Baldwin: contributed fixes for compatibility problems with more
|
||||||
|
recent versions of the gcc assembler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// We only need IASIOThiscallResolver at all if we are on Win32. For other
|
||||||
|
// platforms we simply bypass the IASIOThiscallResolver definition to allow us
|
||||||
|
// to be safely #include'd whatever the platform to keep client code portable
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||||
|
|
||||||
|
|
||||||
|
// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver
|
||||||
|
// is not used.
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
// We have a mechanism in iasiothiscallresolver.h to ensure that asio.h is
|
||||||
|
// #include'd before it in client code, we do NOT want to do this test here.
|
||||||
|
#define iasiothiscallresolver_sourcefile 1
|
||||||
|
#include "iasiothiscallresolver.h"
|
||||||
|
#undef iasiothiscallresolver_sourcefile
|
||||||
|
|
||||||
|
// iasiothiscallresolver.h redefines ASIOInit for clients, but we don't want
|
||||||
|
// this macro defined in this translation unit.
|
||||||
|
#undef ASIOInit
|
||||||
|
|
||||||
|
|
||||||
|
// theAsioDriver is a global pointer to the current IASIO instance which the
|
||||||
|
// ASIO SDK uses to perform all actions on the IASIO interface. We substitute
|
||||||
|
// our own forwarding interface into this pointer.
|
||||||
|
extern IASIO* theAsioDriver;
|
||||||
|
|
||||||
|
|
||||||
|
// The following macros define the inline assembler for BORLAND first then gcc
|
||||||
|
|
||||||
|
#if defined(__BCPLUSPLUS__) || defined(__BORLANDC__)
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_THISCALL_0( resultName, thisPtr, funcOffset )\
|
||||||
|
void *this_ = (thisPtr); \
|
||||||
|
__asm { \
|
||||||
|
mov ecx, this_ ; \
|
||||||
|
mov eax, [ecx] ; \
|
||||||
|
call [eax+funcOffset] ; \
|
||||||
|
mov resultName, eax ; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 )\
|
||||||
|
void *this_ = (thisPtr); \
|
||||||
|
__asm { \
|
||||||
|
mov eax, param1 ; \
|
||||||
|
push eax ; \
|
||||||
|
mov ecx, this_ ; \
|
||||||
|
mov eax, [ecx] ; \
|
||||||
|
call [eax+funcOffset] ; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 )\
|
||||||
|
void *this_ = (thisPtr); \
|
||||||
|
__asm { \
|
||||||
|
mov eax, param1 ; \
|
||||||
|
push eax ; \
|
||||||
|
mov ecx, this_ ; \
|
||||||
|
mov eax, [ecx] ; \
|
||||||
|
call [eax+funcOffset] ; \
|
||||||
|
mov resultName, eax ; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 )\
|
||||||
|
void *this_ = (thisPtr); \
|
||||||
|
void *doubleParamPtr_ (¶m1); \
|
||||||
|
__asm { \
|
||||||
|
mov eax, doubleParamPtr_ ; \
|
||||||
|
push [eax+4] ; \
|
||||||
|
push [eax] ; \
|
||||||
|
mov ecx, this_ ; \
|
||||||
|
mov eax, [ecx] ; \
|
||||||
|
call [eax+funcOffset] ; \
|
||||||
|
mov resultName, eax ; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 )\
|
||||||
|
void *this_ = (thisPtr); \
|
||||||
|
__asm { \
|
||||||
|
mov eax, param2 ; \
|
||||||
|
push eax ; \
|
||||||
|
mov eax, param1 ; \
|
||||||
|
push eax ; \
|
||||||
|
mov ecx, this_ ; \
|
||||||
|
mov eax, [ecx] ; \
|
||||||
|
call [eax+funcOffset] ; \
|
||||||
|
mov resultName, eax ; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\
|
||||||
|
void *this_ = (thisPtr); \
|
||||||
|
__asm { \
|
||||||
|
mov eax, param4 ; \
|
||||||
|
push eax ; \
|
||||||
|
mov eax, param3 ; \
|
||||||
|
push eax ; \
|
||||||
|
mov eax, param2 ; \
|
||||||
|
push eax ; \
|
||||||
|
mov eax, param1 ; \
|
||||||
|
push eax ; \
|
||||||
|
mov ecx, this_ ; \
|
||||||
|
mov eax, [ecx] ; \
|
||||||
|
call [eax+funcOffset] ; \
|
||||||
|
mov resultName, eax ; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_THISCALL_0( resultName, thisPtr, funcOffset ) \
|
||||||
|
__asm__ __volatile__ ("movl (%1), %%edx\n\t" \
|
||||||
|
"call *"#funcOffset"(%%edx)\n\t" \
|
||||||
|
:"=a"(resultName) /* Output Operands */ \
|
||||||
|
:"c"(thisPtr) /* Input Operands */ \
|
||||||
|
); \
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_VOID_THISCALL_1( thisPtr, funcOffset, param1 ) \
|
||||||
|
__asm__ __volatile__ ("pushl %0\n\t" \
|
||||||
|
"movl (%1), %%edx\n\t" \
|
||||||
|
"call *"#funcOffset"(%%edx)\n\t" \
|
||||||
|
: /* Output Operands */ \
|
||||||
|
:"r"(param1), /* Input Operands */ \
|
||||||
|
"c"(thisPtr) \
|
||||||
|
); \
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_THISCALL_1( resultName, thisPtr, funcOffset, param1 ) \
|
||||||
|
__asm__ __volatile__ ("pushl %1\n\t" \
|
||||||
|
"movl (%2), %%edx\n\t" \
|
||||||
|
"call *"#funcOffset"(%%edx)\n\t" \
|
||||||
|
:"=a"(resultName) /* Output Operands */ \
|
||||||
|
:"r"(param1), /* Input Operands */ \
|
||||||
|
"c"(thisPtr) \
|
||||||
|
); \
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_THISCALL_1_DOUBLE( resultName, thisPtr, funcOffset, param1 ) \
|
||||||
|
__asm__ __volatile__ ("pushl 4(%1)\n\t" \
|
||||||
|
"pushl (%1)\n\t" \
|
||||||
|
"movl (%2), %%edx\n\t" \
|
||||||
|
"call *"#funcOffset"(%%edx);\n\t" \
|
||||||
|
:"=a"(resultName) /* Output Operands */ \
|
||||||
|
:"a"(¶m1), /* Input Operands */ \
|
||||||
|
/* Note: Using "r" above instead of "a" fails */ \
|
||||||
|
/* when using GCC 3.3.3, and maybe later versions*/\
|
||||||
|
"c"(thisPtr) \
|
||||||
|
); \
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_THISCALL_2( resultName, thisPtr, funcOffset, param1, param2 ) \
|
||||||
|
__asm__ __volatile__ ("pushl %1\n\t" \
|
||||||
|
"pushl %2\n\t" \
|
||||||
|
"movl (%3), %%edx\n\t" \
|
||||||
|
"call *"#funcOffset"(%%edx)\n\t" \
|
||||||
|
:"=a"(resultName) /* Output Operands */ \
|
||||||
|
:"r"(param2), /* Input Operands */ \
|
||||||
|
"r"(param1), \
|
||||||
|
"c"(thisPtr) \
|
||||||
|
); \
|
||||||
|
|
||||||
|
|
||||||
|
#define CALL_THISCALL_4( resultName, thisPtr, funcOffset, param1, param2, param3, param4 )\
|
||||||
|
__asm__ __volatile__ ("pushl %1\n\t" \
|
||||||
|
"pushl %2\n\t" \
|
||||||
|
"pushl %3\n\t" \
|
||||||
|
"pushl %4\n\t" \
|
||||||
|
"movl (%5), %%edx\n\t" \
|
||||||
|
"call *"#funcOffset"(%%edx)\n\t" \
|
||||||
|
:"=a"(resultName) /* Output Operands */ \
|
||||||
|
:"r"(param4), /* Input Operands */ \
|
||||||
|
"r"(param3), \
|
||||||
|
"r"(param2), \
|
||||||
|
"r"(param1), \
|
||||||
|
"c"(thisPtr) \
|
||||||
|
); \
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Our static singleton instance.
|
||||||
|
IASIOThiscallResolver IASIOThiscallResolver::instance;
|
||||||
|
|
||||||
|
// Constructor called to initialize static Singleton instance above. Note that
|
||||||
|
// it is important not to clear that_ incase it has already been set by the call
|
||||||
|
// to placement new in ASIOInit().
|
||||||
|
IASIOThiscallResolver::IASIOThiscallResolver()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor called from ASIOInit() below
|
||||||
|
IASIOThiscallResolver::IASIOThiscallResolver(IASIO* that)
|
||||||
|
: that_( that )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implement IUnknown methods as assert(false). IASIOThiscallResolver is not
|
||||||
|
// really a COM object, just a wrapper which will work with the ASIO SDK.
|
||||||
|
// If you wanted to use ASIO without the SDK you might want to implement COM
|
||||||
|
// aggregation in these methods.
|
||||||
|
HRESULT STDMETHODCALLTYPE IASIOThiscallResolver::QueryInterface(REFIID riid, void **ppv)
|
||||||
|
{
|
||||||
|
(void)riid; // suppress unused variable warning
|
||||||
|
|
||||||
|
assert( false ); // this function should never be called by the ASIO SDK.
|
||||||
|
|
||||||
|
*ppv = NULL;
|
||||||
|
return E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE IASIOThiscallResolver::AddRef()
|
||||||
|
{
|
||||||
|
assert( false ); // this function should never be called by the ASIO SDK.
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ULONG STDMETHODCALLTYPE IASIOThiscallResolver::Release()
|
||||||
|
{
|
||||||
|
assert( false ); // this function should never be called by the ASIO SDK.
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Implement the IASIO interface methods by performing the vptr manipulation
|
||||||
|
// described above then delegating to the real implementation.
|
||||||
|
ASIOBool IASIOThiscallResolver::init(void *sysHandle)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_1( result, that_, 12, sysHandle );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IASIOThiscallResolver::getDriverName(char *name)
|
||||||
|
{
|
||||||
|
CALL_VOID_THISCALL_1( that_, 16, name );
|
||||||
|
}
|
||||||
|
|
||||||
|
long IASIOThiscallResolver::getDriverVersion()
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_0( result, that_, 20 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IASIOThiscallResolver::getErrorMessage(char *string)
|
||||||
|
{
|
||||||
|
CALL_VOID_THISCALL_1( that_, 24, string );
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::start()
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_0( result, that_, 28 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::stop()
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_0( result, that_, 32 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::getChannels(long *numInputChannels, long *numOutputChannels)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_2( result, that_, 36, numInputChannels, numOutputChannels );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::getLatencies(long *inputLatency, long *outputLatency)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_2( result, that_, 40, inputLatency, outputLatency );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::getBufferSize(long *minSize, long *maxSize,
|
||||||
|
long *preferredSize, long *granularity)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_4( result, that_, 44, minSize, maxSize, preferredSize, granularity );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::canSampleRate(ASIOSampleRate sampleRate)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_1_DOUBLE( result, that_, 48, sampleRate );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::getSampleRate(ASIOSampleRate *sampleRate)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_1( result, that_, 52, sampleRate );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::setSampleRate(ASIOSampleRate sampleRate)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_1_DOUBLE( result, that_, 56, sampleRate );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::getClockSources(ASIOClockSource *clocks, long *numSources)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_2( result, that_, 60, clocks, numSources );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::setClockSource(long reference)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_1( result, that_, 64, reference );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_2( result, that_, 68, sPos, tStamp );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::getChannelInfo(ASIOChannelInfo *info)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_1( result, that_, 72, info );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::createBuffers(ASIOBufferInfo *bufferInfos,
|
||||||
|
long numChannels, long bufferSize, ASIOCallbacks *callbacks)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_4( result, that_, 76, bufferInfos, numChannels, bufferSize, callbacks );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::disposeBuffers()
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_0( result, that_, 80 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::controlPanel()
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_0( result, that_, 84 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::future(long selector,void *opt)
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_2( result, that_, 88, selector, opt );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASIOError IASIOThiscallResolver::outputReady()
|
||||||
|
{
|
||||||
|
ASIOBool result;
|
||||||
|
CALL_THISCALL_0( result, that_, 92 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Implement our substitute ASIOInit() method
|
||||||
|
ASIOError IASIOThiscallResolver::ASIOInit(ASIODriverInfo *info)
|
||||||
|
{
|
||||||
|
// To ensure that our instance's vptr is correctly constructed, even if
|
||||||
|
// ASIOInit is called prior to main(), we explicitly call its constructor
|
||||||
|
// (potentially over the top of an existing instance). Note that this is
|
||||||
|
// pretty ugly, and is only safe because IASIOThiscallResolver has no
|
||||||
|
// destructor and contains no objects with destructors.
|
||||||
|
new((void*)&instance) IASIOThiscallResolver( theAsioDriver );
|
||||||
|
|
||||||
|
// Interpose between ASIO client code and the real driver.
|
||||||
|
theAsioDriver = &instance;
|
||||||
|
|
||||||
|
// Note that we never need to switch theAsioDriver back to point to the
|
||||||
|
// real driver because theAsioDriver is reset to zero in ASIOExit().
|
||||||
|
|
||||||
|
// Delegate to the real ASIOInit
|
||||||
|
return ::ASIOInit(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !defined(_MSC_VER) */
|
||||||
|
|
||||||
|
#endif /* Win32 */
|
||||||
|
|
197
portaudio-v19/src/hostapi/asio/iasiothiscallresolver.h
Normal file
197
portaudio-v19/src/hostapi/asio/iasiothiscallresolver.h
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
// ****************************************************************************
|
||||||
|
// File: IASIOThiscallResolver.h
|
||||||
|
// Description: The IASIOThiscallResolver class implements the IASIO
|
||||||
|
// interface and acts as a proxy to the real IASIO interface by
|
||||||
|
// calling through its vptr table using the thiscall calling
|
||||||
|
// convention. To put it another way, we interpose
|
||||||
|
// IASIOThiscallResolver between ASIO SDK code and the driver.
|
||||||
|
// This is necessary because most non-Microsoft compilers don't
|
||||||
|
// implement the thiscall calling convention used by IASIO.
|
||||||
|
//
|
||||||
|
// iasiothiscallresolver.cpp contains the background of this
|
||||||
|
// problem plus a technical description of the vptr
|
||||||
|
// manipulations.
|
||||||
|
//
|
||||||
|
// In order to use this mechanism one simply has to add
|
||||||
|
// iasiothiscallresolver.cpp to the list of files to compile
|
||||||
|
// and #include <iasiothiscallresolver.h>
|
||||||
|
//
|
||||||
|
// Note that this #include must come after the other ASIO SDK
|
||||||
|
// #includes, for example:
|
||||||
|
//
|
||||||
|
// #include <windows.h>
|
||||||
|
// #include <asiosys.h>
|
||||||
|
// #include <asio.h>
|
||||||
|
// #include <asiodrivers.h>
|
||||||
|
// #include <iasiothiscallresolver.h>
|
||||||
|
//
|
||||||
|
// Actually the important thing is to #include
|
||||||
|
// <iasiothiscallresolver.h> after <asio.h>. We have
|
||||||
|
// incorporated a test to enforce this ordering.
|
||||||
|
//
|
||||||
|
// The code transparently takes care of the interposition by
|
||||||
|
// using macro substitution to intercept calls to ASIOInit()
|
||||||
|
// and ASIOExit(). We save the original ASIO global
|
||||||
|
// "theAsioDriver" in our "that" variable, and then set
|
||||||
|
// "theAsioDriver" to equal our IASIOThiscallResolver instance.
|
||||||
|
//
|
||||||
|
// Whilst this method of resolving the thiscall problem requires
|
||||||
|
// the addition of #include <iasiothiscallresolver.h> to client
|
||||||
|
// code it has the advantage that it does not break the terms
|
||||||
|
// of the ASIO licence by publishing it. We are NOT modifying
|
||||||
|
// any Steinberg code here, we are merely implementing the IASIO
|
||||||
|
// interface in the same way that we would need to do if we
|
||||||
|
// wished to provide an open source ASIO driver.
|
||||||
|
//
|
||||||
|
// For compilation with MinGW -lole32 needs to be added to the
|
||||||
|
// linker options. For BORLAND, linking with Import32.lib is
|
||||||
|
// sufficient.
|
||||||
|
//
|
||||||
|
// The dependencies are with: CoInitialize, CoUninitialize,
|
||||||
|
// CoCreateInstance, CLSIDFromString - used by asiolist.cpp
|
||||||
|
// and are required on Windows whether ThiscallResolver is used
|
||||||
|
// or not.
|
||||||
|
//
|
||||||
|
// Searching for the above strings in the root library path
|
||||||
|
// of your compiler should enable the correct libraries to be
|
||||||
|
// identified if they aren't immediately obvious.
|
||||||
|
//
|
||||||
|
// Note that the current implementation of IASIOThiscallResolver
|
||||||
|
// is not COM compliant - it does not correctly implement the
|
||||||
|
// IUnknown interface. Implementing it is not necessary because
|
||||||
|
// it is not called by parts of the ASIO SDK which call through
|
||||||
|
// theAsioDriver ptr. The IUnknown methods are implemented as
|
||||||
|
// assert(false) to ensure that the code fails if they are
|
||||||
|
// ever called.
|
||||||
|
// Restrictions: None. Public Domain & Open Source distribute freely
|
||||||
|
// You may use IASIOThiscallResolver commercially as well as
|
||||||
|
// privately.
|
||||||
|
// You the user assume the responsibility for the use of the
|
||||||
|
// files, binary or text, and there is no guarantee or warranty,
|
||||||
|
// expressed or implied, including but not limited to the
|
||||||
|
// implied warranties of merchantability and fitness for a
|
||||||
|
// particular purpose. You assume all responsibility and agree
|
||||||
|
// to hold no entity, copyright holder or distributors liable
|
||||||
|
// for any loss of data or inaccurate representations of data
|
||||||
|
// as a result of using IASIOThiscallResolver.
|
||||||
|
// Version: 1.4 Added separate macro CALL_THISCALL_1_DOUBLE from
|
||||||
|
// Andrew Baldwin, and volatile for whole gcc asm blocks,
|
||||||
|
// both for compatibility with newer gcc versions. Cleaned up
|
||||||
|
// Borland asm to use one less register.
|
||||||
|
// 1.3 Switched to including assert.h for better compatibility.
|
||||||
|
// Wrapped entire .h and .cpp contents with a check for
|
||||||
|
// _MSC_VER to provide better compatibility with MS compilers.
|
||||||
|
// Changed Singleton implementation to use static instance
|
||||||
|
// instead of freestore allocated instance. Removed ASIOExit
|
||||||
|
// macro as it is no longer needed.
|
||||||
|
// 1.2 Removed semicolons from ASIOInit and ASIOExit macros to
|
||||||
|
// allow them to be embedded in expressions (if statements).
|
||||||
|
// Cleaned up some comments. Removed combase.c dependency (it
|
||||||
|
// doesn't compile with BCB anyway) by stubbing IUnknown.
|
||||||
|
// 1.1 Incorporated comments from Ross Bencina including things
|
||||||
|
// such as changing name from ThiscallResolver to
|
||||||
|
// IASIOThiscallResolver, tidying up the constructor, fixing
|
||||||
|
// a bug in IASIOThiscallResolver::ASIOExit() and improving
|
||||||
|
// portability through the use of conditional compilation
|
||||||
|
// 1.0 Initial working version.
|
||||||
|
// Created: 6/09/2003
|
||||||
|
// Authors: Fraser Adams
|
||||||
|
// Ross Bencina
|
||||||
|
// Rene G. Ceballos
|
||||||
|
// Martin Fay
|
||||||
|
// Antti Silvast
|
||||||
|
// Andrew Baldwin
|
||||||
|
//
|
||||||
|
// ****************************************************************************
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef included_iasiothiscallresolver_h
|
||||||
|
#define included_iasiothiscallresolver_h
|
||||||
|
|
||||||
|
// We only need IASIOThiscallResolver at all if we are on Win32. For other
|
||||||
|
// platforms we simply bypass the IASIOThiscallResolver definition to allow us
|
||||||
|
// to be safely #include'd whatever the platform to keep client code portable
|
||||||
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||||
|
|
||||||
|
|
||||||
|
// If microsoft compiler we can call IASIO directly so IASIOThiscallResolver
|
||||||
|
// is not used.
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
|
||||||
|
|
||||||
|
// The following is in order to ensure that this header is only included after
|
||||||
|
// the other ASIO headers (except for the case of iasiothiscallresolver.cpp).
|
||||||
|
// We need to do this because IASIOThiscallResolver works by eclipsing the
|
||||||
|
// original definition of ASIOInit() with a macro (see below).
|
||||||
|
#if !defined(iasiothiscallresolver_sourcefile)
|
||||||
|
#if !defined(__ASIO_H)
|
||||||
|
#error iasiothiscallresolver.h must be included AFTER asio.h
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <asiodrvr.h> /* From ASIO SDK */
|
||||||
|
|
||||||
|
|
||||||
|
class IASIOThiscallResolver : public IASIO {
|
||||||
|
private:
|
||||||
|
IASIO* that_; // Points to the real IASIO
|
||||||
|
|
||||||
|
static IASIOThiscallResolver instance; // Singleton instance
|
||||||
|
|
||||||
|
// Constructors - declared private so construction is limited to
|
||||||
|
// our Singleton instance
|
||||||
|
IASIOThiscallResolver();
|
||||||
|
IASIOThiscallResolver(IASIO* that);
|
||||||
|
public:
|
||||||
|
|
||||||
|
// Methods from the IUnknown interface. We don't fully implement IUnknown
|
||||||
|
// because the ASIO SDK never calls these methods through theAsioDriver ptr.
|
||||||
|
// These methods are implemented as assert(false).
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv);
|
||||||
|
virtual ULONG STDMETHODCALLTYPE AddRef();
|
||||||
|
virtual ULONG STDMETHODCALLTYPE Release();
|
||||||
|
|
||||||
|
// Methods from the IASIO interface, implemented as forwarning calls to that.
|
||||||
|
virtual ASIOBool init(void *sysHandle);
|
||||||
|
virtual void getDriverName(char *name);
|
||||||
|
virtual long getDriverVersion();
|
||||||
|
virtual void getErrorMessage(char *string);
|
||||||
|
virtual ASIOError start();
|
||||||
|
virtual ASIOError stop();
|
||||||
|
virtual ASIOError getChannels(long *numInputChannels, long *numOutputChannels);
|
||||||
|
virtual ASIOError getLatencies(long *inputLatency, long *outputLatency);
|
||||||
|
virtual ASIOError getBufferSize(long *minSize, long *maxSize, long *preferredSize, long *granularity);
|
||||||
|
virtual ASIOError canSampleRate(ASIOSampleRate sampleRate);
|
||||||
|
virtual ASIOError getSampleRate(ASIOSampleRate *sampleRate);
|
||||||
|
virtual ASIOError setSampleRate(ASIOSampleRate sampleRate);
|
||||||
|
virtual ASIOError getClockSources(ASIOClockSource *clocks, long *numSources);
|
||||||
|
virtual ASIOError setClockSource(long reference);
|
||||||
|
virtual ASIOError getSamplePosition(ASIOSamples *sPos, ASIOTimeStamp *tStamp);
|
||||||
|
virtual ASIOError getChannelInfo(ASIOChannelInfo *info);
|
||||||
|
virtual ASIOError createBuffers(ASIOBufferInfo *bufferInfos, long numChannels, long bufferSize, ASIOCallbacks *callbacks);
|
||||||
|
virtual ASIOError disposeBuffers();
|
||||||
|
virtual ASIOError controlPanel();
|
||||||
|
virtual ASIOError future(long selector,void *opt);
|
||||||
|
virtual ASIOError outputReady();
|
||||||
|
|
||||||
|
// Class method, see ASIOInit() macro below.
|
||||||
|
static ASIOError ASIOInit(ASIODriverInfo *info); // Delegates to ::ASIOInit
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Replace calls to ASIOInit with our interposing version.
|
||||||
|
// This macro enables us to perform thiscall resolution simply by #including
|
||||||
|
// <iasiothiscallresolver.h> after the asio #includes (this file _must_ be
|
||||||
|
// included _after_ the asio #includes)
|
||||||
|
|
||||||
|
#define ASIOInit(name) IASIOThiscallResolver::ASIOInit((name))
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !defined(_MSC_VER) */
|
||||||
|
|
||||||
|
#endif /* Win32 */
|
||||||
|
|
||||||
|
#endif /* included_iasiothiscallresolver_h */
|
||||||
|
|
||||||
|
|
2969
portaudio-v19/src/hostapi/asio/pa_asio.cpp
Normal file
2969
portaudio-v19/src/hostapi/asio/pa_asio.cpp
Normal file
File diff suppressed because it is too large
Load Diff
145
portaudio-v19/src/hostapi/coreaudio/notes.txt
Normal file
145
portaudio-v19/src/hostapi/coreaudio/notes.txt
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
Notes on status of CoreAudio Implementation of PortAudio
|
||||||
|
|
||||||
|
Document Last Updated December 9, 2005
|
||||||
|
|
||||||
|
There are currently two implementations of PortAudio for Mac Core Audio.
|
||||||
|
|
||||||
|
The original is in pa_mac_core_old.c, and the newer, default implementation
|
||||||
|
is in pa_mac_core.c.
|
||||||
|
Only pa_mac_core.c is currently developed and supported as it uses apple's
|
||||||
|
current core audio technology. To select use the old implementation, replace
|
||||||
|
pa_mac_core.c with pa_mac_core_old.c (eg. "cp pa_mac_core_auhal.c
|
||||||
|
pa_mac_core.c"), then run configure and make as usual.
|
||||||
|
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
Notes on Original implementation:
|
||||||
|
|
||||||
|
by Phil Burk and Darren Gibbs
|
||||||
|
|
||||||
|
Last updated March 20, 2002
|
||||||
|
|
||||||
|
WHAT WORKS
|
||||||
|
|
||||||
|
Output with very low latency, <10 msec.
|
||||||
|
Half duplex input or output.
|
||||||
|
Full duplex on the same CoreAudio device.
|
||||||
|
The paFLoat32, paInt16, paInt8, paUInt8 sample formats.
|
||||||
|
Pa_GetCPULoad()
|
||||||
|
Pa_StreamTime()
|
||||||
|
|
||||||
|
KNOWN BUGS OR LIMITATIONS
|
||||||
|
|
||||||
|
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
|
||||||
|
Built-In audio is typically one CoreAudio device.
|
||||||
|
|
||||||
|
Mono doesn't work.
|
||||||
|
|
||||||
|
DEVICE MAPPING
|
||||||
|
|
||||||
|
CoreAudio devices can support both input and output. But the sample
|
||||||
|
rates supported may be different. So we have map one or two PortAudio
|
||||||
|
device to each CoreAudio device depending on whether it supports
|
||||||
|
input, output or both.
|
||||||
|
|
||||||
|
When we query devices, we first get a list of CoreAudio devices. Then
|
||||||
|
we scan the list and add a PortAudio device for each CoreAudio device
|
||||||
|
that supports input. Then we make a scan for output devices.
|
||||||
|
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
Notes on Newer/Default AUHAL implementation:
|
||||||
|
|
||||||
|
by Bjorn Roche
|
||||||
|
|
||||||
|
Last Updated December 9, 2005
|
||||||
|
|
||||||
|
Principle of Operation:
|
||||||
|
|
||||||
|
This implementation uses AUHAL for audio I/O. To some extent, it also
|
||||||
|
operates at the "HAL" Layer, though this behavior can be limited by
|
||||||
|
platform specific flags (see pa_mac_core.h for details). The default
|
||||||
|
settings should be reasonable: they don't change the SR of the device and
|
||||||
|
don't cause interruptions if other devices are using the device.
|
||||||
|
|
||||||
|
Major Software Elements Used: Apple's HAL AUs provide output SR
|
||||||
|
conversion transparently, however, only on output, so this
|
||||||
|
implementation uses AudioConverters to convert the sample rate on input.
|
||||||
|
A PortAudio ring buffer is used to buffer input when sample rate
|
||||||
|
conversion is required or when separate audio units are used for duplex
|
||||||
|
IO. Finally, a PortAudio buffer processor is used to convert formats and
|
||||||
|
provide additional buffers if needed. Internally, interleaved floating
|
||||||
|
point data streams are used exclusively - the audio unit converts from
|
||||||
|
the audio hardware's native format to interleaved float PCM and
|
||||||
|
PortAudio's Buffer processor is used for conversion to user formats.
|
||||||
|
|
||||||
|
Simplex Input: Simplex input uses a single callback. If sample rate
|
||||||
|
conversion is required, a ring buffer and AudioConverter are used as
|
||||||
|
well.
|
||||||
|
|
||||||
|
Simplex output: Simplex output uses a single callback. No ring buffer or
|
||||||
|
audio converter is used because AUHAL does its own output SR conversion.
|
||||||
|
|
||||||
|
Duplex, one device (no SR conversion): When one device is used, a single
|
||||||
|
callback is used. This achieves very low latency.
|
||||||
|
|
||||||
|
Duplex, separate devices or SR conversion: When SR conversion is
|
||||||
|
required, data must be buffered before it is converted and data is not
|
||||||
|
always available at the same times on input and output, so SR conversion
|
||||||
|
requires the same treatment as separate devices. The input callback
|
||||||
|
reads data and puts it in the ring buffer. The output callback reads the
|
||||||
|
data off the ring buffer, into an audio converter and finally to the
|
||||||
|
buffer processor.
|
||||||
|
|
||||||
|
Platform Specific Options:
|
||||||
|
|
||||||
|
By using the flags in pa_mac_core.h, the user may specify several options.
|
||||||
|
For example, the user can specify the sample-rate conversion quality, and
|
||||||
|
the extent to which PA will attempt to "play nice" and to what extent it
|
||||||
|
will interrupt other apps to improve performance. For example, if 44100 Hz
|
||||||
|
sample rate is requested but the device is set at 48000 Hz, PA can either
|
||||||
|
change the device for optimal playback ("Pro" mode), which may interrupt
|
||||||
|
other programs playing back audio, or simple use a sample-rate coversion,
|
||||||
|
which allows for friendlier sharing of the device ("Play Nice" mode).
|
||||||
|
|
||||||
|
|
||||||
|
Known issues:
|
||||||
|
|
||||||
|
- Latency: Latency settings are ignored in most cases. Exceptions are when
|
||||||
|
doing I/O between different devices and as a hint for selecting a realtively
|
||||||
|
low or relatively high latency in conjunction with
|
||||||
|
paHostFramesPerBufferUnspecified. Latency settings are always automatically
|
||||||
|
bound to "safe" values, however, so setting extreme values here should not be
|
||||||
|
an issue.
|
||||||
|
|
||||||
|
- Buffer Size: paHostFramesPerBufferUnspecified and specific host buffer sizes
|
||||||
|
are supported. paHostFramesPerBufferUnspecified works best in "pro" mode,
|
||||||
|
where the buffer size and sample rate of the audio device is most likely
|
||||||
|
to match the expected values.
|
||||||
|
|
||||||
|
- Timing info. It reports on stream time, but I'm probably doing something
|
||||||
|
wrong since patest_sine_time often reports negative latency numbers.
|
||||||
|
|
||||||
|
- xrun detection: The only xrun detection performed is when reading
|
||||||
|
and writing the ring buffer. There is probably more that can be done.
|
||||||
|
|
||||||
|
- abort/stop issues: stopping a stream is always a complete operation,
|
||||||
|
but latency should be low enough to make the lack of a separate abort
|
||||||
|
unnecessary. Apple clarifies its AudioOutputUnitStop() call here:
|
||||||
|
http://lists.apple.com/archives/coreaudio-api/2005/Dec/msg00055.html
|
||||||
|
|
||||||
|
- blocking interface: Not implemented.
|
||||||
|
|
||||||
|
- multichannel: It has been tested successfully on multichannel hardware
|
||||||
|
from MOTU: traveler and 896HD.
|
||||||
|
|
||||||
|
- sample rate conversion quality: By default, SR conversion is the maximum
|
||||||
|
available. This can be tweaked using flags pa_mac_core.h. Note that the AU
|
||||||
|
render quyality property is used to set the sample rat conversion quality
|
||||||
|
as "documented" here:
|
||||||
|
http://lists.apple.com/archives/coreaudio-api/2004/Jan/msg00141.html
|
||||||
|
|
||||||
|
- x86: I haven't tested it on an x86 Mac myself, but users have reported
|
||||||
|
being able to comiple and run it.
|
2033
portaudio-v19/src/hostapi/coreaudio/pa_mac_core.c
Normal file
2033
portaudio-v19/src/hostapi/coreaudio/pa_mac_core.c
Normal file
File diff suppressed because it is too large
Load Diff
506
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.c
Normal file
506
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.c
Normal file
@ -0,0 +1,506 @@
|
|||||||
|
/* This file contains the implementation
|
||||||
|
* required for blocking I/O. It is separated from pa_mac_core.c simply to ease
|
||||||
|
* development. */
|
||||||
|
|
||||||
|
#include "pa_mac_core_blocking.h"
|
||||||
|
#include "pa_mac_core_internal.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#ifdef MOSX_USE_NON_ATOMIC_FLAG_BITS
|
||||||
|
# define OSAtomicOr32( a, b ) ( (*(b)) |= (a) )
|
||||||
|
# define OSAtomicAnd32( a, b ) ( (*(b)) &= (a) )
|
||||||
|
#else
|
||||||
|
# include <libkern/OSAtomic.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This fnuction determines the size of a particular sample format.
|
||||||
|
* if the format is not recognized, this returns zero.
|
||||||
|
*/
|
||||||
|
static size_t computeSampleSizeFromFormat( PaSampleFormat format )
|
||||||
|
{
|
||||||
|
switch( format ) {
|
||||||
|
case paFloat32: return 4;
|
||||||
|
case paInt32: return 4;
|
||||||
|
case paInt24: return 3;
|
||||||
|
case paInt16: return 2;
|
||||||
|
case paInt8: case paUInt8: return 1;
|
||||||
|
default: return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Functions for initializing, resetting, and destroying BLIO structures.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This should be called with the relevant info when initializing a stream for
|
||||||
|
callback. */
|
||||||
|
PaError initializeBlioRingBuffers(
|
||||||
|
PaMacBlio *blio,
|
||||||
|
PaSampleFormat inputSampleFormat,
|
||||||
|
PaSampleFormat outputSampleFormat,
|
||||||
|
size_t framesPerBuffer,
|
||||||
|
long ringBufferSize,
|
||||||
|
int inChan,
|
||||||
|
int outChan )
|
||||||
|
{
|
||||||
|
void *data;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
/* zeroify things */
|
||||||
|
bzero( blio, sizeof( PaMacBlio ) );
|
||||||
|
/* this is redundant, but the buffers are used to check
|
||||||
|
if the bufffers have been initialized, so we do it explicitly. */
|
||||||
|
blio->inputRingBuffer.buffer = NULL;
|
||||||
|
blio->outputRingBuffer.buffer = NULL;
|
||||||
|
|
||||||
|
/* initialize simple data */
|
||||||
|
blio->inputSampleFormat = inputSampleFormat;
|
||||||
|
blio->inputSampleSize = computeSampleSizeFromFormat(inputSampleFormat);
|
||||||
|
blio->outputSampleFormat = outputSampleFormat;
|
||||||
|
blio->outputSampleSize = computeSampleSizeFromFormat(outputSampleFormat);
|
||||||
|
blio->framesPerBuffer = framesPerBuffer;
|
||||||
|
blio->inChan = inChan;
|
||||||
|
blio->outChan = outChan;
|
||||||
|
blio->statusFlags = 0;
|
||||||
|
blio->errors = paNoError;
|
||||||
|
#ifdef PA_MAC_BLIO_MUTEX
|
||||||
|
blio->isInputEmpty = false;
|
||||||
|
blio->isOutputFull = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* setup ring buffers */
|
||||||
|
#ifdef PA_MAC_BLIO_MUTEX
|
||||||
|
result = PaMacCore_SetUnixError( pthread_mutex_init(&(blio->inputMutex),NULL), 0 );
|
||||||
|
if( result )
|
||||||
|
goto error;
|
||||||
|
result = UNIX_ERR( pthread_cond_init( &(blio->inputCond), NULL ) );
|
||||||
|
if( result )
|
||||||
|
goto error;
|
||||||
|
result = UNIX_ERR( pthread_mutex_init(&(blio->outputMutex),NULL) );
|
||||||
|
if( result )
|
||||||
|
goto error;
|
||||||
|
result = UNIX_ERR( pthread_cond_init( &(blio->outputCond), NULL ) );
|
||||||
|
#endif
|
||||||
|
if( inChan ) {
|
||||||
|
data = calloc( ringBufferSize, blio->inputSampleSize );
|
||||||
|
if( !data )
|
||||||
|
{
|
||||||
|
result = paInsufficientMemory;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( 0 == RingBuffer_Init(
|
||||||
|
&blio->inputRingBuffer,
|
||||||
|
ringBufferSize*blio->inputSampleSize,
|
||||||
|
data ) );
|
||||||
|
}
|
||||||
|
if( outChan ) {
|
||||||
|
data = calloc( ringBufferSize, blio->outputSampleSize );
|
||||||
|
if( !data )
|
||||||
|
{
|
||||||
|
result = paInsufficientMemory;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( 0 == RingBuffer_Init(
|
||||||
|
&blio->outputRingBuffer,
|
||||||
|
ringBufferSize*blio->outputSampleSize,
|
||||||
|
data ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
result = resetBlioRingBuffers( blio );
|
||||||
|
if( result )
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
destroyBlioRingBuffers( blio );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PA_MAC_BLIO_MUTEX
|
||||||
|
PaError blioSetIsInputEmpty( PaMacBlio *blio, bool isEmpty )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
if( isEmpty == blio->isInputEmpty )
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* we need to update the value. Here's what we do:
|
||||||
|
* - Lock the mutex, so noone else can write.
|
||||||
|
* - update the value.
|
||||||
|
* - unlock.
|
||||||
|
* - broadcast to all listeners.
|
||||||
|
*/
|
||||||
|
result = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) );
|
||||||
|
if( result )
|
||||||
|
goto done;
|
||||||
|
blio->isInputEmpty = isEmpty;
|
||||||
|
result = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) );
|
||||||
|
if( result )
|
||||||
|
goto done;
|
||||||
|
result = UNIX_ERR( pthread_cond_broadcast( &blio->inputCond ) );
|
||||||
|
if( result )
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
PaError blioSetIsOutputFull( PaMacBlio *blio, bool isFull )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
if( isFull == blio->isOutputFull )
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* we need to update the value. Here's what we do:
|
||||||
|
* - Lock the mutex, so noone else can write.
|
||||||
|
* - update the value.
|
||||||
|
* - unlock.
|
||||||
|
* - broadcast to all listeners.
|
||||||
|
*/
|
||||||
|
result = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) );
|
||||||
|
if( result )
|
||||||
|
goto done;
|
||||||
|
blio->isOutputFull = isFull;
|
||||||
|
result = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) );
|
||||||
|
if( result )
|
||||||
|
goto done;
|
||||||
|
result = UNIX_ERR( pthread_cond_broadcast( &blio->outputCond ) );
|
||||||
|
if( result )
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This should be called after stopping or aborting the stream, so that on next
|
||||||
|
start, the buffers will be ready. */
|
||||||
|
PaError resetBlioRingBuffers( PaMacBlio *blio )
|
||||||
|
{
|
||||||
|
#ifdef PA_MAC__BLIO_MUTEX
|
||||||
|
int result;
|
||||||
|
#endif
|
||||||
|
blio->statusFlags = 0;
|
||||||
|
if( blio->outputRingBuffer.buffer ) {
|
||||||
|
RingBuffer_Flush( &blio->outputRingBuffer );
|
||||||
|
bzero( blio->outputRingBuffer.buffer,
|
||||||
|
blio->outputRingBuffer.bufferSize );
|
||||||
|
/* Advance buffer */
|
||||||
|
RingBuffer_AdvanceWriteIndex( &blio->outputRingBuffer, blio->outputRingBuffer.bufferSize );
|
||||||
|
|
||||||
|
/* Update isOutputFull. */
|
||||||
|
#ifdef PA_MAC__BLIO_MUTEX
|
||||||
|
result = blioSetIsOutputFull( blio, toAdvance == blio->outputRingBuffer.bufferSize );
|
||||||
|
if( result )
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
printf( "------%d\n" , blio->framesPerBuffer );
|
||||||
|
printf( "------%d\n" , blio->outChan );
|
||||||
|
printf( "------%d\n" , blio->outputSampleSize );
|
||||||
|
printf( "------%d\n" , blio->framesPerBuffer*blio->outChan*blio->outputSampleSize );
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
if( blio->inputRingBuffer.buffer ) {
|
||||||
|
RingBuffer_Flush( &blio->inputRingBuffer );
|
||||||
|
bzero( blio->inputRingBuffer.buffer,
|
||||||
|
blio->inputRingBuffer.bufferSize );
|
||||||
|
/* Update isInputEmpty. */
|
||||||
|
#ifdef PA_MAC__BLIO_MUTEX
|
||||||
|
result = blioSetIsInputEmpty( blio, true );
|
||||||
|
if( result )
|
||||||
|
goto error;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return paNoError;
|
||||||
|
#ifdef PA_MAC__BLIO_MUTEX
|
||||||
|
error:
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*This should be called when you are done with the blio. It can safely be called
|
||||||
|
multiple times if there are no exceptions. */
|
||||||
|
PaError destroyBlioRingBuffers( PaMacBlio *blio )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
if( blio->inputRingBuffer.buffer ) {
|
||||||
|
free( blio->inputRingBuffer.buffer );
|
||||||
|
#ifdef PA_MAC__BLIO_MUTEX
|
||||||
|
result = UNIX_ERR( pthread_mutex_destroy( & blio->inputMutex ) );
|
||||||
|
if( result ) return result;
|
||||||
|
result = UNIX_ERR( pthread_cond_destroy( & blio->inputCond ) );
|
||||||
|
if( result ) return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
blio->inputRingBuffer.buffer = NULL;
|
||||||
|
if( blio->outputRingBuffer.buffer ) {
|
||||||
|
free( blio->outputRingBuffer.buffer );
|
||||||
|
#ifdef PA_MAC__BLIO_MUTEX
|
||||||
|
result = UNIX_ERR( pthread_mutex_destroy( & blio->outputMutex ) );
|
||||||
|
if( result ) return result;
|
||||||
|
result = UNIX_ERR( pthread_cond_destroy( & blio->outputCond ) );
|
||||||
|
if( result ) return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
blio->outputRingBuffer.buffer = NULL;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* this is the BlioCallback function. It expects to recieve a PaMacBlio Object
|
||||||
|
* pointer as userData.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int BlioCallback( const void *input, void *output, unsigned long frameCount,
|
||||||
|
const PaStreamCallbackTimeInfo* timeInfo,
|
||||||
|
PaStreamCallbackFlags statusFlags,
|
||||||
|
void *userData )
|
||||||
|
{
|
||||||
|
PaMacBlio *blio = (PaMacBlio*)userData;
|
||||||
|
long avail;
|
||||||
|
long toRead;
|
||||||
|
long toWrite;
|
||||||
|
|
||||||
|
/* set flags returned by OS: */
|
||||||
|
OSAtomicOr32( statusFlags, &blio->statusFlags ) ;
|
||||||
|
|
||||||
|
/* --- Handle Input Buffer --- */
|
||||||
|
if( blio->inChan ) {
|
||||||
|
avail = RingBuffer_GetWriteAvailable( &blio->inputRingBuffer );
|
||||||
|
|
||||||
|
/* check for underflow */
|
||||||
|
if( avail < frameCount * blio->inputSampleSize * blio->inChan )
|
||||||
|
OSAtomicOr32( paInputOverflow, &blio->statusFlags );
|
||||||
|
|
||||||
|
toRead = MIN( avail, frameCount * blio->inputSampleSize * blio->inChan );
|
||||||
|
|
||||||
|
/* copy the data */
|
||||||
|
/*printf( "reading %d\n", toRead );*/
|
||||||
|
assert( toRead == RingBuffer_Write( &blio->inputRingBuffer, input, toRead ) );
|
||||||
|
#ifdef PA_MAC__BLIO_MUTEX
|
||||||
|
/* Priority inversion. See notes below. */
|
||||||
|
blioSetIsInputEmpty( blio, false );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* --- Handle Output Buffer --- */
|
||||||
|
if( blio->outChan ) {
|
||||||
|
avail = RingBuffer_GetReadAvailable( &blio->outputRingBuffer );
|
||||||
|
|
||||||
|
/* check for underflow */
|
||||||
|
if( avail < frameCount * blio->outputSampleSize * blio->outChan )
|
||||||
|
OSAtomicOr32( paOutputUnderflow, &blio->statusFlags );
|
||||||
|
|
||||||
|
toWrite = MIN( avail, frameCount * blio->outputSampleSize * blio->outChan );
|
||||||
|
|
||||||
|
if( toWrite != frameCount * blio->outputSampleSize * blio->outChan )
|
||||||
|
bzero( ((char *)output)+toWrite,
|
||||||
|
frameCount * blio->outputSampleSize * blio->outChan - toWrite );
|
||||||
|
/* copy the data */
|
||||||
|
/*printf( "writing %d\n", toWrite );*/
|
||||||
|
assert( toWrite == RingBuffer_Read( &blio->outputRingBuffer, output, toWrite ) );
|
||||||
|
#ifdef PA_MAC__BLIO_MUTEX
|
||||||
|
/* We have a priority inversion here. However, we will only have to
|
||||||
|
wait if this was true and is now false, which means we've got
|
||||||
|
some room in the buffer.
|
||||||
|
Hopefully problems will be minimized. */
|
||||||
|
blioSetIsOutputFull( blio, false );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return paContinue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaError ReadStream( PaStream* stream,
|
||||||
|
void *buffer,
|
||||||
|
unsigned long frames )
|
||||||
|
{
|
||||||
|
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
|
||||||
|
char *cbuf = (char *) buffer;
|
||||||
|
PaError ret = paNoError;
|
||||||
|
VVDBUG(("ReadStream()\n"));
|
||||||
|
|
||||||
|
while( frames > 0 ) {
|
||||||
|
long avail;
|
||||||
|
long toRead;
|
||||||
|
do {
|
||||||
|
avail = RingBuffer_GetReadAvailable( &blio->inputRingBuffer );
|
||||||
|
/*
|
||||||
|
printf( "Read Buffer is %%%g full: %ld of %ld.\n",
|
||||||
|
100 * (float)avail / (float) blio->inputRingBuffer.bufferSize,
|
||||||
|
avail, blio->inputRingBuffer.bufferSize );
|
||||||
|
*/
|
||||||
|
if( avail == 0 ) {
|
||||||
|
#ifdef PA_MAC_BLIO_MUTEX
|
||||||
|
/**block when empty*/
|
||||||
|
ret = UNIX_ERR( pthread_mutex_lock( &blio->inputMutex ) );
|
||||||
|
if( ret )
|
||||||
|
return ret;
|
||||||
|
while( blio->isInputEmpty ) {
|
||||||
|
ret = UNIX_ERR( pthread_cond_wait( &blio->inputCond, &blio->inputMutex ) );
|
||||||
|
if( ret )
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = UNIX_ERR( pthread_mutex_unlock( &blio->inputMutex ) );
|
||||||
|
if( ret )
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} while( avail == 0 );
|
||||||
|
toRead = MIN( avail, frames * blio->inputSampleSize * blio->inChan );
|
||||||
|
toRead -= toRead % blio->inputSampleSize * blio->inChan ;
|
||||||
|
RingBuffer_Read( &blio->inputRingBuffer, (void *)cbuf, toRead );
|
||||||
|
cbuf += toRead;
|
||||||
|
frames -= toRead / ( blio->inputSampleSize * blio->inChan );
|
||||||
|
|
||||||
|
if( toRead == avail ) {
|
||||||
|
#ifdef PA_MAC_BLIO_MUTEX
|
||||||
|
/* we just emptied the buffer, so we need to mark it as empty. */
|
||||||
|
ret = blioSetIsInputEmpty( blio, true );
|
||||||
|
if( ret )
|
||||||
|
return ret;
|
||||||
|
/* of course, in the meantime, the callback may have put some sats
|
||||||
|
in, so
|
||||||
|
so check for that, too, to avoid a race condition. */
|
||||||
|
if( RingBuffer_GetReadAvailable( &blio->inputRingBuffer ) ) {
|
||||||
|
blioSetIsInputEmpty( blio, false );
|
||||||
|
if( ret )
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Report either paNoError or paInputOverflowed. */
|
||||||
|
/* may also want to report other errors, but this is non-standard. */
|
||||||
|
ret = blio->statusFlags & paInputOverflow;
|
||||||
|
|
||||||
|
/* report underflow only once: */
|
||||||
|
if( ret ) {
|
||||||
|
OSAtomicAnd32( ~paInputOverflow, &blio->statusFlags );
|
||||||
|
ret = paInputOverflowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PaError WriteStream( PaStream* stream,
|
||||||
|
const void *buffer,
|
||||||
|
unsigned long frames )
|
||||||
|
{
|
||||||
|
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
|
||||||
|
char *cbuf = (char *) buffer;
|
||||||
|
PaError ret = paNoError;
|
||||||
|
VVDBUG(("WriteStream()\n"));
|
||||||
|
|
||||||
|
while( frames > 0 ) {
|
||||||
|
long avail = 0;
|
||||||
|
long toWrite;
|
||||||
|
|
||||||
|
do {
|
||||||
|
avail = RingBuffer_GetWriteAvailable( &blio->outputRingBuffer );
|
||||||
|
/*
|
||||||
|
printf( "Write Buffer is %%%g full: %ld of %ld.\n",
|
||||||
|
100 - 100 * (float)avail / (float) blio->outputRingBuffer.bufferSize,
|
||||||
|
avail, blio->outputRingBuffer.bufferSize );
|
||||||
|
*/
|
||||||
|
if( avail == 0 ) {
|
||||||
|
#ifdef PA_MAC_BLIO_MUTEX
|
||||||
|
/*block while full*/
|
||||||
|
ret = UNIX_ERR( pthread_mutex_lock( &blio->outputMutex ) );
|
||||||
|
if( ret )
|
||||||
|
return ret;
|
||||||
|
while( blio->isOutputFull ) {
|
||||||
|
ret = UNIX_ERR( pthread_cond_wait( &blio->outputCond, &blio->outputMutex ) );
|
||||||
|
if( ret )
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = UNIX_ERR( pthread_mutex_unlock( &blio->outputMutex ) );
|
||||||
|
if( ret )
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
|
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} while( avail == 0 );
|
||||||
|
|
||||||
|
toWrite = MIN( avail, frames * blio->outputSampleSize * blio->outChan );
|
||||||
|
toWrite -= toWrite % blio->outputSampleSize * blio->outChan ;
|
||||||
|
RingBuffer_Write( &blio->outputRingBuffer, (void *)cbuf, toWrite );
|
||||||
|
cbuf += toWrite;
|
||||||
|
frames -= toWrite / ( blio->outputSampleSize * blio->outChan );
|
||||||
|
|
||||||
|
#ifdef PA_MAC_BLIO_MUTEX
|
||||||
|
if( toWrite == avail ) {
|
||||||
|
/* we just filled up the buffer, so we need to mark it as filled. */
|
||||||
|
ret = blioSetIsOutputFull( blio, true );
|
||||||
|
if( ret )
|
||||||
|
return ret;
|
||||||
|
/* of course, in the meantime, we may have emptied the buffer, so
|
||||||
|
so check for that, too, to avoid a race condition. */
|
||||||
|
if( RingBuffer_GetWriteAvailable( &blio->outputRingBuffer ) ) {
|
||||||
|
blioSetIsOutputFull( blio, false );
|
||||||
|
if( ret )
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Report either paNoError or paOutputUnderflowed. */
|
||||||
|
/* may also want to report other errors, but this is non-standard. */
|
||||||
|
ret = blio->statusFlags & paOutputUnderflow;
|
||||||
|
|
||||||
|
/* report underflow only once: */
|
||||||
|
if( ret ) {
|
||||||
|
OSAtomicAnd32( ~paOutputUnderflow, &blio->statusFlags );
|
||||||
|
ret = paOutputUnderflowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio )
|
||||||
|
{
|
||||||
|
if( blio->outputRingBuffer.buffer ) {
|
||||||
|
long avail = RingBuffer_GetWriteAvailable( &blio->outputRingBuffer );
|
||||||
|
while( avail != blio->outputRingBuffer.bufferSize ) {
|
||||||
|
if( avail == 0 )
|
||||||
|
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
|
||||||
|
avail = RingBuffer_GetWriteAvailable( &blio->outputRingBuffer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
signed long GetStreamReadAvailable( PaStream* stream )
|
||||||
|
{
|
||||||
|
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
|
||||||
|
VVDBUG(("GetStreamReadAvailable()\n"));
|
||||||
|
|
||||||
|
return RingBuffer_GetReadAvailable( &blio->inputRingBuffer )
|
||||||
|
/ ( blio->outputSampleSize * blio->outChan );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
signed long GetStreamWriteAvailable( PaStream* stream )
|
||||||
|
{
|
||||||
|
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
|
||||||
|
VVDBUG(("GetStreamWriteAvailable()\n"));
|
||||||
|
|
||||||
|
return RingBuffer_GetWriteAvailable( &blio->outputRingBuffer )
|
||||||
|
/ ( blio->outputSampleSize * blio->outChan );
|
||||||
|
}
|
||||||
|
|
76
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.h
Normal file
76
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_blocking.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
#ifndef PA_MAC_CORE_BLOCKING_H_
|
||||||
|
#define PA_MAC_CORE_BLOCKING_H_
|
||||||
|
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
#include "portaudio.h"
|
||||||
|
#include "pa_mac_core_utilities.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Number of miliseconds to busy wait whil waiting for data in blocking calls.
|
||||||
|
*/
|
||||||
|
#define PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL (5)
|
||||||
|
/*
|
||||||
|
* Define exactly one of these blocking methods
|
||||||
|
* PA_MAC_BLIO_MUTEX is not actively maintained.
|
||||||
|
*/
|
||||||
|
#define PA_MAC_BLIO_BUSY_WAIT
|
||||||
|
/*
|
||||||
|
#define PA_MAC_BLIO_MUTEX
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
RingBuffer inputRingBuffer;
|
||||||
|
RingBuffer outputRingBuffer;
|
||||||
|
PaSampleFormat inputSampleFormat;
|
||||||
|
size_t inputSampleSize;
|
||||||
|
PaSampleFormat outputSampleFormat;
|
||||||
|
size_t outputSampleSize;
|
||||||
|
|
||||||
|
size_t framesPerBuffer;
|
||||||
|
|
||||||
|
int inChan;
|
||||||
|
int outChan;
|
||||||
|
|
||||||
|
//PaStreamCallbackFlags statusFlags;
|
||||||
|
uint32_t statusFlags;
|
||||||
|
PaError errors;
|
||||||
|
|
||||||
|
/* Here we handle blocking, using condition variables. */
|
||||||
|
#ifdef PA_MAC_BLIO_MUTEX
|
||||||
|
volatile bool isInputEmpty;
|
||||||
|
pthread_mutex_t inputMutex;
|
||||||
|
pthread_cond_t inputCond;
|
||||||
|
|
||||||
|
volatile bool isOutputFull;
|
||||||
|
pthread_mutex_t outputMutex;
|
||||||
|
pthread_cond_t outputCond;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
PaMacBlio;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These functions operate on condition and related variables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PaError initializeBlioRingBuffers(
|
||||||
|
PaMacBlio *blio,
|
||||||
|
PaSampleFormat inputSampleFormat,
|
||||||
|
PaSampleFormat outputSampleFormat,
|
||||||
|
size_t framesPerBuffer,
|
||||||
|
long ringBufferSize,
|
||||||
|
int inChan,
|
||||||
|
int outChan );
|
||||||
|
PaError destroyBlioRingBuffers( PaMacBlio *blio );
|
||||||
|
PaError resetBlioRingBuffers( PaMacBlio *blio );
|
||||||
|
|
||||||
|
int BlioCallback(
|
||||||
|
const void *input, void *output,
|
||||||
|
unsigned long frameCount,
|
||||||
|
const PaStreamCallbackTimeInfo* timeInfo,
|
||||||
|
PaStreamCallbackFlags statusFlags,
|
||||||
|
void *userData );
|
||||||
|
|
||||||
|
void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio );
|
||||||
|
|
||||||
|
#endif /*PA_MAC_CORE_BLOCKING_H_*/
|
155
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_internal.h
Normal file
155
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_internal.h
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* This is the AUHAL implementation of portaudio.
|
||||||
|
*
|
||||||
|
* Written by Bjorn Roche of XO Audio LLC, from PA skeleton code.
|
||||||
|
* Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation)
|
||||||
|
*
|
||||||
|
* Dominic's code was based on code by Phil Burk, Darren Gibbs,
|
||||||
|
* Gord Peters, Stephane Letz, and Greg Pfiel.
|
||||||
|
*
|
||||||
|
* Bjorn Roche and XO Audio LLC reserve no rights to this code.
|
||||||
|
* The maintainers of PortAudio may redistribute and modify the code and
|
||||||
|
* licenses as they deam appropriate.
|
||||||
|
*
|
||||||
|
* The following people also deserve acknowledgements:
|
||||||
|
*
|
||||||
|
* Olivier Tristan for feedback and testing
|
||||||
|
* Glenn Zelniker and Z-Systems engineering for sponsoring the Blocking I/O
|
||||||
|
* 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 pa_mac_core
|
||||||
|
@author Bjorn Roche
|
||||||
|
@brief AUHAL implementation of PortAudio
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PA_MAC_CORE_INTERNAL_H__
|
||||||
|
#define PA_MAC_CORE_INTERNAL_H__
|
||||||
|
|
||||||
|
#include <AudioUnit/AudioUnit.h>
|
||||||
|
#include <AudioToolbox/AudioToolbox.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "portaudio.h"
|
||||||
|
#include "pa_util.h"
|
||||||
|
#include "pa_hostapi.h"
|
||||||
|
#include "pa_stream.h"
|
||||||
|
#include "pa_allocation.h"
|
||||||
|
#include "pa_cpuload.h"
|
||||||
|
#include "pa_process.h"
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
|
||||||
|
#include "pa_mac_core_blocking.h"
|
||||||
|
|
||||||
|
/* function prototypes */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#define RING_BUFFER_ADVANCE_DENOMINATOR (4)
|
||||||
|
|
||||||
|
PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
|
||||||
|
PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
|
||||||
|
signed long GetStreamReadAvailable( PaStream* stream );
|
||||||
|
signed long GetStreamWriteAvailable( PaStream* stream );
|
||||||
|
/* PaMacAUHAL - host api datastructure specific to this implementation */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
PaUtilHostApiRepresentation inheritedHostApiRep;
|
||||||
|
PaUtilStreamInterface callbackStreamInterface;
|
||||||
|
PaUtilStreamInterface blockingStreamInterface;
|
||||||
|
|
||||||
|
PaUtilAllocationGroup *allocations;
|
||||||
|
|
||||||
|
/* implementation specific data goes here */
|
||||||
|
long devCount;
|
||||||
|
AudioDeviceID *devIds; /*array of all audio devices*/
|
||||||
|
AudioDeviceID defaultIn;
|
||||||
|
AudioDeviceID defaultOut;
|
||||||
|
}
|
||||||
|
PaMacAUHAL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* stream data structure specifically for this implementation */
|
||||||
|
typedef struct PaMacCoreStream
|
||||||
|
{
|
||||||
|
PaUtilStreamRepresentation streamRepresentation;
|
||||||
|
PaUtilCpuLoadMeasurer cpuLoadMeasurer;
|
||||||
|
PaUtilBufferProcessor bufferProcessor;
|
||||||
|
|
||||||
|
/* implementation specific data goes here */
|
||||||
|
bool bufferProcessorIsInitialized;
|
||||||
|
AudioUnit inputUnit;
|
||||||
|
AudioUnit outputUnit;
|
||||||
|
AudioDeviceID inputDevice;
|
||||||
|
AudioDeviceID outputDevice;
|
||||||
|
size_t userInChan;
|
||||||
|
size_t userOutChan;
|
||||||
|
size_t inputFramesPerBuffer;
|
||||||
|
size_t outputFramesPerBuffer;
|
||||||
|
PaMacBlio blio;
|
||||||
|
/* We use this ring buffer when input and out devs are different. */
|
||||||
|
RingBuffer inputRingBuffer;
|
||||||
|
/* We may need to do SR conversion on input. */
|
||||||
|
AudioConverterRef inputSRConverter;
|
||||||
|
/* We need to preallocate an inputBuffer for reading data. */
|
||||||
|
AudioBufferList inputAudioBufferList;
|
||||||
|
AudioTimeStamp startTime;
|
||||||
|
volatile PaStreamCallbackFlags xrunFlags;
|
||||||
|
volatile bool isTimeSet;
|
||||||
|
volatile enum {
|
||||||
|
STOPPED = 0, /* playback is completely stopped,
|
||||||
|
and the user has called StopStream(). */
|
||||||
|
CALLBACK_STOPPED = 1, /* callback has requested stop,
|
||||||
|
but user has not yet called StopStream(). */
|
||||||
|
STOPPING = 2, /* The stream is in the process of closing.
|
||||||
|
This state is just used internally;
|
||||||
|
externally it is indistinguishable from
|
||||||
|
ACTIVE.*/
|
||||||
|
ACTIVE = 3 /* The stream is active and running. */
|
||||||
|
} state;
|
||||||
|
double sampleRate;
|
||||||
|
//these may be different from the stream sample rate due to SR conversion:
|
||||||
|
double outDeviceSampleRate;
|
||||||
|
double inDeviceSampleRate;
|
||||||
|
}
|
||||||
|
PaMacCoreStream;
|
||||||
|
|
||||||
|
#endif /* PA_MAC_CORE_INTERNAL_H__ */
|
907
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_old.c
Normal file
907
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_old.c
Normal file
@ -0,0 +1,907 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* pa_mac_core.c
|
||||||
|
* Implementation of PortAudio for Mac OS X CoreAudio
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <CoreAudio/CoreAudio.h>
|
||||||
|
#include <AudioToolbox/AudioToolbox.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
|
// ===== constants =====
|
||||||
|
|
||||||
|
// ===== structs =====
|
||||||
|
#pragma mark structs
|
||||||
|
|
||||||
|
// PaMacCoreHostApiRepresentation - host api datastructure specific to this implementation
|
||||||
|
typedef struct PaMacCore_HAR
|
||||||
|
{
|
||||||
|
PaUtilHostApiRepresentation inheritedHostApiRep;
|
||||||
|
PaUtilStreamInterface callbackStreamInterface;
|
||||||
|
PaUtilStreamInterface blockingStreamInterface;
|
||||||
|
|
||||||
|
PaUtilAllocationGroup *allocations;
|
||||||
|
AudioDeviceID *macCoreDeviceIds;
|
||||||
|
}
|
||||||
|
PaMacCoreHostApiRepresentation;
|
||||||
|
|
||||||
|
typedef struct PaMacCore_DI
|
||||||
|
{
|
||||||
|
PaDeviceInfo inheritedDeviceInfo;
|
||||||
|
}
|
||||||
|
PaMacCoreDeviceInfo;
|
||||||
|
|
||||||
|
// PaMacCoreStream - a stream data structure specifically for this implementation
|
||||||
|
typedef struct PaMacCore_S
|
||||||
|
{
|
||||||
|
PaUtilStreamRepresentation streamRepresentation;
|
||||||
|
PaUtilCpuLoadMeasurer cpuLoadMeasurer;
|
||||||
|
PaUtilBufferProcessor bufferProcessor;
|
||||||
|
|
||||||
|
int primeStreamUsingCallback;
|
||||||
|
|
||||||
|
AudioDeviceID inputDevice;
|
||||||
|
AudioDeviceID outputDevice;
|
||||||
|
|
||||||
|
// Processing thread management --------------
|
||||||
|
// HANDLE abortEvent;
|
||||||
|
// HANDLE processingThread;
|
||||||
|
// DWORD processingThreadId;
|
||||||
|
|
||||||
|
char throttleProcessingThreadOnOverload; // 0 -> don't throtte, non-0 -> throttle
|
||||||
|
int processingThreadPriority;
|
||||||
|
int highThreadPriority;
|
||||||
|
int throttledThreadPriority;
|
||||||
|
unsigned long throttledSleepMsecs;
|
||||||
|
|
||||||
|
int isStopped;
|
||||||
|
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
|
||||||
|
}
|
||||||
|
PaMacCoreStream;
|
||||||
|
|
||||||
|
// Data needed by the CoreAudio callback functions
|
||||||
|
typedef struct PaMacCore_CD
|
||||||
|
{
|
||||||
|
PaMacCoreStream *stream;
|
||||||
|
PaStreamCallback *callback;
|
||||||
|
void *userData;
|
||||||
|
PaUtilConverter *inputConverter;
|
||||||
|
PaUtilConverter *outputConverter;
|
||||||
|
void *inputBuffer;
|
||||||
|
void *outputBuffer;
|
||||||
|
int inputChannelCount;
|
||||||
|
int outputChannelCount;
|
||||||
|
PaSampleFormat inputSampleFormat;
|
||||||
|
PaSampleFormat outputSampleFormat;
|
||||||
|
PaUtilTriangularDitherGenerator *ditherGenerator;
|
||||||
|
}
|
||||||
|
PaMacClientData;
|
||||||
|
|
||||||
|
// ===== CoreAudio-PortAudio bridge functions =====
|
||||||
|
#pragma mark CoreAudio-PortAudio bridge functions
|
||||||
|
|
||||||
|
// Maps CoreAudio OSStatus codes to PortAudio PaError codes
|
||||||
|
static PaError conv_err(OSStatus error)
|
||||||
|
{
|
||||||
|
PaError result;
|
||||||
|
|
||||||
|
switch (error) {
|
||||||
|
case kAudioHardwareNoError:
|
||||||
|
result = paNoError; break;
|
||||||
|
case kAudioHardwareNotRunningError:
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioHardwareUnspecifiedError:
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioHardwareUnknownPropertyError:
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioHardwareBadPropertySizeError:
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioHardwareIllegalOperationError:
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioHardwareBadDeviceError:
|
||||||
|
result = paInvalidDevice; break;
|
||||||
|
case kAudioHardwareBadStreamError:
|
||||||
|
result = paBadStreamPtr; break;
|
||||||
|
case kAudioHardwareUnsupportedOperationError:
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioDeviceUnsupportedFormatError:
|
||||||
|
result = paSampleFormatNotSupported; break;
|
||||||
|
case kAudioDevicePermissionsError:
|
||||||
|
result = paDeviceUnavailable; break;
|
||||||
|
default:
|
||||||
|
result = paInternalError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is unused
|
||||||
|
static AudioStreamBasicDescription *InitializeStreamDescription(const PaStreamParameters *parameters, double sampleRate)
|
||||||
|
{
|
||||||
|
struct AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(sizeof(AudioStreamBasicDescription));
|
||||||
|
streamDescription->mSampleRate = sampleRate;
|
||||||
|
streamDescription->mFormatID = kAudioFormatLinearPCM;
|
||||||
|
streamDescription->mFormatFlags = 0;
|
||||||
|
streamDescription->mFramesPerPacket = 1;
|
||||||
|
|
||||||
|
if (parameters->sampleFormat & paNonInterleaved) {
|
||||||
|
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsNonInterleaved;
|
||||||
|
streamDescription->mChannelsPerFrame = 1;
|
||||||
|
streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat);
|
||||||
|
streamDescription->mBytesPerPacket = Pa_GetSampleSize(parameters->sampleFormat);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
streamDescription->mChannelsPerFrame = parameters->channelCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat) * streamDescription->mChannelsPerFrame;
|
||||||
|
streamDescription->mBytesPerPacket = streamDescription->mBytesPerFrame * streamDescription->mFramesPerPacket;
|
||||||
|
|
||||||
|
if (parameters->sampleFormat & paFloat32) {
|
||||||
|
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsFloat;
|
||||||
|
streamDescription->mBitsPerChannel = 32;
|
||||||
|
}
|
||||||
|
else if (parameters->sampleFormat & paInt32) {
|
||||||
|
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||||
|
streamDescription->mBitsPerChannel = 32;
|
||||||
|
}
|
||||||
|
else if (parameters->sampleFormat & paInt24) {
|
||||||
|
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||||
|
streamDescription->mBitsPerChannel = 24;
|
||||||
|
}
|
||||||
|
else if (parameters->sampleFormat & paInt16) {
|
||||||
|
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||||
|
streamDescription->mBitsPerChannel = 16;
|
||||||
|
}
|
||||||
|
else if (parameters->sampleFormat & paInt8) {
|
||||||
|
streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
||||||
|
streamDescription->mBitsPerChannel = 8;
|
||||||
|
}
|
||||||
|
else if (parameters->sampleFormat & paInt32) {
|
||||||
|
streamDescription->mBitsPerChannel = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return streamDescription;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static PaStreamCallbackTimeInfo *InitializeTimeInfo(const AudioTimeStamp* now, const AudioTimeStamp* inputTime, const AudioTimeStamp* outputTime)
|
||||||
|
{
|
||||||
|
PaStreamCallbackTimeInfo *timeInfo = PaUtil_AllocateMemory(sizeof(PaStreamCallbackTimeInfo));
|
||||||
|
|
||||||
|
timeInfo->inputBufferAdcTime = inputTime->mSampleTime;
|
||||||
|
timeInfo->currentTime = now->mSampleTime;
|
||||||
|
timeInfo->outputBufferDacTime = outputTime->mSampleTime;
|
||||||
|
|
||||||
|
return timeInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== support functions =====
|
||||||
|
#pragma mark support functions
|
||||||
|
|
||||||
|
static void CleanUp(PaMacCoreHostApiRepresentation *macCoreHostApi)
|
||||||
|
{
|
||||||
|
if( macCoreHostApi->allocations )
|
||||||
|
{
|
||||||
|
PaUtil_FreeAllAllocations( macCoreHostApi->allocations );
|
||||||
|
PaUtil_DestroyAllocationGroup( macCoreHostApi->allocations );
|
||||||
|
}
|
||||||
|
|
||||||
|
PaUtil_FreeMemory( macCoreHostApi );
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError GetChannelInfo(PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput)
|
||||||
|
{
|
||||||
|
UInt32 propSize;
|
||||||
|
PaError err = paNoError;
|
||||||
|
UInt32 i;
|
||||||
|
int numChannels = 0;
|
||||||
|
AudioBufferList *buflist;
|
||||||
|
|
||||||
|
err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL));
|
||||||
|
buflist = PaUtil_AllocateMemory(propSize);
|
||||||
|
err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist));
|
||||||
|
if (!err) {
|
||||||
|
for (i = 0; i < buflist->mNumberBuffers; ++i) {
|
||||||
|
numChannels += buflist->mBuffers[i].mNumberChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isInput)
|
||||||
|
deviceInfo->maxInputChannels = numChannels;
|
||||||
|
else
|
||||||
|
deviceInfo->maxOutputChannels = numChannels;
|
||||||
|
|
||||||
|
int frameLatency;
|
||||||
|
propSize = sizeof(UInt32);
|
||||||
|
err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency));
|
||||||
|
if (!err) {
|
||||||
|
double secondLatency = frameLatency / deviceInfo->defaultSampleRate;
|
||||||
|
if (isInput) {
|
||||||
|
deviceInfo->defaultLowInputLatency = secondLatency;
|
||||||
|
deviceInfo->defaultHighInputLatency = secondLatency;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
deviceInfo->defaultLowOutputLatency = secondLatency;
|
||||||
|
deviceInfo->defaultHighOutputLatency = secondLatency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PaUtil_FreeMemory(buflist);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError InitializeDeviceInfo(PaMacCoreDeviceInfo *macCoreDeviceInfo, AudioDeviceID macCoreDeviceId, PaHostApiIndex hostApiIndex )
|
||||||
|
{
|
||||||
|
PaDeviceInfo *deviceInfo = &macCoreDeviceInfo->inheritedDeviceInfo;
|
||||||
|
deviceInfo->structVersion = 2;
|
||||||
|
deviceInfo->hostApi = hostApiIndex;
|
||||||
|
|
||||||
|
PaError err = paNoError;
|
||||||
|
UInt32 propSize;
|
||||||
|
|
||||||
|
err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL));
|
||||||
|
// FIXME: this allocation should be part of the allocations group
|
||||||
|
char *name = PaUtil_AllocateMemory(propSize);
|
||||||
|
err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name));
|
||||||
|
if (!err) {
|
||||||
|
deviceInfo->name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Float64 sampleRate;
|
||||||
|
propSize = sizeof(Float64);
|
||||||
|
err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate));
|
||||||
|
if (!err) {
|
||||||
|
deviceInfo->defaultSampleRate = sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get channel info
|
||||||
|
err = GetChannelInfo(deviceInfo, macCoreDeviceId, 1);
|
||||||
|
err = GetChannelInfo(deviceInfo, macCoreDeviceId, 0);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError InitializeDeviceInfos( PaMacCoreHostApiRepresentation *macCoreHostApi, PaHostApiIndex hostApiIndex )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
PaUtilHostApiRepresentation *hostApi;
|
||||||
|
PaMacCoreDeviceInfo *deviceInfoArray;
|
||||||
|
|
||||||
|
// 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 = &macCoreHostApi->inheritedHostApiRep;
|
||||||
|
hostApi->info.deviceCount = 0;
|
||||||
|
hostApi->info.defaultInputDevice = paNoDevice;
|
||||||
|
hostApi->info.defaultOutputDevice = paNoDevice;
|
||||||
|
|
||||||
|
UInt32 propsize;
|
||||||
|
AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propsize, NULL);
|
||||||
|
int numDevices = propsize / sizeof(AudioDeviceID);
|
||||||
|
hostApi->info.deviceCount = numDevices;
|
||||||
|
if (numDevices > 0) {
|
||||||
|
hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
|
||||||
|
macCoreHostApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
|
||||||
|
if( !hostApi->deviceInfos )
|
||||||
|
{
|
||||||
|
return paInsufficientMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate all device info structs in a contiguous block
|
||||||
|
deviceInfoArray = (PaMacCoreDeviceInfo*)PaUtil_GroupAllocateMemory(
|
||||||
|
macCoreHostApi->allocations, sizeof(PaMacCoreDeviceInfo) * numDevices );
|
||||||
|
if( !deviceInfoArray )
|
||||||
|
{
|
||||||
|
return paInsufficientMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
macCoreHostApi->macCoreDeviceIds = PaUtil_GroupAllocateMemory(macCoreHostApi->allocations, propsize);
|
||||||
|
AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propsize, macCoreHostApi->macCoreDeviceIds);
|
||||||
|
|
||||||
|
AudioDeviceID defaultInputDevice, defaultOutputDevice;
|
||||||
|
propsize = sizeof(AudioDeviceID);
|
||||||
|
AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propsize, &defaultInputDevice);
|
||||||
|
AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propsize, &defaultOutputDevice);
|
||||||
|
|
||||||
|
UInt32 i;
|
||||||
|
for (i = 0; i < numDevices; ++i) {
|
||||||
|
if (macCoreHostApi->macCoreDeviceIds[i] == defaultInputDevice) {
|
||||||
|
hostApi->info.defaultInputDevice = i;
|
||||||
|
}
|
||||||
|
if (macCoreHostApi->macCoreDeviceIds[i] == defaultOutputDevice) {
|
||||||
|
hostApi->info.defaultOutputDevice = i;
|
||||||
|
}
|
||||||
|
InitializeDeviceInfo(&deviceInfoArray[i], macCoreHostApi->macCoreDeviceIds[i], hostApiIndex);
|
||||||
|
hostApi->deviceInfos[i] = &(deviceInfoArray[i].inheritedDeviceInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSStatus CheckFormat(AudioDeviceID macCoreDeviceId, const PaStreamParameters *parameters, double sampleRate, int isInput)
|
||||||
|
{
|
||||||
|
UInt32 propSize = sizeof(AudioStreamBasicDescription);
|
||||||
|
AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(propSize);
|
||||||
|
|
||||||
|
streamDescription->mSampleRate = sampleRate;
|
||||||
|
streamDescription->mFormatID = 0;
|
||||||
|
streamDescription->mFormatFlags = 0;
|
||||||
|
streamDescription->mBytesPerPacket = 0;
|
||||||
|
streamDescription->mFramesPerPacket = 0;
|
||||||
|
streamDescription->mBytesPerFrame = 0;
|
||||||
|
streamDescription->mChannelsPerFrame = 0;
|
||||||
|
streamDescription->mBitsPerChannel = 0;
|
||||||
|
streamDescription->mReserved = 0;
|
||||||
|
|
||||||
|
OSStatus result = AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &propSize, streamDescription);
|
||||||
|
PaUtil_FreeMemory(streamDescription);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSStatus CopyInputData(PaMacClientData* destination, const AudioBufferList *source, unsigned long frameCount)
|
||||||
|
{
|
||||||
|
int frameSpacing, channelSpacing;
|
||||||
|
if (destination->inputSampleFormat & paNonInterleaved) {
|
||||||
|
frameSpacing = 1;
|
||||||
|
channelSpacing = destination->inputChannelCount;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frameSpacing = destination->inputChannelCount;
|
||||||
|
channelSpacing = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioBuffer const *inputBuffer = &source->mBuffers[0];
|
||||||
|
void *coreAudioBuffer = inputBuffer->mData;
|
||||||
|
void *portAudioBuffer = destination->inputBuffer;
|
||||||
|
UInt32 i, streamNumber, streamChannel;
|
||||||
|
for (i = streamNumber = streamChannel = 0; i < destination->inputChannelCount; ++i, ++streamChannel) {
|
||||||
|
if (streamChannel >= inputBuffer->mNumberChannels) {
|
||||||
|
++streamNumber;
|
||||||
|
inputBuffer = &source->mBuffers[streamNumber];
|
||||||
|
coreAudioBuffer = inputBuffer->mData;
|
||||||
|
streamChannel = 0;
|
||||||
|
}
|
||||||
|
destination->inputConverter(portAudioBuffer, frameSpacing, coreAudioBuffer, inputBuffer->mNumberChannels, frameCount, destination->ditherGenerator);
|
||||||
|
coreAudioBuffer += sizeof(Float32);
|
||||||
|
portAudioBuffer += Pa_GetSampleSize(destination->inputSampleFormat) * channelSpacing;
|
||||||
|
}
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSStatus CopyOutputData(AudioBufferList* destination, PaMacClientData *source, unsigned long frameCount)
|
||||||
|
{
|
||||||
|
int frameSpacing, channelSpacing;
|
||||||
|
if (source->outputSampleFormat & paNonInterleaved) {
|
||||||
|
frameSpacing = 1;
|
||||||
|
channelSpacing = source->outputChannelCount;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
frameSpacing = source->outputChannelCount;
|
||||||
|
channelSpacing = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioBuffer *outputBuffer = &destination->mBuffers[0];
|
||||||
|
void *coreAudioBuffer = outputBuffer->mData;
|
||||||
|
void *portAudioBuffer = source->outputBuffer;
|
||||||
|
UInt32 i, streamNumber, streamChannel;
|
||||||
|
for (i = streamNumber = streamChannel = 0; i < source->outputChannelCount; ++i, ++streamChannel) {
|
||||||
|
if (streamChannel >= outputBuffer->mNumberChannels) {
|
||||||
|
++streamNumber;
|
||||||
|
outputBuffer = &destination->mBuffers[streamNumber];
|
||||||
|
coreAudioBuffer = outputBuffer->mData;
|
||||||
|
streamChannel = 0;
|
||||||
|
}
|
||||||
|
source->outputConverter(coreAudioBuffer, outputBuffer->mNumberChannels, portAudioBuffer, frameSpacing, frameCount, NULL);
|
||||||
|
coreAudioBuffer += sizeof(Float32);
|
||||||
|
portAudioBuffer += Pa_GetSampleSize(source->outputSampleFormat) * channelSpacing;
|
||||||
|
}
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSStatus AudioIOProc( AudioDeviceID inDevice,
|
||||||
|
const AudioTimeStamp* inNow,
|
||||||
|
const AudioBufferList* inInputData,
|
||||||
|
const AudioTimeStamp* inInputTime,
|
||||||
|
AudioBufferList* outOutputData,
|
||||||
|
const AudioTimeStamp* inOutputTime,
|
||||||
|
void* inClientData)
|
||||||
|
{
|
||||||
|
PaMacClientData *clientData = (PaMacClientData *)inClientData;
|
||||||
|
PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
|
||||||
|
|
||||||
|
PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
|
||||||
|
|
||||||
|
AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
|
||||||
|
unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
|
||||||
|
|
||||||
|
if (clientData->inputBuffer) {
|
||||||
|
CopyInputData(clientData, inInputData, frameCount);
|
||||||
|
}
|
||||||
|
PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
|
||||||
|
if (clientData->outputBuffer) {
|
||||||
|
CopyOutputData(outOutputData, clientData, frameCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
|
||||||
|
|
||||||
|
if (result == paComplete || result == paAbort) {
|
||||||
|
Pa_StopStream(clientData->stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
PaUtil_FreeMemory( timeInfo );
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not for input-only streams, this is for streams where the input device is different from the output device
|
||||||
|
static OSStatus AudioInputProc( AudioDeviceID inDevice,
|
||||||
|
const AudioTimeStamp* inNow,
|
||||||
|
const AudioBufferList* inInputData,
|
||||||
|
const AudioTimeStamp* inInputTime,
|
||||||
|
AudioBufferList* outOutputData,
|
||||||
|
const AudioTimeStamp* inOutputTime,
|
||||||
|
void* inClientData)
|
||||||
|
{
|
||||||
|
PaMacClientData *clientData = (PaMacClientData *)inClientData;
|
||||||
|
PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
|
||||||
|
|
||||||
|
PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
|
||||||
|
|
||||||
|
AudioBuffer const *inputBuffer = &inInputData->mBuffers[0];
|
||||||
|
unsigned long frameCount = inputBuffer->mDataByteSize / (inputBuffer->mNumberChannels * sizeof(Float32));
|
||||||
|
|
||||||
|
CopyInputData(clientData, inInputData, frameCount);
|
||||||
|
PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
|
||||||
|
|
||||||
|
PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
|
||||||
|
if( result == paComplete || result == paAbort )
|
||||||
|
Pa_StopStream(clientData->stream);
|
||||||
|
PaUtil_FreeMemory( timeInfo );
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is not for output-only streams, this is for streams where the input device is different from the output device
|
||||||
|
static OSStatus AudioOutputProc( AudioDeviceID inDevice,
|
||||||
|
const AudioTimeStamp* inNow,
|
||||||
|
const AudioBufferList* inInputData,
|
||||||
|
const AudioTimeStamp* inInputTime,
|
||||||
|
AudioBufferList* outOutputData,
|
||||||
|
const AudioTimeStamp* inOutputTime,
|
||||||
|
void* inClientData)
|
||||||
|
{
|
||||||
|
PaMacClientData *clientData = (PaMacClientData *)inClientData;
|
||||||
|
//PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
|
||||||
|
|
||||||
|
PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
|
||||||
|
|
||||||
|
AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
|
||||||
|
unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
|
||||||
|
|
||||||
|
//clientData->callback(NULL, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
|
||||||
|
|
||||||
|
CopyOutputData(outOutputData, clientData, frameCount);
|
||||||
|
|
||||||
|
PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError SetSampleRate(AudioDeviceID device, double sampleRate, int isInput)
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
|
||||||
|
double actualSampleRate;
|
||||||
|
UInt32 propSize = sizeof(double);
|
||||||
|
result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyNominalSampleRate, propSize, &sampleRate));
|
||||||
|
|
||||||
|
result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSampleRate));
|
||||||
|
|
||||||
|
if (result == paNoError && actualSampleRate != sampleRate) {
|
||||||
|
result = paInvalidSampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError SetFramesPerBuffer(AudioDeviceID device, unsigned long framesPerBuffer, int isInput)
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
UInt32 preferredFramesPerBuffer = framesPerBuffer;
|
||||||
|
// while (preferredFramesPerBuffer > UINT32_MAX) {
|
||||||
|
// preferredFramesPerBuffer /= 2;
|
||||||
|
// }
|
||||||
|
|
||||||
|
UInt32 actualFramesPerBuffer;
|
||||||
|
UInt32 propSize = sizeof(UInt32);
|
||||||
|
result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propSize, &preferredFramesPerBuffer));
|
||||||
|
|
||||||
|
result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &actualFramesPerBuffer));
|
||||||
|
|
||||||
|
if (result != paNoError) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
else if (actualFramesPerBuffer > framesPerBuffer) {
|
||||||
|
result = paBufferTooSmall;
|
||||||
|
}
|
||||||
|
else if (actualFramesPerBuffer < framesPerBuffer) {
|
||||||
|
result = paBufferTooBig;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError SetUpUnidirectionalStream(AudioDeviceID device, double sampleRate, unsigned long framesPerBuffer, int isInput)
|
||||||
|
{
|
||||||
|
PaError err = paNoError;
|
||||||
|
err = SetSampleRate(device, sampleRate, isInput);
|
||||||
|
if( err == paNoError )
|
||||||
|
err = SetFramesPerBuffer(device, framesPerBuffer, isInput);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== PortAudio functions =====
|
||||||
|
#pragma mark PortAudio functions
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
|
||||||
|
{
|
||||||
|
PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
|
||||||
|
|
||||||
|
CleanUp(macCoreHostApi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
|
||||||
|
const PaStreamParameters *inputParameters,
|
||||||
|
const PaStreamParameters *outputParameters,
|
||||||
|
double sampleRate )
|
||||||
|
{
|
||||||
|
PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
|
||||||
|
PaDeviceInfo *deviceInfo;
|
||||||
|
|
||||||
|
PaError result = paNoError;
|
||||||
|
if (inputParameters) {
|
||||||
|
deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
|
||||||
|
if (inputParameters->channelCount > deviceInfo->maxInputChannels)
|
||||||
|
result = paInvalidChannelCount;
|
||||||
|
else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[inputParameters->device], inputParameters, sampleRate, 1) != kAudioHardwareNoError) {
|
||||||
|
result = paInvalidSampleRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (outputParameters && result == paNoError) {
|
||||||
|
deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
|
||||||
|
if (outputParameters->channelCount > deviceInfo->maxOutputChannels)
|
||||||
|
result = paInvalidChannelCount;
|
||||||
|
else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[outputParameters->device], outputParameters, sampleRate, 0) != kAudioHardwareNoError) {
|
||||||
|
result = paInvalidSampleRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 err = paNoError;
|
||||||
|
PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)hostApi;
|
||||||
|
PaMacCoreStream *stream = PaUtil_AllocateMemory(sizeof(PaMacCoreStream));
|
||||||
|
stream->isActive = 0;
|
||||||
|
stream->isStopped = 1;
|
||||||
|
stream->inputDevice = kAudioDeviceUnknown;
|
||||||
|
stream->outputDevice = kAudioDeviceUnknown;
|
||||||
|
|
||||||
|
PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
|
||||||
|
( (streamCallback)
|
||||||
|
? &macCoreHostApi->callbackStreamInterface
|
||||||
|
: &macCoreHostApi->blockingStreamInterface ),
|
||||||
|
streamCallback, userData );
|
||||||
|
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
|
||||||
|
|
||||||
|
*s = (PaStream*)stream;
|
||||||
|
PaMacClientData *clientData = PaUtil_AllocateMemory(sizeof(PaMacClientData));
|
||||||
|
clientData->stream = stream;
|
||||||
|
clientData->callback = streamCallback;
|
||||||
|
clientData->userData = userData;
|
||||||
|
clientData->inputBuffer = 0;
|
||||||
|
clientData->outputBuffer = 0;
|
||||||
|
clientData->ditherGenerator = PaUtil_AllocateMemory(sizeof(PaUtilTriangularDitherGenerator));
|
||||||
|
PaUtil_InitializeTriangularDitherState(clientData->ditherGenerator);
|
||||||
|
|
||||||
|
if (inputParameters != NULL) {
|
||||||
|
stream->inputDevice = macCoreHostApi->macCoreDeviceIds[inputParameters->device];
|
||||||
|
clientData->inputConverter = PaUtil_SelectConverter(paFloat32, inputParameters->sampleFormat, streamFlags);
|
||||||
|
clientData->inputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(inputParameters->sampleFormat) * framesPerBuffer * inputParameters->channelCount);
|
||||||
|
clientData->inputChannelCount = inputParameters->channelCount;
|
||||||
|
clientData->inputSampleFormat = inputParameters->sampleFormat;
|
||||||
|
err = SetUpUnidirectionalStream(stream->inputDevice, sampleRate, framesPerBuffer, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == paNoError && outputParameters != NULL) {
|
||||||
|
stream->outputDevice = macCoreHostApi->macCoreDeviceIds[outputParameters->device];
|
||||||
|
clientData->outputConverter = PaUtil_SelectConverter(outputParameters->sampleFormat, paFloat32, streamFlags);
|
||||||
|
clientData->outputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(outputParameters->sampleFormat) * framesPerBuffer * outputParameters->channelCount);
|
||||||
|
clientData->outputChannelCount = outputParameters->channelCount;
|
||||||
|
clientData->outputSampleFormat = outputParameters->sampleFormat;
|
||||||
|
err = SetUpUnidirectionalStream(stream->outputDevice, sampleRate, framesPerBuffer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputParameters == NULL || outputParameters == NULL || stream->inputDevice == stream->outputDevice) {
|
||||||
|
AudioDeviceID device = (inputParameters == NULL) ? stream->outputDevice : stream->inputDevice;
|
||||||
|
|
||||||
|
AudioDeviceAddIOProc(device, AudioIOProc, clientData);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// using different devices for input and output
|
||||||
|
AudioDeviceAddIOProc(stream->inputDevice, AudioInputProc, clientData);
|
||||||
|
AudioDeviceAddIOProc(stream->outputDevice, AudioOutputProc, clientData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted.
|
||||||
|
static PaError CloseStream( PaStream* s )
|
||||||
|
{
|
||||||
|
PaError err = paNoError;
|
||||||
|
PaMacCoreStream *stream = (PaMacCoreStream*)s;
|
||||||
|
|
||||||
|
PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
|
||||||
|
|
||||||
|
if (stream->inputDevice != kAudioDeviceUnknown) {
|
||||||
|
if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
|
||||||
|
err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioIOProc));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioInputProc));
|
||||||
|
err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioOutputProc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioIOProc));
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PaError StartStream( PaStream *s )
|
||||||
|
{
|
||||||
|
PaError err = paNoError;
|
||||||
|
PaMacCoreStream *stream = (PaMacCoreStream*)s;
|
||||||
|
|
||||||
|
if (stream->inputDevice != kAudioDeviceUnknown) {
|
||||||
|
if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
|
||||||
|
err = conv_err(AudioDeviceStart(stream->inputDevice, AudioIOProc));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
err = conv_err(AudioDeviceStart(stream->inputDevice, AudioInputProc));
|
||||||
|
err = conv_err(AudioDeviceStart(stream->outputDevice, AudioOutputProc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
err = conv_err(AudioDeviceStart(stream->outputDevice, AudioIOProc));
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->isActive = 1;
|
||||||
|
stream->isStopped = 0;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError AbortStream( PaStream *s )
|
||||||
|
{
|
||||||
|
PaError err = paNoError;
|
||||||
|
PaMacCoreStream *stream = (PaMacCoreStream*)s;
|
||||||
|
|
||||||
|
if (stream->inputDevice != kAudioDeviceUnknown) {
|
||||||
|
if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
|
||||||
|
err = conv_err(AudioDeviceStop(stream->inputDevice, AudioIOProc));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
err = conv_err(AudioDeviceStop(stream->inputDevice, AudioInputProc));
|
||||||
|
err = conv_err(AudioDeviceStop(stream->outputDevice, AudioOutputProc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
err = conv_err(AudioDeviceStop(stream->outputDevice, AudioIOProc));
|
||||||
|
}
|
||||||
|
|
||||||
|
stream->isActive = 0;
|
||||||
|
stream->isStopped = 1;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError StopStream( PaStream *s )
|
||||||
|
{
|
||||||
|
// TODO: this should be nicer than abort
|
||||||
|
return AbortStream(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError IsStreamStopped( PaStream *s )
|
||||||
|
{
|
||||||
|
PaMacCoreStream *stream = (PaMacCoreStream*)s;
|
||||||
|
|
||||||
|
return stream->isStopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PaError IsStreamActive( PaStream *s )
|
||||||
|
{
|
||||||
|
PaMacCoreStream *stream = (PaMacCoreStream*)s;
|
||||||
|
|
||||||
|
return stream->isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PaTime GetStreamTime( PaStream *s )
|
||||||
|
{
|
||||||
|
OSStatus err;
|
||||||
|
PaTime result;
|
||||||
|
PaMacCoreStream *stream = (PaMacCoreStream*)s;
|
||||||
|
|
||||||
|
AudioTimeStamp *timeStamp = PaUtil_AllocateMemory(sizeof(AudioTimeStamp));
|
||||||
|
if (stream->inputDevice != kAudioDeviceUnknown) {
|
||||||
|
err = AudioDeviceGetCurrentTime(stream->inputDevice, timeStamp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
err = AudioDeviceGetCurrentTime(stream->outputDevice, timeStamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = err ? 0 : timeStamp->mSampleTime;
|
||||||
|
PaUtil_FreeMemory(timeStamp);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static double GetStreamCpuLoad( PaStream* s )
|
||||||
|
{
|
||||||
|
PaMacCoreStream *stream = (PaMacCoreStream*)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 )
|
||||||
|
{
|
||||||
|
return paInternalError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PaError WriteStream( PaStream* s,
|
||||||
|
const void *buffer,
|
||||||
|
unsigned long frames )
|
||||||
|
{
|
||||||
|
return paInternalError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static signed long GetStreamReadAvailable( PaStream* s )
|
||||||
|
{
|
||||||
|
return paInternalError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static signed long GetStreamWriteAvailable( PaStream* s )
|
||||||
|
{
|
||||||
|
return paInternalError;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HostAPI-specific initialization function
|
||||||
|
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaMacCoreHostApiRepresentation) );
|
||||||
|
if( !macCoreHostApi )
|
||||||
|
{
|
||||||
|
result = paInsufficientMemory;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
macCoreHostApi->allocations = PaUtil_CreateAllocationGroup();
|
||||||
|
if( !macCoreHostApi->allocations )
|
||||||
|
{
|
||||||
|
result = paInsufficientMemory;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
*hostApi = &macCoreHostApi->inheritedHostApiRep;
|
||||||
|
(*hostApi)->info.structVersion = 1;
|
||||||
|
(*hostApi)->info.type = paCoreAudio;
|
||||||
|
(*hostApi)->info.name = "CoreAudio";
|
||||||
|
|
||||||
|
result = InitializeDeviceInfos(macCoreHostApi, hostApiIndex);
|
||||||
|
if (result != paNoError) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the proper callbacks to this HostApi's functions
|
||||||
|
(*hostApi)->Terminate = Terminate;
|
||||||
|
(*hostApi)->OpenStream = OpenStream;
|
||||||
|
(*hostApi)->IsFormatSupported = IsFormatSupported;
|
||||||
|
|
||||||
|
PaUtil_InitializeStreamInterface( &macCoreHostApi->callbackStreamInterface, CloseStream, StartStream,
|
||||||
|
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
||||||
|
GetStreamTime, GetStreamCpuLoad,
|
||||||
|
PaUtil_DummyRead, PaUtil_DummyWrite,
|
||||||
|
PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
|
||||||
|
|
||||||
|
PaUtil_InitializeStreamInterface( &macCoreHostApi->blockingStreamInterface, CloseStream, StartStream,
|
||||||
|
StopStream, AbortStream, IsStreamStopped, IsStreamActive,
|
||||||
|
GetStreamTime, PaUtil_DummyGetCpuLoad,
|
||||||
|
ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if( macCoreHostApi ) {
|
||||||
|
CleanUp(macCoreHostApi);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
565
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_utilities.c
Normal file
565
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_utilities.c
Normal file
@ -0,0 +1,565 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* pa_mac_core_utilities.c
|
||||||
|
*
|
||||||
|
* utilitiy functions for pa_mac_core.c
|
||||||
|
*
|
||||||
|
* This functions are more like helper functions than part of the core,
|
||||||
|
* so I moved them to a separate file so the core code would be cleaner.
|
||||||
|
*
|
||||||
|
* by Bjorn Roche.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pa_mac_core_utilities.h"
|
||||||
|
|
||||||
|
PaError PaMacCore_SetUnixError( int err, int line )
|
||||||
|
{
|
||||||
|
PaError ret;
|
||||||
|
const char *errorText;
|
||||||
|
|
||||||
|
if( err == 0 )
|
||||||
|
{
|
||||||
|
return paNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = paNoError;
|
||||||
|
errorText = strerror( err );
|
||||||
|
|
||||||
|
/** Map Unix error to PaError. Pretty much the only one that maps
|
||||||
|
is ENOMEM. */
|
||||||
|
if( err == ENOMEM )
|
||||||
|
ret = paInsufficientMemory;
|
||||||
|
else
|
||||||
|
ret = paInternalError;
|
||||||
|
|
||||||
|
DBUG(("%d on line %d: msg='%s'\n", err, line, errorText));
|
||||||
|
PaUtil_SetLastHostErrorInfo( paCoreAudio, err, errorText );
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translates MacOS generated errors into PaErrors
|
||||||
|
*/
|
||||||
|
PaError PaMacCore_SetError(OSStatus error, int line, int isError)
|
||||||
|
{
|
||||||
|
/*FIXME: still need to handle possible ComponentResult values.*/
|
||||||
|
/* unfortunately, they don't seem to be documented anywhere.*/
|
||||||
|
PaError result;
|
||||||
|
const char *errorType;
|
||||||
|
const char *errorText;
|
||||||
|
|
||||||
|
switch (error) {
|
||||||
|
case kAudioHardwareNoError:
|
||||||
|
return paNoError;
|
||||||
|
case kAudioHardwareNotRunningError:
|
||||||
|
errorText = "Audio Hardware Not Running";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioHardwareUnspecifiedError:
|
||||||
|
errorText = "Unspecified Audio Hardware Error";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioHardwareUnknownPropertyError:
|
||||||
|
errorText = "Audio Hardware: Unknown Property";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioHardwareBadPropertySizeError:
|
||||||
|
errorText = "Audio Hardware: Bad Property Size";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioHardwareIllegalOperationError:
|
||||||
|
errorText = "Audio Hardware: Illegal Operation";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioHardwareBadDeviceError:
|
||||||
|
errorText = "Audio Hardware: Bad Device";
|
||||||
|
result = paInvalidDevice; break;
|
||||||
|
case kAudioHardwareBadStreamError:
|
||||||
|
errorText = "Audio Hardware: BadStream";
|
||||||
|
result = paBadStreamPtr; break;
|
||||||
|
case kAudioHardwareUnsupportedOperationError:
|
||||||
|
errorText = "Audio Hardware: Unsupported Operation";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioDeviceUnsupportedFormatError:
|
||||||
|
errorText = "Audio Device: Unsupported Format";
|
||||||
|
result = paSampleFormatNotSupported; break;
|
||||||
|
case kAudioDevicePermissionsError:
|
||||||
|
errorText = "Audio Device: Permissions Error";
|
||||||
|
result = paDeviceUnavailable; break;
|
||||||
|
/* Audio Unit Errors: http://developer.apple.com/documentation/MusicAudio/Reference/CoreAudio/audio_units/chapter_5_section_3.html */
|
||||||
|
case kAudioUnitErr_InvalidProperty:
|
||||||
|
errorText = "Audio Unit: Invalid Property";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_InvalidParameter:
|
||||||
|
errorText = "Audio Unit: Invalid Parameter";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_NoConnection:
|
||||||
|
errorText = "Audio Unit: No Connection";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_FailedInitialization:
|
||||||
|
errorText = "Audio Unit: Initialization Failed";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_TooManyFramesToProcess:
|
||||||
|
errorText = "Audio Unit: Too Many Frames";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_IllegalInstrument:
|
||||||
|
errorText = "Audio Unit: Illegal Instrument";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_InstrumentTypeNotFound:
|
||||||
|
errorText = "Audio Unit: Instrument Type Not Found";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_InvalidFile:
|
||||||
|
errorText = "Audio Unit: Invalid File";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_UnknownFileType:
|
||||||
|
errorText = "Audio Unit: Unknown File Type";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_FileNotSpecified:
|
||||||
|
errorText = "Audio Unit: File Not Specified";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_FormatNotSupported:
|
||||||
|
errorText = "Audio Unit: Format Not Supported";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_Uninitialized:
|
||||||
|
errorText = "Audio Unit: Unitialized";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_InvalidScope:
|
||||||
|
errorText = "Audio Unit: Invalid Scope";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_PropertyNotWritable:
|
||||||
|
errorText = "Audio Unit: PropertyNotWritable";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_InvalidPropertyValue:
|
||||||
|
errorText = "Audio Unit: Invalid Property Value";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_PropertyNotInUse:
|
||||||
|
errorText = "Audio Unit: Property Not In Use";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_Initialized:
|
||||||
|
errorText = "Audio Unit: Initialized";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_InvalidOfflineRender:
|
||||||
|
errorText = "Audio Unit: Invalid Offline Render";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_Unauthorized:
|
||||||
|
errorText = "Audio Unit: Unauthorized";
|
||||||
|
result = paInternalError; break;
|
||||||
|
case kAudioUnitErr_CannotDoInCurrentContext:
|
||||||
|
errorText = "Audio Unit: cannot do in current context";
|
||||||
|
result = paInternalError; break;
|
||||||
|
default:
|
||||||
|
errorText = "Unknown Error";
|
||||||
|
result = paInternalError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isError)
|
||||||
|
errorType = "Error";
|
||||||
|
else
|
||||||
|
errorType = "Warning";
|
||||||
|
|
||||||
|
if ((int)error < -99999 || (int)error > 99999)
|
||||||
|
DBUG(("%s on line %d: err='%4s', msg='%s'\n", errorType, line, (const char *)&error, errorText));
|
||||||
|
else
|
||||||
|
DBUG(("%s on line %d: err=%d, 0x%x, msg='%s'\n", errorType, line, (int)error, (unsigned)error, errorText));
|
||||||
|
|
||||||
|
PaUtil_SetLastHostErrorInfo( paCoreAudio, error, errorText );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function computes an appropriate ring buffer size given
|
||||||
|
* a requested latency (in seconds), sample rate and framesPerBuffer.
|
||||||
|
*
|
||||||
|
* The returned ringBufferSize is computed using the following
|
||||||
|
* constraints:
|
||||||
|
* - it must be at least 4.
|
||||||
|
* - it must be at least 3x framesPerBuffer.
|
||||||
|
* - it must be at least 2x the suggestedLatency.
|
||||||
|
* - it must be a power of 2.
|
||||||
|
* This function attempts to compute the minimum such size.
|
||||||
|
*
|
||||||
|
* FEEDBACK: too liberal/conservative/another way?
|
||||||
|
*/
|
||||||
|
long computeRingBufferSize( const PaStreamParameters *inputParameters,
|
||||||
|
const PaStreamParameters *outputParameters,
|
||||||
|
long inputFramesPerBuffer,
|
||||||
|
long outputFramesPerBuffer,
|
||||||
|
double sampleRate )
|
||||||
|
{
|
||||||
|
long ringSize;
|
||||||
|
int index;
|
||||||
|
int i;
|
||||||
|
double latencyTimesChannelCount ;
|
||||||
|
long framesPerBufferTimesChannelCount ;
|
||||||
|
|
||||||
|
VVDBUG(( "computeRingBufferSize()\n" ));
|
||||||
|
|
||||||
|
assert( inputParameters || outputParameters );
|
||||||
|
|
||||||
|
if( outputParameters && inputParameters )
|
||||||
|
{
|
||||||
|
latencyTimesChannelCount = MAX(
|
||||||
|
inputParameters->suggestedLatency * inputParameters->channelCount,
|
||||||
|
outputParameters->suggestedLatency * outputParameters->channelCount );
|
||||||
|
framesPerBufferTimesChannelCount = MAX(
|
||||||
|
inputFramesPerBuffer * inputParameters->channelCount,
|
||||||
|
outputFramesPerBuffer * outputParameters->channelCount );
|
||||||
|
}
|
||||||
|
else if( outputParameters )
|
||||||
|
{
|
||||||
|
latencyTimesChannelCount
|
||||||
|
= outputParameters->suggestedLatency * outputParameters->channelCount;
|
||||||
|
framesPerBufferTimesChannelCount
|
||||||
|
= outputFramesPerBuffer * outputParameters->channelCount;
|
||||||
|
}
|
||||||
|
else /* we have inputParameters */
|
||||||
|
{
|
||||||
|
latencyTimesChannelCount
|
||||||
|
= inputParameters->suggestedLatency * inputParameters->channelCount;
|
||||||
|
framesPerBufferTimesChannelCount
|
||||||
|
= inputFramesPerBuffer * inputParameters->channelCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
ringSize = (long) ( latencyTimesChannelCount * sampleRate * 2 + .5);
|
||||||
|
VDBUG( ( "suggested latency * channelCount: %d\n", (int) (latencyTimesChannelCount*sampleRate) ) );
|
||||||
|
if( ringSize < framesPerBufferTimesChannelCount * 3 )
|
||||||
|
ringSize = framesPerBufferTimesChannelCount * 3 ;
|
||||||
|
VDBUG(("framesPerBuffer*channelCount:%d\n",(int)framesPerBufferTimesChannelCount));
|
||||||
|
VDBUG(("Ringbuffer size (1): %d\n", (int)ringSize ));
|
||||||
|
|
||||||
|
/* make sure it's at least 4 */
|
||||||
|
ringSize = MAX( ringSize, 4 );
|
||||||
|
|
||||||
|
/* round up to the next power of 2 */
|
||||||
|
index = -1;
|
||||||
|
for( i=0; i<sizeof(long)*8; ++i )
|
||||||
|
if( ringSize >> i & 0x01 )
|
||||||
|
index = i;
|
||||||
|
assert( index > 0 );
|
||||||
|
if( ringSize <= ( 0x01 << index ) )
|
||||||
|
ringSize = 0x01 << index ;
|
||||||
|
else
|
||||||
|
ringSize = 0x01 << ( index + 1 );
|
||||||
|
|
||||||
|
VDBUG(( "Final Ringbuffer size (2): %d\n", (int)ringSize ));
|
||||||
|
return ringSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Durring testing of core audio, I found that serious crashes could occur
|
||||||
|
* if properties such as sample rate were changed multiple times in rapid
|
||||||
|
* succession. The function below has some fancy logic to make sure that changes
|
||||||
|
* are acknowledged before another is requested. That seems to help a lot.
|
||||||
|
*/
|
||||||
|
|
||||||
|
OSStatus propertyProc(
|
||||||
|
AudioDeviceID inDevice,
|
||||||
|
UInt32 inChannel,
|
||||||
|
Boolean isInput,
|
||||||
|
AudioDevicePropertyID inPropertyID,
|
||||||
|
void* inClientData )
|
||||||
|
{
|
||||||
|
MutexAndBool *mab = (MutexAndBool *) inClientData;
|
||||||
|
mab->once = TRUE;
|
||||||
|
pthread_mutex_unlock( &(mab->mutex) );
|
||||||
|
return noErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sets the value of the given property and waits for the change to
|
||||||
|
be acknowledged, and returns the final value, which is not guaranteed
|
||||||
|
by this function to be the same as the desired value. Obviously, this
|
||||||
|
function can only be used for data whose input and output are the
|
||||||
|
same size and format, and their size and format are known in advance.*/
|
||||||
|
PaError AudioDeviceSetPropertyNowAndWaitForChange(
|
||||||
|
AudioDeviceID inDevice,
|
||||||
|
UInt32 inChannel,
|
||||||
|
Boolean isInput,
|
||||||
|
AudioDevicePropertyID inPropertyID,
|
||||||
|
UInt32 inPropertyDataSize,
|
||||||
|
const void *inPropertyData,
|
||||||
|
void *outPropertyData )
|
||||||
|
{
|
||||||
|
OSStatus macErr;
|
||||||
|
int unixErr;
|
||||||
|
MutexAndBool mab;
|
||||||
|
UInt32 outPropertyDataSize = inPropertyDataSize;
|
||||||
|
|
||||||
|
/* First, see if it already has that value. If so, return. */
|
||||||
|
macErr = AudioDeviceGetProperty( inDevice, inChannel,
|
||||||
|
isInput, inPropertyID,
|
||||||
|
&outPropertyDataSize, outPropertyData );
|
||||||
|
if( macErr )
|
||||||
|
goto failMac2;
|
||||||
|
if( inPropertyDataSize!=outPropertyDataSize )
|
||||||
|
return paInternalError;
|
||||||
|
if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) )
|
||||||
|
return paNoError;
|
||||||
|
|
||||||
|
/* setup and lock mutex */
|
||||||
|
mab.once = FALSE;
|
||||||
|
unixErr = pthread_mutex_init( &mab.mutex, NULL );
|
||||||
|
if( unixErr )
|
||||||
|
goto failUnix2;
|
||||||
|
unixErr = pthread_mutex_lock( &mab.mutex );
|
||||||
|
if( unixErr )
|
||||||
|
goto failUnix;
|
||||||
|
|
||||||
|
/* add property listener */
|
||||||
|
macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput,
|
||||||
|
inPropertyID, propertyProc,
|
||||||
|
&mab );
|
||||||
|
if( macErr )
|
||||||
|
goto failMac;
|
||||||
|
/* set property */
|
||||||
|
macErr = AudioDeviceSetProperty( inDevice, NULL, inChannel,
|
||||||
|
isInput, inPropertyID,
|
||||||
|
inPropertyDataSize, inPropertyData );
|
||||||
|
if( macErr ) {
|
||||||
|
/* we couldn't set the property, so we'll just unlock the mutex
|
||||||
|
and move on. */
|
||||||
|
pthread_mutex_unlock( &mab.mutex );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* wait for property to change */
|
||||||
|
unixErr = pthread_mutex_lock( &mab.mutex );
|
||||||
|
if( unixErr )
|
||||||
|
goto failUnix;
|
||||||
|
|
||||||
|
/* now read the property back out */
|
||||||
|
macErr = AudioDeviceGetProperty( inDevice, inChannel,
|
||||||
|
isInput, inPropertyID,
|
||||||
|
&outPropertyDataSize, outPropertyData );
|
||||||
|
if( macErr )
|
||||||
|
goto failMac;
|
||||||
|
/* cleanup */
|
||||||
|
AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput,
|
||||||
|
inPropertyID, propertyProc );
|
||||||
|
unixErr = pthread_mutex_unlock( &mab.mutex );
|
||||||
|
if( unixErr )
|
||||||
|
goto failUnix2;
|
||||||
|
unixErr = pthread_mutex_destroy( &mab.mutex );
|
||||||
|
if( unixErr )
|
||||||
|
goto failUnix2;
|
||||||
|
|
||||||
|
return paNoError;
|
||||||
|
|
||||||
|
failUnix:
|
||||||
|
pthread_mutex_destroy( &mab.mutex );
|
||||||
|
AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput,
|
||||||
|
inPropertyID, propertyProc );
|
||||||
|
|
||||||
|
failUnix2:
|
||||||
|
DBUG( ("Error #%d while setting a device property: %s\n", unixErr, strerror( unixErr ) ) );
|
||||||
|
return paUnanticipatedHostError;
|
||||||
|
|
||||||
|
failMac:
|
||||||
|
pthread_mutex_destroy( &mab.mutex );
|
||||||
|
AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput,
|
||||||
|
inPropertyID, propertyProc );
|
||||||
|
failMac2:
|
||||||
|
return ERR( macErr );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the sample rate the HAL device.
|
||||||
|
* if requireExact: set the sample rate or fail.
|
||||||
|
*
|
||||||
|
* otherwise : set the exact sample rate.
|
||||||
|
* If that fails, check for available sample rates, and choose one
|
||||||
|
* higher than the requested rate. If there isn't a higher one,
|
||||||
|
* just use the highest available.
|
||||||
|
*/
|
||||||
|
PaError setBestSampleRateForDevice( const AudioDeviceID device,
|
||||||
|
const bool isOutput,
|
||||||
|
const bool requireExact,
|
||||||
|
const Float64 desiredSrate )
|
||||||
|
{
|
||||||
|
/*FIXME: changing the sample rate is disruptive to other programs using the
|
||||||
|
device, so it might be good to offer a custom flag to not change the
|
||||||
|
sample rate and just do conversion. (in my casual tests, there is
|
||||||
|
no disruption unless the sample rate really does need to change) */
|
||||||
|
const bool isInput = isOutput ? 0 : 1;
|
||||||
|
Float64 srate;
|
||||||
|
UInt32 propsize = sizeof( Float64 );
|
||||||
|
OSErr err;
|
||||||
|
AudioValueRange *ranges;
|
||||||
|
int i=0;
|
||||||
|
Float64 max = -1; /*the maximum rate available*/
|
||||||
|
Float64 best = -1; /*the lowest sample rate still greater than desired rate*/
|
||||||
|
VDBUG(("Setting sample rate for device %ld to %g.\n",device,(float)desiredSrate));
|
||||||
|
|
||||||
|
/* -- try setting the sample rate -- */
|
||||||
|
err = AudioDeviceSetPropertyNowAndWaitForChange(
|
||||||
|
device, 0, isInput,
|
||||||
|
kAudioDevicePropertyNominalSampleRate,
|
||||||
|
propsize, &desiredSrate, &srate );
|
||||||
|
if( err )
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* -- if the rate agrees, and we got no errors, we are done -- */
|
||||||
|
if( !err && srate == desiredSrate )
|
||||||
|
return paNoError;
|
||||||
|
/* -- we've failed if the rates disagree and we are setting input -- */
|
||||||
|
if( requireExact )
|
||||||
|
return paInvalidSampleRate;
|
||||||
|
|
||||||
|
/* -- generate a list of available sample rates -- */
|
||||||
|
err = AudioDeviceGetPropertyInfo( device, 0, isInput,
|
||||||
|
kAudioDevicePropertyAvailableNominalSampleRates,
|
||||||
|
&propsize, NULL );
|
||||||
|
if( err )
|
||||||
|
return ERR( err );
|
||||||
|
ranges = (AudioValueRange *)calloc( 1, propsize );
|
||||||
|
if( !ranges )
|
||||||
|
return paInsufficientMemory;
|
||||||
|
err = AudioDeviceGetProperty( device, 0, isInput,
|
||||||
|
kAudioDevicePropertyAvailableNominalSampleRates,
|
||||||
|
&propsize, ranges );
|
||||||
|
if( err )
|
||||||
|
{
|
||||||
|
free( ranges );
|
||||||
|
return ERR( err );
|
||||||
|
}
|
||||||
|
VDBUG(("Requested sample rate of %g was not available.\n", (float)desiredSrate));
|
||||||
|
VDBUG(("%lu Available Sample Rates are:\n",propsize/sizeof(AudioValueRange)));
|
||||||
|
#ifdef MAC_CORE_VERBOSE_DEBUG
|
||||||
|
for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
|
||||||
|
VDBUG( ("\t%g-%g\n",
|
||||||
|
(float) ranges[i].mMinimum,
|
||||||
|
(float) ranges[i].mMaximum ) );
|
||||||
|
#endif
|
||||||
|
VDBUG(("-----\n"));
|
||||||
|
|
||||||
|
/* -- now pick the best available sample rate -- */
|
||||||
|
for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
|
||||||
|
{
|
||||||
|
if( ranges[i].mMaximum > max ) max = ranges[i].mMaximum;
|
||||||
|
if( ranges[i].mMinimum > desiredSrate ) {
|
||||||
|
if( best < 0 )
|
||||||
|
best = ranges[i].mMinimum;
|
||||||
|
else if( ranges[i].mMinimum < best )
|
||||||
|
best = ranges[i].mMinimum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( best < 0 )
|
||||||
|
best = max;
|
||||||
|
VDBUG( ("Maximum Rate %g. best is %g.\n", max, best ) );
|
||||||
|
free( ranges );
|
||||||
|
|
||||||
|
/* -- set the sample rate -- */
|
||||||
|
propsize = sizeof( best );
|
||||||
|
err = AudioDeviceSetPropertyNowAndWaitForChange(
|
||||||
|
device, 0, isInput,
|
||||||
|
kAudioDevicePropertyNominalSampleRate,
|
||||||
|
propsize, &best, &srate );
|
||||||
|
if( err )
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if( err )
|
||||||
|
return ERR( err );
|
||||||
|
/* -- if the set rate matches, we are done -- */
|
||||||
|
if( srate == best )
|
||||||
|
return paNoError;
|
||||||
|
|
||||||
|
/* -- otherwise, something wierd happened: we didn't set the rate, and we got no errors. Just bail. */
|
||||||
|
return paInternalError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Attempts to set the requestedFramesPerBuffer. If it can't set the exact
|
||||||
|
value, it settles for something smaller if available. If nothing smaller
|
||||||
|
is available, it uses the smallest available size.
|
||||||
|
actualFramesPerBuffer will be set to the actual value on successful return.
|
||||||
|
OK to pass NULL to actualFramesPerBuffer.
|
||||||
|
The logic is very simmilar too setBestSampleRate only failure here is
|
||||||
|
not usually catastrophic.
|
||||||
|
*/
|
||||||
|
PaError setBestFramesPerBuffer( const AudioDeviceID device,
|
||||||
|
const bool isOutput,
|
||||||
|
unsigned long requestedFramesPerBuffer,
|
||||||
|
unsigned long *actualFramesPerBuffer )
|
||||||
|
{
|
||||||
|
UInt32 afpb;
|
||||||
|
const bool isInput = !isOutput;
|
||||||
|
UInt32 propsize = sizeof(UInt32);
|
||||||
|
OSErr err;
|
||||||
|
Float64 min = -1; /*the min blocksize*/
|
||||||
|
Float64 best = -1; /*the best blocksize*/
|
||||||
|
int i=0;
|
||||||
|
AudioValueRange *ranges;
|
||||||
|
|
||||||
|
if( actualFramesPerBuffer == NULL )
|
||||||
|
actualFramesPerBuffer = &afpb;
|
||||||
|
|
||||||
|
|
||||||
|
/* -- try and set exact FPB -- */
|
||||||
|
err = AudioDeviceSetProperty( device, NULL, 0, isInput,
|
||||||
|
kAudioDevicePropertyBufferFrameSize,
|
||||||
|
propsize, &requestedFramesPerBuffer);
|
||||||
|
err = AudioDeviceGetProperty( device, 0, isInput,
|
||||||
|
kAudioDevicePropertyBufferFrameSize,
|
||||||
|
&propsize, actualFramesPerBuffer);
|
||||||
|
if( err )
|
||||||
|
return ERR( err );
|
||||||
|
if( *actualFramesPerBuffer == requestedFramesPerBuffer )
|
||||||
|
return paNoError; /* we are done */
|
||||||
|
|
||||||
|
/* -- fetch available block sizes -- */
|
||||||
|
err = AudioDeviceGetPropertyInfo( device, 0, isInput,
|
||||||
|
kAudioDevicePropertyBufferSizeRange,
|
||||||
|
&propsize, NULL );
|
||||||
|
if( err )
|
||||||
|
return ERR( err );
|
||||||
|
ranges = (AudioValueRange *)calloc( 1, propsize );
|
||||||
|
if( !ranges )
|
||||||
|
return paInsufficientMemory;
|
||||||
|
err = AudioDeviceGetProperty( device, 0, isInput,
|
||||||
|
kAudioDevicePropertyBufferSizeRange,
|
||||||
|
&propsize, ranges );
|
||||||
|
if( err )
|
||||||
|
{
|
||||||
|
free( ranges );
|
||||||
|
return ERR( err );
|
||||||
|
}
|
||||||
|
VDBUG(("Requested block size of %lu was not available.\n",
|
||||||
|
requestedFramesPerBuffer ));
|
||||||
|
VDBUG(("%lu Available block sizes are:\n",propsize/sizeof(AudioValueRange)));
|
||||||
|
#ifdef MAC_CORE_VERBOSE_DEBUG
|
||||||
|
for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
|
||||||
|
VDBUG( ("\t%g-%g\n",
|
||||||
|
(float) ranges[i].mMinimum,
|
||||||
|
(float) ranges[i].mMaximum ) );
|
||||||
|
#endif
|
||||||
|
VDBUG(("-----\n"));
|
||||||
|
|
||||||
|
/* --- now pick the best available framesPerBuffer -- */
|
||||||
|
for( i=0; i<propsize/sizeof(AudioValueRange); ++i )
|
||||||
|
{
|
||||||
|
if( min == -1 || ranges[i].mMinimum < min ) min = ranges[i].mMinimum;
|
||||||
|
if( ranges[i].mMaximum < requestedFramesPerBuffer ) {
|
||||||
|
if( best < 0 )
|
||||||
|
best = ranges[i].mMaximum;
|
||||||
|
else if( ranges[i].mMaximum > best )
|
||||||
|
best = ranges[i].mMaximum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( best == -1 )
|
||||||
|
best = min;
|
||||||
|
VDBUG( ("Minimum FPB %g. best is %g.\n", min, best ) );
|
||||||
|
free( ranges );
|
||||||
|
|
||||||
|
/* --- set the buffer size (ignore errors) -- */
|
||||||
|
requestedFramesPerBuffer = (UInt32) best ;
|
||||||
|
propsize = sizeof( UInt32 );
|
||||||
|
err = AudioDeviceSetProperty( device, NULL, 0, isInput,
|
||||||
|
kAudioDevicePropertyBufferSize,
|
||||||
|
propsize, &requestedFramesPerBuffer );
|
||||||
|
/* --- read the property to check that it was set -- */
|
||||||
|
err = AudioDeviceGetProperty( device, 0, isInput,
|
||||||
|
kAudioDevicePropertyBufferSize,
|
||||||
|
&propsize, actualFramesPerBuffer );
|
||||||
|
|
||||||
|
if( err )
|
||||||
|
return ERR( err );
|
||||||
|
|
||||||
|
return paNoError;
|
||||||
|
}
|
159
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_utilities.h
Normal file
159
portaudio-v19/src/hostapi/coreaudio/pa_mac_core_utilities.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* pa_mac_core_utilities.c
|
||||||
|
*
|
||||||
|
* utilitiy functions for pa_mac_core.c
|
||||||
|
*
|
||||||
|
* This functions are more like helper functions than part of the core,
|
||||||
|
* so I moved them to a separate file so the core code would be cleaner.
|
||||||
|
*
|
||||||
|
* by Bjorn Roche.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PA_MAC_CORE_UTILITIES_H__
|
||||||
|
#define PA_MAC_CORE_UTILITIES_H__
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "portaudio.h"
|
||||||
|
#include "pa_util.h"
|
||||||
|
#include <AudioUnit/AudioUnit.h>
|
||||||
|
#include <AudioToolbox/AudioToolbox.h>
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(a, b) (((a)<(b))?(a):(b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(a, b) (((a)<(b))?(b):(a))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ERR(mac_error) PaMacCore_SetError(mac_error, __LINE__, 1 )
|
||||||
|
#define WARNING(mac_error) PaMacCore_SetError(mac_error, __LINE__, 0 )
|
||||||
|
|
||||||
|
|
||||||
|
/* Help keep track of AUHAL element numbers */
|
||||||
|
#define INPUT_ELEMENT (1)
|
||||||
|
#define OUTPUT_ELEMENT (0)
|
||||||
|
|
||||||
|
/* Normal level of debugging: fine for most apps that don't mind the occational warning being printf'ed */
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
#define MAC_CORE_DEBUG
|
||||||
|
#ifdef MAC_CORE_DEBUG
|
||||||
|
# define DBUG(MSG) do { printf("||PaMacCore (AUHAL)|| "); printf MSG ; fflush(stdout); } while(0)
|
||||||
|
#else
|
||||||
|
# define DBUG(MSG)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Verbose Debugging: useful for developement */
|
||||||
|
/*
|
||||||
|
#define MAC_CORE_VERBOSE_DEBUG
|
||||||
|
*/
|
||||||
|
#ifdef MAC_CORE_VERBOSE_DEBUG
|
||||||
|
# define VDBUG(MSG) do { printf("||PaMacCore (v )|| "); printf MSG ; fflush(stdout); } while(0)
|
||||||
|
#else
|
||||||
|
# define VDBUG(MSG)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Very Verbose Debugging: Traces every call. */
|
||||||
|
/*
|
||||||
|
#define MAC_CORE_VERY_VERBOSE_DEBUG
|
||||||
|
*/
|
||||||
|
#ifdef MAC_CORE_VERY_VERBOSE_DEBUG
|
||||||
|
# define VVDBUG(MSG) do { printf("||PaMacCore (vv)|| "); printf MSG ; fflush(stdout); } while(0)
|
||||||
|
#else
|
||||||
|
# define VVDBUG(MSG)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define UNIX_ERR(err) PaMacCore_SetUnixError( err, __LINE__ )
|
||||||
|
|
||||||
|
PaError PaMacCore_SetUnixError( int err, int line );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Translates MacOS generated errors into PaErrors
|
||||||
|
*/
|
||||||
|
PaError PaMacCore_SetError(OSStatus error, int line, int isError);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function computes an appropriate ring buffer size given
|
||||||
|
* a requested latency (in seconds), sample rate and framesPerBuffer.
|
||||||
|
*
|
||||||
|
* The returned ringBufferSize is computed using the following
|
||||||
|
* constraints:
|
||||||
|
* - it must be at least 4.
|
||||||
|
* - it must be at least 3x framesPerBuffer.
|
||||||
|
* - it must be at least 2x the suggestedLatency.
|
||||||
|
* - it must be a power of 2.
|
||||||
|
* This function attempts to compute the minimum such size.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
long computeRingBufferSize( const PaStreamParameters *inputParameters,
|
||||||
|
const PaStreamParameters *outputParameters,
|
||||||
|
long inputFramesPerBuffer,
|
||||||
|
long outputFramesPerBuffer,
|
||||||
|
double sampleRate );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Durring testing of core audio, I found that serious crashes could occur
|
||||||
|
* if properties such as sample rate were changed multiple times in rapid
|
||||||
|
* succession. The function below has some fancy logic to make sure that changes
|
||||||
|
* are acknowledged before another is requested. That seems to help a lot.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool once; /* I didn't end up using this. bdr */
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
} MutexAndBool ;
|
||||||
|
|
||||||
|
OSStatus propertyProc(
|
||||||
|
AudioDeviceID inDevice,
|
||||||
|
UInt32 inChannel,
|
||||||
|
Boolean isInput,
|
||||||
|
AudioDevicePropertyID inPropertyID,
|
||||||
|
void* inClientData );
|
||||||
|
|
||||||
|
/* sets the value of the given property and waits for the change to
|
||||||
|
be acknowledged, and returns the final value, which is not guaranteed
|
||||||
|
by this function to be the same as the desired value. Obviously, this
|
||||||
|
function can only be used for data whose input and output are the
|
||||||
|
same size and format, and their size and format are known in advance.*/
|
||||||
|
PaError AudioDeviceSetPropertyNowAndWaitForChange(
|
||||||
|
AudioDeviceID inDevice,
|
||||||
|
UInt32 inChannel,
|
||||||
|
Boolean isInput,
|
||||||
|
AudioDevicePropertyID inPropertyID,
|
||||||
|
UInt32 inPropertyDataSize,
|
||||||
|
const void *inPropertyData,
|
||||||
|
void *outPropertyData );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sets the sample rate the HAL device.
|
||||||
|
* if requireExact: set the sample rate or fail.
|
||||||
|
*
|
||||||
|
* otherwise : set the exact sample rate.
|
||||||
|
* If that fails, check for available sample rates, and choose one
|
||||||
|
* higher than the requested rate. If there isn't a higher one,
|
||||||
|
* just use the highest available.
|
||||||
|
*/
|
||||||
|
PaError setBestSampleRateForDevice( const AudioDeviceID device,
|
||||||
|
const bool isOutput,
|
||||||
|
const bool requireExact,
|
||||||
|
const Float64 desiredSrate );
|
||||||
|
/*
|
||||||
|
Attempts to set the requestedFramesPerBuffer. If it can't set the exact
|
||||||
|
value, it settles for something smaller if available. If nothing smaller
|
||||||
|
is available, it uses the smallest available size.
|
||||||
|
actualFramesPerBuffer will be set to the actual value on successful return.
|
||||||
|
OK to pass NULL to actualFramesPerBuffer.
|
||||||
|
The logic is very simmilar too setBestSampleRate only failure here is
|
||||||
|
not usually catastrophic.
|
||||||
|
*/
|
||||||
|
PaError setBestFramesPerBuffer( const AudioDeviceID device,
|
||||||
|
const bool isOutput,
|
||||||
|
unsigned long requestedFramesPerBuffer,
|
||||||
|
unsigned long *actualFramesPerBuffer );
|
||||||
|
#endif /* PA_MAC_CORE_UTILITIES_H__*/
|
254
portaudio-v19/src/hostapi/coreaudio/ringbuffer.c
Normal file
254
portaudio-v19/src/hostapi/coreaudio/ringbuffer.c
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* ringbuffer.c
|
||||||
|
* Ring Buffer utility..
|
||||||
|
*
|
||||||
|
* Author: Phil Burk, http://www.softsynth.com
|
||||||
|
* modified for SMP safety on Mac OS X by Bjorn Roche
|
||||||
|
* also, alowed for const where possible
|
||||||
|
* Note that this is safe only for a single-thread reader and a
|
||||||
|
* single-thread writer.
|
||||||
|
*
|
||||||
|
* 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 <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can undefine this, to turn off memory barriers, but that
|
||||||
|
* is only useful if we know we don't need to be MP safe or
|
||||||
|
* we are interested in doing some kind of tests.
|
||||||
|
*/
|
||||||
|
#define MPSAFE
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* First, we'll define some memory barrier primitives based on the system.
|
||||||
|
* right now only OS X and FreeBSD are supported. In addition to providing
|
||||||
|
* memory barriers, these functions should ensure that data cached in registers
|
||||||
|
* is written out to cache where it can be snooped by other CPUs. (ie, the volatile
|
||||||
|
* keyword should not be required)
|
||||||
|
*
|
||||||
|
* the primitives that must be defined are:
|
||||||
|
*
|
||||||
|
* FullMemoryBarrier()
|
||||||
|
* ReadMemoryBarrier()
|
||||||
|
* WriteMemoryBarrier()
|
||||||
|
*
|
||||||
|
****************/
|
||||||
|
|
||||||
|
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||||
|
# include <libkern/OSAtomic.h>
|
||||||
|
/* Here are the memory barrier functions. Mac OS X and FreeBSD only provide
|
||||||
|
full memory barriers, so the three types of barriers are the same.
|
||||||
|
The asm volatile may be redundant with the memory barrier, but
|
||||||
|
until I have proof of that, I'm leaving it. */
|
||||||
|
# define FullMemoryBarrier() do{ asm volatile("":::"memory"); OSMemoryBarrier(); }while(false)
|
||||||
|
# define ReadMemoryBarrier() do{ asm volatile("":::"memory"); OSMemoryBarrier(); }while(false)
|
||||||
|
# define WriteMemoryBarrier() do{ asm volatile("":::"memory"); OSMemoryBarrier(); }while(false)
|
||||||
|
#else
|
||||||
|
# error Memory Barriers not defined on this system or system unknown
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Initialize FIFO.
|
||||||
|
* numBytes must be power of 2, returns -1 if not.
|
||||||
|
*/
|
||||||
|
long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )
|
||||||
|
{
|
||||||
|
if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */
|
||||||
|
rbuf->bufferSize = numBytes;
|
||||||
|
rbuf->buffer = (char *)dataPtr;
|
||||||
|
RingBuffer_Flush( rbuf );
|
||||||
|
rbuf->bigMask = (numBytes*2)-1;
|
||||||
|
rbuf->smallMask = (numBytes)-1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/***************************************************************************
|
||||||
|
** Return number of bytes available for reading. */
|
||||||
|
long RingBuffer_GetReadAvailable( RingBuffer *rbuf )
|
||||||
|
{
|
||||||
|
#ifdef MPSAFE
|
||||||
|
ReadMemoryBarrier();
|
||||||
|
#endif
|
||||||
|
return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );
|
||||||
|
}
|
||||||
|
/***************************************************************************
|
||||||
|
** Return number of bytes available for writing. */
|
||||||
|
long RingBuffer_GetWriteAvailable( RingBuffer *rbuf )
|
||||||
|
{
|
||||||
|
/* Since we are calling RingBuffer_GetReadAvailable, we don't need an aditional MB */
|
||||||
|
return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Clear buffer. Should only be called when buffer is NOT being read. */
|
||||||
|
void RingBuffer_Flush( RingBuffer *rbuf )
|
||||||
|
{
|
||||||
|
rbuf->writeIndex = rbuf->readIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Get address of region(s) to which we can write data.
|
||||||
|
** If the region is contiguous, size2 will be zero.
|
||||||
|
** If non-contiguous, size2 will be the size of second region.
|
||||||
|
** Returns room available to be written or numBytes, whichever is smaller.
|
||||||
|
*/
|
||||||
|
long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
|
||||||
|
void **dataPtr1, long *sizePtr1,
|
||||||
|
void **dataPtr2, long *sizePtr2 )
|
||||||
|
{
|
||||||
|
long index;
|
||||||
|
long available = RingBuffer_GetWriteAvailable( rbuf );
|
||||||
|
if( numBytes > available ) numBytes = available;
|
||||||
|
/* Check to see if write is not contiguous. */
|
||||||
|
index = rbuf->writeIndex & rbuf->smallMask;
|
||||||
|
if( (index + numBytes) > rbuf->bufferSize )
|
||||||
|
{
|
||||||
|
/* Write data in two blocks that wrap the buffer. */
|
||||||
|
long firstHalf = rbuf->bufferSize - index;
|
||||||
|
*dataPtr1 = &rbuf->buffer[index];
|
||||||
|
*sizePtr1 = firstHalf;
|
||||||
|
*dataPtr2 = &rbuf->buffer[0];
|
||||||
|
*sizePtr2 = numBytes - firstHalf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dataPtr1 = &rbuf->buffer[index];
|
||||||
|
*sizePtr1 = numBytes;
|
||||||
|
*dataPtr2 = NULL;
|
||||||
|
*sizePtr2 = 0;
|
||||||
|
}
|
||||||
|
return numBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*/
|
||||||
|
long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )
|
||||||
|
{
|
||||||
|
#ifdef MPSAFE
|
||||||
|
/* we need to ensure that previous writes are seen before we update the write index */
|
||||||
|
WriteMemoryBarrier();
|
||||||
|
return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
|
||||||
|
#else
|
||||||
|
return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Get address of region(s) from which we can read data.
|
||||||
|
** If the region is contiguous, size2 will be zero.
|
||||||
|
** If non-contiguous, size2 will be the size of second region.
|
||||||
|
** Returns room available to be written or numBytes, whichever is smaller.
|
||||||
|
*/
|
||||||
|
long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
|
||||||
|
void **dataPtr1, long *sizePtr1,
|
||||||
|
void **dataPtr2, long *sizePtr2 )
|
||||||
|
{
|
||||||
|
long index;
|
||||||
|
long available = RingBuffer_GetReadAvailable( rbuf );
|
||||||
|
if( numBytes > available ) numBytes = available;
|
||||||
|
/* Check to see if read is not contiguous. */
|
||||||
|
index = rbuf->readIndex & rbuf->smallMask;
|
||||||
|
if( (index + numBytes) > rbuf->bufferSize )
|
||||||
|
{
|
||||||
|
/* Write data in two blocks that wrap the buffer. */
|
||||||
|
long firstHalf = rbuf->bufferSize - index;
|
||||||
|
*dataPtr1 = &rbuf->buffer[index];
|
||||||
|
*sizePtr1 = firstHalf;
|
||||||
|
*dataPtr2 = &rbuf->buffer[0];
|
||||||
|
*sizePtr2 = numBytes - firstHalf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dataPtr1 = &rbuf->buffer[index];
|
||||||
|
*sizePtr1 = numBytes;
|
||||||
|
*dataPtr2 = NULL;
|
||||||
|
*sizePtr2 = 0;
|
||||||
|
}
|
||||||
|
return numBytes;
|
||||||
|
}
|
||||||
|
/***************************************************************************
|
||||||
|
*/
|
||||||
|
long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )
|
||||||
|
{
|
||||||
|
#ifdef MPSAFE
|
||||||
|
/* we need to ensure that previous writes are always seen before updating the index. */
|
||||||
|
WriteMemoryBarrier();
|
||||||
|
return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
|
||||||
|
#else
|
||||||
|
return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Return bytes written. */
|
||||||
|
long RingBuffer_Write( RingBuffer *rbuf, const void *data, long numBytes )
|
||||||
|
{
|
||||||
|
long size1, size2, numWritten;
|
||||||
|
void *data1, *data2;
|
||||||
|
numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
|
||||||
|
if( size2 > 0 )
|
||||||
|
{
|
||||||
|
|
||||||
|
memcpy( data1, data, size1 );
|
||||||
|
data = ((char *)data) + size1;
|
||||||
|
memcpy( data2, data, size2 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy( data1, data, size1 );
|
||||||
|
}
|
||||||
|
RingBuffer_AdvanceWriteIndex( rbuf, numWritten );
|
||||||
|
return numWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Return bytes read. */
|
||||||
|
long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )
|
||||||
|
{
|
||||||
|
long size1, size2, numRead;
|
||||||
|
void *data1, *data2;
|
||||||
|
numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
|
||||||
|
if( size2 > 0 )
|
||||||
|
{
|
||||||
|
memcpy( data, data1, size1 );
|
||||||
|
data = ((char *)data) + size1;
|
||||||
|
memcpy( data, data2, size2 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy( data, data1, size1 );
|
||||||
|
}
|
||||||
|
RingBuffer_AdvanceReadIndex( rbuf, numRead );
|
||||||
|
return numRead;
|
||||||
|
}
|
105
portaudio-v19/src/hostapi/coreaudio/ringbuffer.h
Normal file
105
portaudio-v19/src/hostapi/coreaudio/ringbuffer.h
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#ifndef _RINGBUFFER_H
|
||||||
|
#define _RINGBUFFER_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* ringbuffer.h
|
||||||
|
* Ring Buffer utility..
|
||||||
|
*
|
||||||
|
* Author: Phil Burk, http://www.softsynth.com
|
||||||
|
* modified for SMP safety on OS X by Bjorn Roche.
|
||||||
|
* also allowed for const where possible.
|
||||||
|
* Note that this is safe only for a single-thread reader
|
||||||
|
* and a single-thread writer.
|
||||||
|
*
|
||||||
|
* This program is distributed with 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 <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */
|
||||||
|
long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */
|
||||||
|
long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */
|
||||||
|
long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */
|
||||||
|
long smallMask; /* Used for fitting indices to buffer. */
|
||||||
|
char * buffer;
|
||||||
|
}
|
||||||
|
RingBuffer;
|
||||||
|
/*
|
||||||
|
* Initialize Ring Buffer.
|
||||||
|
* numBytes must be power of 2, returns -1 if not.
|
||||||
|
*/
|
||||||
|
long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
|
||||||
|
|
||||||
|
/* Clear buffer. Should only be called when buffer is NOT being read. */
|
||||||
|
void RingBuffer_Flush( RingBuffer *rbuf );
|
||||||
|
|
||||||
|
/* Return number of bytes available for writing. */
|
||||||
|
long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
|
||||||
|
/* Return number of bytes available for read. */
|
||||||
|
long RingBuffer_GetReadAvailable( RingBuffer *rbuf );
|
||||||
|
/* Return bytes written. */
|
||||||
|
long RingBuffer_Write( RingBuffer *rbuf, const void *data, long numBytes );
|
||||||
|
/* Return bytes read. */
|
||||||
|
long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );
|
||||||
|
|
||||||
|
/* Get address of region(s) to which we can write data.
|
||||||
|
** If the region is contiguous, size2 will be zero.
|
||||||
|
** If non-contiguous, size2 will be the size of second region.
|
||||||
|
** Returns room available to be written or numBytes, whichever is smaller.
|
||||||
|
*/
|
||||||
|
long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
|
||||||
|
void **dataPtr1, long *sizePtr1,
|
||||||
|
void **dataPtr2, long *sizePtr2 );
|
||||||
|
long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );
|
||||||
|
|
||||||
|
/* Get address of region(s) from which we can read data.
|
||||||
|
** If the region is contiguous, size2 will be zero.
|
||||||
|
** If non-contiguous, size2 will be the size of second region.
|
||||||
|
** Returns room available to be written or numBytes, whichever is smaller.
|
||||||
|
*/
|
||||||
|
long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
|
||||||
|
void **dataPtr1, long *sizePtr1,
|
||||||
|
void **dataPtr2, long *sizePtr2 );
|
||||||
|
|
||||||
|
long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* _RINGBUFFER_H */
|
2178
portaudio-v19/src/hostapi/dsound/pa_win_ds.c
Normal file
2178
portaudio-v19/src/hostapi/dsound/pa_win_ds.c
Normal file
File diff suppressed because it is too large
Load Diff
121
portaudio-v19/src/hostapi/dsound/pa_win_ds_dynlink.c
Normal file
121
portaudio-v19/src/hostapi/dsound/pa_win_ds_dynlink.c
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
#include "pa_win_ds_dynlink.h"
|
||||||
|
|
||||||
|
|
||||||
|
PaWinDsDSoundEntryPoints paWinDsDSoundEntryPoints = { 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 PaWinDs_InitializeDSoundEntryPoints(void)
|
||||||
|
{
|
||||||
|
paWinDsDSoundEntryPoints.hInstance_ = LoadLibrary("dsound.dll");
|
||||||
|
if( paWinDsDSoundEntryPoints.hInstance_ != NULL )
|
||||||
|
{
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCreate =
|
||||||
|
(HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN))
|
||||||
|
GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCreate" );
|
||||||
|
if( paWinDsDSoundEntryPoints.DirectSoundCreate == NULL )
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
|
||||||
|
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundEnumerateW =
|
||||||
|
(HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
|
||||||
|
GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundEnumerateW" );
|
||||||
|
if( paWinDsDSoundEntryPoints.DirectSoundEnumerateW == NULL )
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
|
||||||
|
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundEnumerateA =
|
||||||
|
(HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
|
||||||
|
GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundEnumerateA" );
|
||||||
|
if( paWinDsDSoundEntryPoints.DirectSoundEnumerateA == NULL )
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
|
||||||
|
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureCreate =
|
||||||
|
(HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN))
|
||||||
|
GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCaptureCreate" );
|
||||||
|
if( paWinDsDSoundEntryPoints.DirectSoundCaptureCreate == NULL )
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
|
||||||
|
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW =
|
||||||
|
(HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
|
||||||
|
GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateW" );
|
||||||
|
if( paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW == NULL )
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
|
||||||
|
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA =
|
||||||
|
(HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
|
||||||
|
GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateA" );
|
||||||
|
if( paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA == NULL )
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* initialize with dummy entry points to make live easy when ds isn't present */
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PaWinDs_TerminateDSoundEntryPoints(void)
|
||||||
|
{
|
||||||
|
if( paWinDsDSoundEntryPoints.hInstance_ != NULL )
|
||||||
|
{
|
||||||
|
/* ensure that we crash reliably if the entry points arent initialised */
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCreate = 0;
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundEnumerateW = 0;
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundEnumerateA = 0;
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureCreate = 0;
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateW = 0;
|
||||||
|
paWinDsDSoundEntryPoints.DirectSoundCaptureEnumerateA = 0;
|
||||||
|
|
||||||
|
FreeLibrary( paWinDsDSoundEntryPoints.hInstance_ );
|
||||||
|
paWinDsDSoundEntryPoints.hInstance_ = NULL;
|
||||||
|
}
|
||||||
|
}
|
82
portaudio-v19/src/hostapi/dsound/pa_win_ds_dynlink.h
Normal file
82
portaudio-v19/src/hostapi/dsound/pa_win_ds_dynlink.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
#ifndef INCLUDED_PA_DSOUND_DYNLINK_H
|
||||||
|
#define INCLUDED_PA_DSOUND_DYNLINK_H
|
||||||
|
/*
|
||||||
|
* Interface for dynamically loading directsound and providing a dummy
|
||||||
|
* implementation if it isn't present.
|
||||||
|
*
|
||||||
|
* Author: Ross Bencina (some portions Phil Burk & Robert Marsanyi
|
||||||
|
*
|
||||||
|
* For PortAudio Portable Real-Time Audio Library
|
||||||
|
* For more information see: http://www.portaudio.com
|
||||||
|
* Copyright (c) 1999-2006 Phil Burk, Robert Marsanyi and 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
|
/*
|
||||||
|
We are only using DX3 in here, no need to polute the namespace - davidv
|
||||||
|
*/
|
||||||
|
#define DIRECTSOUND_VERSION 0x0300
|
||||||
|
|
||||||
|
#include <DSound.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}PaWinDsDSoundEntryPoints;
|
||||||
|
|
||||||
|
extern PaWinDsDSoundEntryPoints paWinDsDSoundEntryPoints;
|
||||||
|
|
||||||
|
void PaWinDs_InitializeDSoundEntryPoints(void);
|
||||||
|
void PaWinDs_TerminateDSoundEntryPoints(void);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#endif /* INCLUDED_PA_DSOUND_DYNLINK_H */
|
1724
portaudio-v19/src/hostapi/jack/pa_jack.c
Normal file
1724
portaudio-v19/src/hostapi/jack/pa_jack.c
Normal file
File diff suppressed because it is too large
Load Diff
BIN
portaudio-v19/src/hostapi/oss/low_latency_tip.txt
Normal file
BIN
portaudio-v19/src/hostapi/oss/low_latency_tip.txt
Normal file
Binary file not shown.
1929
portaudio-v19/src/hostapi/oss/pa_unix_oss.c
Normal file
1929
portaudio-v19/src/hostapi/oss/pa_unix_oss.c
Normal file
File diff suppressed because it is too large
Load Diff
1924
portaudio-v19/src/hostapi/oss/pa_unix_oss.c.orig
Normal file
1924
portaudio-v19/src/hostapi/oss/pa_unix_oss.c.orig
Normal file
File diff suppressed because it is too large
Load Diff
114
portaudio-v19/src/hostapi/oss/recplay.c
Normal file
114
portaudio-v19/src/hostapi/oss/recplay.c
Normal file
@ -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 );
|
||||||
|
}
|
1770
portaudio-v19/src/hostapi/wasapi/pa_win_wasapi.cpp
Normal file
1770
portaudio-v19/src/hostapi/wasapi/pa_win_wasapi.cpp
Normal file
File diff suppressed because it is too large
Load Diff
3269
portaudio-v19/src/hostapi/wdmks/pa_win_wdmks.c
Normal file
3269
portaudio-v19/src/hostapi/wdmks/pa_win_wdmks.c
Normal file
File diff suppressed because it is too large
Load Diff
82
portaudio-v19/src/hostapi/wdmks/readme.txt
Normal file
82
portaudio-v19/src/hostapi/wdmks/readme.txt
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
Notes about WDM-KS host API
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
Status history
|
||||||
|
--------------
|
||||||
|
10th November 2005:
|
||||||
|
Made following changes:
|
||||||
|
* OpenStream: Try all PaSampleFormats internally if the the chosen
|
||||||
|
format is not supported natively. This fixed several problems
|
||||||
|
with soundcards that soundcards that did not take kindly to
|
||||||
|
using 24-bit 3-byte formats.
|
||||||
|
* OpenStream: Make the minimum framesPerHostIBuffer (and framesPerHostOBuffer)
|
||||||
|
the default frameSize for the playback/recording pin.
|
||||||
|
* ProcessingThread: Added a switch to only call PaUtil_EndBufferProcessing
|
||||||
|
if the total input frames equals the total output frames
|
||||||
|
|
||||||
|
5th September 2004:
|
||||||
|
This is the first public version of the code. It should be considered
|
||||||
|
an alpha release with zero guarantee not to crash on any particular
|
||||||
|
system. So far it has only been tested in the author's development
|
||||||
|
environment, which means a Win2k/SP2 PIII laptop with integrated
|
||||||
|
SoundMAX driver and USB Tascam US-428 compiled with both MinGW
|
||||||
|
(GCC 3.3) and MSVC++6 using the MS DirectX 9 SDK.
|
||||||
|
It has been most widely tested with the MinGW build, with most of the
|
||||||
|
test programs (particularly paqa_devs and paqa_errs) passing.
|
||||||
|
There are some notable failures: patest_out_underflow and both of the
|
||||||
|
blocking I/O tests (as blocking I/O is not implemented).
|
||||||
|
At this point the code needs to be tested with a much wider variety
|
||||||
|
of configurations and feedback provided from testers regarding
|
||||||
|
both working and failing cases.
|
||||||
|
|
||||||
|
What is the WDM-KS host API?
|
||||||
|
----------------------------
|
||||||
|
PortAudio for Windows currently has 3 functional host implementations.
|
||||||
|
MME uses the oldest Windows audio API which does not offer good
|
||||||
|
play/record latency.
|
||||||
|
DirectX improves this, but still imposes a penalty
|
||||||
|
of 10s of milliseconds due to the system mixing of streams from
|
||||||
|
multiple applications.
|
||||||
|
ASIO offers very good latency, but requires special drivers which are
|
||||||
|
not always available for cheaper audio hardware. Also, when ASIO
|
||||||
|
drivers are available, they are not always so robust because they
|
||||||
|
bypass all of the standardised Windows device driver architecture
|
||||||
|
and hit the hardware their own way.
|
||||||
|
Alternatively there are a couple of free (but closed source) ASIO
|
||||||
|
implementations which connect to the lower level Windows
|
||||||
|
"Kernel Streaming" API, but again these require special installation
|
||||||
|
by the user, and can be limited in functionality or difficult to use.
|
||||||
|
|
||||||
|
This is where the PortAudio "WDM-KS" host implementation comes in.
|
||||||
|
It directly connects PortAudio to the same Kernel Streaming API which
|
||||||
|
those ASIO bridges use. This avoids the mixing penatly of DirectX,
|
||||||
|
giving at least as good latency as any ASIO driver, but it has the
|
||||||
|
advantage of working with ANY Windows audio hardware which is available
|
||||||
|
through the normal MME/DirectX routes without the user requiring
|
||||||
|
any additional device drivers to be installed, and allowing all
|
||||||
|
device selection to be done through the normal PortAudio API.
|
||||||
|
|
||||||
|
Note that in general you should only be using this host API if your
|
||||||
|
application has a real requirement for very low latency audio (<20ms),
|
||||||
|
either because you are generating sounds in real-time based upon
|
||||||
|
user input, or you a processing recorded audio in real time.
|
||||||
|
|
||||||
|
The only thing to be aware of is that using the KS interface will
|
||||||
|
block that device from being used by the rest of system through
|
||||||
|
the higher level APIs, or conversely, if the system is using
|
||||||
|
a device, the KS API will not be able to use it. MS recommend that
|
||||||
|
you should keep the device open only when your application has focus.
|
||||||
|
In PortAudio terms, this means having a stream Open on a WDMKS device.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
-----
|
||||||
|
To add the WDMKS backend to your program which is already using
|
||||||
|
PortAudio, you must undefine PA_NO_WDMKS from your build file,
|
||||||
|
and include the pa_win_wdmks\pa_win_wdmks.c into your build.
|
||||||
|
The file should compile in both C and C++.
|
||||||
|
You will need a DirectX SDK installed on your system for the
|
||||||
|
ks.h and ksmedia.h header files.
|
||||||
|
You will need to link to the system "setupapi" library.
|
||||||
|
Note that if you use MinGW, you will get more warnings from
|
||||||
|
the DX header files when using GCC(C), and still a few warnings
|
||||||
|
with G++(CPP).
|
3634
portaudio-v19/src/hostapi/wmme/pa_win_wmme.c
Normal file
3634
portaudio-v19/src/hostapi/wmme/pa_win_wmme.c
Normal file
File diff suppressed because it is too large
Load Diff
79
portaudio-v19/src/os/mac_osx/pa_mac_hostapis.c
Normal file
79
portaudio-v19/src/os/mac_osx/pa_mac_hostapis.c
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
Mac OS host API initialization function table.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "pa_hostapi.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
PaError PaMacSm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
PaError PaMacAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
PaUtilHostApiInitializer *paHostApiInitializers[] =
|
||||||
|
{
|
||||||
|
#ifdef PA_USE_COREAUDIO
|
||||||
|
PaMacCore_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PA_USE_SM
|
||||||
|
PaMacSm_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PA_USE_JACK
|
||||||
|
PaJack_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PA_USE_ASIO
|
||||||
|
PaMacAsio_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PaSkeleton_Initialize, /* just for testing */
|
||||||
|
|
||||||
|
0 /* NULL terminated array */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int paDefaultHostApiIndex = 0;
|
68
portaudio-v19/src/os/unix/pa_unix_hostapis.c
Normal file
68
portaudio-v19/src/os/unix/pa_unix_hostapis.c
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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 );
|
||||||
|
/* Added for IRIX, Pieter, oct 2, 2003: */
|
||||||
|
PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
/* Linux AudioScience HPI */
|
||||||
|
PaError PaAsiHpi_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
|
||||||
|
/* Added for IRIX, Pieter, oct 2, 2003: */
|
||||||
|
#ifdef PA_USE_SGI
|
||||||
|
PaSGI_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PA_USE_ASIHPI
|
||||||
|
PaAsiHpi_Initialize,
|
||||||
|
#endif
|
||||||
|
0 /* NULL terminated array */
|
||||||
|
};
|
||||||
|
|
||||||
|
int paDefaultHostApiIndex = 0;
|
672
portaudio-v19/src/os/unix/pa_unix_util.c
Normal file
672
portaudio-v19/src/os/unix/pa_unix_util.c
Normal file
@ -0,0 +1,672 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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 <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h> /* For memset */
|
||||||
|
#include <math.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "pa_util.h"
|
||||||
|
#include "pa_unix_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 )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_NANOSLEEP
|
||||||
|
struct timespec req = {0}, rem = {0};
|
||||||
|
PaTime time = msec / 1.e3;
|
||||||
|
req.tv_sec = (time_t)time;
|
||||||
|
assert(time - req.tv_sec < 1.0);
|
||||||
|
req.tv_nsec = (long)((time - req.tv_sec) * 1.e9);
|
||||||
|
nanosleep(&req, &rem);
|
||||||
|
/* XXX: Try sleeping the remaining time (contained in rem) if interrupted by a signal? */
|
||||||
|
#else
|
||||||
|
while( msec > 999 ) /* For OpenBSD and IRIX, argument */
|
||||||
|
{ /* to usleep must be < 1000000. */
|
||||||
|
usleep( 999000 );
|
||||||
|
msec -= 999;
|
||||||
|
}
|
||||||
|
usleep( msec * 1000 );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* *** NOT USED YET: ***
|
||||||
|
static int usePerformanceCounter_;
|
||||||
|
static double microsecondsPerTick_;
|
||||||
|
*/
|
||||||
|
|
||||||
|
void PaUtil_InitializeClock( void )
|
||||||
|
{
|
||||||
|
/* TODO */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PaTime PaUtil_GetTime( void )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_CLOCK_GETTIME
|
||||||
|
struct timespec tp;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &tp);
|
||||||
|
return (PaTime)(tp.tv_sec + tp.tv_nsec / 1.e9);
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday( &tv, NULL );
|
||||||
|
return (PaTime) tv.tv_usec / 1000000. + tv.tv_sec;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
PaError PaUtil_InitializeThreading( PaUtilThreading *threading )
|
||||||
|
{
|
||||||
|
(void) paUtilErr_;
|
||||||
|
return paNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaUtil_TerminateThreading( PaUtilThreading *threading )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data )
|
||||||
|
{
|
||||||
|
pthread_create( &threading->callbackThread, NULL, threadRoutine, data );
|
||||||
|
return paNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
void *pret;
|
||||||
|
|
||||||
|
if( exitResult )
|
||||||
|
*exitResult = paNoError;
|
||||||
|
|
||||||
|
/* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
|
||||||
|
if( !wait )
|
||||||
|
pthread_cancel( threading->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */
|
||||||
|
pthread_join( threading->callbackThread, &pret );
|
||||||
|
|
||||||
|
#ifdef PTHREAD_CANCELED
|
||||||
|
if( pret && PTHREAD_CANCELED != pret )
|
||||||
|
#else
|
||||||
|
/* !wait means the thread may have been canceled */
|
||||||
|
if( pret && wait )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if( exitResult )
|
||||||
|
*exitResult = *(PaError *) pret;
|
||||||
|
free( pret );
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Threading */
|
||||||
|
/* paUnixMainThread
|
||||||
|
* We have to be a bit careful with defining this global variable,
|
||||||
|
* as explained below. */
|
||||||
|
#ifdef __apple__
|
||||||
|
/* apple/gcc has a "problem" with global vars and dynamic libs.
|
||||||
|
Initializing it seems to fix the problem.
|
||||||
|
Described a bit in this thread:
|
||||||
|
http://gcc.gnu.org/ml/gcc/2005-06/msg00179.html
|
||||||
|
*/
|
||||||
|
pthread_t paUnixMainThread = 0;
|
||||||
|
#else
|
||||||
|
/*pthreads are opaque. We don't know that asigning it an int value
|
||||||
|
always makes sense, so we don't initialize it unless we have to.*/
|
||||||
|
pthread_t paUnixMainThread = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PaError PaUnixThreading_Initialize()
|
||||||
|
{
|
||||||
|
paUnixMainThread = pthread_self();
|
||||||
|
return paNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
PaError PaUnixThread_Initialize( PaUnixThread* self )
|
||||||
|
{
|
||||||
|
th->watchdogRunning = 0;
|
||||||
|
th->rtSched = 0;
|
||||||
|
th->callbackTime = 0;
|
||||||
|
th->callbackCpuTime = 0;
|
||||||
|
th->useWatchdog = 1;
|
||||||
|
th->throttledSleepTime = 0;
|
||||||
|
th->cpuLoadMeasurer = clm;
|
||||||
|
|
||||||
|
th->rtPrio = (sched_get_priority_max( SCHED_FIFO ) - sched_get_priority_min( SCHED_FIFO )) / 2
|
||||||
|
+ sched_get_priority_min( SCHED_FIFO );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
int started = 0;
|
||||||
|
|
||||||
|
memset( self, 0, sizeof (PaUnixThread) );
|
||||||
|
PaUnixMutex_Initialize( &self->mtx );
|
||||||
|
PA_ASSERT_CALL( pthread_cond_init( &self->cond, NULL ), 0 );
|
||||||
|
|
||||||
|
self->parentWaiting = 0 != waitForChild;
|
||||||
|
|
||||||
|
/* Spawn thread */
|
||||||
|
|
||||||
|
#if 0 && defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1)
|
||||||
|
if( th->rtSched )
|
||||||
|
{
|
||||||
|
if( mlockall( MCL_CURRENT | MCL_FUTURE ) < 0 )
|
||||||
|
{
|
||||||
|
int savedErrno = errno; /* In case errno gets overwritten */
|
||||||
|
assert( savedErrno != EINVAL ); /* Most likely a programmer error */
|
||||||
|
PA_UNLESS( (savedErrno == EPERM), paInternalError );
|
||||||
|
PA_DEBUG(( "%s: Failed locking memory\n", __FUNCTION__ ));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PA_DEBUG(( "%s: Successfully locked memory\n", __FUNCTION__ ));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
|
||||||
|
/* Priority relative to other processes */
|
||||||
|
PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
|
||||||
|
|
||||||
|
PA_UNLESS( !pthread_create( &self->thread, &attr, threadFunc, threadArg ), paInternalError );
|
||||||
|
started = 1;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if( th->rtSched )
|
||||||
|
{
|
||||||
|
if( th->useWatchdog )
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct sched_param wdSpm = { 0 };
|
||||||
|
/* Launch watchdog, watchdog sets callback thread priority */
|
||||||
|
int prio = PA_MIN( th->rtPrio + 4, sched_get_priority_max( SCHED_FIFO ) );
|
||||||
|
wdSpm.sched_priority = prio;
|
||||||
|
|
||||||
|
PA_UNLESS( !pthread_attr_init( &attr ), paInternalError );
|
||||||
|
PA_UNLESS( !pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ), paInternalError );
|
||||||
|
PA_UNLESS( !pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ), paInternalError );
|
||||||
|
PA_UNLESS( !pthread_attr_setschedpolicy( &attr, SCHED_FIFO ), paInternalError );
|
||||||
|
PA_UNLESS( !pthread_attr_setschedparam( &attr, &wdSpm ), paInternalError );
|
||||||
|
if( (err = pthread_create( &th->watchdogThread, &attr, &WatchdogFunc, th )) )
|
||||||
|
{
|
||||||
|
PA_UNLESS( err == EPERM, paInternalError );
|
||||||
|
/* Permission error, go on without realtime privileges */
|
||||||
|
PA_DEBUG(( "Failed bumping priority\n" ));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int policy;
|
||||||
|
th->watchdogRunning = 1;
|
||||||
|
PA_ENSURE_SYSTEM( pthread_getschedparam( th->watchdogThread, &policy, &wdSpm ), 0 );
|
||||||
|
/* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */
|
||||||
|
if( wdSpm.sched_priority != prio )
|
||||||
|
{
|
||||||
|
PA_DEBUG(( "Watchdog priority not set correctly (%d)\n", wdSpm.sched_priority ));
|
||||||
|
PA_ENSURE( paInternalError );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PA_ENSURE( BoostPriority( th ) );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( self->parentWaiting )
|
||||||
|
{
|
||||||
|
PaTime till;
|
||||||
|
struct timespec ts;
|
||||||
|
int res = 0;
|
||||||
|
PaTime now;
|
||||||
|
|
||||||
|
PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
|
||||||
|
|
||||||
|
/* Wait for stream to be started */
|
||||||
|
now = PaUtil_GetTime();
|
||||||
|
till = now + waitForChild;
|
||||||
|
|
||||||
|
while( self->parentWaiting && !res )
|
||||||
|
{
|
||||||
|
if( waitForChild > 0 )
|
||||||
|
{
|
||||||
|
ts.tv_sec = (time_t) floor( till );
|
||||||
|
ts.tv_nsec = (long) ((till - floor( till )) * 1e9);
|
||||||
|
res = pthread_cond_timedwait( &self->cond, &self->mtx.mtx, &ts );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = pthread_cond_wait( &self->cond, &self->mtx.mtx );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) );
|
||||||
|
|
||||||
|
PA_UNLESS( !res || ETIMEDOUT == res, paInternalError );
|
||||||
|
PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - now ));
|
||||||
|
if( ETIMEDOUT == res )
|
||||||
|
{
|
||||||
|
PA_ENSURE( paTimedOut );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
return result;
|
||||||
|
error:
|
||||||
|
if( started )
|
||||||
|
{
|
||||||
|
PaUnixThread_Terminate( self, 0, NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
void* pret;
|
||||||
|
|
||||||
|
if( exitResult )
|
||||||
|
{
|
||||||
|
*exitResult = paNoError;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
if( watchdogExitResult )
|
||||||
|
*watchdogExitResult = paNoError;
|
||||||
|
|
||||||
|
if( th->watchdogRunning )
|
||||||
|
{
|
||||||
|
pthread_cancel( th->watchdogThread );
|
||||||
|
PA_ENSURE_SYSTEM( pthread_join( th->watchdogThread, &pret ), 0 );
|
||||||
|
|
||||||
|
if( pret && pret != PTHREAD_CANCELED )
|
||||||
|
{
|
||||||
|
if( watchdogExitResult )
|
||||||
|
*watchdogExitResult = *(PaError *) pret;
|
||||||
|
free( pret );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
|
||||||
|
/* TODO: Make join time out */
|
||||||
|
self->stopRequested = wait;
|
||||||
|
if( !wait )
|
||||||
|
{
|
||||||
|
PA_DEBUG(( "%s: Canceling thread %d\n", __FUNCTION__, self->thread ));
|
||||||
|
/* XXX: Safe to call this if the thread has exited on its own? */
|
||||||
|
pthread_cancel( self->thread );
|
||||||
|
}
|
||||||
|
PA_DEBUG(( "%s: Joining thread %d\n", __FUNCTION__, self->thread ));
|
||||||
|
PA_ENSURE_SYSTEM( pthread_join( self->thread, &pret ), 0 );
|
||||||
|
|
||||||
|
if( pret && PTHREAD_CANCELED != pret )
|
||||||
|
{
|
||||||
|
if( exitResult )
|
||||||
|
{
|
||||||
|
*exitResult = *(PaError*)pret;
|
||||||
|
}
|
||||||
|
free( pret );
|
||||||
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
|
PA_ASSERT_CALL( PaUnixMutex_Terminate( &self->mtx ), paNoError );
|
||||||
|
PA_ASSERT_CALL( pthread_cond_destroy( &self->cond ), 0 );
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaError PaUnixThread_PrepareNotify( PaUnixThread* self )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
PA_UNLESS( self->parentWaiting, paInternalError );
|
||||||
|
|
||||||
|
PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
|
||||||
|
self->locked = 1;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaError PaUnixThread_NotifyParent( PaUnixThread* self )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
PA_UNLESS( self->parentWaiting, paInternalError );
|
||||||
|
|
||||||
|
if( !self->locked )
|
||||||
|
{
|
||||||
|
PA_ENSURE( PaUnixMutex_Lock( &self->mtx ) );
|
||||||
|
self->locked = 1;
|
||||||
|
}
|
||||||
|
self->parentWaiting = 0;
|
||||||
|
pthread_cond_signal( &self->cond );
|
||||||
|
PA_ENSURE( PaUnixMutex_Unlock( &self->mtx ) );
|
||||||
|
self->locked = 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PaUnixThread_StopRequested( PaUnixThread* self )
|
||||||
|
{
|
||||||
|
return self->stopRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaError PaUnixMutex_Initialize( PaUnixMutex* self )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
PA_ASSERT_CALL( pthread_mutex_init( &self->mtx, NULL ), 0 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaError PaUnixMutex_Terminate( PaUnixMutex* self )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
PA_ASSERT_CALL( pthread_mutex_destroy( &self->mtx ), 0 );
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Lock mutex.
|
||||||
|
*
|
||||||
|
* We're disabling thread cancellation while the thread is holding a lock, so mutexes are
|
||||||
|
* properly unlocked at termination time.
|
||||||
|
*/
|
||||||
|
PaError PaUnixMutex_Lock( PaUnixMutex* self )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
int oldState;
|
||||||
|
|
||||||
|
PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 );
|
||||||
|
PA_ENSURE_SYSTEM( pthread_mutex_lock( &self->mtx ), 0 );
|
||||||
|
|
||||||
|
error:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Unlock mutex.
|
||||||
|
*
|
||||||
|
* Thread cancellation is enabled again after the mutex is properly unlocked.
|
||||||
|
*/
|
||||||
|
PaError PaUnixMutex_Unlock( PaUnixMutex* self )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
int oldState;
|
||||||
|
|
||||||
|
PA_ENSURE_SYSTEM( pthread_mutex_unlock( &self->mtx ), 0 );
|
||||||
|
PA_ENSURE_SYSTEM( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 );
|
||||||
|
|
||||||
|
error:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Threading utility struct */
|
||||||
|
typedef struct PaAlsaThreading
|
||||||
|
{
|
||||||
|
pthread_t watchdogThread;
|
||||||
|
pthread_t callbackThread;
|
||||||
|
int watchdogRunning;
|
||||||
|
int rtSched;
|
||||||
|
int rtPrio;
|
||||||
|
int useWatchdog;
|
||||||
|
unsigned long throttledSleepTime;
|
||||||
|
volatile PaTime callbackTime;
|
||||||
|
volatile PaTime callbackCpuTime;
|
||||||
|
PaUtilCpuLoadMeasurer *cpuLoadMeasurer;
|
||||||
|
} PaAlsaThreading;
|
||||||
|
|
||||||
|
static void OnWatchdogExit( void *userData )
|
||||||
|
{
|
||||||
|
PaAlsaThreading *th = (PaAlsaThreading *) userData;
|
||||||
|
struct sched_param spm = { 0 };
|
||||||
|
assert( th );
|
||||||
|
|
||||||
|
PA_ASSERT_CALL( pthread_setschedparam( th->callbackThread, SCHED_OTHER, &spm ), 0 ); /* Lower before exiting */
|
||||||
|
PA_DEBUG(( "Watchdog exiting\n" ));
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError BoostPriority( PaAlsaThreading *th )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
struct sched_param spm = { 0 };
|
||||||
|
spm.sched_priority = th->rtPrio;
|
||||||
|
|
||||||
|
assert( th );
|
||||||
|
|
||||||
|
if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )
|
||||||
|
{
|
||||||
|
PA_UNLESS( errno == EPERM, paInternalError ); /* Lack permission to raise priority */
|
||||||
|
PA_DEBUG(( "Failed bumping priority\n" ));
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
result = 1; /* Success */
|
||||||
|
error:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *WatchdogFunc( void *userData )
|
||||||
|
{
|
||||||
|
PaError result = paNoError, *pres = NULL;
|
||||||
|
int err;
|
||||||
|
PaAlsaThreading *th = (PaAlsaThreading *) userData;
|
||||||
|
unsigned intervalMsec = 500;
|
||||||
|
const PaTime maxSeconds = 3.; /* Max seconds between callbacks */
|
||||||
|
PaTime timeThen = PaUtil_GetTime(), timeNow, timeElapsed, cpuTimeThen, cpuTimeNow, cpuTimeElapsed;
|
||||||
|
double cpuLoad, avgCpuLoad = 0.;
|
||||||
|
int throttled = 0;
|
||||||
|
|
||||||
|
assert( th );
|
||||||
|
|
||||||
|
/* Execute OnWatchdogExit when exiting */
|
||||||
|
pthread_cleanup_push( &OnWatchdogExit, th );
|
||||||
|
|
||||||
|
/* Boost priority of callback thread */
|
||||||
|
PA_ENSURE( result = BoostPriority( th ) );
|
||||||
|
if( !result )
|
||||||
|
{
|
||||||
|
/* Boost failed, might as well exit */
|
||||||
|
pthread_exit( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
cpuTimeThen = th->callbackCpuTime;
|
||||||
|
{
|
||||||
|
int policy;
|
||||||
|
struct sched_param spm = { 0 };
|
||||||
|
pthread_getschedparam( pthread_self(), &policy, &spm );
|
||||||
|
PA_DEBUG(( "%s: Watchdog priority is %d\n", __FUNCTION__, spm.sched_priority ));
|
||||||
|
}
|
||||||
|
|
||||||
|
while( 1 )
|
||||||
|
{
|
||||||
|
double lowpassCoeff = 0.9, lowpassCoeff1 = 0.99999 - lowpassCoeff;
|
||||||
|
|
||||||
|
/* Test before and after in case whatever underlying sleep call isn't interrupted by pthread_cancel */
|
||||||
|
pthread_testcancel();
|
||||||
|
Pa_Sleep( intervalMsec );
|
||||||
|
pthread_testcancel();
|
||||||
|
|
||||||
|
if( PaUtil_GetTime() - th->callbackTime > maxSeconds )
|
||||||
|
{
|
||||||
|
PA_DEBUG(( "Watchdog: Terminating callback thread\n" ));
|
||||||
|
/* Tell thread to terminate */
|
||||||
|
err = pthread_kill( th->callbackThread, SIGKILL );
|
||||||
|
pthread_exit( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
PA_DEBUG(( "%s: PortAudio reports CPU load: %g\n", __FUNCTION__, PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) ));
|
||||||
|
|
||||||
|
/* Check if we should throttle, or unthrottle :P */
|
||||||
|
cpuTimeNow = th->callbackCpuTime;
|
||||||
|
cpuTimeElapsed = cpuTimeNow - cpuTimeThen;
|
||||||
|
cpuTimeThen = cpuTimeNow;
|
||||||
|
|
||||||
|
timeNow = PaUtil_GetTime();
|
||||||
|
timeElapsed = timeNow - timeThen;
|
||||||
|
timeThen = timeNow;
|
||||||
|
cpuLoad = cpuTimeElapsed / timeElapsed;
|
||||||
|
avgCpuLoad = avgCpuLoad * lowpassCoeff + cpuLoad * lowpassCoeff1;
|
||||||
|
/*
|
||||||
|
if( throttled )
|
||||||
|
PA_DEBUG(( "Watchdog: CPU load: %g, %g\n", avgCpuLoad, cpuTimeElapsed ));
|
||||||
|
*/
|
||||||
|
if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) > .925 )
|
||||||
|
{
|
||||||
|
static int policy;
|
||||||
|
static struct sched_param spm = { 0 };
|
||||||
|
static const struct sched_param defaultSpm = { 0 };
|
||||||
|
PA_DEBUG(( "%s: Throttling audio thread, priority %d\n", __FUNCTION__, spm.sched_priority ));
|
||||||
|
|
||||||
|
pthread_getschedparam( th->callbackThread, &policy, &spm );
|
||||||
|
if( !pthread_setschedparam( th->callbackThread, SCHED_OTHER, &defaultSpm ) )
|
||||||
|
{
|
||||||
|
throttled = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PA_DEBUG(( "Watchdog: Couldn't lower priority of audio thread: %s\n", strerror( errno ) ));
|
||||||
|
|
||||||
|
/* Give other processes a go, before raising priority again */
|
||||||
|
PA_DEBUG(( "%s: Watchdog sleeping for %lu msecs before unthrottling\n", __FUNCTION__, th->throttledSleepTime ));
|
||||||
|
Pa_Sleep( th->throttledSleepTime );
|
||||||
|
|
||||||
|
/* Reset callback priority */
|
||||||
|
if( pthread_setschedparam( th->callbackThread, SCHED_FIFO, &spm ) != 0 )
|
||||||
|
{
|
||||||
|
PA_DEBUG(( "%s: Couldn't raise priority of audio thread: %s\n", __FUNCTION__, strerror( errno ) ));
|
||||||
|
}
|
||||||
|
|
||||||
|
if( PaUtil_GetCpuLoad( th->cpuLoadMeasurer ) >= .99 )
|
||||||
|
intervalMsec = 50;
|
||||||
|
else
|
||||||
|
intervalMsec = 100;
|
||||||
|
|
||||||
|
/*
|
||||||
|
lowpassCoeff = .97;
|
||||||
|
lowpassCoeff1 = .99999 - lowpassCoeff;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else if( throttled && avgCpuLoad < .8 )
|
||||||
|
{
|
||||||
|
intervalMsec = 500;
|
||||||
|
throttled = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
lowpassCoeff = .9;
|
||||||
|
lowpassCoeff1 = .99999 - lowpassCoeff;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_cleanup_pop( 1 ); /* Execute cleanup on exit */
|
||||||
|
|
||||||
|
error:
|
||||||
|
/* Shouldn't get here in the normal case */
|
||||||
|
|
||||||
|
/* Pass on error code */
|
||||||
|
pres = malloc( sizeof (PaError) );
|
||||||
|
*pres = result;
|
||||||
|
|
||||||
|
pthread_exit( pres );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CallbackUpdate( PaAlsaThreading *th )
|
||||||
|
{
|
||||||
|
th->callbackTime = PaUtil_GetTime();
|
||||||
|
th->callbackCpuTime = PaUtil_GetCpuLoad( th->cpuLoadMeasurer );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
static void *CanaryFunc( void *userData )
|
||||||
|
{
|
||||||
|
const unsigned intervalMsec = 1000;
|
||||||
|
PaUtilThreading *th = (PaUtilThreading *) userData;
|
||||||
|
|
||||||
|
while( 1 )
|
||||||
|
{
|
||||||
|
th->canaryTime = PaUtil_GetTime();
|
||||||
|
|
||||||
|
pthread_testcancel();
|
||||||
|
Pa_Sleep( intervalMsec );
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_exit( NULL );
|
||||||
|
}
|
||||||
|
*/
|
179
portaudio-v19/src/os/unix/pa_unix_util.h
Normal file
179
portaudio-v19/src/os/unix/pa_unix_util.h
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
#ifndef PA_UNIX_UTIL_H
|
||||||
|
#define PA_UNIX_UTIL_H
|
||||||
|
|
||||||
|
#include "pa_cpuload.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
#define PA_MIN(x,y) ( (x) < (y) ? (x) : (y) )
|
||||||
|
#define PA_MAX(x,y) ( (x) > (y) ? (x) : (y) )
|
||||||
|
|
||||||
|
/* Utilize GCC branch prediction for error tests */
|
||||||
|
#if defined __GNUC__ && __GNUC__ >= 3
|
||||||
|
#define UNLIKELY(expr) __builtin_expect( (expr), 0 )
|
||||||
|
#else
|
||||||
|
#define UNLIKELY(expr) (expr)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STRINGIZE_HELPER(expr) #expr
|
||||||
|
#define STRINGIZE(expr) STRINGIZE_HELPER(expr)
|
||||||
|
|
||||||
|
#define PA_UNLESS(expr, code) \
|
||||||
|
do { \
|
||||||
|
if( UNLIKELY( (expr) == 0 ) ) \
|
||||||
|
{ \
|
||||||
|
PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
|
||||||
|
result = (code); \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
static PaError paUtilErr_; /* Used with PA_ENSURE */
|
||||||
|
|
||||||
|
/* Check PaError */
|
||||||
|
#define PA_ENSURE(expr) \
|
||||||
|
do { \
|
||||||
|
if( UNLIKELY( (paUtilErr_ = (expr)) < paNoError ) ) \
|
||||||
|
{ \
|
||||||
|
PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
|
||||||
|
result = paUtilErr_; \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
#define PA_ASSERT_CALL(expr, success) \
|
||||||
|
paUtilErr_ = (expr); \
|
||||||
|
assert( success == paUtilErr_ );
|
||||||
|
|
||||||
|
#define PA_ENSURE_SYSTEM(expr, success) \
|
||||||
|
do { \
|
||||||
|
if( UNLIKELY( (paUtilErr_ = (expr)) != success ) ) \
|
||||||
|
{ \
|
||||||
|
/* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
|
||||||
|
if( pthread_equal(pthread_self(), paUnixMainThread) ) \
|
||||||
|
{ \
|
||||||
|
PaUtil_SetLastHostErrorInfo( paALSA, paUtilErr_, strerror( paUtilErr_ ) ); \
|
||||||
|
} \
|
||||||
|
PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \
|
||||||
|
result = paUnanticipatedHostError; \
|
||||||
|
goto error; \
|
||||||
|
} \
|
||||||
|
} while( 0 );
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
pthread_t callbackThread;
|
||||||
|
} PaUtilThreading;
|
||||||
|
|
||||||
|
PaError PaUtil_InitializeThreading( PaUtilThreading *threading );
|
||||||
|
void PaUtil_TerminateThreading( PaUtilThreading *threading );
|
||||||
|
PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data );
|
||||||
|
PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult );
|
||||||
|
|
||||||
|
/* State accessed by utility functions */
|
||||||
|
|
||||||
|
/*
|
||||||
|
void PaUnix_SetRealtimeScheduling( int rt );
|
||||||
|
|
||||||
|
void PaUtil_InitializeThreading( PaUtilThreading *th, PaUtilCpuLoadMeasurer *clm );
|
||||||
|
|
||||||
|
PaError PaUtil_CreateCallbackThread( PaUtilThreading *th, void *(*CallbackThreadFunc)( void * ), PaStream *s );
|
||||||
|
|
||||||
|
PaError PaUtil_KillCallbackThread( PaUtilThreading *th, PaError *exitResult );
|
||||||
|
|
||||||
|
void PaUtil_CallbackUpdate( PaUtilThreading *th );
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern pthread_t paUnixMainThread;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
pthread_mutex_t mtx;
|
||||||
|
} PaUnixMutex;
|
||||||
|
|
||||||
|
PaError PaUnixMutex_Initialize( PaUnixMutex* self );
|
||||||
|
PaError PaUnixMutex_Terminate( PaUnixMutex* self );
|
||||||
|
PaError PaUnixMutex_Lock( PaUnixMutex* self );
|
||||||
|
PaError PaUnixMutex_Unlock( PaUnixMutex* self );
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
pthread_t thread;
|
||||||
|
int parentWaiting;
|
||||||
|
int stopRequested;
|
||||||
|
int locked;
|
||||||
|
PaUnixMutex mtx;
|
||||||
|
pthread_cond_t cond;
|
||||||
|
volatile sig_atomic_t stopRequest;
|
||||||
|
} PaUnixThread;
|
||||||
|
|
||||||
|
/** Initialize global threading state.
|
||||||
|
*/
|
||||||
|
PaError PaUnixThreading_Initialize();
|
||||||
|
|
||||||
|
/** Perish, passing on eventual error code.
|
||||||
|
*
|
||||||
|
* A thin wrapper around pthread_exit, will automatically pass on any error code to the joining thread.
|
||||||
|
* If the result indicates an error, i.e. it is not equal to paNoError, this function will automatically
|
||||||
|
* allocate a pointer so the error is passed on with pthread_exit. If the result indicates that all is
|
||||||
|
* well however, only a NULL pointer will be handed to pthread_exit. Thus, the joining thread should
|
||||||
|
* check whether a non-NULL result pointer is obtained from pthread_join and make sure to free it.
|
||||||
|
* @param result: The error code to pass on to the joining thread.
|
||||||
|
*/
|
||||||
|
#define PaUnixThreading_EXIT(result) \
|
||||||
|
do { \
|
||||||
|
PaError* pres = NULL; \
|
||||||
|
if( paNoError != (result) ) \
|
||||||
|
{ \
|
||||||
|
pres = malloc( sizeof (PaError) ); \
|
||||||
|
*pres = (result); \
|
||||||
|
} \
|
||||||
|
pthread_exit( pres ); \
|
||||||
|
} while (0);
|
||||||
|
|
||||||
|
/** Spawn a thread.
|
||||||
|
*
|
||||||
|
* Intended for spawning the callback thread from the main thread. This function can even block (for a certain
|
||||||
|
* time or indefinitely) untill notified by the callback thread (using PaUnixThread_NotifyParent), which can be
|
||||||
|
* useful in order to make sure that callback has commenced before returning from Pa_StartStream.
|
||||||
|
* @param threadFunc: The function to be executed in the child thread.
|
||||||
|
* @param waitForChild: If not 0, wait for child thread to call PaUnixThread_NotifyParent. Less than 0 means
|
||||||
|
* wait for ever, greater than 0 wait for the specified time.
|
||||||
|
* @return: If timed out waiting on child, paTimedOut.
|
||||||
|
*/
|
||||||
|
PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild );
|
||||||
|
|
||||||
|
/** Terminate thread.
|
||||||
|
*
|
||||||
|
* @param wait: If true, request that background thread stop and wait untill it does, else cancel it.
|
||||||
|
* @param exitResult: If non-null this will upon return contain the exit status of the thread.
|
||||||
|
*/
|
||||||
|
PaError PaUnixThread_Terminate( PaUnixThread* self, int wait, PaError* exitResult );
|
||||||
|
|
||||||
|
/** Prepare to notify waiting parent thread.
|
||||||
|
*
|
||||||
|
* An internal lock must be held before the parent is notified in PaUnixThread_NotifyParent, call this to
|
||||||
|
* acquire it beforehand.
|
||||||
|
* @return: If parent is not waiting, paInternalError.
|
||||||
|
*/
|
||||||
|
PaError PaUnixThread_PrepareNotify( PaUnixThread* self );
|
||||||
|
|
||||||
|
/** Notify waiting parent thread.
|
||||||
|
*
|
||||||
|
* @return: If parent timed out waiting, paTimedOut. If parent was never waiting, paInternalError.
|
||||||
|
*/
|
||||||
|
PaError PaUnixThread_NotifyParent( PaUnixThread* self );
|
||||||
|
|
||||||
|
/** Has the parent thread requested this thread to stop?
|
||||||
|
*/
|
||||||
|
int PaUnixThread_StopRequested( PaUnixThread* self );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif
|
91
portaudio-v19/src/os/win/pa_win_hostapis.c
Normal file
91
portaudio-v19/src/os/win/pa_win_hostapis.c
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
Win32 host API initialization function table.
|
||||||
|
|
||||||
|
@todo Consider using PA_USE_WMME etc instead of PA_NO_WMME. This is what
|
||||||
|
the Unix version does, we should consider being consistent.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "pa_hostapi.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
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 );
|
||||||
|
PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
PaError PaWinWasapi_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
PaUtilHostApiInitializer *paHostApiInitializers[] =
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifndef PA_NO_WMME
|
||||||
|
PaWinMme_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PA_NO_DS
|
||||||
|
PaWinDs_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PA_NO_ASIO
|
||||||
|
PaAsio_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef PA_NO_WASAPI
|
||||||
|
PaWinWasapi_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PA_NO_WDMKS
|
||||||
|
PaWinWdm_Initialize,
|
||||||
|
#endif
|
||||||
|
*/
|
||||||
|
|
||||||
|
PaSkeleton_Initialize, /* just for testing */
|
||||||
|
|
||||||
|
0 /* NULL terminated array */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int paDefaultHostApiIndex = 0;
|
||||||
|
|
134
portaudio-v19/src/os/win/pa_win_util.c
Normal file
134
portaudio-v19/src/os/win/pa_win_util.c
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* $Id$
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
Win32 platform-specific support functions.
|
||||||
|
|
||||||
|
@todo Implement workaround for QueryPerformanceCounter() skipping forward
|
||||||
|
bug. (see msdn kb Q274323).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
1167
portaudio-v19/src/os/win/pa_x86_plain_converters.c
Normal file
1167
portaudio-v19/src/os/win/pa_x86_plain_converters.c
Normal file
File diff suppressed because it is too large
Load Diff
19
portaudio-v19/src/os/win/pa_x86_plain_converters.h
Normal file
19
portaudio-v19/src/os/win/pa_x86_plain_converters.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef PA_X86_PLAIN_CONVERTERS_H
|
||||||
|
#define PA_X86_PLAIN_CONVERTERS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Install optimised converter functions suitable for all IA32 processors
|
||||||
|
*/
|
||||||
|
void PaUtil_InitializeX86PlainConverters( void );
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_X86_PLAIN_CONVERTERS_H */
|
Loading…
x
Reference in New Issue
Block a user