mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-20 02:52:00 -05: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
|
||||
#
|
||||
# Dominic Mazzoni
|
||||
# Modifications by Mikael Magnusson
|
||||
#
|
||||
|
||||
top_srcdir = .
|
||||
srcdir = .
|
||||
|
||||
top_builddir = .
|
||||
PREFIX = /usr/local
|
||||
CC = cc
|
||||
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
|
||||
LIBS = -lpthread -lm -lpthread
|
||||
prefix = $(PREFIX)
|
||||
exec_prefix = ${prefix}
|
||||
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
|
||||
RANLIB = ranlib
|
||||
LIBTOOL = $(SHELL) $(top_builddir)/libtool
|
||||
INSTALL = /usr/bin/install -c
|
||||
INSTALL_DATA = ${INSTALL} -m 644
|
||||
SHARED_FLAGS = -shared -fPIC
|
||||
DLL_LIBS =
|
||||
CXXFLAGS =
|
||||
LDFLAGS =
|
||||
DLL_LIBS = -lrt -lm -lpthread
|
||||
CXXFLAGS = -g -O2
|
||||
NASM =
|
||||
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
|
||||
PADLL = libportaudio.so
|
||||
PADLLV = $(PADLL).0.0.19
|
||||
PAINC = pa_common/portaudio.h
|
||||
PALIB = libportaudio.la
|
||||
PAINC = include/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 = \
|
||||
pa_common/pa_allocation.o \
|
||||
pa_common/pa_converters.o \
|
||||
pa_common/pa_cpuload.o \
|
||||
pa_common/pa_dither.o \
|
||||
pa_common/pa_front.o \
|
||||
pa_common/pa_process.o \
|
||||
pa_common/pa_skeleton.o \
|
||||
pa_common/pa_stream.o \
|
||||
pa_common/pa_trace.o
|
||||
src/common/pa_allocation.o \
|
||||
src/common/pa_converters.o \
|
||||
src/common/pa_cpuload.o \
|
||||
src/common/pa_dither.o \
|
||||
src/common/pa_front.o \
|
||||
src/common/pa_process.o \
|
||||
src/common/pa_skeleton.o \
|
||||
src/common/pa_stream.o \
|
||||
src/common/pa_trace.o
|
||||
|
||||
TESTS = \
|
||||
bin/paqa_devs \
|
||||
@ -56,6 +74,7 @@ TESTS = \
|
||||
bin/patest_pink \
|
||||
bin/patest_prime \
|
||||
bin/patest_read_record \
|
||||
bin/patest_read_write_wire \
|
||||
bin/patest_record \
|
||||
bin/patest_ringmix \
|
||||
bin/patest_saw \
|
||||
@ -65,7 +84,6 @@ TESTS = \
|
||||
bin/patest_sine_time \
|
||||
bin/patest_start_stop \
|
||||
bin/patest_stop \
|
||||
bin/patest_sync \
|
||||
bin/patest_toomanysines \
|
||||
bin/patest_underflow \
|
||||
bin/patest_wire \
|
||||
@ -77,6 +95,8 @@ TESTS = \
|
||||
# Most of these don't compile yet. Put them in TESTS, above, if
|
||||
# you want to try to compile them...
|
||||
ALL_TESTS = \
|
||||
$(TESTS) \
|
||||
bin/patest_sync \
|
||||
bin/debug_convert \
|
||||
bin/debug_dither_calc \
|
||||
bin/debug_dual \
|
||||
@ -88,65 +108,34 @@ ALL_TESTS = \
|
||||
bin/debug_sine \
|
||||
bin/debug_sine_formats \
|
||||
bin/debug_srate \
|
||||
bin/debug_test1 \
|
||||
bin/pa_devs \
|
||||
bin/pa_fuzz \
|
||||
bin/pa_minlat \
|
||||
bin/paqa_devs \
|
||||
bin/paqa_errs \
|
||||
bin/patest1 \
|
||||
bin/patest_buffer \
|
||||
bin/patest_clip \
|
||||
bin/patest_dither \
|
||||
bin/patest_hang \
|
||||
bin/patest_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
|
||||
bin/debug_test1
|
||||
|
||||
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)
|
||||
$(AR) ruv lib/$(PALIB) $(OBJS)
|
||||
$(RANLIB) lib/$(PALIB)
|
||||
all: lib/$(PALIB) all-recursive tests
|
||||
|
||||
lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC)
|
||||
$(CC) $(SHARED_FLAGS) -o lib/$(PADLLV) $(OBJS) $(DLL_LIBS)
|
||||
tests: bin-stamp $(TESTS)
|
||||
|
||||
$(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c
|
||||
$(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS)
|
||||
|
||||
install: lib/$(PALIB) lib/$(PADLLV)
|
||||
$(INSTALL) -d $(PREFIX)/lib
|
||||
$(INSTALL) -m 644 lib/$(PADLLV) $(PREFIX)/lib/$(PADLLV)
|
||||
$(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB)
|
||||
cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL)
|
||||
$(INSTALL) -d $(PREFIX)/include
|
||||
$(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h
|
||||
lib/$(PALIB): lib-stamp $(LTOBJS) $(MAKEFILE) $(PAINC)
|
||||
$(LIBTOOL) --mode=link $(CC) $(PA_LDFLAGS) -o lib/$(PALIB) $(LTOBJS) $(DLL_LIBS)
|
||||
|
||||
$(ALL_TESTS): bin/%: lib/$(PALIB) $(MAKEFILE) $(PAINC) test/%.c
|
||||
$(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(top_srcdir)/test/$*.c lib/$(PALIB) $(LIBS)
|
||||
|
||||
|
||||
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 "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 "to make the shared object available. You may also need to"
|
||||
@echo "modify your LD_LIBRARY_PATH environment variable to include"
|
||||
@echo "the directory $(PREFIX)/lib"
|
||||
@echo "the directory $(libdir)"
|
||||
@echo "------------------------------------------------------------"
|
||||
@echo ""
|
||||
$(MAKE) install-recursive
|
||||
|
||||
uninstall:
|
||||
rm -f $(PREFIX)/lib/$(PADLLV)
|
||||
rm -f $(PREFIX)/lib/$(PALIB)
|
||||
rm -f $(PREFIX)/lib/$(PADLL)
|
||||
rm -f $(PREFIX)/include/portaudio.h
|
||||
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$(PALIB)
|
||||
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(includedir)/portaudio.h
|
||||
$(MAKE) uninstall-recursive
|
||||
|
||||
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 $@
|
||||
|
||||
%.o: %.cpp Makefile $(PAINC)
|
||||
%.lo: %.c $(MAKEFILE) $(PAINC)
|
||||
$(LIBTOOL) --mode=compile $(CC) -c $(CFLAGS) $< -o $@
|
||||
|
||||
%.o: %.cpp $(MAKEFILE) $(PAINC)
|
||||
$(CXX) -c $(CXXFLAGS) $< -o $@
|
||||
|
||||
%.o: %.asm
|
||||
$(NASM) $(NASMOPT) -o $@ $<
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
bin-stamp:
|
||||
-mkdir bin
|
||||
touch $@
|
||||
|
||||
lib:
|
||||
mkdir lib
|
||||
lib-stamp:
|
||||
-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
|
||||
#
|
||||
# Dominic Mazzoni
|
||||
# Modifications by Mikael Magnusson
|
||||
#
|
||||
|
||||
top_srcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
top_builddir = .
|
||||
PREFIX = @prefix@
|
||||
prefix = $(PREFIX)
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
includedir = @includedir@
|
||||
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@
|
||||
AR = @AR@
|
||||
RANLIB = @RANLIB@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
SHARED_FLAGS = @SHARED_FLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
DLL_LIBS = @DLL_LIBS@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
NASM = @NASM@
|
||||
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@
|
||||
|
||||
PALIB = libportaudio.a
|
||||
PADLL = @PADLL@
|
||||
PADLLV = $(PADLL).0.0.19
|
||||
PAINC = pa_common/portaudio.h
|
||||
PALIB = libportaudio.la
|
||||
PAINC = include/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 = \
|
||||
pa_common/pa_allocation.o \
|
||||
pa_common/pa_converters.o \
|
||||
pa_common/pa_cpuload.o \
|
||||
pa_common/pa_dither.o \
|
||||
pa_common/pa_front.o \
|
||||
pa_common/pa_process.o \
|
||||
pa_common/pa_skeleton.o \
|
||||
pa_common/pa_stream.o \
|
||||
pa_common/pa_trace.o
|
||||
src/common/pa_allocation.o \
|
||||
src/common/pa_converters.o \
|
||||
src/common/pa_cpuload.o \
|
||||
src/common/pa_dither.o \
|
||||
src/common/pa_front.o \
|
||||
src/common/pa_process.o \
|
||||
src/common/pa_skeleton.o \
|
||||
src/common/pa_stream.o \
|
||||
src/common/pa_trace.o
|
||||
|
||||
TESTS = \
|
||||
bin/paqa_devs \
|
||||
@ -55,6 +74,7 @@ TESTS = \
|
||||
bin/patest_pink \
|
||||
bin/patest_prime \
|
||||
bin/patest_read_record \
|
||||
bin/patest_read_write_wire \
|
||||
bin/patest_record \
|
||||
bin/patest_ringmix \
|
||||
bin/patest_saw \
|
||||
@ -64,7 +84,6 @@ TESTS = \
|
||||
bin/patest_sine_time \
|
||||
bin/patest_start_stop \
|
||||
bin/patest_stop \
|
||||
bin/patest_sync \
|
||||
bin/patest_toomanysines \
|
||||
bin/patest_underflow \
|
||||
bin/patest_wire \
|
||||
@ -76,6 +95,8 @@ TESTS = \
|
||||
# Most of these don't compile yet. Put them in TESTS, above, if
|
||||
# you want to try to compile them...
|
||||
ALL_TESTS = \
|
||||
$(TESTS) \
|
||||
bin/patest_sync \
|
||||
bin/debug_convert \
|
||||
bin/debug_dither_calc \
|
||||
bin/debug_dual \
|
||||
@ -87,65 +108,34 @@ ALL_TESTS = \
|
||||
bin/debug_sine \
|
||||
bin/debug_sine_formats \
|
||||
bin/debug_srate \
|
||||
bin/debug_test1 \
|
||||
bin/pa_devs \
|
||||
bin/pa_fuzz \
|
||||
bin/pa_minlat \
|
||||
bin/paqa_devs \
|
||||
bin/paqa_errs \
|
||||
bin/patest1 \
|
||||
bin/patest_buffer \
|
||||
bin/patest_clip \
|
||||
bin/patest_dither \
|
||||
bin/patest_hang \
|
||||
bin/patest_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
|
||||
bin/debug_test1
|
||||
|
||||
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)
|
||||
$(AR) ruv lib/$(PALIB) $(OBJS)
|
||||
$(RANLIB) lib/$(PALIB)
|
||||
all: lib/$(PALIB) all-recursive tests
|
||||
|
||||
lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC)
|
||||
$(CC) $(SHARED_FLAGS) -o lib/$(PADLLV) $(OBJS) $(DLL_LIBS)
|
||||
tests: bin-stamp $(TESTS)
|
||||
|
||||
$(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c
|
||||
$(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS)
|
||||
|
||||
install: lib/$(PALIB) lib/$(PADLLV)
|
||||
$(INSTALL) -d $(PREFIX)/lib
|
||||
$(INSTALL) -m 644 lib/$(PADLLV) $(PREFIX)/lib/$(PADLLV)
|
||||
$(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB)
|
||||
cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL)
|
||||
$(INSTALL) -d $(PREFIX)/include
|
||||
$(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h
|
||||
lib/$(PALIB): lib-stamp $(LTOBJS) $(MAKEFILE) $(PAINC)
|
||||
$(LIBTOOL) --mode=link $(CC) $(PA_LDFLAGS) -o lib/$(PALIB) $(LTOBJS) $(DLL_LIBS)
|
||||
|
||||
$(ALL_TESTS): bin/%: lib/$(PALIB) $(MAKEFILE) $(PAINC) test/%.c
|
||||
$(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(top_srcdir)/test/$*.c lib/$(PALIB) $(LIBS)
|
||||
|
||||
|
||||
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 "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 "to make the shared object available. You may also need to"
|
||||
@echo "modify your LD_LIBRARY_PATH environment variable to include"
|
||||
@echo "the directory $(PREFIX)/lib"
|
||||
@echo "the directory $(libdir)"
|
||||
@echo "------------------------------------------------------------"
|
||||
@echo ""
|
||||
$(MAKE) install-recursive
|
||||
|
||||
uninstall:
|
||||
rm -f $(PREFIX)/lib/$(PADLLV)
|
||||
rm -f $(PREFIX)/lib/$(PALIB)
|
||||
rm -f $(PREFIX)/lib/$(PADLL)
|
||||
rm -f $(PREFIX)/include/portaudio.h
|
||||
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$(PALIB)
|
||||
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(includedir)/portaudio.h
|
||||
$(MAKE) uninstall-recursive
|
||||
|
||||
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 $@
|
||||
|
||||
%.o: %.cpp Makefile $(PAINC)
|
||||
%.lo: %.c $(MAKEFILE) $(PAINC)
|
||||
$(LIBTOOL) --mode=compile $(CC) -c $(CFLAGS) $< -o $@
|
||||
|
||||
%.o: %.cpp $(MAKEFILE) $(PAINC)
|
||||
$(CXX) -c $(CXXFLAGS) $< -o $@
|
||||
|
||||
%.o: %.asm
|
||||
$(NASM) $(NASMOPT) -o $@ $<
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
bin-stamp:
|
||||
-mkdir bin
|
||||
touch $@
|
||||
|
||||
lib:
|
||||
mkdir lib
|
||||
lib-stamp:
|
||||
-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
|
||||
tutorial at:
|
||||
|
||||
http://www.portaudio.com/docs/pa_tutorial.html
|
||||
http://portaudio.com/trac/wiki/TutorialDir/TutorialStart
|
||||
|
||||
Important Files and Folders:
|
||||
pa_common/ = platform independant code
|
||||
|
@ -1,78 +1,147 @@
|
||||
import sys, os.path
|
||||
|
||||
class ConfigurationError(Exception):
|
||||
def __init__(self, reason):
|
||||
Exception.__init__(self, "Configuration failed: %s" % reason)
|
||||
def rsplit(toSplit, sub, max=-1):
|
||||
""" str.rsplit seems to have been introduced in 2.4 :( """
|
||||
l = []
|
||||
i = 0
|
||||
while i != max:
|
||||
try: idx = toSplit.rindex(sub)
|
||||
except ValueError: break
|
||||
|
||||
def _PackageOption(pkgName, default="yes"):
|
||||
return BoolOption("use%s" % pkgName[0].upper() + pkgName[1:], "use %s if available" % (pkgName), default)
|
||||
toSplit, splitOff = toSplit[:idx], toSplit[idx + len(sub):]
|
||||
l.insert(0, splitOff)
|
||||
i += 1
|
||||
|
||||
def _BoolOption(opt, explanation, default="yes"):
|
||||
return BoolOption("enable%s" % opt[0].upper() + opt[1:], explanation, default)
|
||||
l.insert(0, toSplit)
|
||||
return l
|
||||
|
||||
def _DirectoryOption(path, help, default):
|
||||
return PathOption(path, help, default)
|
||||
# Incompatible with the latest stable SCons
|
||||
# return PathOption(path, help, default, PathOption.PathIsDir)
|
||||
sconsDir = os.path.join("build", "scons")
|
||||
SConscript(os.path.join(sconsDir, "SConscript_common"))
|
||||
Import("Platform", "Posix", "ApiVer")
|
||||
|
||||
def _EnumOption(opt, explanation, allowedValues, default):
|
||||
assert default in allowedValues
|
||||
return EnumOption("with%s" % opt[0].upper() + opt[1:], explanation, default, allowed_values=allowedValues)
|
||||
# SConscript_opts exports PortAudio options
|
||||
optsDict = SConscript(os.path.join(sconsDir, "SConscript_opts"))
|
||||
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():
|
||||
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"]
|
||||
buildDir = os.path.join("#", sconsDir, env["PLATFORM"])
|
||||
|
||||
return __platform
|
||||
|
||||
# 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)
|
||||
# Determine parameters to build tools
|
||||
if Platform in Posix:
|
||||
opts.AddOptions(
|
||||
_DirectoryOption("prefix", "installation prefix", "/usr/local"),
|
||||
_PackageOption("ALSA"),
|
||||
_PackageOption("OSS"),
|
||||
_PackageOption("JACK"),
|
||||
)
|
||||
elif Platform in Windows:
|
||||
if Platform == "cygwin":
|
||||
opts.AddOptions(_DirectoryOption("prefix", "installation prefix", "/usr/local"))
|
||||
opts.AddOptions(_EnumOption("winAPI", "Windows API to use", ("wmme", "directx", "asio"), "wmme"))
|
||||
baseLinkFlags = threadCFlags = "-pthread"
|
||||
baseCxxFlags = baseCFlags = "-Wall -pedantic -pipe " + threadCFlags
|
||||
debugCxxFlags = debugCFlags = "-g"
|
||||
optCxxFlags = optCFlags = "-O2"
|
||||
env["CCFLAGS"] = baseCFlags.split()
|
||||
env["CXXFLAGS"] = baseCxxFlags.split()
|
||||
env["LINKFLAGS"] = baseLinkFlags.split()
|
||||
if env["enableDebug"]:
|
||||
env.AppendUnique(CCFLAGS=debugCFlags.split())
|
||||
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":
|
||||
opts.AddOptions(_EnumOption("macAPI", "Mac API to use", ("asio", "core", "sm"), "core"))
|
||||
env.Append(CPPPATH=[os.path.join("#", "include"), "common"])
|
||||
|
||||
opts.AddOptions(
|
||||
_BoolOption("shared", "create shared library"),
|
||||
_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))
|
||||
# Store all signatures in one file, otherwise .sconsign files will get installed along with our own files
|
||||
env.SConsignFile(os.path.join(sconsDir, ".sconsign"))
|
||||
|
||||
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_NUMBER = 2.0
|
||||
OUTPUT_DIRECTORY = "./docs/"
|
||||
OUTPUT_DIRECTORY = ./doc/
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
USE_WINDOWS_ENCODING = NO
|
||||
BRIEF_MEMBER_DESC = 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
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = NO
|
||||
STRIP_FROM_PATH =
|
||||
INTERNAL_DOCS = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
CASE_SENSE_NAMES = YES
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
DETAILS_AT_TOP = NO
|
||||
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
|
||||
SORT_MEMBER_DOCS = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
TAB_SIZE = 8
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
ALIASES =
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = ./pa_common ./pa_win_wmme ./pa_asio ./pa_win_ds ./pa_linux_alsa ./pa_unix_oss ./pa_jack ./pa_tests
|
||||
FILE_PATTERNS = *.h *.c *.cpp
|
||||
INPUT = src \
|
||||
include \
|
||||
test
|
||||
FILE_PATTERNS = *.h \
|
||||
*.c \
|
||||
*.cpp
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
@ -64,14 +97,18 @@ EXAMPLE_PATTERNS =
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
@ -82,13 +119,15 @@ IGNORE_PREFIX =
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = doxygen_html
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
@ -110,6 +149,7 @@ LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
@ -130,11 +170,22 @@ MAN_LINKS = NO
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
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
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
@ -147,7 +198,7 @@ PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to external references
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
@ -162,24 +213,25 @@ HIDE_UNDOC_RELATIONS = NO
|
||||
HAVE_DOT = NO
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = YES
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_WIDTH = 1024
|
||||
MAX_DOT_GRAPH_HEIGHT = 1024
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::addtions related to the search engine
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
||||
CGI_NAME = search.cgi
|
||||
CGI_URL =
|
||||
DOC_URL =
|
||||
DOC_ABSPATH =
|
||||
BIN_ABSPATH = /usr/local/bin/
|
||||
EXT_DOC_PATHS =
|
||||
|
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,
|
||||
# 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
|
||||
# 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} ;
|
||||
{ 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) ; } ||
|
||||
{ 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 ; } ;
|
||||
dummy=$tmp/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.
|
||||
echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
|
||||
exit 0 ;;
|
||||
Alpha*:OpenVMS:*:*)
|
||||
echo alpha-hp-vms
|
||||
exit 0 ;;
|
||||
Alpha\ *:Windows_NT*:*)
|
||||
# How do we know it's Interix rather than the generic POSIX subsystem?
|
||||
# Should we change UNAME_MACHINE based on the output of uname instead
|
||||
@ -324,9 +320,6 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
|
||||
NILE*:*:*:dcosx)
|
||||
echo pyramid-pyramid-svr4
|
||||
exit 0 ;;
|
||||
DRS?6000:unix:4.0:6*)
|
||||
echo sparc-icl-nx6
|
||||
exit 0 ;;
|
||||
DRS?6000:UNIX_SV:4.2*:7*)
|
||||
case `/usr/bin/uname -p` in
|
||||
sparc) echo sparc-icl-nx7 && exit 0 ;;
|
||||
@ -751,7 +744,7 @@ EOF
|
||||
*:BSD/OS:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
*:FreeBSD:*:*|*:GNU/FreeBSD:*:*)
|
||||
*:FreeBSD:*:*)
|
||||
# Determine whether the default compiler uses glibc.
|
||||
eval $set_cc_for_build
|
||||
sed 's/^ //' << EOF >$dummy.c
|
||||
@ -763,10 +756,7 @@ EOF
|
||||
#endif
|
||||
EOF
|
||||
eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep ^LIBC=`
|
||||
# GNU/FreeBSD systems have a "k" prefix to indicate we are using
|
||||
# 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}
|
||||
echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`${LIBC:+-$LIBC}
|
||||
exit 0 ;;
|
||||
i*:CYGWIN*:*)
|
||||
echo ${UNAME_MACHINE}-pc-cygwin
|
||||
@ -777,8 +767,8 @@ EOF
|
||||
i*:PW*:*)
|
||||
echo ${UNAME_MACHINE}-pc-pw32
|
||||
exit 0 ;;
|
||||
x86:Interix*:[34]*)
|
||||
echo i586-pc-interix${UNAME_RELEASE}|sed -e 's/\..*//'
|
||||
x86:Interix*:3*)
|
||||
echo i586-pc-interix3
|
||||
exit 0 ;;
|
||||
[345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
|
||||
echo i${UNAME_MACHINE}-pc-mks
|
||||
@ -807,9 +797,6 @@ EOF
|
||||
arm*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit 0 ;;
|
||||
cris:Linux:*:*)
|
||||
echo cris-axis-linux-gnu
|
||||
exit 0 ;;
|
||||
ia64:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit 0 ;;
|
||||
@ -888,9 +875,6 @@ EOF
|
||||
s390:Linux:*:* | s390x:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-ibm-linux
|
||||
exit 0 ;;
|
||||
sh64*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit 0 ;;
|
||||
sh*:Linux:*:*)
|
||||
echo ${UNAME_MACHINE}-unknown-linux-gnu
|
||||
exit 0 ;;
|
||||
@ -1049,7 +1033,7 @@ EOF
|
||||
exit 0 ;;
|
||||
M68*:*:R3V[567]*:*)
|
||||
test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
|
||||
3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 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=''
|
||||
test -r /etc/.relid \
|
||||
&& OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
|
||||
@ -1205,9 +1189,6 @@ EOF
|
||||
*:ITS:*:*)
|
||||
echo pdp10-unknown-its
|
||||
exit 0 ;;
|
||||
SEI:*:*:SEIUX)
|
||||
echo mips-sei-seiux${UNAME_RELEASE}
|
||||
exit 0 ;;
|
||||
esac
|
||||
|
||||
#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,
|
||||
# 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.
|
||||
# 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.
|
||||
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
|
||||
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
|
||||
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
|
||||
;;
|
||||
@ -229,7 +229,7 @@ case $basic_machine in
|
||||
| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
|
||||
| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
|
||||
| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr \
|
||||
| c4x | clipper \
|
||||
| clipper \
|
||||
| d10v | d30v | dlx | dsp16xx \
|
||||
| fr30 | frv \
|
||||
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
|
||||
@ -261,7 +261,7 @@ case $basic_machine in
|
||||
| sh64 | sh64le \
|
||||
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
|
||||
| strongarm \
|
||||
| tahoe | thumb | tic4x | tic80 | tron \
|
||||
| tahoe | thumb | tic80 | tron \
|
||||
| v850 | v850e \
|
||||
| we32k \
|
||||
| x86 | xscale | xstormy16 | xtensa \
|
||||
@ -292,7 +292,7 @@ case $basic_machine in
|
||||
| a29k-* \
|
||||
| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
|
||||
| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | amd64-* | arc-* \
|
||||
| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
|
||||
| arm-* | armbe-* | armle-* | armeb-* | armv*-* \
|
||||
| avr-* \
|
||||
| bs2000-* \
|
||||
@ -373,9 +373,6 @@ case $basic_machine in
|
||||
basic_machine=a29k-none
|
||||
os=-bsd
|
||||
;;
|
||||
amd64)
|
||||
basic_machine=x86_64-pc
|
||||
;;
|
||||
amdahl)
|
||||
basic_machine=580-amdahl
|
||||
os=-sysv
|
||||
@ -771,24 +768,18 @@ case $basic_machine in
|
||||
pentiumpro | p6 | 6x86 | athlon | athlon_*)
|
||||
basic_machine=i686-pc
|
||||
;;
|
||||
pentiumii | pentium2 | pentiumiii | pentium3)
|
||||
pentiumii | pentium2)
|
||||
basic_machine=i686-pc
|
||||
;;
|
||||
pentium4)
|
||||
basic_machine=i786-pc
|
||||
;;
|
||||
pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
|
||||
basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
pentiumpro-* | p6-* | 6x86-* | athlon-*)
|
||||
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
|
||||
pentiumii-* | pentium2-*)
|
||||
basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
pentium4-*)
|
||||
basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
|
||||
;;
|
||||
pn)
|
||||
basic_machine=pn-gould
|
||||
;;
|
||||
@ -847,10 +838,6 @@ case $basic_machine in
|
||||
sb1el)
|
||||
basic_machine=mipsisa64sb1el-unknown
|
||||
;;
|
||||
sei)
|
||||
basic_machine=mips-sei
|
||||
os=-seiux
|
||||
;;
|
||||
sequent)
|
||||
basic_machine=i386-sequent
|
||||
;;
|
||||
@ -858,9 +845,6 @@ case $basic_machine in
|
||||
basic_machine=sh-hitachi
|
||||
os=-hms
|
||||
;;
|
||||
sh64)
|
||||
basic_machine=sh64-unknown
|
||||
;;
|
||||
sparclite-wrs | simso-wrs)
|
||||
basic_machine=sparclite-wrs
|
||||
os=-vxworks
|
||||
@ -935,6 +919,10 @@ case $basic_machine in
|
||||
basic_machine=t90-cray
|
||||
os=-unicos
|
||||
;;
|
||||
tic4x | c4x*)
|
||||
basic_machine=tic4x-unknown
|
||||
os=-coff
|
||||
;;
|
||||
tic54x | c54x*)
|
||||
basic_machine=tic54x-unknown
|
||||
os=-coff
|
||||
@ -1128,7 +1116,7 @@ case $os in
|
||||
| -aos* \
|
||||
| -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
|
||||
| -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* \
|
||||
| -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
|
||||
| -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
|
||||
@ -1140,7 +1128,7 @@ case $os in
|
||||
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
|
||||
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
|
||||
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
|
||||
| -powermax* | -dnix* | -nx6 | -nx7 | -sei*)
|
||||
| -powermax* | -dnix*)
|
||||
# Remember, each alternative MUST END IN *, to match a version number.
|
||||
;;
|
||||
-qnx*)
|
||||
@ -1286,9 +1274,6 @@ case $basic_machine in
|
||||
arm*-semi)
|
||||
os=-aout
|
||||
;;
|
||||
c4x-* | tic4x-*)
|
||||
os=-coff
|
||||
;;
|
||||
# This must come before the *-dec entry.
|
||||
pdp10-*)
|
||||
os=-tops20
|
||||
|
22329
portaudio-v19/configure
vendored
22329
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 from the right directory
|
||||
AC_INIT([pa_common/portaudio.h])
|
||||
AC_INIT([include/portaudio.h])
|
||||
|
||||
dnl Specify options
|
||||
|
||||
@ -25,6 +25,10 @@ AC_ARG_WITH(oss,
|
||||
[ --with-oss (default=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,
|
||||
[ --with-host_os (no default)],
|
||||
host_os=$withval)
|
||||
@ -46,12 +50,24 @@ AC_ARG_WITH(dxdir,
|
||||
[ --with-dxdir (default=/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.
|
||||
|
||||
AC_PROG_CC
|
||||
AC_PROG_RANLIB
|
||||
AC_LIBTOOL_WIN32_DLL
|
||||
AC_PROG_LIBTOOL
|
||||
AC_PROG_INSTALL
|
||||
AC_PROG_LN_S
|
||||
AC_PATH_PROG(AR, ar, no)
|
||||
if [[ $AR = "no" ]] ; then
|
||||
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
|
||||
|
||||
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 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 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)
|
||||
|
||||
@ -79,16 +96,34 @@ AC_CHECK_SIZEOF(short)
|
||||
AC_CHECK_SIZEOF(int)
|
||||
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
|
||||
AC_SUBST(OTHER_OBJS)
|
||||
AC_SUBST(PADLL)
|
||||
AC_SUBST(SHARED_FLAGS)
|
||||
AC_SUBST(THREAD_CFLAGS)
|
||||
AC_SUBST(DLL_LIBS)
|
||||
AC_SUBST(CXXFLAGS)
|
||||
AC_SUBST(NASM)
|
||||
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
|
||||
CFLAGS="$CFLAGS -DPA_BIG_ENDIAN"
|
||||
@ -101,10 +136,10 @@ case "${host_os}" in
|
||||
dnl Mac OS X configuration
|
||||
|
||||
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";
|
||||
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_asiodir ]] ; then
|
||||
ASIODIR="$with_asiodir";
|
||||
@ -114,7 +149,7 @@ case "${host_os}" in
|
||||
echo "ASIODIR: $ASIODIR";
|
||||
|
||||
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";
|
||||
fi
|
||||
;;
|
||||
@ -130,14 +165,15 @@ case "${host_os}" in
|
||||
DXDIR="/usr/local/dx7sdk";
|
||||
fi
|
||||
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";
|
||||
PADLL="portaudio.dll";
|
||||
SHARED_FLAGS="-shared -mthreads";
|
||||
DLL_LIBS="-lwinmm -lm -L./dx7sdk/lib -ldsound -lole32";
|
||||
THREAD_CFLAGS="-mthreads"
|
||||
SHARED_FLAGS="-shared";
|
||||
DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L./dx7sdk/lib -ldsound -lole32";
|
||||
#VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"";
|
||||
#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
|
||||
if [[ $with_asiodir ]] ; then
|
||||
ASIODIR="$with_asiodir";
|
||||
@ -146,12 +182,13 @@ case "${host_os}" in
|
||||
fi
|
||||
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";
|
||||
PADLL="portaudio.dll";
|
||||
SHARED_FLAGS="-shared -mthreads";
|
||||
DLL_LIBS="-lwinmm -lm -lstdc++ -lole32 -luuid";
|
||||
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";
|
||||
THREAD_CFLAGS="-mthreads"
|
||||
SHARED_FLAGS="-shared";
|
||||
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";
|
||||
elif [[ $with_winapi = "wdmks" ]] ; then
|
||||
if [[ $with_dxdir ]] ; then
|
||||
@ -160,32 +197,35 @@ case "${host_os}" in
|
||||
DXDIR="/usr/local/dx7sdk";
|
||||
fi
|
||||
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";
|
||||
PADLL="portaudio.dll";
|
||||
SHARED_FLAGS="-shared -mthreads";
|
||||
DLL_LIBS="-lwinmm -lm -L./dx7sdk/lib -luuid -lsetupapi -lole32";
|
||||
THREAD_CFLAGS="-mthreads"
|
||||
SHARED_FLAGS="-shared";
|
||||
DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L./dx7sdk/lib -luuid -lsetupapi -lole32";
|
||||
#VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\"";
|
||||
#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
|
||||
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";
|
||||
PADLL="portaudio.dll";
|
||||
SHARED_FLAGS="-shared -mthreads";
|
||||
DLL_LIBS="-lwinmm";
|
||||
CFLAGS="$CFLAGS -Ipa_common -DPA_NO_DS -DPA_NO_ASIO -DPA_NO_WDMKS";
|
||||
THREAD_CFLAGS="-mthreads"
|
||||
SHARED_FLAGS="-shared";
|
||||
DLL_LIBS="${DLL_LIBS} -lwinmm";
|
||||
CFLAGS="$CFLAGS -I\$(top_srcdir)/src/common -DPA_NO_DS -DPA_NO_ASIO -DPA_NO_WDMKS";
|
||||
fi
|
||||
;;
|
||||
|
||||
cygwin* )
|
||||
dnl Cygwin configuration
|
||||
|
||||
OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
|
||||
OTHER_OBJS="src/hostapi/wmme/pa_win_wmme.o";
|
||||
LIBS="-lwinmm -lm";
|
||||
PADLL="portaudio.dll";
|
||||
SHARED_FLAGS="-shared -mthreads";
|
||||
DLL_LIBS="-lwinmm";
|
||||
THREAD_CFLAGS="-mthreads"
|
||||
SHARED_FLAGS="-shared";
|
||||
DLL_LIBS="${DLL_LIBS} -lwinmm";
|
||||
;;
|
||||
|
||||
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
|
||||
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
|
||||
LIBS="-lm -ldmedia -laudio -lpthread";
|
||||
PADLL="libportaudio.so";
|
||||
SHARED_FLAGS="-shared";
|
||||
SHARED_FLAGS="";
|
||||
;;
|
||||
|
||||
*)
|
||||
dnl Unix configuration
|
||||
|
||||
AC_CHECK_LIB(pthread, pthread_create,
|
||||
AC_CHECK_LIB(pthread, pthread_create,[have_pthread="yes"]
|
||||
,
|
||||
AC_MSG_ERROR([libpthread not found!]))
|
||||
|
||||
if [[ $have_alsa = "yes" ] && [ $with_alsa != "no" ]] ; then
|
||||
LIBS="$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)
|
||||
fi
|
||||
|
||||
if [[ $have_jack = "yes" ] && [ $with_jack != "no" ]] ; then
|
||||
LIBS="$LIBS $JACK_LIBS"
|
||||
DLL_LIBS="$DLL_LIBS $JACK_LIBS"
|
||||
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)
|
||||
fi
|
||||
|
||||
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)
|
||||
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";
|
||||
PADLL="libportaudio.so";
|
||||
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
|
||||
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…
Reference in New Issue
Block a user