mirror of https://github.com/PCSX2/pcsx2.git
Fetched a snapshot of the source from portaudio site, and embedded it into the project. I might have missed something, so this will need some more work before it's fully stable.
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2441 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
de4f27d421
commit
f878a438ff
|
@ -0,0 +1,239 @@
|
||||||
|
# Doxyfile 1.4.6
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Project related configuration options
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
PROJECT_NAME = PortAudio
|
||||||
|
PROJECT_NUMBER = 2.0
|
||||||
|
OUTPUT_DIRECTORY = ./doc/
|
||||||
|
CREATE_SUBDIRS = NO
|
||||||
|
OUTPUT_LANGUAGE = English
|
||||||
|
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 =
|
||||||
|
STRIP_FROM_INC_PATH =
|
||||||
|
SHORT_NAMES = NO
|
||||||
|
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
|
||||||
|
SORT_BRIEF_DOCS = NO
|
||||||
|
SORT_BY_SCOPE_NAME = NO
|
||||||
|
GENERATE_TODOLIST = YES
|
||||||
|
GENERATE_TESTLIST = YES
|
||||||
|
GENERATE_BUGLIST = YES
|
||||||
|
GENERATE_DEPRECATEDLIST= YES
|
||||||
|
ENABLED_SECTIONS =
|
||||||
|
MAX_INITIALIZER_LINES = 30
|
||||||
|
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 = doc/src \
|
||||||
|
src \
|
||||||
|
include \
|
||||||
|
test
|
||||||
|
FILE_PATTERNS = *.h \
|
||||||
|
*.c \
|
||||||
|
*.cpp \
|
||||||
|
*.dox
|
||||||
|
RECURSIVE = YES
|
||||||
|
EXCLUDE =
|
||||||
|
EXCLUDE_SYMLINKS = NO
|
||||||
|
EXCLUDE_PATTERNS =
|
||||||
|
EXAMPLE_PATH =
|
||||||
|
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
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
ALPHABETICAL_INDEX = NO
|
||||||
|
COLS_IN_ALPHA_INDEX = 5
|
||||||
|
IGNORE_PREFIX =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the HTML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_HTML = YES
|
||||||
|
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
|
||||||
|
DISABLE_INDEX = NO
|
||||||
|
ENUM_VALUES_PER_LINE = 4
|
||||||
|
GENERATE_TREEVIEW = NO
|
||||||
|
TREEVIEW_WIDTH = 250
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the LaTeX output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
LATEX_OUTPUT = latex
|
||||||
|
LATEX_CMD_NAME = latex
|
||||||
|
MAKEINDEX_CMD_NAME = makeindex
|
||||||
|
COMPACT_LATEX = NO
|
||||||
|
PAPER_TYPE = a4wide
|
||||||
|
EXTRA_PACKAGES =
|
||||||
|
LATEX_HEADER =
|
||||||
|
PDF_HYPERLINKS = NO
|
||||||
|
USE_PDFLATEX = NO
|
||||||
|
LATEX_BATCHMODE = NO
|
||||||
|
LATEX_HIDE_INDICES = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the RTF output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_RTF = NO
|
||||||
|
RTF_OUTPUT = rtf
|
||||||
|
COMPACT_RTF = NO
|
||||||
|
RTF_HYPERLINKS = NO
|
||||||
|
RTF_STYLESHEET_FILE =
|
||||||
|
RTF_EXTENSIONS_FILE =
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the man page output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_MAN = NO
|
||||||
|
MAN_OUTPUT = man
|
||||||
|
MAN_EXTENSION = .3
|
||||||
|
MAN_LINKS = NO
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# configuration options related to the XML output
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
GENERATE_XML = NO
|
||||||
|
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
|
||||||
|
MACRO_EXPANSION = NO
|
||||||
|
EXPAND_ONLY_PREDEF = NO
|
||||||
|
SEARCH_INCLUDES = YES
|
||||||
|
INCLUDE_PATH =
|
||||||
|
INCLUDE_FILE_PATTERNS =
|
||||||
|
PREDEFINED =
|
||||||
|
EXPAND_AS_DEFINED =
|
||||||
|
SKIP_FUNCTION_MACROS = YES
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration::additions related to external references
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
TAGFILES =
|
||||||
|
GENERATE_TAGFILE =
|
||||||
|
ALLEXTERNALS = NO
|
||||||
|
EXTERNAL_GROUPS = YES
|
||||||
|
PERL_PATH = /usr/bin/perl
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
# Configuration options related to the dot tool
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
CLASS_DIAGRAMS = NO
|
||||||
|
HIDE_UNDOC_RELATIONS = NO
|
||||||
|
HAVE_DOT = NO
|
||||||
|
CLASS_GRAPH = YES
|
||||||
|
COLLABORATION_GRAPH = YES
|
||||||
|
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::additions related to the search engine
|
||||||
|
#---------------------------------------------------------------------------
|
||||||
|
SEARCHENGINE = NO
|
|
@ -0,0 +1,81 @@
|
||||||
|
Portable header file to contain:
|
||||||
|
>>>>>
|
||||||
|
/*
|
||||||
|
* PortAudio Portable Real-Time Audio Library
|
||||||
|
* PortAudio API Header File
|
||||||
|
* Latest version available at: http://www.portaudio.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 1999-2006 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
<<<<<
|
||||||
|
|
||||||
|
|
||||||
|
Implementation files to contain:
|
||||||
|
>>>>>
|
||||||
|
/*
|
||||||
|
* PortAudio Portable Real-Time Audio Library
|
||||||
|
* Latest version at: http://www.portaudio.com
|
||||||
|
* <platform> Implementation
|
||||||
|
* Copyright (c) 1999-2000 <author(s)>
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||||
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||||
|
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
<<<<<
|
|
@ -0,0 +1,223 @@
|
||||||
|
#
|
||||||
|
# PortAudio V19 Makefile.in
|
||||||
|
#
|
||||||
|
# Dominic Mazzoni
|
||||||
|
# Modifications by Mikael Magnusson
|
||||||
|
# Modifications by Stelios Bounanos
|
||||||
|
#
|
||||||
|
|
||||||
|
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@
|
||||||
|
CXX = @CXX@
|
||||||
|
CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/common -I$(top_srcdir)/src/os/unix @CFLAGS@ @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_CURRENT=@LT_CURRENT@
|
||||||
|
LT_REVISION=@LT_REVISION@
|
||||||
|
LT_AGE=@LT_AGE@
|
||||||
|
|
||||||
|
OTHER_OBJS = @OTHER_OBJS@
|
||||||
|
|
||||||
|
PALIB = libportaudio.la
|
||||||
|
PAINC = include/portaudio.h
|
||||||
|
|
||||||
|
PA_LDFLAGS = $(LDFLAGS) $(SHARED_FLAGS) -rpath $(libdir) -no-undefined \
|
||||||
|
-export-symbols-regex "(Pa|PaMacCore|PaJack|PaAlsa|PaAsio)_.*" \
|
||||||
|
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
||||||
|
|
||||||
|
COMMON_OBJS = \
|
||||||
|
src/common/pa_allocation.o \
|
||||||
|
src/common/pa_converters.o \
|
||||||
|
src/common/pa_cpuload.o \
|
||||||
|
src/common/pa_dither.o \
|
||||||
|
src/common/pa_debugprint.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 \
|
||||||
|
bin/paqa_errs \
|
||||||
|
bin/patest1 \
|
||||||
|
bin/patest_buffer \
|
||||||
|
bin/patest_callbackstop \
|
||||||
|
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_prime \
|
||||||
|
bin/patest_read_record \
|
||||||
|
bin/patest_read_write_wire \
|
||||||
|
bin/patest_record \
|
||||||
|
bin/patest_ringmix \
|
||||||
|
bin/patest_saw \
|
||||||
|
bin/patest_sine8 \
|
||||||
|
bin/patest_sine \
|
||||||
|
bin/patest_sine_channelmaps \
|
||||||
|
bin/patest_sine_formats \
|
||||||
|
bin/patest_sine_time \
|
||||||
|
bin/patest_sine_srate \
|
||||||
|
bin/patest_start_stop \
|
||||||
|
bin/patest_stop \
|
||||||
|
bin/patest_stop_playout \
|
||||||
|
bin/patest_toomanysines \
|
||||||
|
bin/patest_underflow \
|
||||||
|
bin/patest_wire \
|
||||||
|
bin/patest_write_sine \
|
||||||
|
bin/pa_devs \
|
||||||
|
bin/pa_fuzz \
|
||||||
|
bin/pa_minlat
|
||||||
|
|
||||||
|
# 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 \
|
||||||
|
bin/debug_multi_in \
|
||||||
|
bin/debug_multi_out \
|
||||||
|
bin/debug_record \
|
||||||
|
bin/debug_record_reuse \
|
||||||
|
bin/debug_sine_amp \
|
||||||
|
bin/debug_sine \
|
||||||
|
bin/debug_sine_formats \
|
||||||
|
bin/debug_srate \
|
||||||
|
bin/debug_test1
|
||||||
|
|
||||||
|
OBJS := $(COMMON_OBJS) $(OTHER_OBJS)
|
||||||
|
|
||||||
|
LTOBJS := $(OBJS:.o=.lo)
|
||||||
|
|
||||||
|
SRC_DIRS = \
|
||||||
|
src/common \
|
||||||
|
src/hostapi/alsa \
|
||||||
|
src/hostapi/asihpi \
|
||||||
|
src/hostapi/asio \
|
||||||
|
src/hostapi/coreaudio \
|
||||||
|
src/hostapi/dsound \
|
||||||
|
src/hostapi/jack \
|
||||||
|
src/hostapi/oss \
|
||||||
|
src/hostapi/wasapi \
|
||||||
|
src/hostapi/wdmks \
|
||||||
|
src/hostapi/wmme \
|
||||||
|
src/os/mac_osx \
|
||||||
|
src/os/unix \
|
||||||
|
src/os/win
|
||||||
|
|
||||||
|
SUBDIRS =
|
||||||
|
@ENABLE_CXX_TRUE@SUBDIRS += bindings/cpp
|
||||||
|
|
||||||
|
all: lib/$(PALIB) all-recursive tests
|
||||||
|
|
||||||
|
tests: bin-stamp $(TESTS)
|
||||||
|
|
||||||
|
|
||||||
|
# With ASIO enabled we must link libportaudio and all test programs with CXX
|
||||||
|
lib/$(PALIB): lib-stamp $(LTOBJS) $(MAKEFILE) $(PAINC)
|
||||||
|
@WITH_ASIO_FALSE@ $(LIBTOOL) --mode=link $(CC) $(PA_LDFLAGS) -o lib/$(PALIB) $(LTOBJS) $(DLL_LIBS)
|
||||||
|
@WITH_ASIO_TRUE@ $(LIBTOOL) --mode=link --tag=CXX $(CXX) $(PA_LDFLAGS) -o lib/$(PALIB) $(LTOBJS) $(DLL_LIBS)
|
||||||
|
|
||||||
|
$(ALL_TESTS): bin/%: lib/$(PALIB) $(MAKEFILE) $(PAINC) test/%.c
|
||||||
|
@WITH_ASIO_FALSE@ $(LIBTOOL) --mode=link $(CC) -o $@ $(CFLAGS) $(top_srcdir)/test/$*.c lib/$(PALIB) $(LIBS)
|
||||||
|
@WITH_ASIO_TRUE@ $(LIBTOOL) --mode=link --tag=CXX $(CXX) -o $@ $(CXXFLAGS) $(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."
|
||||||
|
@echo ""
|
||||||
|
@echo "On some systems (e.g. Linux) you should run 'ldconfig' now"
|
||||||
|
@echo "to make the shared object available. You may also need to"
|
||||||
|
@echo "modify your LD_LIBRARY_PATH environment variable to include"
|
||||||
|
@echo "the directory $(libdir)"
|
||||||
|
@echo "------------------------------------------------------------"
|
||||||
|
@echo ""
|
||||||
|
$(MAKE) install-recursive
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$(PALIB)
|
||||||
|
$(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(includedir)/portaudio.h
|
||||||
|
$(MAKE) uninstall-recursive
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(LIBTOOL) --mode=clean rm -f $(LTOBJS) $(ALL_TESTS) lib/$(PALIB)
|
||||||
|
$(RM) bin-stamp lib-stamp
|
||||||
|
-$(RM) -r bin lib
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
$(RM) config.log config.status Makefile libtool portaudio-2.0.pc
|
||||||
|
|
||||||
|
%.o: %.c $(MAKEFILE) $(PAINC)
|
||||||
|
$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
%.lo: %.c $(MAKEFILE) $(PAINC)
|
||||||
|
$(LIBTOOL) --mode=compile $(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
%.lo: %.cpp $(MAKEFILE) $(PAINC)
|
||||||
|
$(LIBTOOL) --mode=compile --tag=CXX $(CXX) -c $(CXXFLAGS) $< -o $@
|
||||||
|
|
||||||
|
%.o: %.cpp $(MAKEFILE) $(PAINC)
|
||||||
|
$(CXX) -c $(CXXFLAGS) $< -o $@
|
||||||
|
|
||||||
|
%.o: %.asm
|
||||||
|
$(NASM) $(NASMOPT) -o $@ $<
|
||||||
|
|
||||||
|
bin-stamp:
|
||||||
|
-mkdir bin
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
lib-stamp:
|
||||||
|
-mkdir lib
|
||||||
|
-mkdir -p $(SRC_DIRS)
|
||||||
|
touch $@
|
||||||
|
|
||||||
|
Makefile: Makefile.in config.status
|
||||||
|
$(SHELL) config.status
|
||||||
|
|
||||||
|
all-recursive:
|
||||||
|
if test -n "$(SUBDIRS)" ; then for dir in "$(SUBDIRS)"; do $(MAKE) -C $$dir all; done ; fi
|
||||||
|
|
||||||
|
install-recursive:
|
||||||
|
if test -n "$(SUBDIRS)" ; then for dir in "$(SUBDIRS)"; do $(MAKE) -C $$dir install; done ; fi
|
||||||
|
|
||||||
|
uninstall-recursive:
|
||||||
|
if test -n "$(SUBDIRS)" ; then for dir in "$(SUBDIRS)"; do $(MAKE) -C $$dir uninstall; done ; fi
|
|
@ -0,0 +1,98 @@
|
||||||
|
README for PortAudio
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PortAudio Portable Real-Time Audio Library
|
||||||
|
* Latest Version at: http://www.portaudio.com
|
||||||
|
*
|
||||||
|
* Copyright (c) 1999-2008 Phil Burk 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
PortAudio is a portable audio I/O library designed for cross-platform
|
||||||
|
support of audio. It uses either a callback mechanism to request audio
|
||||||
|
processing, or blocking read/write calls to buffer data between the
|
||||||
|
native audio subsystem and the client. Audio can be processed in various
|
||||||
|
formats, including 32 bit floating point, and will be converted to the
|
||||||
|
native format internally.
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
Documentation is available in "/doc/html/index.html"
|
||||||
|
Also see "src/common/portaudio.h" for API spec.
|
||||||
|
Also see http://www.portaudio.com/docs/
|
||||||
|
And see the "test/" directory for many examples of usage
|
||||||
|
(we suggest "test/patest_saw.c" for an example)
|
||||||
|
|
||||||
|
For information on compiling programs with PortAudio, please see the
|
||||||
|
tutorial at:
|
||||||
|
|
||||||
|
http://portaudio.com/trac/wiki/TutorialDir/TutorialStart
|
||||||
|
|
||||||
|
We have an active mailing list for user and developer discussions.
|
||||||
|
Please feel free to join. See http://www.portaudio.com for details.
|
||||||
|
|
||||||
|
|
||||||
|
Important Files and Folders:
|
||||||
|
include/portaudio.h = header file for PortAudio API. Specifies API.
|
||||||
|
src/common/ = platform independant code, host independant
|
||||||
|
code for all implementations.
|
||||||
|
src/os = os specific (but host api neutral) code
|
||||||
|
src/hostapi = implementations for different host apis
|
||||||
|
|
||||||
|
|
||||||
|
Host API Implementations:
|
||||||
|
src/hostapi/alsa = Advanced Linux Sound Architecture (ALSA)
|
||||||
|
src/hostapi/asihpi = AudioScience HPI
|
||||||
|
src/hostapi/asio = ASIO for Windows and Macintosh
|
||||||
|
src/hostapi/coreaudio = Macintosh Core Audio for OS X
|
||||||
|
src/hostapi/dsound = Windows Direct Sound
|
||||||
|
src/hostapi/jack = JACK Audio Connection Kit
|
||||||
|
src/hostapi/oss = Unix Open Sound System (OSS)
|
||||||
|
src/hostapi/wasapi = Windows Vista WASAPI
|
||||||
|
src/hostapi/wdmks = Windows WDM Kernel Streaming
|
||||||
|
src/hostapi/wmme = Windows MultiMedia Extensions (MME)
|
||||||
|
|
||||||
|
|
||||||
|
Test Programs:
|
||||||
|
test/pa_fuzz.c = guitar fuzz box
|
||||||
|
test/pa_devs.c = print a list of available devices
|
||||||
|
test/pa_minlat.c = determine minimum latency for your machine
|
||||||
|
test/paqa_devs.c = self test that opens all devices
|
||||||
|
test/paqa_errs.c = test error detection and reporting
|
||||||
|
test/patest_clip.c = hear a sine wave clipped and unclipped
|
||||||
|
test/patest_dither.c = hear effects of dithering (extremely subtle)
|
||||||
|
test/patest_pink.c = fun with pink noise
|
||||||
|
test/patest_record.c = record and playback some audio
|
||||||
|
test/patest_maxsines.c = how many sine waves can we play? Tests Pa_GetCPULoad().
|
||||||
|
test/patest_sine.c = output a sine wave in a simple PA app
|
||||||
|
test/patest_sync.c = test syncronization of audio and video
|
||||||
|
test/patest_wire.c = pass input to output, wire simulator
|
|
@ -0,0 +1,197 @@
|
||||||
|
import sys, os.path
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
toSplit, splitOff = toSplit[:idx], toSplit[idx + len(sub):]
|
||||||
|
l.insert(0, splitOff)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
l.insert(0, toSplit)
|
||||||
|
return l
|
||||||
|
|
||||||
|
sconsDir = os.path.join("build", "scons")
|
||||||
|
SConscript(os.path.join(sconsDir, "SConscript_common"))
|
||||||
|
Import("Platform", "Posix", "ApiVer")
|
||||||
|
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
buildDir = os.path.join("#", sconsDir, env["PLATFORM"])
|
||||||
|
|
||||||
|
# Determine parameters to build tools
|
||||||
|
if Platform in Posix:
|
||||||
|
threadCFlags = ''
|
||||||
|
if Platform != 'darwin':
|
||||||
|
threadCFlags = "-pthread "
|
||||||
|
baseLinkFlags = threadCFlags
|
||||||
|
baseCxxFlags = baseCFlags = "-Wall -pedantic -pipe " + threadCFlags
|
||||||
|
debugCxxFlags = debugCFlags = "-g"
|
||||||
|
optCxxFlags = optCFlags = "-O2"
|
||||||
|
env.Append(CCFLAGS = baseCFlags)
|
||||||
|
env.Append(CXXFLAGS = baseCxxFlags)
|
||||||
|
env.Append(LINKFLAGS = baseLinkFlags)
|
||||||
|
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=Split(env["customCFlags"]))
|
||||||
|
if env["customCxxFlags"]:
|
||||||
|
env.Append(CXXFLAGS=Split(env["customCxxFlags"]))
|
||||||
|
if env["customLinkFlags"]:
|
||||||
|
env.Append(LINKFLAGS=Split(env["customLinkFlags"]))
|
||||||
|
|
||||||
|
env.Append(CPPPATH=[os.path.join("#", "include"), "common"])
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
sources, sharedLib, staticLib, tests, portEnv, hostApis = 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)
|
||||||
|
|
||||||
|
# Generate portaudio_config.h header with compile-time definitions of which PA
|
||||||
|
# back-ends are available, and which includes back-end extension headers
|
||||||
|
|
||||||
|
# Host-specific headers
|
||||||
|
hostApiHeaders = {"ALSA": "pa_linux_alsa.h",
|
||||||
|
"ASIO": "pa_asio.h",
|
||||||
|
"COREAUDIO": "pa_mac_core.h",
|
||||||
|
"JACK": "pa_jack.h",
|
||||||
|
"WMME": "pa_winwmme.h",
|
||||||
|
}
|
||||||
|
|
||||||
|
def buildConfigH(target, source, env):
|
||||||
|
"""builder for portaudio_config.h"""
|
||||||
|
global hostApiHeaders, hostApis
|
||||||
|
out = ""
|
||||||
|
for hostApi in hostApis:
|
||||||
|
out += "#define PA_HAVE_%s\n" % hostApi
|
||||||
|
|
||||||
|
hostApiSpecificHeader = hostApiHeaders.get(hostApi, None)
|
||||||
|
if hostApiSpecificHeader:
|
||||||
|
out += "#include \"%s\"\n" % hostApiSpecificHeader
|
||||||
|
|
||||||
|
out += "\n"
|
||||||
|
# Strip the last newline
|
||||||
|
if out and out[-1] == "\n":
|
||||||
|
out = out[:-1]
|
||||||
|
|
||||||
|
f = file(str(target[0]), 'w')
|
||||||
|
try: f.write(out)
|
||||||
|
finally: f.close()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
# Define the builder for the config header
|
||||||
|
env.Append(BUILDERS={"portaudioConfig": env.Builder(
|
||||||
|
action=Action(buildConfigH), target_factory=env.fs.File)})
|
||||||
|
|
||||||
|
confH = env.portaudioConfig(File("portaudio_config.h", "include"),
|
||||||
|
File("portaudio.h", "include"))
|
||||||
|
env.Default(confH)
|
||||||
|
env.Install(os.path.join(includeDir, "portaudio"), confH)
|
||||||
|
|
||||||
|
for api in hostApis:
|
||||||
|
if api in hostApiHeaders:
|
||||||
|
env.Install(os.path.join(includeDir, "portaudio"),
|
||||||
|
File(hostApiHeaders[api], "include"))
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,78 @@
|
||||||
|
# Project: portaudio-dll
|
||||||
|
# Makefile created by Dev-C++ 4.9.8.2
|
||||||
|
|
||||||
|
CPP = g++.exe
|
||||||
|
CC = gcc.exe
|
||||||
|
WINDRES = windres.exe
|
||||||
|
RES =
|
||||||
|
OBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES)
|
||||||
|
LINKOBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES)
|
||||||
|
LIBS = -L"C:/Dev-CPP/lib" -fmessage-length=0 --no-export-all-symbols --add-stdcall-alias ../../../asiosdk2/asiosdk2.a -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lwinmm -O3 -s
|
||||||
|
INCS = -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common"
|
||||||
|
CXXINCS = -I"C:/Dev-CPP/include/c++" -I"C:/Dev-CPP/include/c++/mingw32" -I"C:/Dev-CPP/include/c++/backward" -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common"
|
||||||
|
BIN = portaudio-dll.dll
|
||||||
|
CXXFLAGS = $(CXXINCS)-O3 -fmessage-length=0 -Wall
|
||||||
|
CFLAGS = $(INCS)-DBUILDING_DLL=1 -O3 -fmessage-length=0 -Wall
|
||||||
|
|
||||||
|
.PHONY: all all-before all-after clean clean-custom
|
||||||
|
|
||||||
|
all: all-before portaudio-dll.dll all-after
|
||||||
|
|
||||||
|
|
||||||
|
clean: clean-custom
|
||||||
|
rm -f $(OBJ) $(BIN)
|
||||||
|
|
||||||
|
DLLWRAP=dllwrap.exe
|
||||||
|
DEFFILE=libportaudio-dll.def
|
||||||
|
STATICLIB=libportaudio-dll.a
|
||||||
|
|
||||||
|
$(BIN): $(LINKOBJ)
|
||||||
|
$(DLLWRAP) --output-def $(DEFFILE) --driver-name c++ --implib $(STATICLIB) $(LINKOBJ) $(LIBS) -o $(BIN)
|
||||||
|
|
||||||
|
./pa_skeleton.o: ../../pa_common/pa_skeleton.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_skeleton.c -o ./pa_skeleton.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_stream.o: ../../pa_common/pa_stream.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_stream.c -o ./pa_stream.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_trace.o: ../../pa_common/pa_trace.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_trace.c -o ./pa_trace.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_allocation.o: ../../pa_common/pa_allocation.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_allocation.c -o ./pa_allocation.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_converters.o: ../../pa_common/pa_converters.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_converters.c -o ./pa_converters.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_cpuload.o: ../../pa_common/pa_cpuload.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_cpuload.c -o ./pa_cpuload.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_dither.o: ../../pa_common/pa_dither.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_dither.c -o ./pa_dither.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_front.o: ../../pa_common/pa_front.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_front.c -o ./pa_front.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_process.o: ../../pa_common/pa_process.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_process.c -o ./pa_process.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_asio.o: ../../pa_asio/pa_asio.cpp
|
||||||
|
$(CPP) -c ../../pa_asio/pa_asio.cpp -o ./pa_asio.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_win_util.o: ../pa_win_util.c
|
||||||
|
$(CPP) -c ../pa_win_util.c -o ./pa_win_util.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_win_hostapis.o: ../pa_win_hostapis.c
|
||||||
|
$(CPP) -c ../pa_win_hostapis.c -o ./pa_win_hostapis.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_win_ds.o: ../../pa_win_ds/pa_win_ds.c
|
||||||
|
$(CPP) -c ../../pa_win_ds/pa_win_ds.c -o ./pa_win_ds.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./dsound_wrapper.o: ../../pa_win_ds/dsound_wrapper.c
|
||||||
|
$(CPP) -c ../../pa_win_ds/dsound_wrapper.c -o ./dsound_wrapper.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_win_wmme.o: ../../pa_win_wmme/pa_win_wmme.c
|
||||||
|
$(CPP) -c ../../pa_win_wmme/pa_win_wmme.c -o ./pa_win_wmme.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./iasiothiscallresolver.o: ../../pa_asio/iasiothiscallresolver.cpp
|
||||||
|
$(CPP) -c ../../pa_asio/iasiothiscallresolver.cpp -o ./iasiothiscallresolver.o $(CXXFLAGS)
|
|
@ -0,0 +1,75 @@
|
||||||
|
# Project: portaudio-static
|
||||||
|
# Makefile created by Dev-C++ 4.9.8.2
|
||||||
|
|
||||||
|
CPP = g++.exe
|
||||||
|
CC = gcc.exe
|
||||||
|
WINDRES = windres.exe
|
||||||
|
RES =
|
||||||
|
OBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES)
|
||||||
|
LINKOBJ = ./pa_skeleton.o ./pa_stream.o ./pa_trace.o ./pa_allocation.o ./pa_converters.o ./pa_cpuload.o ./pa_dither.o ./pa_front.o ./pa_process.o ./pa_asio.o ./pa_win_util.o ./pa_win_hostapis.o ./pa_win_ds.o ./dsound_wrapper.o ./pa_win_wmme.o ./iasiothiscallresolver.o $(RES)
|
||||||
|
LIBS = -L"C:/Dev-CPP/lib" -fmessage-length=0 -O3 -s
|
||||||
|
INCS = -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common"
|
||||||
|
CXXINCS = -I"C:/Dev-CPP/include/c++" -I"C:/Dev-CPP/include/c++/mingw32" -I"C:/Dev-CPP/include/c++/backward" -I"C:/Dev-CPP/include" -I"../../../asiosdk2" -I"../../../asiosdk2/common" -I"../../../asiosdk2/host" -I"../../../asiosdk2/host/pc" -I"../../pa_common"
|
||||||
|
BIN = portaudio-static.a
|
||||||
|
CXXFLAGS = $(CXXINCS)-O3 -fmessage-length=0 -Wall
|
||||||
|
CFLAGS = $(INCS)-O3 -fmessage-length=0 -Wall
|
||||||
|
|
||||||
|
.PHONY: all all-before all-after clean clean-custom
|
||||||
|
|
||||||
|
all: all-before portaudio-static.a all-after
|
||||||
|
|
||||||
|
|
||||||
|
clean: clean-custom
|
||||||
|
rm -f $(OBJ) $(BIN)
|
||||||
|
|
||||||
|
$(BIN): $(LINKOBJ)
|
||||||
|
ar r $(BIN) $(LINKOBJ)
|
||||||
|
ranlib $(BIN)
|
||||||
|
|
||||||
|
./pa_skeleton.o: ../../pa_common/pa_skeleton.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_skeleton.c -o ./pa_skeleton.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_stream.o: ../../pa_common/pa_stream.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_stream.c -o ./pa_stream.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_trace.o: ../../pa_common/pa_trace.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_trace.c -o ./pa_trace.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_allocation.o: ../../pa_common/pa_allocation.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_allocation.c -o ./pa_allocation.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_converters.o: ../../pa_common/pa_converters.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_converters.c -o ./pa_converters.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_cpuload.o: ../../pa_common/pa_cpuload.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_cpuload.c -o ./pa_cpuload.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_dither.o: ../../pa_common/pa_dither.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_dither.c -o ./pa_dither.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_front.o: ../../pa_common/pa_front.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_front.c -o ./pa_front.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_process.o: ../../pa_common/pa_process.c
|
||||||
|
$(CPP) -c ../../pa_common/pa_process.c -o ./pa_process.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_asio.o: ../../pa_asio/pa_asio.cpp
|
||||||
|
$(CPP) -c ../../pa_asio/pa_asio.cpp -o ./pa_asio.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_win_util.o: ../pa_win_util.c
|
||||||
|
$(CPP) -c ../pa_win_util.c -o ./pa_win_util.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_win_hostapis.o: ../pa_win_hostapis.c
|
||||||
|
$(CPP) -c ../pa_win_hostapis.c -o ./pa_win_hostapis.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_win_ds.o: ../../pa_win_ds/pa_win_ds.c
|
||||||
|
$(CPP) -c ../../pa_win_ds/pa_win_ds.c -o ./pa_win_ds.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./dsound_wrapper.o: ../../pa_win_ds/dsound_wrapper.c
|
||||||
|
$(CPP) -c ../../pa_win_ds/dsound_wrapper.c -o ./dsound_wrapper.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./pa_win_wmme.o: ../../pa_win_wmme/pa_win_wmme.c
|
||||||
|
$(CPP) -c ../../pa_win_wmme/pa_win_wmme.c -o ./pa_win_wmme.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
./iasiothiscallresolver.o: ../../pa_asio/iasiothiscallresolver.cpp
|
||||||
|
$(CPP) -c ../../pa_asio/iasiothiscallresolver.cpp -o ./iasiothiscallresolver.o $(CXXFLAGS)
|
|
@ -0,0 +1,209 @@
|
||||||
|
[Project]
|
||||||
|
FileName=portaudio-dll.dev
|
||||||
|
Name=portaudio-dll
|
||||||
|
UnitCount=16
|
||||||
|
Type=3
|
||||||
|
Ver=1
|
||||||
|
ObjFiles=
|
||||||
|
Includes=..\..\..\asiosdk2;..\..\..\asiosdk2\common;..\..\..\asiosdk2\host;..\..\..\asiosdk2\host\pc;..\..\pa_common
|
||||||
|
Libs=
|
||||||
|
PrivateResource=
|
||||||
|
ResourceIncludes=
|
||||||
|
MakeIncludes=
|
||||||
|
Compiler=-DBUILDING_DLL=1_@@_-O3_@@_
|
||||||
|
CppCompiler=-O3_@@_
|
||||||
|
Linker=--no-export-all-symbols --add-stdcall-alias_@@_../../../asiosdk2/asiosdk2.a_@@_-lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -lwinmm_@@_-O3 -s_@@_
|
||||||
|
IsCpp=1
|
||||||
|
Icon=
|
||||||
|
ExeOutput=.
|
||||||
|
ObjectOutput=.
|
||||||
|
OverrideOutput=0
|
||||||
|
OverrideOutputName=portaudio.a
|
||||||
|
HostApplication=
|
||||||
|
Folders=
|
||||||
|
CommandLine=
|
||||||
|
IncludeVersionInfo=0
|
||||||
|
SupportXPThemes=0
|
||||||
|
CompilerSet=0
|
||||||
|
CompilerSettings=0000000000000000000
|
||||||
|
UseCustomMakefile=0
|
||||||
|
CustomMakefile=
|
||||||
|
|
||||||
|
[Unit1]
|
||||||
|
FileName=..\..\pa_common\pa_skeleton.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_skeleton.c -o ./pa_skeleton.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit2]
|
||||||
|
FileName=..\..\pa_common\pa_stream.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_stream.c -o ./pa_stream.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit3]
|
||||||
|
FileName=..\..\pa_common\pa_trace.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_trace.c -o ./pa_trace.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit4]
|
||||||
|
FileName=..\..\pa_common\pa_allocation.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_allocation.c -o ./pa_allocation.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit5]
|
||||||
|
FileName=..\..\pa_common\pa_converters.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_converters.c -o ./pa_converters.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit6]
|
||||||
|
FileName=..\..\pa_common\pa_cpuload.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_cpuload.c -o ./pa_cpuload.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit7]
|
||||||
|
FileName=..\..\pa_common\pa_dither.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_dither.c -o ./pa_dither.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit8]
|
||||||
|
FileName=..\..\pa_common\pa_front.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_front.c -o ./pa_front.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit9]
|
||||||
|
FileName=..\..\pa_common\pa_process.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_process.c -o ./pa_process.o $(CFLAGS)
|
||||||
|
|
||||||
|
[VersionInfo]
|
||||||
|
Major=0
|
||||||
|
Minor=1
|
||||||
|
Release=1
|
||||||
|
Build=1
|
||||||
|
LanguageID=1033
|
||||||
|
CharsetID=1252
|
||||||
|
CompanyName=
|
||||||
|
FileVersion=
|
||||||
|
FileDescription=Developed using the Dev-C++ IDE
|
||||||
|
InternalName=
|
||||||
|
LegalCopyright=
|
||||||
|
LegalTrademarks=
|
||||||
|
OriginalFilename=
|
||||||
|
ProductName=
|
||||||
|
ProductVersion=
|
||||||
|
AutoIncBuildNr=0
|
||||||
|
|
||||||
|
[Unit10]
|
||||||
|
FileName=..\..\pa_asio\pa_asio.cpp
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CPP) -c pa_asio.cpp -o ./pa_asio.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
[Unit11]
|
||||||
|
FileName=..\pa_win_util.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_win_util.c -o ./pa_win_util.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit12]
|
||||||
|
FileName=..\pa_win_hostapis.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_win_hostapis.c -o ./pa_win_hostapis.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit13]
|
||||||
|
FileName=..\..\pa_win_ds\pa_win_ds.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_win_ds.c -o ./pa_win_ds.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit14]
|
||||||
|
FileName=..\..\pa_win_ds\dsound_wrapper.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c dsound_wrapper.c -o ./dsound_wrapper.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit15]
|
||||||
|
FileName=..\..\pa_win_wmme\pa_win_wmme.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_win_wmme.c -o ./pa_win_wmme.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit16]
|
||||||
|
FileName=..\..\pa_asio\iasiothiscallresolver.cpp
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
[Project]
|
||||||
|
FileName=portaudio-static.dev
|
||||||
|
Name=portaudio-static
|
||||||
|
UnitCount=16
|
||||||
|
Type=2
|
||||||
|
Ver=1
|
||||||
|
ObjFiles=
|
||||||
|
Includes=..\..\..\asiosdk2;..\..\..\asiosdk2\common;..\..\..\asiosdk2\host;..\..\..\asiosdk2\host\pc;..\..\pa_common
|
||||||
|
Libs=
|
||||||
|
PrivateResource=
|
||||||
|
ResourceIncludes=
|
||||||
|
MakeIncludes=
|
||||||
|
Compiler=-O3_@@_
|
||||||
|
CppCompiler=-O3_@@_
|
||||||
|
Linker=-O3 -s_@@_
|
||||||
|
IsCpp=1
|
||||||
|
Icon=
|
||||||
|
ExeOutput=.
|
||||||
|
ObjectOutput=.
|
||||||
|
OverrideOutput=0
|
||||||
|
OverrideOutputName=portaudio.a
|
||||||
|
HostApplication=
|
||||||
|
Folders=
|
||||||
|
CommandLine=
|
||||||
|
IncludeVersionInfo=0
|
||||||
|
SupportXPThemes=0
|
||||||
|
CompilerSet=0
|
||||||
|
CompilerSettings=0000000000000000000
|
||||||
|
UseCustomMakefile=0
|
||||||
|
CustomMakefile=
|
||||||
|
|
||||||
|
[Unit1]
|
||||||
|
FileName=..\..\pa_common\pa_skeleton.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_skeleton.c -o ./pa_skeleton.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit2]
|
||||||
|
FileName=..\..\pa_common\pa_stream.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_stream.c -o ./pa_stream.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit3]
|
||||||
|
FileName=..\..\pa_common\pa_trace.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_trace.c -o ./pa_trace.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit4]
|
||||||
|
FileName=..\..\pa_common\pa_allocation.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_allocation.c -o ./pa_allocation.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit5]
|
||||||
|
FileName=..\..\pa_common\pa_converters.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_converters.c -o ./pa_converters.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit6]
|
||||||
|
FileName=..\..\pa_common\pa_cpuload.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_cpuload.c -o ./pa_cpuload.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit7]
|
||||||
|
FileName=..\..\pa_common\pa_dither.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_dither.c -o ./pa_dither.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit8]
|
||||||
|
FileName=..\..\pa_common\pa_front.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_front.c -o ./pa_front.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit9]
|
||||||
|
FileName=..\..\pa_common\pa_process.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_process.c -o ./pa_process.o $(CFLAGS)
|
||||||
|
|
||||||
|
[VersionInfo]
|
||||||
|
Major=0
|
||||||
|
Minor=1
|
||||||
|
Release=1
|
||||||
|
Build=1
|
||||||
|
LanguageID=1033
|
||||||
|
CharsetID=1252
|
||||||
|
CompanyName=
|
||||||
|
FileVersion=
|
||||||
|
FileDescription=Developed using the Dev-C++ IDE
|
||||||
|
InternalName=
|
||||||
|
LegalCopyright=
|
||||||
|
LegalTrademarks=
|
||||||
|
OriginalFilename=
|
||||||
|
ProductName=
|
||||||
|
ProductVersion=
|
||||||
|
AutoIncBuildNr=0
|
||||||
|
|
||||||
|
[Unit10]
|
||||||
|
FileName=..\..\pa_asio\pa_asio.cpp
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CPP) -c pa_asio.cpp -o ./pa_asio.o $(CXXFLAGS)
|
||||||
|
|
||||||
|
[Unit11]
|
||||||
|
FileName=..\..\pa_win\pa_win_util.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_win_util.c -o ./pa_win_util.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit12]
|
||||||
|
FileName=..\..\pa_win\pa_win_hostapis.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_win_hostapis.c -o ./pa_win_hostapis.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit13]
|
||||||
|
FileName=..\..\pa_win_ds\pa_win_ds.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_win_ds.c -o ./pa_win_ds.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit14]
|
||||||
|
FileName=..\..\pa_win_ds\dsound_wrapper.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c dsound_wrapper.c -o ./dsound_wrapper.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit15]
|
||||||
|
FileName=..\..\pa_win_wmme\pa_win_wmme.c
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=$(CC) -c pa_win_wmme.c -o ./pa_win_wmme.o $(CFLAGS)
|
||||||
|
|
||||||
|
[Unit16]
|
||||||
|
FileName=..\..\pa_asio\iasiothiscallresolver.cpp
|
||||||
|
CompileCpp=1
|
||||||
|
Folder=portaudio
|
||||||
|
Compile=1
|
||||||
|
Link=1
|
||||||
|
Priority=1000
|
||||||
|
OverrideBuildCmd=0
|
||||||
|
BuildCmd=
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
From: "Peter L Jones"
|
||||||
|
Sent: Wednesday, September 17, 2003 5:18 AM
|
||||||
|
Subject: Dev-C++ project files
|
||||||
|
|
||||||
|
I attach two project files intended for portaudio/pa_win/dev-cpp (i.e. in
|
||||||
|
parallel with the msvc directory), if you want them. One is for a static
|
||||||
|
library build and one for a DLL. I've used the static library (in building
|
||||||
|
a single monolithic DLL) but I can't guarantee the DLL version will build a
|
||||||
|
working library (I think it's mostly there, though!).
|
||||||
|
|
||||||
|
I also attach the resulting makefiles, which may be of use to other MinGW
|
||||||
|
users.
|
||||||
|
|
||||||
|
They're rooted in the directory given above and drop their object and
|
||||||
|
library files in the same place. They assume the asiosdk2 files are in the
|
||||||
|
same directory as portaudio/ in a sub-directory called asiosdk2/. Oh! The
|
||||||
|
DLL is built against a static asiosdk2.a library... maybe not the best way
|
||||||
|
to do it... I ought to figure out how to link against a "home made" dll in
|
||||||
|
Dev-C++, I guess ;-)
|
||||||
|
|
||||||
|
Cheers,
|
||||||
|
|
||||||
|
-- Peter
|
|
@ -0,0 +1,43 @@
|
||||||
|
EXPORTS
|
||||||
|
|
||||||
|
;
|
||||||
|
Pa_GetVersion @1
|
||||||
|
Pa_GetVersionText @2
|
||||||
|
Pa_GetErrorText @3
|
||||||
|
Pa_Initialize @4
|
||||||
|
Pa_Terminate @5
|
||||||
|
Pa_GetHostApiCount @6
|
||||||
|
Pa_GetDefaultHostApi @7
|
||||||
|
Pa_GetHostApiInfo @8
|
||||||
|
Pa_HostApiTypeIdToHostApiIndex @9
|
||||||
|
Pa_HostApiDeviceIndexToDeviceIndex @10
|
||||||
|
Pa_GetLastHostErrorInfo @11
|
||||||
|
Pa_GetDeviceCount @12
|
||||||
|
Pa_GetDefaultInputDevice @13
|
||||||
|
Pa_GetDefaultOutputDevice @14
|
||||||
|
Pa_GetDeviceInfo @15
|
||||||
|
Pa_IsFormatSupported @16
|
||||||
|
Pa_OpenStream @17
|
||||||
|
Pa_OpenDefaultStream @18
|
||||||
|
Pa_CloseStream @19
|
||||||
|
Pa_SetStreamFinishedCallback @20
|
||||||
|
Pa_StartStream @21
|
||||||
|
Pa_StopStream @22
|
||||||
|
Pa_AbortStream @23
|
||||||
|
Pa_IsStreamStopped @24
|
||||||
|
Pa_IsStreamActive @25
|
||||||
|
Pa_GetStreamInfo @26
|
||||||
|
Pa_GetStreamTime @27
|
||||||
|
Pa_GetStreamCpuLoad @28
|
||||||
|
Pa_ReadStream @29
|
||||||
|
Pa_WriteStream @30
|
||||||
|
Pa_GetStreamReadAvailable @31
|
||||||
|
Pa_GetStreamWriteAvailable @32
|
||||||
|
Pa_GetSampleSize @33
|
||||||
|
Pa_Sleep @34
|
||||||
|
PaAsio_GetAvailableLatencyValues @50
|
||||||
|
PaAsio_ShowControlPanel @51
|
||||||
|
PaUtil_InitializeX86PlainConverters @52
|
||||||
|
PaAsio_GetInputChannelName @53
|
||||||
|
PaAsio_GetOutputChannelName @54
|
||||||
|
PaUtil_SetDebugPrintFunction @55
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,39 @@
|
||||||
|
EXPORTS
|
||||||
|
|
||||||
|
;
|
||||||
|
Pa_GetVersion @1
|
||||||
|
Pa_GetVersionText @2
|
||||||
|
Pa_GetErrorText @3
|
||||||
|
Pa_Initialize @4
|
||||||
|
Pa_Terminate @5
|
||||||
|
Pa_GetHostApiCount @6
|
||||||
|
Pa_GetDefaultHostApi @7
|
||||||
|
Pa_GetHostApiInfo @8
|
||||||
|
Pa_HostApiTypeIdToHostApiIndex @9
|
||||||
|
Pa_HostApiDeviceIndexToDeviceIndex @10
|
||||||
|
Pa_GetLastHostErrorInfo @11
|
||||||
|
Pa_GetDeviceCount @12
|
||||||
|
Pa_GetDefaultInputDevice @13
|
||||||
|
Pa_GetDefaultOutputDevice @14
|
||||||
|
Pa_GetDeviceInfo @15
|
||||||
|
Pa_IsFormatSupported @16
|
||||||
|
Pa_OpenStream @17
|
||||||
|
Pa_OpenDefaultStream @18
|
||||||
|
Pa_CloseStream @19
|
||||||
|
Pa_SetStreamFinishedCallback @20
|
||||||
|
Pa_StartStream @21
|
||||||
|
Pa_StopStream @22
|
||||||
|
Pa_AbortStream @23
|
||||||
|
Pa_IsStreamStopped @24
|
||||||
|
Pa_IsStreamActive @25
|
||||||
|
Pa_GetStreamInfo @26
|
||||||
|
Pa_GetStreamTime @27
|
||||||
|
Pa_GetStreamCpuLoad @28
|
||||||
|
Pa_ReadStream @29
|
||||||
|
Pa_WriteStream @30
|
||||||
|
Pa_GetStreamReadAvailable @31
|
||||||
|
Pa_GetStreamWriteAvailable @32
|
||||||
|
Pa_GetSampleSize @33
|
||||||
|
Pa_Sleep @34
|
||||||
|
PaUtil_InitializeX86PlainConverters @52
|
||||||
|
PaUtil_SetDebugPrintFunction @55
|
|
@ -0,0 +1,30 @@
|
||||||
|
import os.path, sys
|
||||||
|
|
||||||
|
class ConfigurationError(Exception):
|
||||||
|
def __init__(self, reason):
|
||||||
|
Exception.__init__(self, "Configuration failed: %s" % reason)
|
||||||
|
|
||||||
|
env = Environment()
|
||||||
|
|
||||||
|
# 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", "netbsd")
|
||||||
|
Windows = ("win32", "cygwin")
|
||||||
|
|
||||||
|
if env["PLATFORM"] == "posix":
|
||||||
|
if sys.platform[:5] == "linux":
|
||||||
|
Platform = "linux"
|
||||||
|
elif sys.platform[:6] == "netbsd":
|
||||||
|
Platform = "netbsd"
|
||||||
|
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"]
|
||||||
|
|
||||||
|
# Inspired by the versioning scheme followed by Qt, it seems sensible enough. There are three components: major, minor
|
||||||
|
# and micro. Major changes with each subtraction from the API (backward-incompatible, i.e. V19 vs. V18), minor changes
|
||||||
|
# with each addition to the API (backward-compatible), micro changes with each revision of the source code.
|
||||||
|
ApiVer = "2.0.0"
|
||||||
|
|
||||||
|
Export("Platform", "Posix", "ConfigurationError", "ApiVer")
|
|
@ -0,0 +1,91 @@
|
||||||
|
import os.path, sys
|
||||||
|
|
||||||
|
def _PackageOption(pkgName, default=1):
|
||||||
|
""" Allow user to choose whether a package should be used if available. This results in a commandline option use<Pkgname>,
|
||||||
|
where Pkgname is the name of the package with a capitalized first letter.
|
||||||
|
@param pkgName: Name of package.
|
||||||
|
@param default: The default value for this option ("yes"/"no").
|
||||||
|
"""
|
||||||
|
return BoolOption("use%s" % pkgName[0].upper() + pkgName[1:], "use %s if available" % (pkgName), default)
|
||||||
|
|
||||||
|
def _BoolOption(opt, explanation, default=1):
|
||||||
|
""" Allow user to enable/disable a certain option. This results in a commandline option enable<Option>, where Option
|
||||||
|
is the name of the option with a capitalized first letter.
|
||||||
|
@param opt: Name of option.
|
||||||
|
@param explanation: Explanation of option.
|
||||||
|
@param default: The default value for this option (1/0).
|
||||||
|
"""
|
||||||
|
return BoolOption("enable%s" % opt[0].upper() + opt[1:], explanation, default)
|
||||||
|
|
||||||
|
def _EnumOption(opt, explanation, allowedValues, default):
|
||||||
|
""" Allow the user to choose among a set of values for an option. This results in a commandline option with<Option>,
|
||||||
|
where Option is the name of the option with a capitalized first letter.
|
||||||
|
@param opt: The name of the option.
|
||||||
|
@param explanation: Explanation of option.
|
||||||
|
@param allowedValues: The set of values to choose from.
|
||||||
|
@param default: The default value.
|
||||||
|
"""
|
||||||
|
assert default in allowedValues
|
||||||
|
return EnumOption("with%s" % opt[0].upper() + opt[1:], explanation, default, allowed_values=allowedValues)
|
||||||
|
|
||||||
|
def _DirectoryOption(opt, explanation, default):
|
||||||
|
""" Allow the user to configure the location for a certain directory, for instance the prefix. This results in a
|
||||||
|
commandline option which is simply the name of this option.
|
||||||
|
@param opt: The configurable directory, for instance "prefix".
|
||||||
|
@param explanation: Explanation of option.
|
||||||
|
@param default: The default value for this option.
|
||||||
|
"""
|
||||||
|
return PathOption(opt, explanation, default)
|
||||||
|
# Incompatible with the latest stable SCons
|
||||||
|
# return PathOption(path, help, default, PathOption.PathIsDir)
|
||||||
|
|
||||||
|
import SCons.Errors
|
||||||
|
try:
|
||||||
|
Import("Platform", "Posix")
|
||||||
|
except SCons.Errors.UserError:
|
||||||
|
# The common objects must be exported first
|
||||||
|
SConscript("SConscript_common")
|
||||||
|
Import("Platform", "Posix")
|
||||||
|
|
||||||
|
# Expose the options as a dictionary of sets of options
|
||||||
|
opts = {}
|
||||||
|
|
||||||
|
if Platform in Posix:
|
||||||
|
opts["Installation Dirs"] = [_DirectoryOption("prefix", "installation prefix", "/usr/local")]
|
||||||
|
elif Platform in Windows:
|
||||||
|
if Platform == "cygwin":
|
||||||
|
opts["Installation Dirs"] = [_DirectoryOption("prefix", "installation prefix", "/usr/local")]
|
||||||
|
|
||||||
|
opts["Build Targets"] = [_BoolOption("shared", "create shared library"), _BoolOption("static", "create static library"),
|
||||||
|
_BoolOption("tests", "build test programs")]
|
||||||
|
|
||||||
|
apis = []
|
||||||
|
if Platform in Posix:
|
||||||
|
apis.append(_PackageOption("OSS"))
|
||||||
|
apis.append(_PackageOption("JACK"))
|
||||||
|
apis.append(_PackageOption("ALSA", Platform == "linux"))
|
||||||
|
apis.append(_PackageOption("ASIHPI", Platform == "linux"))
|
||||||
|
apis.append(_PackageOption("COREAUDIO", Platform == "darwin"))
|
||||||
|
elif Platform in Windows:
|
||||||
|
if Platform == "cygwin":
|
||||||
|
apis.append(_EnumOption("winAPI", "Windows API to use", ("wmme", "directx", "asio"), "wmme"))
|
||||||
|
|
||||||
|
opts["Host APIs"] = apis
|
||||||
|
|
||||||
|
opts["Build Parameters"] = [\
|
||||||
|
_BoolOption("debug", "compile with debug symbols"),
|
||||||
|
_BoolOption("optimize", "compile with optimization", default=0),
|
||||||
|
_BoolOption("asserts", "runtime assertions are helpful for debugging, but can be detrimental to performance",
|
||||||
|
default=1),
|
||||||
|
_BoolOption("debugOutput", "enable debug output", default=0),
|
||||||
|
# _BoolOption("python", "create Python binding"),
|
||||||
|
("customCFlags", "customize compilation of C code", ""),
|
||||||
|
("customCxxFlags", "customize compilation of C++ code", ""),
|
||||||
|
("customLinkFlags", "customize linking", ""),
|
||||||
|
]
|
||||||
|
|
||||||
|
opts["Bindings"] = [\
|
||||||
|
_BoolOption("cxx", "build Merlijn Blaauw's PA C++ wrapper", default=0)
|
||||||
|
]
|
||||||
|
|
||||||
|
Return("opts")
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,417 @@
|
||||||
|
dnl
|
||||||
|
dnl portaudio V19 configure.in script
|
||||||
|
dnl
|
||||||
|
dnl Dominic Mazzoni, Arve Knudsen, Stelios Bounanos
|
||||||
|
dnl
|
||||||
|
|
||||||
|
dnl Require autoconf >= 2.13
|
||||||
|
AC_PREREQ(2.13)
|
||||||
|
|
||||||
|
dnl Init autoconf and make sure configure is being called
|
||||||
|
dnl from the right directory
|
||||||
|
AC_INIT([include/portaudio.h])
|
||||||
|
|
||||||
|
dnl Define build, build_cpu, build_vendor, build_os
|
||||||
|
AC_CANONICAL_BUILD
|
||||||
|
dnl Define host, host_cpu, host_vendor, host_os
|
||||||
|
AC_CANONICAL_HOST
|
||||||
|
dnl Define target, target_cpu, target_vendor, target_os
|
||||||
|
AC_CANONICAL_TARGET
|
||||||
|
|
||||||
|
dnl Specify options
|
||||||
|
|
||||||
|
AC_ARG_WITH(alsa,
|
||||||
|
AS_HELP_STRING([--with-alsa], [Enable support for ALSA @<:@autodetect@:>@]),
|
||||||
|
[with_alsa=$withval])
|
||||||
|
|
||||||
|
AC_ARG_WITH(jack,
|
||||||
|
AS_HELP_STRING([--with-jack], [Enable support for JACK @<:@autodetect@:>@]),
|
||||||
|
[with_jack=$withval])
|
||||||
|
|
||||||
|
AC_ARG_WITH(oss,
|
||||||
|
AS_HELP_STRING([--with-oss], [Enable support for OSS @<:@autodetect@:>@]),
|
||||||
|
[with_oss=$withval])
|
||||||
|
|
||||||
|
AC_ARG_WITH(asihpi,
|
||||||
|
AS_HELP_STRING([--with-asihpi], [Enable support for ASIHPI @<:@autodetect@:>@]),
|
||||||
|
[with_asihpi=$withval])
|
||||||
|
|
||||||
|
AC_ARG_WITH(winapi,
|
||||||
|
AS_HELP_STRING([--with-winapi],
|
||||||
|
[Select Windows API support (@<:@wmme|directx|asio|wdmks@:>@@<:@,...@:>@) @<:@wmme@:>@]),
|
||||||
|
[with_winapi=$withval], [with_winapi="wmme"])
|
||||||
|
case "$target_os" in *mingw* | *cygwin*)
|
||||||
|
with_wmme=no
|
||||||
|
with_directx=no
|
||||||
|
with_asio=no
|
||||||
|
with_wdmks=no
|
||||||
|
for api in $(echo $with_winapi | sed 's/,/ /g'); do
|
||||||
|
case "$api" in
|
||||||
|
wmme|directx|asio|wdmks)
|
||||||
|
eval with_$api=yes
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR([unknown Windows API \"$api\" (do you need --help?)])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
AC_ARG_WITH(asiodir,
|
||||||
|
AS_HELP_STRING([--with-asiodir], [ASIO directory @<:@/usr/local/asiosdk2@:>@]),
|
||||||
|
with_asiodir=$withval, with_asiodir="/usr/local/asiosdk2")
|
||||||
|
|
||||||
|
AC_ARG_WITH(dxdir,
|
||||||
|
AS_HELP_STRING([--with-dxdir], [DirectX directory @<:@/usr/local/dx7sdk@:>@]),
|
||||||
|
with_dxdir=$withval, with_dxdir="/usr/local/dx7sdk")
|
||||||
|
|
||||||
|
debug_output=no
|
||||||
|
AC_ARG_ENABLE(debug-output,
|
||||||
|
AS_HELP_STRING([--enable-debug-output], [Enable debug output @<:@no@:>@]),
|
||||||
|
[if test "x$enableval" != "xno" ; then
|
||||||
|
AC_DEFINE(PA_ENABLE_DEBUG_OUTPUT,,[Enable debugging messages])
|
||||||
|
debug_output=yes
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(cxx,
|
||||||
|
AS_HELP_STRING([--enable-cxx], [Enable C++ bindings @<:@no@:>@]),
|
||||||
|
enable_cxx=$enableval, enable_cxx="no")
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(mac-debug,
|
||||||
|
AS_HELP_STRING([--enable-mac-debug], [Enable Mac debug @<:@no@:>@]),
|
||||||
|
enable_mac_debug=$enableval, enable_mac_debug="no")
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(mac-universal,
|
||||||
|
AS_HELP_STRING([--enable-mac-universal], [Build Mac universal binaries @<:@yes@:>@]),
|
||||||
|
enable_mac_universal=$enableval, enable_mac_universal="yes")
|
||||||
|
|
||||||
|
dnl Continue to accept --host_os for compatibility but do not document
|
||||||
|
dnl it (the correct way to change host_os is with --host=...). Moved
|
||||||
|
dnl here because the empty help string generates a blank line which we
|
||||||
|
dnl can use to separate PA options from libtool options.
|
||||||
|
AC_ARG_WITH(host_os, [], host_os=$withval)
|
||||||
|
|
||||||
|
dnl Checks for programs.
|
||||||
|
|
||||||
|
AC_PROG_CC
|
||||||
|
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")
|
||||||
|
fi
|
||||||
|
|
||||||
|
dnl This must be one of the first tests we do or it will fail...
|
||||||
|
AC_C_BIGENDIAN
|
||||||
|
|
||||||
|
dnl checks for various host APIs and arguments to configure that
|
||||||
|
dnl turn them on or off
|
||||||
|
|
||||||
|
have_alsa=no
|
||||||
|
if test "x$with_alsa" != "xno"; then
|
||||||
|
AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no)
|
||||||
|
fi
|
||||||
|
have_asihpi=no
|
||||||
|
if test "x$with_asihpi" != "xno"; then
|
||||||
|
AC_CHECK_LIB(hpi, HPI_SubSysCreate, have_asihpi=yes, have_asihpi=no, -lm)
|
||||||
|
fi
|
||||||
|
have_libossaudio=no
|
||||||
|
have_oss=no
|
||||||
|
if test "x$with_oss" != "xno"; then
|
||||||
|
AC_CHECK_HEADERS([sys/soundcard.h linux/soundcard.h machine/soundcard.h], [have_oss=yes])
|
||||||
|
if test "x$have_oss" = "xyes"; then
|
||||||
|
AC_CHECK_LIB(ossaudio, _oss_ioctl, have_libossaudio=yes, have_libossaudio=no)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
have_jack=no
|
||||||
|
if test "x$with_jack" != "xno"; then
|
||||||
|
PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no)
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
dnl sizeof checks: we will need a 16-bit and a 32-bit type
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
dnl -g is optional on darwin
|
||||||
|
if ( echo "${host_os}" | grep ^darwin >> /dev/null ) &&
|
||||||
|
[[ "$enable_mac_universal" = "yes" ] &&
|
||||||
|
[ "$enable_mac_debug" != "yes" ]] ; then
|
||||||
|
CFLAGS="-O2 -Wall -pedantic -pipe -fPIC -DNDEBUG"
|
||||||
|
else
|
||||||
|
CFLAGS=${CFLAGS:-"-g -O2 -Wall -pedantic -pipe -fPIC"}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $ac_cv_c_bigendian = "yes" ]] ; then
|
||||||
|
CFLAGS="$CFLAGS -DPA_BIG_ENDIAN"
|
||||||
|
else
|
||||||
|
CFLAGS="$CFLAGS -DPA_LITTLE_ENDIAN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
add_objects()
|
||||||
|
{
|
||||||
|
for o in $@; do
|
||||||
|
test "${OTHER_OBJS#*${o}*}" = "${OTHER_OBJS}" && OTHER_OBJS="$OTHER_OBJS $o"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${host_os}" in
|
||||||
|
darwin* )
|
||||||
|
dnl Mac OS X configuration
|
||||||
|
|
||||||
|
AC_DEFINE(PA_USE_COREAUDIO)
|
||||||
|
|
||||||
|
CFLAGS="$CFLAGS -Werror"
|
||||||
|
LIBS="-framework CoreAudio -framework AudioToolbox -framework AudioUnit -framework Carbon"
|
||||||
|
|
||||||
|
if test "x$enable_mac_universal" = "xyes" ; then
|
||||||
|
mac_version_min="-mmacosx-version-min=10.3"
|
||||||
|
if [[ -d /Developer/SDKs/MacOSX10.5.sdk ]] ; then
|
||||||
|
mac_arches="-arch i386 -arch ppc -arch x86_64 -arch ppc64"
|
||||||
|
mac_sysroot="-isysroot /Developer/SDKs/MacOSX10.5.sdk"
|
||||||
|
else
|
||||||
|
mac_arches="-arch i386 -arch ppc"
|
||||||
|
mac_sysroot="-isysroot /Developer/SDKs/MacOSX10.4u.sdk"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
mac_arches=""
|
||||||
|
mac_sysroot=""
|
||||||
|
mac_version=""
|
||||||
|
fi
|
||||||
|
SHARED_FLAGS="$LIBS -dynamiclib $mac_arches $mac_sysroot $mac_version_min"
|
||||||
|
CFLAGS="-std=c99 $CFLAGS $mac_arches $mac_sysroot $mac_version_min"
|
||||||
|
OTHER_OBJS="src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o src/hostapi/coreaudio/pa_mac_core.o src/hostapi/coreaudio/pa_mac_core_utilities.o src/hostapi/coreaudio/pa_mac_core_blocking.o src/common/pa_ringbuffer.o"
|
||||||
|
PADLL="libportaudio.dylib"
|
||||||
|
;;
|
||||||
|
|
||||||
|
mingw* )
|
||||||
|
dnl MingW configuration
|
||||||
|
|
||||||
|
PADLL="portaudio.dll"
|
||||||
|
THREAD_CFLAGS="-mthreads"
|
||||||
|
SHARED_FLAGS="-shared"
|
||||||
|
CFLAGS="$CFLAGS -I\$(top_srcdir)/include -DPA_NO_WMME -DPA_NO_ASIO -DPA_NO_WDMKS -DPA_NO_DS"
|
||||||
|
|
||||||
|
if [[ "x$with_directx" = "xyes" ]]; then
|
||||||
|
DXDIR="$with_dxdir"
|
||||||
|
add_objects src/hostapi/dsound/pa_win_ds.o src/hostapi/dsound/pa_win_ds_dynlink.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o
|
||||||
|
LIBS="-lwinmm -lm -ldsound -lole32"
|
||||||
|
DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L$DXDIR/lib -ldsound -lole32"
|
||||||
|
#VC98="\"/c/Program Files/Microsoft Visual Studio/VC98/Include\""
|
||||||
|
#CFLAGS="$CFLAGS -I$VC98 -DPA_NO_WMME -DPA_NO_ASIO"
|
||||||
|
CFLAGS="$CFLAGS -I\$(top_srcdir)/src/os/win -I$DXDIR/include -UPA_NO_DS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "x$with_asio" = "xyes" ]]; then
|
||||||
|
ASIODIR="$with_asiodir"
|
||||||
|
add_objects src/hostapi/asio/pa_asio.o src/common/pa_ringbuffer.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/hostapi/asio/iasiothiscallresolver.o $ASIODIR/common/asio.o $ASIODIR/host/asiodrivers.o $ASIODIR/host/pc/asiolist.o
|
||||||
|
LIBS="-lwinmm -lm -lole32 -luuid"
|
||||||
|
DLL_LIBS="${DLL_LIBS} -lwinmm -lm -lole32 -luuid"
|
||||||
|
CFLAGS="$CFLAGS -ffast-math -fomit-frame-pointer -I\$(top_srcdir)/src/common -I\$(top_srcdir)/src/hostapi/asio -I$ASIODIR/host/pc -I$ASIODIR/common -I$ASIODIR/host -UPA_NO_ASIO -DWINDOWS"
|
||||||
|
CXXFLAGS="$CFLAGS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "x$with_wdmks" = "xyes" ]]; then
|
||||||
|
DXDIR="$with_dxdir"
|
||||||
|
add_objects 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"
|
||||||
|
DLL_LIBS="${DLL_LIBS} -lwinmm -lm -L$DXDIR/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 -I\$(top_srcdir)/src/common -I$DXDIR/include -UPA_NO_WDMKS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "x$with_wmme" = "xyes" ]]; then
|
||||||
|
add_objects src/hostapi/wmme/pa_win_wmme.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o
|
||||||
|
LIBS="-lwinmm -lm -lole32 -luuid"
|
||||||
|
DLL_LIBS="${DLL_LIBS} -lwinmm"
|
||||||
|
CFLAGS="$CFLAGS -I\$(top_srcdir)/src/common -UPA_NO_WMME"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
cygwin* )
|
||||||
|
dnl Cygwin configuration
|
||||||
|
|
||||||
|
OTHER_OBJS="src/hostapi/wmme/pa_win_wmme.o src/os/win/pa_win_hostapis.o src/os/win/pa_win_util.o src/os/win/pa_win_waveformat.o"
|
||||||
|
CFLAGS="$CFLAGS -DPA_NO_DS -DPA_NO_WDMKS -DPA_NO_ASIO -DPA_NO_WASAPI"
|
||||||
|
LIBS="-lwinmm -lm"
|
||||||
|
PADLL="portaudio.dll"
|
||||||
|
THREAD_CFLAGS="-mthreads"
|
||||||
|
SHARED_FLAGS="-shared"
|
||||||
|
DLL_LIBS="${DLL_LIBS} -lwinmm"
|
||||||
|
;;
|
||||||
|
|
||||||
|
irix* )
|
||||||
|
dnl SGI IRIX audio library (AL) configuration (Pieter, oct 2-13, 2003).
|
||||||
|
dnl The 'dmedia' library is needed to read the Unadjusted System Time (UST).
|
||||||
|
dnl
|
||||||
|
AC_CHECK_LIB(pthread, pthread_create, , AC_MSG_ERROR([IRIX posix thread library not found!]))
|
||||||
|
AC_CHECK_LIB(audio, alOpenPort, , AC_MSG_ERROR([IRIX audio library not found!]))
|
||||||
|
AC_CHECK_LIB(dmedia, dmGetUST, , AC_MSG_ERROR([IRIX digital media library not found!]))
|
||||||
|
|
||||||
|
dnl See the '#ifdef PA_USE_SGI' in file pa_unix/pa_unix_hostapis.c
|
||||||
|
dnl which selects the appropriate PaXXX_Initialize() function.
|
||||||
|
dnl
|
||||||
|
AC_DEFINE(PA_USE_SGI)
|
||||||
|
|
||||||
|
dnl The _REENTRANT option for pthread safety. Perhaps not necessary but it 'll do no harm.
|
||||||
|
dnl
|
||||||
|
THREAD_CFLAGS="-D_REENTRANT"
|
||||||
|
|
||||||
|
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=""
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
dnl Unix configuration
|
||||||
|
|
||||||
|
AC_CHECK_LIB(pthread, pthread_create,[have_pthread="yes"],
|
||||||
|
AC_MSG_ERROR([libpthread not found!]))
|
||||||
|
|
||||||
|
if [[ "$have_alsa" = "yes" ] && [ "$with_alsa" != "no" ]] ; then
|
||||||
|
DLL_LIBS="$DLL_LIBS -lasound"
|
||||||
|
LIBS="$LIBS -lasound"
|
||||||
|
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
|
||||||
|
DLL_LIBS="$DLL_LIBS $JACK_LIBS"
|
||||||
|
CFLAGS="$CFLAGS $JACK_CFLAGS"
|
||||||
|
OTHER_OBJS="$OTHER_OBJS src/hostapi/jack/pa_jack.o src/common/pa_ringbuffer.o"
|
||||||
|
AC_DEFINE(PA_USE_JACK)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$with_oss" != "no" ]] ; then
|
||||||
|
OTHER_OBJS="$OTHER_OBJS src/hostapi/oss/pa_unix_oss.o"
|
||||||
|
if [[ "$have_libossaudio" = "yes" ]] ; then
|
||||||
|
DLL_LIBS="$DLL_LIBS -lossaudio"
|
||||||
|
LIBS="$LIBS -lossaudio"
|
||||||
|
fi
|
||||||
|
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
|
||||||
|
|
||||||
|
DLL_LIBS="$DLL_LIBS -lm -lpthread"
|
||||||
|
LIBS="$LIBS -lm -lpthread"
|
||||||
|
PADLL="libportaudio.so"
|
||||||
|
|
||||||
|
## support sun cc compiler flags
|
||||||
|
case "${host_os}" in
|
||||||
|
solaris*)
|
||||||
|
SHARED_FLAGS="-G"
|
||||||
|
THREAD_CFLAGS="-mt"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
SHARED_FLAGS="-shared -fPIC"
|
||||||
|
THREAD_CFLAGS="-pthread"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
OTHER_OBJS="$OTHER_OBJS src/os/unix/pa_unix_hostapis.o src/os/unix/pa_unix_util.o"
|
||||||
|
esac
|
||||||
|
CFLAGS="$CFLAGS $THREAD_CFLAGS"
|
||||||
|
|
||||||
|
if test "$enable_cxx" = "yes"; then
|
||||||
|
AC_CONFIG_SUBDIRS([bindings/cpp])
|
||||||
|
ENABLE_CXX_TRUE=""
|
||||||
|
ENABLE_CXX_FALSE="#"
|
||||||
|
else
|
||||||
|
ENABLE_CXX_TRUE="#"
|
||||||
|
ENABLE_CXX_FALSE=""
|
||||||
|
fi
|
||||||
|
AC_SUBST(ENABLE_CXX_TRUE)
|
||||||
|
AC_SUBST(ENABLE_CXX_FALSE)
|
||||||
|
|
||||||
|
if test "x$with_asio" = "xyes"; then
|
||||||
|
WITH_ASIO_TRUE=""
|
||||||
|
WITH_ASIO_FALSE="@ #"
|
||||||
|
else
|
||||||
|
WITH_ASIO_TRUE="@ #"
|
||||||
|
WITH_ASIO_FALSE=""
|
||||||
|
fi
|
||||||
|
AC_SUBST(WITH_ASIO_TRUE)
|
||||||
|
AC_SUBST(WITH_ASIO_FALSE)
|
||||||
|
|
||||||
|
AC_OUTPUT([Makefile portaudio-2.0.pc])
|
||||||
|
|
||||||
|
AC_MSG_RESULT([
|
||||||
|
Configuration summary:
|
||||||
|
|
||||||
|
Target ...................... $target
|
||||||
|
C++ bindings ................ $enable_cxx
|
||||||
|
Debug output ................ $debug_output])
|
||||||
|
|
||||||
|
case "$target_os" in *linux*)
|
||||||
|
AC_MSG_RESULT([
|
||||||
|
ALSA ........................ $have_alsa
|
||||||
|
ASIHPI ...................... $have_asihpi])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
case "$target_os" in
|
||||||
|
*mingw* | *cygwin*)
|
||||||
|
test "x$with_directx" = "xyes" && with_directx="$with_directx (${with_dxdir})"
|
||||||
|
test "x$with_wdmks" = "xyes" && with_wdmks="$with_wdmks (${with_dxdir})"
|
||||||
|
test "x$with_asio" = "xyes" && with_asio="$with_asio (${with_asiodir})"
|
||||||
|
AC_MSG_RESULT([
|
||||||
|
WMME ........................ $with_wmme
|
||||||
|
DSound ...................... $with_directx
|
||||||
|
WDMKS ....................... $with_wdmks
|
||||||
|
ASIO ........................ $with_asio
|
||||||
|
])
|
||||||
|
;;
|
||||||
|
*darwin*)
|
||||||
|
AC_MSG_RESULT([
|
||||||
|
Mac debug flags ............. $enable_mac_debug
|
||||||
|
])
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_RESULT([
|
||||||
|
OSS ......................... $have_oss
|
||||||
|
JACK ........................ $have_jack
|
||||||
|
])
|
||||||
|
;;
|
||||||
|
esac
|
|
@ -0,0 +1,530 @@
|
||||||
|
#! /bin/sh
|
||||||
|
# depcomp - compile a program generating dependencies as side-effects
|
||||||
|
|
||||||
|
scriptversion=2005-07-09.11
|
||||||
|
|
||||||
|
# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
# 02110-1301, USA.
|
||||||
|
|
||||||
|
# As a special exception to the GNU General Public License, if you
|
||||||
|
# distribute this file as part of a program that contains a
|
||||||
|
# configuration script generated by Autoconf, you may include it under
|
||||||
|
# the same distribution terms that you use for the rest of that program.
|
||||||
|
|
||||||
|
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
'')
|
||||||
|
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
|
||||||
|
exit 1;
|
||||||
|
;;
|
||||||
|
-h | --h*)
|
||||||
|
cat <<\EOF
|
||||||
|
Usage: depcomp [--help] [--version] PROGRAM [ARGS]
|
||||||
|
|
||||||
|
Run PROGRAMS ARGS to compile a file, generating dependencies
|
||||||
|
as side-effects.
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
depmode Dependency tracking mode.
|
||||||
|
source Source file read by `PROGRAMS ARGS'.
|
||||||
|
object Object file output by `PROGRAMS ARGS'.
|
||||||
|
DEPDIR directory where to store dependencies.
|
||||||
|
depfile Dependency file to output.
|
||||||
|
tmpdepfile Temporary file to use when outputing dependencies.
|
||||||
|
libtool Whether libtool is used (yes/no).
|
||||||
|
|
||||||
|
Report bugs to <bug-automake@gnu.org>.
|
||||||
|
EOF
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
-v | --v*)
|
||||||
|
echo "depcomp $scriptversion"
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||||
|
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
|
||||||
|
depfile=${depfile-`echo "$object" |
|
||||||
|
sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
|
||||||
|
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||||
|
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
|
||||||
|
# Some modes work just like other modes, but use different flags. We
|
||||||
|
# parameterize here, but still list the modes in the big case below,
|
||||||
|
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||||
|
# here, because this file can only contain one case statement.
|
||||||
|
if test "$depmode" = hp; then
|
||||||
|
# HP compiler uses -M and no extra arg.
|
||||||
|
gccflag=-M
|
||||||
|
depmode=gcc
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$depmode" = dashXmstdout; then
|
||||||
|
# This is just like dashmstdout with a different argument.
|
||||||
|
dashmflag=-xM
|
||||||
|
depmode=dashmstdout
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$depmode" in
|
||||||
|
gcc3)
|
||||||
|
## gcc 3 implements dependency tracking that does exactly what
|
||||||
|
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||||
|
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||||
|
"$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
|
||||||
|
stat=$?
|
||||||
|
if test $stat -eq 0; then :
|
||||||
|
else
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
exit $stat
|
||||||
|
fi
|
||||||
|
mv "$tmpdepfile" "$depfile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
gcc)
|
||||||
|
## There are various ways to get dependency output from gcc. Here's
|
||||||
|
## why we pick this rather obscure method:
|
||||||
|
## - Don't want to use -MD because we'd like the dependencies to end
|
||||||
|
## up in a subdir. Having to rename by hand is ugly.
|
||||||
|
## (We might end up doing this anyway to support other compilers.)
|
||||||
|
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||||
|
## -MM, not -M (despite what the docs say).
|
||||||
|
## - Using -M directly means running the compiler twice (even worse
|
||||||
|
## than renaming).
|
||||||
|
if test -z "$gccflag"; then
|
||||||
|
gccflag=-MD,
|
||||||
|
fi
|
||||||
|
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||||
|
stat=$?
|
||||||
|
if test $stat -eq 0; then :
|
||||||
|
else
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
exit $stat
|
||||||
|
fi
|
||||||
|
rm -f "$depfile"
|
||||||
|
echo "$object : \\" > "$depfile"
|
||||||
|
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
||||||
|
## The second -e expression handles DOS-style file names with drive letters.
|
||||||
|
sed -e 's/^[^:]*: / /' \
|
||||||
|
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||||
|
## This next piece of magic avoids the `deleted header file' problem.
|
||||||
|
## The problem is that when a header file which appears in a .P file
|
||||||
|
## is deleted, the dependency causes make to die (because there is
|
||||||
|
## typically no way to rebuild the header). We avoid this by adding
|
||||||
|
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||||
|
## this for us directly.
|
||||||
|
tr ' ' '
|
||||||
|
' < "$tmpdepfile" |
|
||||||
|
## Some versions of gcc put a space before the `:'. On the theory
|
||||||
|
## that the space means something, we add a space to the output as
|
||||||
|
## well.
|
||||||
|
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||||
|
## correctly. Breaking it into two sed invocations is a workaround.
|
||||||
|
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
hp)
|
||||||
|
# This case exists only to let depend.m4 do its work. It works by
|
||||||
|
# looking at the text of this script. This case will never be run,
|
||||||
|
# since it is checked for above.
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
sgi)
|
||||||
|
if test "$libtool" = yes; then
|
||||||
|
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||||
|
else
|
||||||
|
"$@" -MDupdate "$tmpdepfile"
|
||||||
|
fi
|
||||||
|
stat=$?
|
||||||
|
if test $stat -eq 0; then :
|
||||||
|
else
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
exit $stat
|
||||||
|
fi
|
||||||
|
rm -f "$depfile"
|
||||||
|
|
||||||
|
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||||
|
echo "$object : \\" > "$depfile"
|
||||||
|
|
||||||
|
# Clip off the initial element (the dependent). Don't try to be
|
||||||
|
# clever and replace this with sed code, as IRIX sed won't handle
|
||||||
|
# lines with more than a fixed number of characters (4096 in
|
||||||
|
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||||
|
# the IRIX cc adds comments like `#:fec' to the end of the
|
||||||
|
# dependency line.
|
||||||
|
tr ' ' '
|
||||||
|
' < "$tmpdepfile" \
|
||||||
|
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
|
||||||
|
tr '
|
||||||
|
' ' ' >> $depfile
|
||||||
|
echo >> $depfile
|
||||||
|
|
||||||
|
# The second pass generates a dummy entry for each header file.
|
||||||
|
tr ' ' '
|
||||||
|
' < "$tmpdepfile" \
|
||||||
|
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||||
|
>> $depfile
|
||||||
|
else
|
||||||
|
# The sourcefile does not contain any dependencies, so just
|
||||||
|
# store a dummy comment line, to avoid errors with the Makefile
|
||||||
|
# "include basename.Plo" scheme.
|
||||||
|
echo "#dummy" > "$depfile"
|
||||||
|
fi
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
aix)
|
||||||
|
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||||
|
# in a .u file. In older versions, this file always lives in the
|
||||||
|
# current directory. Also, the AIX compiler puts `$object:' at the
|
||||||
|
# start of each line; $object doesn't have directory information.
|
||||||
|
# Version 6 uses the directory in both cases.
|
||||||
|
stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'`
|
||||||
|
tmpdepfile="$stripped.u"
|
||||||
|
if test "$libtool" = yes; then
|
||||||
|
"$@" -Wc,-M
|
||||||
|
else
|
||||||
|
"$@" -M
|
||||||
|
fi
|
||||||
|
stat=$?
|
||||||
|
|
||||||
|
if test -f "$tmpdepfile"; then :
|
||||||
|
else
|
||||||
|
stripped=`echo "$stripped" | sed 's,^.*/,,'`
|
||||||
|
tmpdepfile="$stripped.u"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $stat -eq 0; then :
|
||||||
|
else
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
exit $stat
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -f "$tmpdepfile"; then
|
||||||
|
outname="$stripped.o"
|
||||||
|
# Each line is of the form `foo.o: dependent.h'.
|
||||||
|
# Do two passes, one to just change these to
|
||||||
|
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||||
|
sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
|
||||||
|
sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
|
||||||
|
else
|
||||||
|
# The sourcefile does not contain any dependencies, so just
|
||||||
|
# store a dummy comment line, to avoid errors with the Makefile
|
||||||
|
# "include basename.Plo" scheme.
|
||||||
|
echo "#dummy" > "$depfile"
|
||||||
|
fi
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
icc)
|
||||||
|
# Intel's C compiler understands `-MD -MF file'. However on
|
||||||
|
# icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
|
||||||
|
# ICC 7.0 will fill foo.d with something like
|
||||||
|
# foo.o: sub/foo.c
|
||||||
|
# foo.o: sub/foo.h
|
||||||
|
# which is wrong. We want:
|
||||||
|
# sub/foo.o: sub/foo.c
|
||||||
|
# sub/foo.o: sub/foo.h
|
||||||
|
# sub/foo.c:
|
||||||
|
# sub/foo.h:
|
||||||
|
# ICC 7.1 will output
|
||||||
|
# foo.o: sub/foo.c sub/foo.h
|
||||||
|
# and will wrap long lines using \ :
|
||||||
|
# foo.o: sub/foo.c ... \
|
||||||
|
# sub/foo.h ... \
|
||||||
|
# ...
|
||||||
|
|
||||||
|
"$@" -MD -MF "$tmpdepfile"
|
||||||
|
stat=$?
|
||||||
|
if test $stat -eq 0; then :
|
||||||
|
else
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
exit $stat
|
||||||
|
fi
|
||||||
|
rm -f "$depfile"
|
||||||
|
# Each line is of the form `foo.o: dependent.h',
|
||||||
|
# or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
|
||||||
|
# Do two passes, one to just change these to
|
||||||
|
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||||
|
sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
|
||||||
|
# Some versions of the HPUX 10.20 sed can't process this invocation
|
||||||
|
# correctly. Breaking it into two sed invocations is a workaround.
|
||||||
|
sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
|
||||||
|
sed -e 's/$/ :/' >> "$depfile"
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
tru64)
|
||||||
|
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||||
|
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
|
||||||
|
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||||
|
# dependencies in `foo.d' instead, so we check for that too.
|
||||||
|
# Subdirectories are respected.
|
||||||
|
dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
|
||||||
|
test "x$dir" = "x$object" && dir=
|
||||||
|
base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'`
|
||||||
|
|
||||||
|
if test "$libtool" = yes; then
|
||||||
|
# With Tru64 cc, shared objects can also be used to make a
|
||||||
|
# static library. This mecanism is used in libtool 1.4 series to
|
||||||
|
# handle both shared and static libraries in a single compilation.
|
||||||
|
# With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d.
|
||||||
|
#
|
||||||
|
# With libtool 1.5 this exception was removed, and libtool now
|
||||||
|
# generates 2 separate objects for the 2 libraries. These two
|
||||||
|
# compilations output dependencies in in $dir.libs/$base.o.d and
|
||||||
|
# in $dir$base.o.d. We have to check for both files, because
|
||||||
|
# one of the two compilations can be disabled. We should prefer
|
||||||
|
# $dir$base.o.d over $dir.libs/$base.o.d because the latter is
|
||||||
|
# automatically cleaned when .libs/ is deleted, while ignoring
|
||||||
|
# the former would cause a distcleancheck panic.
|
||||||
|
tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4
|
||||||
|
tmpdepfile2=$dir$base.o.d # libtool 1.5
|
||||||
|
tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5
|
||||||
|
tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504
|
||||||
|
"$@" -Wc,-MD
|
||||||
|
else
|
||||||
|
tmpdepfile1=$dir$base.o.d
|
||||||
|
tmpdepfile2=$dir$base.d
|
||||||
|
tmpdepfile3=$dir$base.d
|
||||||
|
tmpdepfile4=$dir$base.d
|
||||||
|
"$@" -MD
|
||||||
|
fi
|
||||||
|
|
||||||
|
stat=$?
|
||||||
|
if test $stat -eq 0; then :
|
||||||
|
else
|
||||||
|
rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
|
||||||
|
exit $stat
|
||||||
|
fi
|
||||||
|
|
||||||
|
for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4"
|
||||||
|
do
|
||||||
|
test -f "$tmpdepfile" && break
|
||||||
|
done
|
||||||
|
if test -f "$tmpdepfile"; then
|
||||||
|
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||||
|
# That's a tab and a space in the [].
|
||||||
|
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||||
|
else
|
||||||
|
echo "#dummy" > "$depfile"
|
||||||
|
fi
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
#nosideeffect)
|
||||||
|
# This comment above is used by automake to tell side-effect
|
||||||
|
# dependency tracking mechanisms from slower ones.
|
||||||
|
|
||||||
|
dashmstdout)
|
||||||
|
# Important note: in order to support this mode, a compiler *must*
|
||||||
|
# always write the preprocessed file to stdout, regardless of -o.
|
||||||
|
"$@" || exit $?
|
||||||
|
|
||||||
|
# Remove the call to Libtool.
|
||||||
|
if test "$libtool" = yes; then
|
||||||
|
while test $1 != '--mode=compile'; do
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove `-o $object'.
|
||||||
|
IFS=" "
|
||||||
|
for arg
|
||||||
|
do
|
||||||
|
case $arg in
|
||||||
|
-o)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
$object)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
set fnord "$@" "$arg"
|
||||||
|
shift # fnord
|
||||||
|
shift # $arg
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
test -z "$dashmflag" && dashmflag=-M
|
||||||
|
# Require at least two characters before searching for `:'
|
||||||
|
# in the target name. This is to cope with DOS-style filenames:
|
||||||
|
# a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
|
||||||
|
"$@" $dashmflag |
|
||||||
|
sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
|
||||||
|
rm -f "$depfile"
|
||||||
|
cat < "$tmpdepfile" > "$depfile"
|
||||||
|
tr ' ' '
|
||||||
|
' < "$tmpdepfile" | \
|
||||||
|
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||||
|
## correctly. Breaking it into two sed invocations is a workaround.
|
||||||
|
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
dashXmstdout)
|
||||||
|
# This case only exists to satisfy depend.m4. It is never actually
|
||||||
|
# run, as this mode is specially recognized in the preamble.
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
makedepend)
|
||||||
|
"$@" || exit $?
|
||||||
|
# Remove any Libtool call
|
||||||
|
if test "$libtool" = yes; then
|
||||||
|
while test $1 != '--mode=compile'; do
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
# X makedepend
|
||||||
|
shift
|
||||||
|
cleared=no
|
||||||
|
for arg in "$@"; do
|
||||||
|
case $cleared in
|
||||||
|
no)
|
||||||
|
set ""; shift
|
||||||
|
cleared=yes ;;
|
||||||
|
esac
|
||||||
|
case "$arg" in
|
||||||
|
-D*|-I*)
|
||||||
|
set fnord "$@" "$arg"; shift ;;
|
||||||
|
# Strip any option that makedepend may not understand. Remove
|
||||||
|
# the object too, otherwise makedepend will parse it as a source file.
|
||||||
|
-*|$object)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
set fnord "$@" "$arg"; shift ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
obj_suffix="`echo $object | sed 's/^.*\././'`"
|
||||||
|
touch "$tmpdepfile"
|
||||||
|
${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||||
|
rm -f "$depfile"
|
||||||
|
cat < "$tmpdepfile" > "$depfile"
|
||||||
|
sed '1,2d' "$tmpdepfile" | tr ' ' '
|
||||||
|
' | \
|
||||||
|
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||||
|
## correctly. Breaking it into two sed invocations is a workaround.
|
||||||
|
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||||
|
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||||
|
;;
|
||||||
|
|
||||||
|
cpp)
|
||||||
|
# Important note: in order to support this mode, a compiler *must*
|
||||||
|
# always write the preprocessed file to stdout.
|
||||||
|
"$@" || exit $?
|
||||||
|
|
||||||
|
# Remove the call to Libtool.
|
||||||
|
if test "$libtool" = yes; then
|
||||||
|
while test $1 != '--mode=compile'; do
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove `-o $object'.
|
||||||
|
IFS=" "
|
||||||
|
for arg
|
||||||
|
do
|
||||||
|
case $arg in
|
||||||
|
-o)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
$object)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
set fnord "$@" "$arg"
|
||||||
|
shift # fnord
|
||||||
|
shift # $arg
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
"$@" -E |
|
||||||
|
sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
|
||||||
|
-e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
|
||||||
|
sed '$ s: \\$::' > "$tmpdepfile"
|
||||||
|
rm -f "$depfile"
|
||||||
|
echo "$object : \\" > "$depfile"
|
||||||
|
cat < "$tmpdepfile" >> "$depfile"
|
||||||
|
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
msvisualcpp)
|
||||||
|
# Important note: in order to support this mode, a compiler *must*
|
||||||
|
# always write the preprocessed file to stdout, regardless of -o,
|
||||||
|
# because we must use -o when running libtool.
|
||||||
|
"$@" || exit $?
|
||||||
|
IFS=" "
|
||||||
|
for arg
|
||||||
|
do
|
||||||
|
case "$arg" in
|
||||||
|
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||||
|
set fnord "$@"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
set fnord "$@" "$arg"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
"$@" -E |
|
||||||
|
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
|
||||||
|
rm -f "$depfile"
|
||||||
|
echo "$object : \\" > "$depfile"
|
||||||
|
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
|
||||||
|
echo " " >> "$depfile"
|
||||||
|
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||||
|
rm -f "$tmpdepfile"
|
||||||
|
;;
|
||||||
|
|
||||||
|
none)
|
||||||
|
exec "$@"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Unknown depmode $depmode" 1>&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
# Local Variables:
|
||||||
|
# mode: shell-script
|
||||||
|
# sh-indentation: 2
|
||||||
|
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||||
|
# time-stamp-start: "scriptversion="
|
||||||
|
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||||
|
# time-stamp-end: "$"
|
||||||
|
# End:
|
|
@ -0,0 +1,38 @@
|
||||||
|
/** @page License PortAudio License
|
||||||
|
|
||||||
|
PortAudio Portable Real-Time Audio Library <br>
|
||||||
|
Copyright (c) 1999-2006 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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
The text above constitutes the entire PortAudio license; however,
|
||||||
|
the PortAudio community also makes the following non-binding requests:
|
||||||
|
|
||||||
|
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. It is also
|
||||||
|
requested that these non-binding requests be included along with the
|
||||||
|
license above.
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* doxygen index page */
|
||||||
|
/** @mainpage
|
||||||
|
|
||||||
|
PortAudio is an open-source cross-platform ‘C’ library for audio input
|
||||||
|
and output. It is designed to simplify the porting of audio applications
|
||||||
|
between various platforms, and also to simplify the development of audio
|
||||||
|
software in general by hiding the complexities of device interfacing.
|
||||||
|
|
||||||
|
See the PortAudio website for further information http://www.portaudio.com
|
||||||
|
|
||||||
|
This documentation pertains to PortAudio V19, API version 2.0 which is
|
||||||
|
currently under development. API version 2.0 differs in a number of ways from
|
||||||
|
previous versions, please consult the enhancement proposals for further details:
|
||||||
|
http://www.portaudio.com/docs/proposals/index.html
|
||||||
|
|
||||||
|
This documentation is under construction. Things you might be interested in
|
||||||
|
include:
|
||||||
|
|
||||||
|
- The PortAudio API 2.0, as documented in portaudio.h
|
||||||
|
|
||||||
|
- Tutorials for the V19 API, currently housed on the PortAudio Wiki:
|
||||||
|
http://www.portaudio.com/trac/wiki/TutorialDir/TutorialStart
|
||||||
|
|
||||||
|
- Implementation status is documented here:
|
||||||
|
http://www.portaudio.com/docs/proposals/status.html
|
||||||
|
|
||||||
|
- @ref srcguide
|
||||||
|
|
||||||
|
- The @ref License
|
||||||
|
|
||||||
|
|
||||||
|
If you're interested in contributing to PortAudio, you may be interested in:
|
||||||
|
|
||||||
|
- The doxygen generated <a href="todo.html">TODO List</a>. Feel free to pick an item off TODO list
|
||||||
|
and fix/implement it. You may want to enquire about status on the PortAudio mailing list first.
|
||||||
|
|
||||||
|
- Our issue tracking system:
|
||||||
|
http://www.portaudio.com/trac
|
||||||
|
|
||||||
|
- Coding guidelines:
|
||||||
|
http://www.portaudio.com/docs/proposals/014-StyleGuide.html
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
define all of the file groups used to structure the documentation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@defgroup public_header Public API definitions for users of PortAudio
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@defgroup common_src Source code common to all implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@defgroup win_src Source code common to all Windows implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@defgroup unix_src Source code common to all Unix implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@defgroup macosx_src Source code common to all Macintosh implementations
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@defgroup hostapi_src Source code for specific Host APIs
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@defgroup test_src Test and example programs
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@page srcguide A guide to the PortAudio sources.
|
||||||
|
|
||||||
|
- \ref public_header
|
||||||
|
- \ref common_src
|
||||||
|
- \ref win_src
|
||||||
|
- \ref unix_src
|
||||||
|
- \ref macosx_src
|
||||||
|
- \ref hostapi_src
|
||||||
|
- \ref test_src
|
||||||
|
*/
|
|
@ -0,0 +1,77 @@
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import string
|
||||||
|
|
||||||
|
paRootDirectory = '../../'
|
||||||
|
paHtmlDocDirectory = os.path.join( paRootDirectory, "doc", "html" )
|
||||||
|
|
||||||
|
## Script to check documentation status
|
||||||
|
## this script assumes that html doxygen documentation has been generated
|
||||||
|
##
|
||||||
|
## it then walks the entire portaudio source tree and check that
|
||||||
|
## - every source file (.c,.h,.cpp) has a doxygen comment block containing
|
||||||
|
## - a @file directive
|
||||||
|
## - a @brief directive
|
||||||
|
## - a @ingroup directive
|
||||||
|
## - it also checks that a corresponding html documentation file has been generated.
|
||||||
|
##
|
||||||
|
## This can be used as a first-level check to make sure the documentation is in order.
|
||||||
|
##
|
||||||
|
## The idea is to get a list of which files are missing doxygen documentation.
|
||||||
|
|
||||||
|
|
||||||
|
# recurse from top and return a list of all with the given
|
||||||
|
# extensions. ignore .svn directories. return absolute paths
|
||||||
|
def recursiveFindFiles( top, extensions, includePaths ):
|
||||||
|
result = []
|
||||||
|
for (dirpath, dirnames, filenames) in os.walk(top):
|
||||||
|
if not '.svn' in dirpath:
|
||||||
|
for f in filenames:
|
||||||
|
if os.path.splitext(f)[1] in extensions:
|
||||||
|
if includePaths:
|
||||||
|
result.append( os.path.abspath( os.path.join( dirpath, f ) ) )
|
||||||
|
else:
|
||||||
|
result.append( f )
|
||||||
|
return result
|
||||||
|
|
||||||
|
# generate the html file name that doxygen would use for
|
||||||
|
# a particular source file. this is a brittle conversion
|
||||||
|
# which i worked out by trial and error
|
||||||
|
def doxygenHtmlDocFileName( sourceFile ):
|
||||||
|
return sourceFile.replace( '_', '__' ).replace( '.', '_8' ) + '.html'
|
||||||
|
|
||||||
|
|
||||||
|
sourceFiles = recursiveFindFiles( paRootDirectory, [ '.c', '.h', '.cpp' ], True );
|
||||||
|
docFiles = recursiveFindFiles( paHtmlDocDirectory, [ '.html' ], False );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
currentFile = ""
|
||||||
|
|
||||||
|
def printError( f, message ):
|
||||||
|
global currentFile
|
||||||
|
if f != currentFile:
|
||||||
|
currentFile = f
|
||||||
|
print f, ":"
|
||||||
|
print "\t!", message
|
||||||
|
|
||||||
|
|
||||||
|
for f in sourceFiles:
|
||||||
|
if not doxygenHtmlDocFileName( os.path.basename(f) ) in docFiles:
|
||||||
|
printError( f, "no doxygen generated doc page" )
|
||||||
|
|
||||||
|
s = file( f, 'rt' ).read()
|
||||||
|
|
||||||
|
if not '/**' in s:
|
||||||
|
printError( f, "no doxygen /** block" )
|
||||||
|
|
||||||
|
if not '@file' in s:
|
||||||
|
printError( f, "no doxygen @file tag" )
|
||||||
|
|
||||||
|
if not '@brief' in s:
|
||||||
|
printError( f, "no doxygen @brief tag" )
|
||||||
|
|
||||||
|
if not '@ingroup' in s:
|
||||||
|
printError( f, "no doxygen @ingroup tag" )
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
rem Use Astyle to fix style in 'C' files
|
||||||
|
cd %1%
|
||||||
|
|
||||||
|
fixlines -p *.c
|
||||||
|
fixlines -p *.cpp
|
||||||
|
fixlines -p *.cc
|
||||||
|
|
||||||
|
astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.c
|
||||||
|
astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cpp
|
||||||
|
astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cc
|
||||||
|
del *.orig
|
||||||
|
@rem convert line terminators to Unix style LFs
|
||||||
|
fixlines -u *.c
|
||||||
|
fixlines -u *.cpp
|
||||||
|
fixlines -u *.cc
|
||||||
|
fixlines -u *.h
|
||||||
|
del *.bak
|
||||||
|
|
||||||
|
cd ..\
|
|
@ -0,0 +1,7 @@
|
||||||
|
rem Use Astyle to fix style in a file
|
||||||
|
fixlines -p %1%
|
||||||
|
astyle --style=ansi -c -o --convert-tabs --indent-preprocessor %1%
|
||||||
|
del %1%.orig
|
||||||
|
@rem convert line terminators to Unix style LFs
|
||||||
|
fixlines -u %1%
|
||||||
|
del %1%.bak
|
|
@ -0,0 +1,105 @@
|
||||||
|
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||||
|
<meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
|
||||||
|
<meta name="Author" content="Phil Burk">
|
||||||
|
<meta name="Description" content="PortAudio is a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||||
|
<meta name="KeyWords" content="audio, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||||
|
<title>PortAudio Implementations for DirectSound</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<center>
|
||||||
|
<h1>
|
||||||
|
PortAudio - Portable Audio Library</h1></center>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table></center>
|
||||||
|
|
||||||
|
<p>PortAudio is a cross platform, <a href="#License">open-source</a>, audio
|
||||||
|
I/O library proposed by <b>Ross Bencina</b> to the <a href="http://shoko.calarts.edu/~glmrboy/musicdsp/music-dsp.html">music-dsp</a>
|
||||||
|
mailing list. It lets you write simple audio programs in 'C' that will
|
||||||
|
compile and run on <b>Windows, Macintosh, Unix, BeOS</b>. PortAudio is
|
||||||
|
intended to promote the exchange of audio synthesis software between developers
|
||||||
|
on different platforms.
|
||||||
|
<p>For complete information on PortAudio and to download the latest releases,
|
||||||
|
please visit "<b><font size=+2><a href="http://www.portaudio.com">http://www.portaudio.com</a></font></b>".
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<center>
|
||||||
|
<h2>
|
||||||
|
<b><a href="doc/html/index.html">Click here for Documentation</a></b></h2></center>
|
||||||
|
|
||||||
|
<h2>
|
||||||
|
<b><font size=+2></font></b></h2>
|
||||||
|
|
||||||
|
<h2>
|
||||||
|
<b><font size=+2>Contacts and E-Mail List</font></b></h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
If you are using or implementing PortAudio then please join the <b><font size=+1><a href="http://techweb.rfa.org/mailman/listinfo/portaudio">PortAudio
|
||||||
|
mail list</a></font><font size=+2> </font></b>.</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
If you find bugs in one of these implementations, or have suggestions,
|
||||||
|
please e-mail them to <a href="mailto:philburk@softsynth.com">Phil Burk</a>.</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
If you make improvements to the library, please send them to us so we can
|
||||||
|
incorporate the improvements.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h2>
|
||||||
|
<a NAME="License"></a>License</h2>
|
||||||
|
|
||||||
|
<table width="600">
|
||||||
|
<tr><td>
|
||||||
|
<p>
|
||||||
|
PortAudio Portable Real-Time Audio Library
|
||||||
|
<br>Copyright © 1999-2006 Ross Bencina and Phil Burk
|
||||||
|
</p>
|
||||||
|
<p>Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the Software
|
||||||
|
is furnished to do so, subject to the following conditions:
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The above copyright notice and this permission notice shall be included
|
||||||
|
in all copies or substantial portions of the Software.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||||
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND ON INFRINGEMENT.
|
||||||
|
<br>IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
||||||
|
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
||||||
|
THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><i>
|
||||||
|
The text above constitutes the entire PortAudio license; however,
|
||||||
|
the PortAudio community also makes the following non-binding requests:
|
||||||
|
</i></p>
|
||||||
|
<p><i>
|
||||||
|
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. It is also
|
||||||
|
requested that these non-binding requests be included along with the
|
||||||
|
license above.
|
||||||
|
</i></p>
|
||||||
|
|
||||||
|
</td></tr></table>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<br>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,251 @@
|
||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# install - install a program, script, or datafile
|
||||||
|
# This comes from X11R5 (mit/util/scripts/install.sh).
|
||||||
|
#
|
||||||
|
# Copyright 1991 by the Massachusetts Institute of Technology
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, distribute, and sell this software and its
|
||||||
|
# documentation for any purpose is hereby granted without fee, provided that
|
||||||
|
# the above copyright notice appear in all copies and that both that
|
||||||
|
# copyright notice and this permission notice appear in supporting
|
||||||
|
# documentation, and that the name of M.I.T. not be used in advertising or
|
||||||
|
# publicity pertaining to distribution of the software without specific,
|
||||||
|
# written prior permission. M.I.T. makes no representations about the
|
||||||
|
# suitability of this software for any purpose. It is provided "as is"
|
||||||
|
# without express or implied warranty.
|
||||||
|
#
|
||||||
|
# Calling this script install-sh is preferred over install.sh, to prevent
|
||||||
|
# `make' implicit rules from creating a file called install from it
|
||||||
|
# when there is no Makefile.
|
||||||
|
#
|
||||||
|
# This script is compatible with the BSD install script, but was written
|
||||||
|
# from scratch. It can only install one file at a time, a restriction
|
||||||
|
# shared with many OS's install programs.
|
||||||
|
|
||||||
|
|
||||||
|
# set DOITPROG to echo to test this script
|
||||||
|
|
||||||
|
# Don't use :- since 4.3BSD and earlier shells don't like it.
|
||||||
|
doit="${DOITPROG-}"
|
||||||
|
|
||||||
|
|
||||||
|
# put in absolute paths if you don't have them in your path; or use env. vars.
|
||||||
|
|
||||||
|
mvprog="${MVPROG-mv}"
|
||||||
|
cpprog="${CPPROG-cp}"
|
||||||
|
chmodprog="${CHMODPROG-chmod}"
|
||||||
|
chownprog="${CHOWNPROG-chown}"
|
||||||
|
chgrpprog="${CHGRPPROG-chgrp}"
|
||||||
|
stripprog="${STRIPPROG-strip}"
|
||||||
|
rmprog="${RMPROG-rm}"
|
||||||
|
mkdirprog="${MKDIRPROG-mkdir}"
|
||||||
|
|
||||||
|
transformbasename=""
|
||||||
|
transform_arg=""
|
||||||
|
instcmd="$mvprog"
|
||||||
|
chmodcmd="$chmodprog 0755"
|
||||||
|
chowncmd=""
|
||||||
|
chgrpcmd=""
|
||||||
|
stripcmd=""
|
||||||
|
rmcmd="$rmprog -f"
|
||||||
|
mvcmd="$mvprog"
|
||||||
|
src=""
|
||||||
|
dst=""
|
||||||
|
dir_arg=""
|
||||||
|
|
||||||
|
while [ x"$1" != x ]; do
|
||||||
|
case $1 in
|
||||||
|
-c) instcmd="$cpprog"
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-d) dir_arg=true
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-m) chmodcmd="$chmodprog $2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-o) chowncmd="$chownprog $2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-g) chgrpcmd="$chgrpprog $2"
|
||||||
|
shift
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-s) stripcmd="$stripprog"
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
|
||||||
|
*) if [ x"$src" = x ]
|
||||||
|
then
|
||||||
|
src=$1
|
||||||
|
else
|
||||||
|
# this colon is to work around a 386BSD /bin/sh bug
|
||||||
|
:
|
||||||
|
dst=$1
|
||||||
|
fi
|
||||||
|
shift
|
||||||
|
continue;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ x"$src" = x ]
|
||||||
|
then
|
||||||
|
echo "install: no input file specified"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x"$dir_arg" != x ]; then
|
||||||
|
dst=$src
|
||||||
|
src=""
|
||||||
|
|
||||||
|
if [ -d $dst ]; then
|
||||||
|
instcmd=:
|
||||||
|
chmodcmd=""
|
||||||
|
else
|
||||||
|
instcmd=mkdir
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
|
||||||
|
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||||
|
# might cause directories to be created, which would be especially bad
|
||||||
|
# if $src (and thus $dsttmp) contains '*'.
|
||||||
|
|
||||||
|
if [ -f $src -o -d $src ]
|
||||||
|
then
|
||||||
|
true
|
||||||
|
else
|
||||||
|
echo "install: $src does not exist"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x"$dst" = x ]
|
||||||
|
then
|
||||||
|
echo "install: no destination specified"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If destination is a directory, append the input filename; if your system
|
||||||
|
# does not like double slashes in filenames, you may need to add some logic
|
||||||
|
|
||||||
|
if [ -d $dst ]
|
||||||
|
then
|
||||||
|
dst="$dst"/`basename $src`
|
||||||
|
else
|
||||||
|
true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
## this sed command emulates the dirname command
|
||||||
|
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||||
|
|
||||||
|
# Make sure that the destination directory exists.
|
||||||
|
# this part is taken from Noah Friedman's mkinstalldirs script
|
||||||
|
|
||||||
|
# Skip lots of stat calls in the usual case.
|
||||||
|
if [ ! -d "$dstdir" ]; then
|
||||||
|
defaultIFS='
|
||||||
|
'
|
||||||
|
IFS="${IFS-${defaultIFS}}"
|
||||||
|
|
||||||
|
oIFS="${IFS}"
|
||||||
|
# Some sh's can't handle IFS=/ for some reason.
|
||||||
|
IFS='%'
|
||||||
|
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
|
||||||
|
IFS="${oIFS}"
|
||||||
|
|
||||||
|
pathcomp=''
|
||||||
|
|
||||||
|
while [ $# -ne 0 ] ; do
|
||||||
|
pathcomp="${pathcomp}${1}"
|
||||||
|
shift
|
||||||
|
|
||||||
|
if [ ! -d "${pathcomp}" ] ;
|
||||||
|
then
|
||||||
|
$mkdirprog "${pathcomp}"
|
||||||
|
else
|
||||||
|
true
|
||||||
|
fi
|
||||||
|
|
||||||
|
pathcomp="${pathcomp}/"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ x"$dir_arg" != x ]
|
||||||
|
then
|
||||||
|
$doit $instcmd $dst &&
|
||||||
|
|
||||||
|
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
|
||||||
|
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
|
||||||
|
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
|
||||||
|
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
|
||||||
|
else
|
||||||
|
|
||||||
|
# If we're going to rename the final executable, determine the name now.
|
||||||
|
|
||||||
|
if [ x"$transformarg" = x ]
|
||||||
|
then
|
||||||
|
dstfile=`basename $dst`
|
||||||
|
else
|
||||||
|
dstfile=`basename $dst $transformbasename |
|
||||||
|
sed $transformarg`$transformbasename
|
||||||
|
fi
|
||||||
|
|
||||||
|
# don't allow the sed command to completely eliminate the filename
|
||||||
|
|
||||||
|
if [ x"$dstfile" = x ]
|
||||||
|
then
|
||||||
|
dstfile=`basename $dst`
|
||||||
|
else
|
||||||
|
true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make a temp file name in the proper directory.
|
||||||
|
|
||||||
|
dsttmp=$dstdir/#inst.$$#
|
||||||
|
|
||||||
|
# Move or copy the file name to the temp name
|
||||||
|
|
||||||
|
$doit $instcmd $src $dsttmp &&
|
||||||
|
|
||||||
|
trap "rm -f ${dsttmp}" 0 &&
|
||||||
|
|
||||||
|
# and set any options; do chmod last to preserve setuid bits
|
||||||
|
|
||||||
|
# If any of these fail, we abort the whole thing. If we want to
|
||||||
|
# ignore errors from any of these, just make sure not to ignore
|
||||||
|
# errors from the above "$doit $instcmd $src $dsttmp" command.
|
||||||
|
|
||||||
|
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
|
||||||
|
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
|
||||||
|
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
|
||||||
|
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
|
||||||
|
|
||||||
|
# Now rename the file to the real destination.
|
||||||
|
|
||||||
|
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||||
|
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||||
|
|
||||||
|
fi &&
|
||||||
|
|
||||||
|
|
||||||
|
exit 0
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,360 @@
|
||||||
|
#! /bin/sh
|
||||||
|
# Common stub for a few missing GNU programs while installing.
|
||||||
|
|
||||||
|
scriptversion=2005-06-08.21
|
||||||
|
|
||||||
|
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005
|
||||||
|
# Free Software Foundation, Inc.
|
||||||
|
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
# any later version.
|
||||||
|
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
# 02110-1301, USA.
|
||||||
|
|
||||||
|
# As a special exception to the GNU General Public License, if you
|
||||||
|
# distribute this file as part of a program that contains a
|
||||||
|
# configuration script generated by Autoconf, you may include it under
|
||||||
|
# the same distribution terms that you use for the rest of that program.
|
||||||
|
|
||||||
|
if test $# -eq 0; then
|
||||||
|
echo 1>&2 "Try \`$0 --help' for more information"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
run=:
|
||||||
|
|
||||||
|
# In the cases where this matters, `missing' is being run in the
|
||||||
|
# srcdir already.
|
||||||
|
if test -f configure.ac; then
|
||||||
|
configure_ac=configure.ac
|
||||||
|
else
|
||||||
|
configure_ac=configure.in
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg="missing on your system"
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
--run)
|
||||||
|
# Try to run requested program, and just exit if it succeeds.
|
||||||
|
run=
|
||||||
|
shift
|
||||||
|
"$@" && exit 0
|
||||||
|
# Exit code 63 means version mismatch. This often happens
|
||||||
|
# when the user try to use an ancient version of a tool on
|
||||||
|
# a file that requires a minimum version. In this case we
|
||||||
|
# we should proceed has if the program had been absent, or
|
||||||
|
# if --run hadn't been passed.
|
||||||
|
if test $? = 63; then
|
||||||
|
run=:
|
||||||
|
msg="probably too old"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
-h|--h|--he|--hel|--help)
|
||||||
|
echo "\
|
||||||
|
$0 [OPTION]... PROGRAM [ARGUMENT]...
|
||||||
|
|
||||||
|
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
|
||||||
|
error status if there is no known handling for PROGRAM.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help display this help and exit
|
||||||
|
-v, --version output version information and exit
|
||||||
|
--run try to run the given command, and emulate it if it fails
|
||||||
|
|
||||||
|
Supported PROGRAM values:
|
||||||
|
aclocal touch file \`aclocal.m4'
|
||||||
|
autoconf touch file \`configure'
|
||||||
|
autoheader touch file \`config.h.in'
|
||||||
|
automake touch all \`Makefile.in' files
|
||||||
|
bison create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||||
|
flex create \`lex.yy.c', if possible, from existing .c
|
||||||
|
help2man touch the output file
|
||||||
|
lex create \`lex.yy.c', if possible, from existing .c
|
||||||
|
makeinfo touch the output file
|
||||||
|
tar try tar, gnutar, gtar, then tar without non-portable flags
|
||||||
|
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
|
||||||
|
|
||||||
|
Send bug reports to <bug-automake@gnu.org>."
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
|
||||||
|
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
|
||||||
|
echo "missing $scriptversion (GNU Automake)"
|
||||||
|
exit $?
|
||||||
|
;;
|
||||||
|
|
||||||
|
-*)
|
||||||
|
echo 1>&2 "$0: Unknown \`$1' option"
|
||||||
|
echo 1>&2 "Try \`$0 --help' for more information"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Now exit if we have it, but it failed. Also exit now if we
|
||||||
|
# don't have it and --version was passed (most likely to detect
|
||||||
|
# the program).
|
||||||
|
case "$1" in
|
||||||
|
lex|yacc)
|
||||||
|
# Not GNU programs, they don't have --version.
|
||||||
|
;;
|
||||||
|
|
||||||
|
tar)
|
||||||
|
if test -n "$run"; then
|
||||||
|
echo 1>&2 "ERROR: \`tar' requires --run"
|
||||||
|
exit 1
|
||||||
|
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
|
||||||
|
# We have it, but it failed.
|
||||||
|
exit 1
|
||||||
|
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
|
||||||
|
# Could not run --version or --help. This is probably someone
|
||||||
|
# running `$TOOL --version' or `$TOOL --help' to check whether
|
||||||
|
# $TOOL exists and not knowing $TOOL uses missing.
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# If it does not exist, or fails to run (possibly an outdated version),
|
||||||
|
# try to emulate it.
|
||||||
|
case "$1" in
|
||||||
|
aclocal*)
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: \`$1' is $msg. You should only need it if
|
||||||
|
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
|
||||||
|
to install the \`Automake' and \`Perl' packages. Grab them from
|
||||||
|
any GNU archive site."
|
||||||
|
touch aclocal.m4
|
||||||
|
;;
|
||||||
|
|
||||||
|
autoconf)
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: \`$1' is $msg. You should only need it if
|
||||||
|
you modified \`${configure_ac}'. You might want to install the
|
||||||
|
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
|
||||||
|
archive site."
|
||||||
|
touch configure
|
||||||
|
;;
|
||||||
|
|
||||||
|
autoheader)
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: \`$1' is $msg. You should only need it if
|
||||||
|
you modified \`acconfig.h' or \`${configure_ac}'. You might want
|
||||||
|
to install the \`Autoconf' and \`GNU m4' packages. Grab them
|
||||||
|
from any GNU archive site."
|
||||||
|
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
|
||||||
|
test -z "$files" && files="config.h"
|
||||||
|
touch_files=
|
||||||
|
for f in $files; do
|
||||||
|
case "$f" in
|
||||||
|
*:*) touch_files="$touch_files "`echo "$f" |
|
||||||
|
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
|
||||||
|
*) touch_files="$touch_files $f.in";;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
touch $touch_files
|
||||||
|
;;
|
||||||
|
|
||||||
|
automake*)
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: \`$1' is $msg. You should only need it if
|
||||||
|
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
|
||||||
|
You might want to install the \`Automake' and \`Perl' packages.
|
||||||
|
Grab them from any GNU archive site."
|
||||||
|
find . -type f -name Makefile.am -print |
|
||||||
|
sed 's/\.am$/.in/' |
|
||||||
|
while read f; do touch "$f"; done
|
||||||
|
;;
|
||||||
|
|
||||||
|
autom4te)
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: \`$1' is needed, but is $msg.
|
||||||
|
You might have modified some files without having the
|
||||||
|
proper tools for further handling them.
|
||||||
|
You can get \`$1' as part of \`Autoconf' from any GNU
|
||||||
|
archive site."
|
||||||
|
|
||||||
|
file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
|
||||||
|
test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
|
||||||
|
if test -f "$file"; then
|
||||||
|
touch $file
|
||||||
|
else
|
||||||
|
test -z "$file" || exec >$file
|
||||||
|
echo "#! /bin/sh"
|
||||||
|
echo "# Created by GNU Automake missing as a replacement of"
|
||||||
|
echo "# $ $@"
|
||||||
|
echo "exit 0"
|
||||||
|
chmod +x $file
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
bison|yacc)
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: \`$1' $msg. You should only need it if
|
||||||
|
you modified a \`.y' file. You may need the \`Bison' package
|
||||||
|
in order for those modifications to take effect. You can get
|
||||||
|
\`Bison' from any GNU archive site."
|
||||||
|
rm -f y.tab.c y.tab.h
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
eval LASTARG="\${$#}"
|
||||||
|
case "$LASTARG" in
|
||||||
|
*.y)
|
||||||
|
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
|
||||||
|
if [ -f "$SRCFILE" ]; then
|
||||||
|
cp "$SRCFILE" y.tab.c
|
||||||
|
fi
|
||||||
|
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
|
||||||
|
if [ -f "$SRCFILE" ]; then
|
||||||
|
cp "$SRCFILE" y.tab.h
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
if [ ! -f y.tab.h ]; then
|
||||||
|
echo >y.tab.h
|
||||||
|
fi
|
||||||
|
if [ ! -f y.tab.c ]; then
|
||||||
|
echo 'main() { return 0; }' >y.tab.c
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
lex|flex)
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: \`$1' is $msg. You should only need it if
|
||||||
|
you modified a \`.l' file. You may need the \`Flex' package
|
||||||
|
in order for those modifications to take effect. You can get
|
||||||
|
\`Flex' from any GNU archive site."
|
||||||
|
rm -f lex.yy.c
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
eval LASTARG="\${$#}"
|
||||||
|
case "$LASTARG" in
|
||||||
|
*.l)
|
||||||
|
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
|
||||||
|
if [ -f "$SRCFILE" ]; then
|
||||||
|
cp "$SRCFILE" lex.yy.c
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
if [ ! -f lex.yy.c ]; then
|
||||||
|
echo 'main() { return 0; }' >lex.yy.c
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
help2man)
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: \`$1' is $msg. You should only need it if
|
||||||
|
you modified a dependency of a manual page. You may need the
|
||||||
|
\`Help2man' package in order for those modifications to take
|
||||||
|
effect. You can get \`Help2man' from any GNU archive site."
|
||||||
|
|
||||||
|
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
|
||||||
|
if test -z "$file"; then
|
||||||
|
file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
|
||||||
|
fi
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
touch $file
|
||||||
|
else
|
||||||
|
test -z "$file" || exec >$file
|
||||||
|
echo ".ab help2man is required to generate this page"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
makeinfo)
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: \`$1' is $msg. You should only need it if
|
||||||
|
you modified a \`.texi' or \`.texinfo' file, or any other file
|
||||||
|
indirectly affecting the aspect of the manual. The spurious
|
||||||
|
call might also be the consequence of using a buggy \`make' (AIX,
|
||||||
|
DU, IRIX). You might want to install the \`Texinfo' package or
|
||||||
|
the \`GNU make' package. Grab either from any GNU archive site."
|
||||||
|
# The file to touch is that specified with -o ...
|
||||||
|
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
|
||||||
|
if test -z "$file"; then
|
||||||
|
# ... or it is the one specified with @setfilename ...
|
||||||
|
infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
|
||||||
|
file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile`
|
||||||
|
# ... or it is derived from the source name (dir/f.texi becomes f.info)
|
||||||
|
test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
|
||||||
|
fi
|
||||||
|
# If the file does not exist, the user really needs makeinfo;
|
||||||
|
# let's fail without touching anything.
|
||||||
|
test -f $file || exit 1
|
||||||
|
touch $file
|
||||||
|
;;
|
||||||
|
|
||||||
|
tar)
|
||||||
|
shift
|
||||||
|
|
||||||
|
# We have already tried tar in the generic part.
|
||||||
|
# Look for gnutar/gtar before invocation to avoid ugly error
|
||||||
|
# messages.
|
||||||
|
if (gnutar --version > /dev/null 2>&1); then
|
||||||
|
gnutar "$@" && exit 0
|
||||||
|
fi
|
||||||
|
if (gtar --version > /dev/null 2>&1); then
|
||||||
|
gtar "$@" && exit 0
|
||||||
|
fi
|
||||||
|
firstarg="$1"
|
||||||
|
if shift; then
|
||||||
|
case "$firstarg" in
|
||||||
|
*o*)
|
||||||
|
firstarg=`echo "$firstarg" | sed s/o//`
|
||||||
|
tar "$firstarg" "$@" && exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
case "$firstarg" in
|
||||||
|
*h*)
|
||||||
|
firstarg=`echo "$firstarg" | sed s/h//`
|
||||||
|
tar "$firstarg" "$@" && exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: I can't seem to be able to run \`tar' with the given arguments.
|
||||||
|
You may want to install GNU tar or Free paxutils, or check the
|
||||||
|
command line arguments."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo 1>&2 "\
|
||||||
|
WARNING: \`$1' is needed, and is $msg.
|
||||||
|
You might have modified some files without having the
|
||||||
|
proper tools for further handling them. Check the \`README' file,
|
||||||
|
it often tells you about the needed prerequisites for installing
|
||||||
|
this package. You may also peek at any GNU archive site, in case
|
||||||
|
some other package would contain this missing \`$1' program."
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
||||||
|
|
||||||
|
# Local variables:
|
||||||
|
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||||
|
# time-stamp-start: "scriptversion="
|
||||||
|
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||||
|
# time-stamp-end: "$"
|
||||||
|
# End:
|
|
@ -0,0 +1,45 @@
|
||||||
|
README for PABLIO
|
||||||
|
Portable Audio Blocking I/O Library
|
||||||
|
Author: Phil Burk
|
||||||
|
|
||||||
|
PABLIO is a simplified interface to PortAudio that provide
|
||||||
|
read/write style blocking I/O.
|
||||||
|
|
||||||
|
Please see the .DOC file for documentation.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* More information on PortAudio at: http://www.portaudio.com
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,314 @@
|
||||||
|
/*
|
||||||
|
* $Id: pablio.c 1151 2006-11-29 02:11:16Z leland_lucius $
|
||||||
|
* pablio.c
|
||||||
|
* Portable Audio Blocking Input/Output utility.
|
||||||
|
*
|
||||||
|
* Author: Phil Burk, http://www.softsynth.com
|
||||||
|
*
|
||||||
|
* This program uses the PortAudio Portable Audio Library.
|
||||||
|
* For more information see: http://www.portaudio.com
|
||||||
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "portaudio.h"
|
||||||
|
#include "pa_ringbuffer.h"
|
||||||
|
#include "pablio.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/******** Constants *****************************************************/
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
#define FRAMES_PER_BUFFER (256)
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/******** Prototypes ****************************************************/
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
|
||||||
|
unsigned long framesPerBuffer,
|
||||||
|
PaTimestamp outTime, void *userData );
|
||||||
|
static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );
|
||||||
|
static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
|
||||||
|
|
||||||
|
/************************************************************************/
|
||||||
|
/******** Functions *****************************************************/
|
||||||
|
/************************************************************************/
|
||||||
|
|
||||||
|
/* Called from PortAudio.
|
||||||
|
* Read and write data only if there is room in FIFOs.
|
||||||
|
*/
|
||||||
|
static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
|
||||||
|
unsigned long framesPerBuffer,
|
||||||
|
PaTimestamp outTime, void *userData )
|
||||||
|
{
|
||||||
|
PABLIO_Stream *data = (PABLIO_Stream*)userData;
|
||||||
|
long numBytes = data->bytesPerFrame * framesPerBuffer;
|
||||||
|
(void) outTime;
|
||||||
|
|
||||||
|
/* This may get called with NULL inputBuffer during initial setup. */
|
||||||
|
if( inputBuffer != NULL )
|
||||||
|
{
|
||||||
|
PaUtil_WriteRingBuffer( &data->inFIFO, inputBuffer, numBytes );
|
||||||
|
}
|
||||||
|
if( outputBuffer != NULL )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int numRead = PaUtil_ReadRingBuffer( &data->outFIFO, outputBuffer, numBytes );
|
||||||
|
/* Zero out remainder of buffer if we run out of data. */
|
||||||
|
for( i=numRead; i<numBytes; i++ )
|
||||||
|
{
|
||||||
|
((char *)outputBuffer)[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate buffer. */
|
||||||
|
static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )
|
||||||
|
{
|
||||||
|
long numBytes = numFrames * bytesPerFrame;
|
||||||
|
char *buffer = (char *) malloc( numBytes );
|
||||||
|
if( buffer == NULL ) return paInsufficientMemory;
|
||||||
|
memset( buffer, 0, numBytes );
|
||||||
|
return (PaError) PaUtil_InitializeRingBuffer( rbuf, numBytes, buffer );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free buffer. */
|
||||||
|
static PaError PABLIO_TermFIFO( RingBuffer *rbuf )
|
||||||
|
{
|
||||||
|
if( rbuf->buffer ) free( rbuf->buffer );
|
||||||
|
rbuf->buffer = NULL;
|
||||||
|
return paNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Write data to ring buffer.
|
||||||
|
* Will not return until all the data has been written.
|
||||||
|
*/
|
||||||
|
long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
|
||||||
|
{
|
||||||
|
long bytesWritten;
|
||||||
|
char *p = (char *) data;
|
||||||
|
long numBytes = aStream->bytesPerFrame * numFrames;
|
||||||
|
while( numBytes > 0)
|
||||||
|
{
|
||||||
|
bytesWritten = PaUtil_WriteRingBuffer( &aStream->outFIFO, p, numBytes );
|
||||||
|
numBytes -= bytesWritten;
|
||||||
|
p += bytesWritten;
|
||||||
|
if( numBytes > 0) Pa_Sleep(10);
|
||||||
|
}
|
||||||
|
return numFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Read data from ring buffer.
|
||||||
|
* Will not return until all the data has been read.
|
||||||
|
*/
|
||||||
|
long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
|
||||||
|
{
|
||||||
|
long bytesRead;
|
||||||
|
char *p = (char *) data;
|
||||||
|
long numBytes = aStream->bytesPerFrame * numFrames;
|
||||||
|
while( numBytes > 0)
|
||||||
|
{
|
||||||
|
bytesRead = PaUtil_ReadRingBuffer( &aStream->inFIFO, p, numBytes );
|
||||||
|
numBytes -= bytesRead;
|
||||||
|
p += bytesRead;
|
||||||
|
if( numBytes > 0) Pa_Sleep(10);
|
||||||
|
}
|
||||||
|
return numFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Return the number of frames that could be written to the stream without
|
||||||
|
* having to wait.
|
||||||
|
*/
|
||||||
|
long GetAudioStreamWriteable( PABLIO_Stream *aStream )
|
||||||
|
{
|
||||||
|
int bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO );
|
||||||
|
return bytesEmpty / aStream->bytesPerFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Return the number of frames that are available to be read from the
|
||||||
|
* stream without having to wait.
|
||||||
|
*/
|
||||||
|
long GetAudioStreamReadable( PABLIO_Stream *aStream )
|
||||||
|
{
|
||||||
|
int bytesFull = PaUtil_GetRingBufferReadAvailable( &aStream->inFIFO );
|
||||||
|
return bytesFull / aStream->bytesPerFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************/
|
||||||
|
static unsigned long RoundUpToNextPowerOf2( unsigned long n )
|
||||||
|
{
|
||||||
|
long numBits = 0;
|
||||||
|
if( ((n-1) & n) == 0) return n; /* Already Power of two. */
|
||||||
|
while( n > 0 )
|
||||||
|
{
|
||||||
|
n= n>>1;
|
||||||
|
numBits++;
|
||||||
|
}
|
||||||
|
return (1<<numBits);
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Opens a PortAudio stream with default characteristics.
|
||||||
|
* Allocates PABLIO_Stream structure.
|
||||||
|
*
|
||||||
|
* flags parameter can be an ORed combination of:
|
||||||
|
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
|
||||||
|
* and either PABLIO_MONO or PABLIO_STEREO
|
||||||
|
*/
|
||||||
|
PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
|
||||||
|
PaSampleFormat format, long flags )
|
||||||
|
{
|
||||||
|
long bytesPerSample;
|
||||||
|
long doRead = 0;
|
||||||
|
long doWrite = 0;
|
||||||
|
PaError err;
|
||||||
|
PABLIO_Stream *aStream;
|
||||||
|
long minNumBuffers;
|
||||||
|
long numFrames;
|
||||||
|
|
||||||
|
/* Allocate PABLIO_Stream structure for caller. */
|
||||||
|
aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );
|
||||||
|
if( aStream == NULL ) return paInsufficientMemory;
|
||||||
|
memset( aStream, 0, sizeof(PABLIO_Stream) );
|
||||||
|
|
||||||
|
/* Determine size of a sample. */
|
||||||
|
bytesPerSample = Pa_GetSampleSize( format );
|
||||||
|
if( bytesPerSample < 0 )
|
||||||
|
{
|
||||||
|
err = (PaError) bytesPerSample;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
aStream->samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2;
|
||||||
|
aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
|
||||||
|
|
||||||
|
/* Initialize PortAudio */
|
||||||
|
err = Pa_Initialize();
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
/* Warning: numFrames must be larger than amount of data processed per interrupt
|
||||||
|
* inside PA to prevent glitches. Just to be safe, adjust size upwards.
|
||||||
|
*/
|
||||||
|
minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );
|
||||||
|
numFrames = minNumBuffers * FRAMES_PER_BUFFER;
|
||||||
|
numFrames = RoundUpToNextPowerOf2( numFrames );
|
||||||
|
|
||||||
|
/* Initialize Ring Buffers */
|
||||||
|
doRead = ((flags & PABLIO_READ) != 0);
|
||||||
|
doWrite = ((flags & PABLIO_WRITE) != 0);
|
||||||
|
if(doRead)
|
||||||
|
{
|
||||||
|
err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
}
|
||||||
|
if(doWrite)
|
||||||
|
{
|
||||||
|
long numBytes;
|
||||||
|
err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
/* Make Write FIFO appear full initially. */
|
||||||
|
numBytes = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO );
|
||||||
|
PaUtil_AdvanceRingBufferWriteIndex( &aStream->outFIFO, numBytes );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open a PortAudio stream that we will use to communicate with the underlying
|
||||||
|
* audio drivers. */
|
||||||
|
err = Pa_OpenStream(
|
||||||
|
&aStream->stream,
|
||||||
|
(doRead ? Pa_GetDefaultInputDeviceID() : paNoDevice),
|
||||||
|
(doRead ? aStream->samplesPerFrame : 0 ),
|
||||||
|
format,
|
||||||
|
NULL,
|
||||||
|
(doWrite ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
|
||||||
|
(doWrite ? aStream->samplesPerFrame : 0 ),
|
||||||
|
format,
|
||||||
|
NULL,
|
||||||
|
sampleRate,
|
||||||
|
FRAMES_PER_BUFFER,
|
||||||
|
minNumBuffers,
|
||||||
|
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||||
|
blockingIOCallback,
|
||||||
|
aStream );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
err = Pa_StartStream( aStream->stream );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
*rwblPtr = aStream;
|
||||||
|
return paNoError;
|
||||||
|
|
||||||
|
error:
|
||||||
|
CloseAudioStream( aStream );
|
||||||
|
*rwblPtr = NULL;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************/
|
||||||
|
PaError CloseAudioStream( PABLIO_Stream *aStream )
|
||||||
|
{
|
||||||
|
PaError err;
|
||||||
|
int bytesEmpty;
|
||||||
|
int byteSize = aStream->outFIFO.bufferSize;
|
||||||
|
|
||||||
|
/* If we are writing data, make sure we play everything written. */
|
||||||
|
if( byteSize > 0 )
|
||||||
|
{
|
||||||
|
bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO );
|
||||||
|
while( bytesEmpty < byteSize )
|
||||||
|
{
|
||||||
|
Pa_Sleep( 10 );
|
||||||
|
bytesEmpty = PaUtil_GetRingBufferWriteAvailable( &aStream->outFIFO );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = Pa_StopStream( aStream->stream );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
err = Pa_CloseStream( aStream->stream );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
Pa_Terminate();
|
||||||
|
|
||||||
|
error:
|
||||||
|
PABLIO_TermFIFO( &aStream->inFIFO );
|
||||||
|
PABLIO_TermFIFO( &aStream->outFIFO );
|
||||||
|
free( aStream );
|
||||||
|
return err;
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
LIBRARY PABLIO
|
||||||
|
DESCRIPTION 'PABLIO Portable Audio Blocking I/O'
|
||||||
|
|
||||||
|
EXPORTS
|
||||||
|
; Explicit exports can go here
|
||||||
|
Pa_Initialize @1
|
||||||
|
Pa_Terminate @2
|
||||||
|
Pa_GetHostError @3
|
||||||
|
Pa_GetErrorText @4
|
||||||
|
Pa_CountDevices @5
|
||||||
|
Pa_GetDefaultInputDeviceID @6
|
||||||
|
Pa_GetDefaultOutputDeviceID @7
|
||||||
|
Pa_GetDeviceInfo @8
|
||||||
|
Pa_OpenStream @9
|
||||||
|
Pa_OpenDefaultStream @10
|
||||||
|
Pa_CloseStream @11
|
||||||
|
Pa_StartStream @12
|
||||||
|
Pa_StopStream @13
|
||||||
|
Pa_StreamActive @14
|
||||||
|
Pa_StreamTime @15
|
||||||
|
Pa_GetCPULoad @16
|
||||||
|
Pa_GetMinNumBuffers @17
|
||||||
|
Pa_Sleep @18
|
||||||
|
|
||||||
|
OpenAudioStream @19
|
||||||
|
CloseAudioStream @20
|
||||||
|
WriteAudioStream @21
|
||||||
|
ReadAudioStream @22
|
||||||
|
|
||||||
|
Pa_GetSampleSize @23
|
||||||
|
|
||||||
|
;123456789012345678901234567890123456
|
||||||
|
;000000000111111111122222222223333333
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
#ifndef _PABLIO_H
|
||||||
|
#define _PABLIO_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* $Id: pablio.h 1083 2006-08-23 07:30:49Z rossb $
|
||||||
|
* PABLIO.h
|
||||||
|
* Portable Audio Blocking read/write utility.
|
||||||
|
*
|
||||||
|
* Author: Phil Burk, http://www.softsynth.com/portaudio/
|
||||||
|
*
|
||||||
|
* Include file for PABLIO, the Portable Audio Blocking I/O Library.
|
||||||
|
* PABLIO is built on top of PortAudio, the Portable Audio Library.
|
||||||
|
* For more information see: http://www.portaudio.com
|
||||||
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "portaudio.h"
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
RingBuffer inFIFO;
|
||||||
|
RingBuffer outFIFO;
|
||||||
|
PortAudioStream *stream;
|
||||||
|
int bytesPerFrame;
|
||||||
|
int samplesPerFrame;
|
||||||
|
}
|
||||||
|
PABLIO_Stream;
|
||||||
|
|
||||||
|
/* Values for flags for OpenAudioStream(). */
|
||||||
|
#define PABLIO_READ (1<<0)
|
||||||
|
#define PABLIO_WRITE (1<<1)
|
||||||
|
#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE)
|
||||||
|
#define PABLIO_MONO (1<<2)
|
||||||
|
#define PABLIO_STEREO (1<<3)
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Write data to ring buffer.
|
||||||
|
* Will not return until all the data has been written.
|
||||||
|
*/
|
||||||
|
long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Read data from ring buffer.
|
||||||
|
* Will not return until all the data has been read.
|
||||||
|
*/
|
||||||
|
long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Return the number of frames that could be written to the stream without
|
||||||
|
* having to wait.
|
||||||
|
*/
|
||||||
|
long GetAudioStreamWriteable( PABLIO_Stream *aStream );
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Return the number of frames that are available to be read from the
|
||||||
|
* stream without having to wait.
|
||||||
|
*/
|
||||||
|
long GetAudioStreamReadable( PABLIO_Stream *aStream );
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* Opens a PortAudio stream with default characteristics.
|
||||||
|
* Allocates PABLIO_Stream structure.
|
||||||
|
*
|
||||||
|
* flags parameter can be an ORed combination of:
|
||||||
|
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
|
||||||
|
* and either PABLIO_MONO or PABLIO_STEREO
|
||||||
|
*/
|
||||||
|
PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,
|
||||||
|
PaSampleFormat format, long flags );
|
||||||
|
|
||||||
|
PaError CloseAudioStream( PABLIO_Stream *aStream );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* _PABLIO_H */
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* $Id: test_rw.c 1083 2006-08-23 07:30:49Z rossb $
|
||||||
|
* test_rw.c
|
||||||
|
* Read input from one stream and write it to another.
|
||||||
|
*
|
||||||
|
* Author: Phil Burk, http://www.softsynth.com/portaudio/
|
||||||
|
*
|
||||||
|
* This program uses PABLIO, the Portable Audio Blocking I/O Library.
|
||||||
|
* PABLIO is built on top of PortAudio, the Portable Audio Library.
|
||||||
|
* For more information see: http://www.portaudio.com
|
||||||
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "pablio.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Note that many of the older ISA sound cards on PCs do NOT support
|
||||||
|
** full duplex audio (simultaneous record and playback).
|
||||||
|
** And some only support full duplex at lower sample rates.
|
||||||
|
*/
|
||||||
|
#define SAMPLE_RATE (44100)
|
||||||
|
#define NUM_SECONDS (5)
|
||||||
|
#define SAMPLES_PER_FRAME (2)
|
||||||
|
#define FRAMES_PER_BLOCK (64)
|
||||||
|
|
||||||
|
/* Select whether we will use floats or shorts. */
|
||||||
|
#if 1
|
||||||
|
#define SAMPLE_TYPE paFloat32
|
||||||
|
typedef float SAMPLE;
|
||||||
|
#else
|
||||||
|
#define SAMPLE_TYPE paInt16
|
||||||
|
typedef short SAMPLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
int main(void);
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK];
|
||||||
|
PaError err;
|
||||||
|
PABLIO_Stream *aStream;
|
||||||
|
|
||||||
|
printf("Full duplex sound test using PortAudio and RingBuffers\n");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
/* Open simplified blocking I/O layer on top of PortAudio. */
|
||||||
|
err = OpenAudioStream( &aStream, SAMPLE_RATE, SAMPLE_TYPE,
|
||||||
|
(PABLIO_READ_WRITE | PABLIO_STEREO) );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
/* Process samples in the foreground. */
|
||||||
|
for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK )
|
||||||
|
{
|
||||||
|
/* Read one block of data into sample array from audio input. */
|
||||||
|
ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK );
|
||||||
|
/* Write that same block of data to output. */
|
||||||
|
WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK );
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseAudioStream( aStream );
|
||||||
|
|
||||||
|
printf("Full duplex sound test complete.\n" );
|
||||||
|
fflush(stdout);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Pa_Terminate();
|
||||||
|
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||||
|
fprintf( stderr, "Error number: %d\n", err );
|
||||||
|
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
* $Id: test_rw_echo.c 1083 2006-08-23 07:30:49Z rossb $
|
||||||
|
* test_rw_echo.c
|
||||||
|
* Echo delayed input to output.
|
||||||
|
*
|
||||||
|
* Author: Phil Burk, http://www.softsynth.com/portaudio/
|
||||||
|
*
|
||||||
|
* This program uses PABLIO, the Portable Audio Blocking I/O Library.
|
||||||
|
* PABLIO is built on top of PortAudio, the Portable Audio Library.
|
||||||
|
*
|
||||||
|
* Note that if you need low latency, you should not use PABLIO.
|
||||||
|
* Use the PA_OpenStream callback technique which is lower level
|
||||||
|
* than PABLIO.
|
||||||
|
*
|
||||||
|
* For more information see: http://www.portaudio.com
|
||||||
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "pablio.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Note that many of the older ISA sound cards on PCs do NOT support
|
||||||
|
** full duplex audio (simultaneous record and playback).
|
||||||
|
** And some only support full duplex at lower sample rates.
|
||||||
|
*/
|
||||||
|
#define SAMPLE_RATE (22050)
|
||||||
|
#define NUM_SECONDS (20)
|
||||||
|
#define SAMPLES_PER_FRAME (2)
|
||||||
|
|
||||||
|
/* Select whether we will use floats or shorts. */
|
||||||
|
#if 1
|
||||||
|
#define SAMPLE_TYPE paFloat32
|
||||||
|
typedef float SAMPLE;
|
||||||
|
#else
|
||||||
|
#define SAMPLE_TYPE paInt16
|
||||||
|
typedef short SAMPLE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NUM_ECHO_FRAMES (2*SAMPLE_RATE)
|
||||||
|
SAMPLE samples[NUM_ECHO_FRAMES][SAMPLES_PER_FRAME] = {0.0};
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
int main(void);
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PaError err;
|
||||||
|
PABLIO_Stream *aInStream;
|
||||||
|
PABLIO_Stream *aOutStream;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
printf("Full duplex sound test using PABLIO\n");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
/* Open simplified blocking I/O layer on top of PortAudio. */
|
||||||
|
/* Open input first so it can start to fill buffers. */
|
||||||
|
err = OpenAudioStream( &aInStream, SAMPLE_RATE, SAMPLE_TYPE,
|
||||||
|
(PABLIO_READ | PABLIO_STEREO) );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
/* printf("opened input\n"); fflush(stdout); /**/
|
||||||
|
|
||||||
|
err = OpenAudioStream( &aOutStream, SAMPLE_RATE, SAMPLE_TYPE,
|
||||||
|
(PABLIO_WRITE | PABLIO_STEREO) );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
/* printf("opened output\n"); fflush(stdout); /**/
|
||||||
|
|
||||||
|
/* Process samples in the foreground. */
|
||||||
|
index = 0;
|
||||||
|
for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ )
|
||||||
|
{
|
||||||
|
/* Write old frame of data to output. */
|
||||||
|
/* samples[index][1] = (i&256) * (1.0f/256.0f); /* sawtooth */
|
||||||
|
WriteAudioStream( aOutStream, &samples[index][0], 1 );
|
||||||
|
|
||||||
|
/* Read one frame of data into sample array for later output. */
|
||||||
|
ReadAudioStream( aInStream, &samples[index][0], 1 );
|
||||||
|
index += 1;
|
||||||
|
if( index >= NUM_ECHO_FRAMES ) index = 0;
|
||||||
|
|
||||||
|
if( (i & 0xFFFF) == 0 ) printf("i = %d\n", i ); fflush(stdout); /**/
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseAudioStream( aOutStream );
|
||||||
|
CloseAudioStream( aInStream );
|
||||||
|
|
||||||
|
printf("R/W echo sound test complete.\n" );
|
||||||
|
fflush(stdout);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
fprintf( stderr, "An error occured while using PortAudio\n" );
|
||||||
|
fprintf( stderr, "Error number: %d\n", err );
|
||||||
|
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* $Id: test_w_saw.c 1083 2006-08-23 07:30:49Z rossb $
|
||||||
|
* test_w_saw.c
|
||||||
|
* Generate stereo sawtooth waveforms.
|
||||||
|
*
|
||||||
|
* Author: Phil Burk, http://www.softsynth.com
|
||||||
|
*
|
||||||
|
* This program uses PABLIO, the Portable Audio Blocking I/O Library.
|
||||||
|
* PABLIO is built on top of PortAudio, the Portable Audio Library.
|
||||||
|
*
|
||||||
|
* For more information see: http://www.portaudio.com
|
||||||
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "pablio.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SAMPLE_RATE (44100)
|
||||||
|
#define NUM_SECONDS (6)
|
||||||
|
#define SAMPLES_PER_FRAME (2)
|
||||||
|
|
||||||
|
#define FREQUENCY (220.0f)
|
||||||
|
#define PHASE_INCREMENT (2.0f * FREQUENCY / SAMPLE_RATE)
|
||||||
|
#define FRAMES_PER_BLOCK (100)
|
||||||
|
|
||||||
|
float samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME];
|
||||||
|
float phases[SAMPLES_PER_FRAME];
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
int main(void);
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
PaError err;
|
||||||
|
PABLIO_Stream *aOutStream;
|
||||||
|
|
||||||
|
printf("Generate sawtooth waves using PABLIO.\n");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
/* Open simplified blocking I/O layer on top of PortAudio. */
|
||||||
|
err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paFloat32,
|
||||||
|
(PABLIO_WRITE | PABLIO_STEREO) );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
/* Initialize oscillator phases. */
|
||||||
|
phases[0] = 0.0;
|
||||||
|
phases[1] = 0.0;
|
||||||
|
|
||||||
|
for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK )
|
||||||
|
{
|
||||||
|
/* Generate sawtooth waveforms in a block for efficiency. */
|
||||||
|
for( j=0; j<FRAMES_PER_BLOCK; j++ )
|
||||||
|
{
|
||||||
|
/* Generate a sawtooth wave by incrementing a variable. */
|
||||||
|
phases[0] += PHASE_INCREMENT;
|
||||||
|
/* The signal range is -1.0 to +1.0 so wrap around if we go over. */
|
||||||
|
if( phases[0] > 1.0f ) phases[0] -= 2.0f;
|
||||||
|
samples[j][0] = phases[0];
|
||||||
|
|
||||||
|
/* On the second channel, generate a sawtooth wave a fifth higher. */
|
||||||
|
phases[1] += PHASE_INCREMENT * (3.0f / 2.0f);
|
||||||
|
if( phases[1] > 1.0f ) phases[1] -= 2.0f;
|
||||||
|
samples[j][1] = phases[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write samples to output. */
|
||||||
|
WriteAudioStream( aOutStream, samples, FRAMES_PER_BLOCK );
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseAudioStream( aOutStream );
|
||||||
|
|
||||||
|
printf("Sawtooth sound test complete.\n" );
|
||||||
|
fflush(stdout);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
fprintf( stderr, "An error occured while using PABLIO\n" );
|
||||||
|
fprintf( stderr, "Error number: %d\n", err );
|
||||||
|
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* $Id: test_w_saw8.c 1083 2006-08-23 07:30:49Z rossb $
|
||||||
|
* test_w_saw8.c
|
||||||
|
* Generate stereo 8 bit sawtooth waveforms.
|
||||||
|
*
|
||||||
|
* Author: Phil Burk, http://www.softsynth.com
|
||||||
|
*
|
||||||
|
* This program uses PABLIO, the Portable Audio Blocking I/O Library.
|
||||||
|
* PABLIO is built on top of PortAudio, the Portable Audio Library.
|
||||||
|
*
|
||||||
|
* For more information see: http://www.portaudio.com
|
||||||
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "pablio.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define SAMPLE_RATE (22050)
|
||||||
|
#define NUM_SECONDS (6)
|
||||||
|
#define SAMPLES_PER_FRAME (2)
|
||||||
|
|
||||||
|
|
||||||
|
#define FRAMES_PER_BLOCK (100)
|
||||||
|
|
||||||
|
unsigned char samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME];
|
||||||
|
unsigned char phases[SAMPLES_PER_FRAME];
|
||||||
|
|
||||||
|
/*******************************************************************/
|
||||||
|
int main(void);
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int i,j;
|
||||||
|
PaError err;
|
||||||
|
PABLIO_Stream *aOutStream;
|
||||||
|
|
||||||
|
printf("Generate unsigned 8 bit sawtooth waves using PABLIO.\n");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
/* Open simplified blocking I/O layer on top of PortAudio. */
|
||||||
|
err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paUInt8,
|
||||||
|
(PABLIO_WRITE | PABLIO_STEREO) );
|
||||||
|
if( err != paNoError ) goto error;
|
||||||
|
|
||||||
|
/* Initialize oscillator phases to "ground" level for paUInt8. */
|
||||||
|
phases[0] = 128;
|
||||||
|
phases[1] = 128;
|
||||||
|
|
||||||
|
for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK )
|
||||||
|
{
|
||||||
|
/* Generate sawtooth waveforms in a block for efficiency. */
|
||||||
|
for( j=0; j<FRAMES_PER_BLOCK; j++ )
|
||||||
|
{
|
||||||
|
/* Generate a sawtooth wave by incrementing a variable. */
|
||||||
|
phases[0] += 1;
|
||||||
|
/* We don't have to do anything special to wrap when using paUint8 because
|
||||||
|
* 8 bit arithmetic automatically wraps. */
|
||||||
|
samples[j][0] = phases[0];
|
||||||
|
|
||||||
|
/* On the second channel, generate a higher sawtooth wave. */
|
||||||
|
phases[1] += 3;
|
||||||
|
samples[j][1] = phases[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write samples to output. */
|
||||||
|
WriteAudioStream( aOutStream, samples, FRAMES_PER_BLOCK );
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseAudioStream( aOutStream );
|
||||||
|
|
||||||
|
printf("Sawtooth sound test complete.\n" );
|
||||||
|
fflush(stdout);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
fprintf( stderr, "An error occured while using PABLIO\n" );
|
||||||
|
fprintf( stderr, "Error number: %d\n", err );
|
||||||
|
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
prefix=@prefix@
|
||||||
|
exec_prefix=@exec_prefix@
|
||||||
|
libdir=@libdir@
|
||||||
|
includedir=@includedir@
|
||||||
|
|
||||||
|
Name: PortAudio
|
||||||
|
Description: Portable audio I/O
|
||||||
|
Requires:
|
||||||
|
Version: 19
|
||||||
|
|
||||||
|
Libs: -L${libdir} -lportaudio @LIBS@
|
||||||
|
Cflags: -I${includedir} @THREAD_CFLAGS@
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,219 @@
|
||||||
|
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 Platform == 'netbsd':
|
||||||
|
optionalImpls["OSS"] = ("ossaudio", "sys/soundcard.h", "_oss_ioctl")
|
||||||
|
if env["useASIHPI"]:
|
||||||
|
optionalImpls["ASIHPI"] = ("hpi", "asihpi/hpi.h", "HPI_SubSysCreate")
|
||||||
|
if env["useCOREAUDIO"]:
|
||||||
|
optionalImpls["COREAUDIO"] = ("CoreAudio", "CoreAudio/CoreAudio.h", None)
|
||||||
|
else:
|
||||||
|
raise ConfigurationError("unknown platform %s" % Platform)
|
||||||
|
|
||||||
|
if Platform == "darwin":
|
||||||
|
env.Append(LINKFLAGS="-framework CoreFoundation -framework CoreServices -framework CoreAudio -framework AudioToolBox -framework AudioUnit")
|
||||||
|
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"])
|
||||||
|
if conf.CheckCHeader("sys/soundcard.h"):
|
||||||
|
conf.env.Append(CPPDEFINES=["HAVE_SYS_SOUNDCARD_H"])
|
||||||
|
if conf.CheckCHeader("linux/soundcard.h"):
|
||||||
|
conf.env.Append(CPPDEFINES=["HAVE_LINUX_SOUNDCARD_H"])
|
||||||
|
if conf.CheckCHeader("machine/soundcard.h"):
|
||||||
|
conf.env.Append(CPPDEFINES=["HAVE_MACHINE_SOUNDCARD_H"])
|
||||||
|
|
||||||
|
# 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 pa_debugprint.c pa_ringbuffer.c".split()]
|
||||||
|
|
||||||
|
# Host APIs 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"))
|
||||||
|
if "COREAUDIO" in optionalImpls:
|
||||||
|
ImplSources.append([os.path.join("hostapi", "coreaudio", f) for f in """
|
||||||
|
pa_mac_core.c pa_mac_core_blocking.c pa_mac_core_utilities.c
|
||||||
|
""".split()])
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
if Platform != 'darwin':
|
||||||
|
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", \
|
||||||
|
"patest_sine_channelmaps",]
|
||||||
|
|
||||||
|
# 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]
|
||||||
|
|
||||||
|
# Detect host APIs
|
||||||
|
hostApis = []
|
||||||
|
for cppdef in env["CPPDEFINES"]:
|
||||||
|
if cppdef.startswith("PA_USE_"):
|
||||||
|
hostApis.append(cppdef[7:-2])
|
||||||
|
|
||||||
|
Return("sources", "sharedLib", "staticLib", "tests", "env", "hostApis")
|
|
@ -0,0 +1,243 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_allocation.c 1097 2006-08-26 08:27:53Z rossb $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
#ifndef PA_ALLOCATION_H
|
||||||
|
#define PA_ALLOCATION_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_allocation.h 1339 2008-02-15 07:50:33Z rossb $
|
||||||
|
* 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-2008 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Allocation Group prototypes. An Allocation Group makes it easy to
|
||||||
|
allocate multiple blocks of memory and free them all at once.
|
||||||
|
|
||||||
|
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 free all allocations at once. This
|
||||||
|
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 */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,263 @@
|
||||||
|
#ifndef PA_CONVERTERS_H
|
||||||
|
#define PA_CONVERTERS_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_converters.h 1097 2006-08-26 08:27:53Z rossb $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@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 */
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_cpuload.c 1097 2006-08-26 08:27:53Z rossb $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
#ifndef PA_CPULOAD_H
|
||||||
|
#define PA_CPULOAD_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_cpuload.h 1097 2006-08-26 08:27:53Z rossb $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@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 */
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_log.c $
|
||||||
|
* Portable Audio I/O Library Multi-Host API front end
|
||||||
|
* Validate function parameters and manage multiple host APIs.
|
||||||
|
*
|
||||||
|
* Based on the Open Source API proposed by Ross Bencina
|
||||||
|
* Copyright (c) 1999-2006 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Implements log function.
|
||||||
|
|
||||||
|
PaUtil_SetLogPrintFunction can be user called to replace the provided
|
||||||
|
DefaultLogPrint function, which writes to stderr.
|
||||||
|
One can NOT pass var_args across compiler/dll boundaries as it is not
|
||||||
|
"byte code/abi portable". So the technique used here is to allocate a local
|
||||||
|
a static array, write in it, then callback the user with a pointer to its
|
||||||
|
start.
|
||||||
|
|
||||||
|
@todo Consider allocating strdump using dynamic allocation.
|
||||||
|
@todo Consider reentrancy and possibly corrupted strdump buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "pa_debugprint.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static PaUtilLogCallback userCB=0;
|
||||||
|
|
||||||
|
|
||||||
|
void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb)
|
||||||
|
{
|
||||||
|
userCB = cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
If your platform doesn’t have vsnprintf, you are stuck with a
|
||||||
|
VERY dangerous alternative, vsprintf (with no n)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if _MSC_VER
|
||||||
|
/* Some Windows Mobile SDKs don't define vsnprintf but all define _vsnprintf (hopefully).
|
||||||
|
According to MSDN "vsnprintf is identical to _vsnprintf". So we use _vsnprintf with MSC.
|
||||||
|
*/
|
||||||
|
#define VSNPRINTF _vsnprintf
|
||||||
|
#else
|
||||||
|
#define VSNPRINTF vsnprintf
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SIZEDUMP 1024
|
||||||
|
|
||||||
|
|
||||||
|
void PaUtil_DebugPrint( const char *format, ... )
|
||||||
|
{
|
||||||
|
|
||||||
|
if (userCB)
|
||||||
|
{
|
||||||
|
char strdump[SIZEDUMP];
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start( ap, format );
|
||||||
|
VSNPRINTF( strdump, SIZEDUMP, format, ap );
|
||||||
|
strdump[SIZEDUMP-1] = 0;
|
||||||
|
userCB(strdump);
|
||||||
|
va_end( ap );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start( ap, format );
|
||||||
|
vfprintf( stderr, format, ap );
|
||||||
|
va_end( ap );
|
||||||
|
fflush( stderr );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
#ifndef PA_LOG_H
|
||||||
|
#define PA_LOG_H
|
||||||
|
/*
|
||||||
|
* Log file redirector function
|
||||||
|
* Copyright (c) 1999-2006 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void PaUtil_DebugPrint( const char *format, ... );
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
The basic format for log messages is described below. If you need to
|
||||||
|
add any log messages, please follow this format.
|
||||||
|
|
||||||
|
Function entry (void function):
|
||||||
|
|
||||||
|
"FunctionName called.\n"
|
||||||
|
|
||||||
|
Function entry (non void function):
|
||||||
|
|
||||||
|
"FunctionName called:\n"
|
||||||
|
"\tParam1Type param1: param1Value\n"
|
||||||
|
"\tParam2Type param2: param2Value\n" (etc...)
|
||||||
|
|
||||||
|
|
||||||
|
Function exit (no return value):
|
||||||
|
|
||||||
|
"FunctionName returned.\n"
|
||||||
|
|
||||||
|
Function exit (simple return value):
|
||||||
|
|
||||||
|
"FunctionName returned:\n"
|
||||||
|
"\tReturnType: returnValue\n"
|
||||||
|
|
||||||
|
If the return type is an error code, the error text is displayed in ()
|
||||||
|
|
||||||
|
If the return type is not an error code, but has taken a special value
|
||||||
|
because an error occurred, then the reason for the error is shown in []
|
||||||
|
|
||||||
|
If the return type is a struct ptr, the struct is dumped.
|
||||||
|
|
||||||
|
See the code below for examples
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** 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 ));
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef PA_ENABLE_DEBUG_OUTPUT
|
||||||
|
#define PA_DEBUG(x) PaUtil_DebugPrint x ;
|
||||||
|
#else
|
||||||
|
#define PA_DEBUG(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef PA_LOG_API_CALLS
|
||||||
|
#define PA_LOGAPI(x) PaUtil_DebugPrint x
|
||||||
|
|
||||||
|
#define PA_LOGAPI_ENTER(functionName) PaUtil_DebugPrint( functionName " called.\n" )
|
||||||
|
|
||||||
|
#define PA_LOGAPI_ENTER_PARAMS(functionName) PaUtil_DebugPrint( functionName " called:\n" )
|
||||||
|
|
||||||
|
#define PA_LOGAPI_EXIT(functionName) PaUtil_DebugPrint( functionName " returned.\n" )
|
||||||
|
|
||||||
|
#define PA_LOGAPI_EXIT_PAERROR( functionName, result ) \
|
||||||
|
PaUtil_DebugPrint( functionName " returned:\n" ); \
|
||||||
|
PaUtil_DebugPrint("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )
|
||||||
|
|
||||||
|
#define PA_LOGAPI_EXIT_T( functionName, resultFormatString, result ) \
|
||||||
|
PaUtil_DebugPrint( functionName " returned:\n" ); \
|
||||||
|
PaUtil_DebugPrint("\t" resultFormatString "\n", result )
|
||||||
|
|
||||||
|
#define PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( functionName, positiveResultFormatString, result ) \
|
||||||
|
PaUtil_DebugPrint( functionName " returned:\n" ); \
|
||||||
|
if( result > 0 ) \
|
||||||
|
PaUtil_DebugPrint("\t" positiveResultFormatString "\n", result ); \
|
||||||
|
else \
|
||||||
|
PaUtil_DebugPrint("\tPaError: %d ( %s )\n", result, Pa_GetErrorText( result ) )
|
||||||
|
#else
|
||||||
|
#define PA_LOGAPI(x)
|
||||||
|
#define PA_LOGAPI_ENTER(functionName)
|
||||||
|
#define PA_LOGAPI_ENTER_PARAMS(functionName)
|
||||||
|
#define PA_LOGAPI_EXIT(functionName)
|
||||||
|
#define PA_LOGAPI_EXIT_PAERROR( functionName, result )
|
||||||
|
#define PA_LOGAPI_EXIT_T( functionName, resultFormatString, result )
|
||||||
|
#define PA_LOGAPI_EXIT_PAERROR_OR_T_RESULT( functionName, positiveResultFormatString, result )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*PaUtilLogCallback ) (const char *log);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Install user provided log function
|
||||||
|
*/
|
||||||
|
void PaUtil_SetDebugPrintFunction(PaUtilLogCallback cb);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_LOG_H */
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_dither.c 1418 2009-10-12 21:00:53Z philburk $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Functions for generating dither noise
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pa_types.h"
|
||||||
|
#include "pa_dither.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Note that the linear congruential algorithm requires 32 bit integers
|
||||||
|
* because it uses arithmetic overflow. So use PaUint32 instead of
|
||||||
|
* unsigned long so it will work on 64 bit systems.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PA_DITHER_BITS_ (15)
|
||||||
|
|
||||||
|
|
||||||
|
void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *state )
|
||||||
|
{
|
||||||
|
state->previous = 0;
|
||||||
|
state->randSeed1 = 22222;
|
||||||
|
state->randSeed2 = 5555555;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PaInt32 PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *state )
|
||||||
|
{
|
||||||
|
PaInt32 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(PaInt32)*8 - PA_DITHER_BITS_) + 1)
|
||||||
|
|
||||||
|
current = (((PaInt32)state->randSeed1)>>DITHER_SHIFT_) +
|
||||||
|
(((PaInt32)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 )
|
||||||
|
{
|
||||||
|
PaInt32 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.
|
||||||
|
*/
|
||||||
|
current = (((PaInt32)state->randSeed1)>>DITHER_SHIFT_) +
|
||||||
|
(((PaInt32)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;
|
||||||
|
}
|
||||||
|
*/
|
|
@ -0,0 +1,106 @@
|
||||||
|
#ifndef PA_DITHER_H
|
||||||
|
#define PA_DITHER_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_dither.h 1418 2009-10-12 21:00:53Z philburk $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Functions for generating dither noise
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pa_types.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
/* Note that the linear congruential algorithm requires 32 bit integers
|
||||||
|
* because it uses arithmetic overflow. So use PaUint32 instead of
|
||||||
|
* unsigned long so it will work on 64 bit systems.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @brief State needed to generate a dither signal */
|
||||||
|
typedef struct PaUtilTriangularDitherGenerator{
|
||||||
|
PaUint32 previous;
|
||||||
|
PaUint32 randSeed1;
|
||||||
|
PaUint32 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 32-bit integer with a range of +32767 to -32768
|
||||||
|
*/
|
||||||
|
PaInt32 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 */
|
|
@ -0,0 +1,145 @@
|
||||||
|
#ifndef PA_ENDIANNESS_H
|
||||||
|
#define PA_ENDIANNESS_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_endianness.h 1324 2008-01-27 02:03:30Z bjornroche $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* 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) || defined(__x86_64__)
|
||||||
|
#define PA_LITTLE_ENDIAN /* win32, assume intel byte order */
|
||||||
|
#else
|
||||||
|
#define PA_BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
#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(NDEBUG)
|
||||||
|
#define PA_VALIDATE_ENDIANNESS
|
||||||
|
#else
|
||||||
|
#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
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_ENDIANNESS_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,259 @@
|
||||||
|
#ifndef PA_HOSTAPI_H
|
||||||
|
#define PA_HOSTAPI_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_hostapi.h 1339 2008-02-15 07:50:33Z rossb $
|
||||||
|
* Portable Audio I/O Library
|
||||||
|
* host api representation
|
||||||
|
*
|
||||||
|
* Based on the Open Source API proposed by Ross Bencina
|
||||||
|
* Copyright (c) 1999-2008 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Interfaces and representation structures used by pa_front.c
|
||||||
|
to manage and communicate with host API implementations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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.
|
||||||
|
|
||||||
|
This function should only return an error other than paNoError if it encounters
|
||||||
|
an unexpected and fatal error (memory allocation error for example). In general,
|
||||||
|
there may be conditions under which it returns a NULL interface pointer and also
|
||||||
|
returns paNoError. For example, if the ASIO implementation detects that ASIO is
|
||||||
|
not installed, it should return a NULL interface, and paNoError.
|
||||||
|
|
||||||
|
@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.c 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 */
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_memorybarrier.h 1240 2007-07-17 13:05:07Z bjornroche $
|
||||||
|
* Portable Audio I/O Library
|
||||||
|
* Memory barrier utilities
|
||||||
|
*
|
||||||
|
* Author: Bjorn Roche, XO Audio, LLC
|
||||||
|
*
|
||||||
|
* This program uses the PortAudio Portable Audio Library.
|
||||||
|
* For more information see: http://www.portaudio.com
|
||||||
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file pa_memorybarrier.h
|
||||||
|
@ingroup common_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* Some memory barrier primitives based on the system.
|
||||||
|
* right now only OS X, FreeBSD, and Linux 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:
|
||||||
|
*
|
||||||
|
* PaUtil_FullMemoryBarrier()
|
||||||
|
* PaUtil_ReadMemoryBarrier()
|
||||||
|
* PaUtil_WriteMemoryBarrier()
|
||||||
|
*
|
||||||
|
****************/
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
# include <libkern/OSAtomic.h>
|
||||||
|
/* Here are the memory barrier functions. Mac OS X only provides
|
||||||
|
full memory barriers, so the three types of barriers are the same,
|
||||||
|
however, these barriers are superior to compiler-based ones. */
|
||||||
|
# define PaUtil_FullMemoryBarrier() OSMemoryBarrier()
|
||||||
|
# define PaUtil_ReadMemoryBarrier() OSMemoryBarrier()
|
||||||
|
# define PaUtil_WriteMemoryBarrier() OSMemoryBarrier()
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
/* GCC >= 4.1 has built-in intrinsics. We'll use those */
|
||||||
|
# if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)
|
||||||
|
# define PaUtil_FullMemoryBarrier() __sync_synchronize()
|
||||||
|
# define PaUtil_ReadMemoryBarrier() __sync_synchronize()
|
||||||
|
# define PaUtil_WriteMemoryBarrier() __sync_synchronize()
|
||||||
|
/* as a fallback, GCC understands volatile asm and "memory" to mean it
|
||||||
|
* should not reorder memory read/writes */
|
||||||
|
/* Note that it is not clear that any compiler actually defines __PPC__,
|
||||||
|
* it can probably removed safely. */
|
||||||
|
# elif defined( __ppc__ ) || defined( __powerpc__) || defined( __PPC__ )
|
||||||
|
# define PaUtil_FullMemoryBarrier() asm volatile("sync":::"memory")
|
||||||
|
# define PaUtil_ReadMemoryBarrier() asm volatile("sync":::"memory")
|
||||||
|
# define PaUtil_WriteMemoryBarrier() asm volatile("sync":::"memory")
|
||||||
|
# elif defined( __i386__ ) || defined( __i486__ ) || defined( __i586__ ) || \
|
||||||
|
defined( __i686__ ) || defined( __x86_64__ )
|
||||||
|
# define PaUtil_FullMemoryBarrier() asm volatile("mfence":::"memory")
|
||||||
|
# define PaUtil_ReadMemoryBarrier() asm volatile("lfence":::"memory")
|
||||||
|
# define PaUtil_WriteMemoryBarrier() asm volatile("sfence":::"memory")
|
||||||
|
# else
|
||||||
|
# ifdef ALLOW_SMP_DANGERS
|
||||||
|
# warning Memory barriers not defined on this system or system unknown
|
||||||
|
# warning For SMP safety, you should fix this.
|
||||||
|
# define PaUtil_FullMemoryBarrier()
|
||||||
|
# define PaUtil_ReadMemoryBarrier()
|
||||||
|
# define PaUtil_WriteMemoryBarrier()
|
||||||
|
# else
|
||||||
|
# error Memory barriers are not defined on this system. You can still compile by defining ALLOW_SMP_DANGERS, but SMP safety will not be guaranteed.
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#elif (_MSC_VER >= 1400) && !defined(_WIN32_WCE)
|
||||||
|
# include <intrin.h>
|
||||||
|
# pragma intrinsic(_ReadWriteBarrier)
|
||||||
|
# pragma intrinsic(_ReadBarrier)
|
||||||
|
# pragma intrinsic(_WriteBarrier)
|
||||||
|
# define PaUtil_FullMemoryBarrier() _ReadWriteBarrier()
|
||||||
|
# define PaUtil_ReadMemoryBarrier() _ReadBarrier()
|
||||||
|
# define PaUtil_WriteMemoryBarrier() _WriteBarrier()
|
||||||
|
#elif defined(_WIN32_WCE)
|
||||||
|
# define PaUtil_FullMemoryBarrier()
|
||||||
|
# define PaUtil_ReadMemoryBarrier()
|
||||||
|
# define PaUtil_WriteMemoryBarrier()
|
||||||
|
#elif defined(_MSC_VER) || defined(__BORLANDC__)
|
||||||
|
# define PaUtil_FullMemoryBarrier() _asm { lock add [esp], 0 }
|
||||||
|
# define PaUtil_ReadMemoryBarrier() _asm { lock add [esp], 0 }
|
||||||
|
# define PaUtil_WriteMemoryBarrier() _asm { lock add [esp], 0 }
|
||||||
|
#else
|
||||||
|
# ifdef ALLOW_SMP_DANGERS
|
||||||
|
# warning Memory barriers not defined on this system or system unknown
|
||||||
|
# warning For SMP safety, you should fix this.
|
||||||
|
# define PaUtil_FullMemoryBarrier()
|
||||||
|
# define PaUtil_ReadMemoryBarrier()
|
||||||
|
# define PaUtil_WriteMemoryBarrier()
|
||||||
|
# else
|
||||||
|
# error Memory barriers are not defined on this system. You can still compile by defining ALLOW_SMP_DANGERS, but SMP safety will not be guaranteed.
|
||||||
|
# endif
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,750 @@
|
||||||
|
#ifndef PA_PROCESS_H
|
||||||
|
#define PA_PROCESS_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_process.h 1097 2006-08-26 08:27:53Z rossb $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@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 */
|
|
@ -0,0 +1,227 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_ringbuffer.c 1421 2009-11-18 16:09:05Z bjornroche $
|
||||||
|
* Portable Audio I/O Library
|
||||||
|
* Ring Buffer utility.
|
||||||
|
*
|
||||||
|
* Author: Phil Burk, http://www.softsynth.com
|
||||||
|
* modified for SMP safety on Mac OS X by Bjorn Roche
|
||||||
|
* modified for SMP safety on Linux by Leland Lucius
|
||||||
|
* also, allowed for const where possible
|
||||||
|
* modified for multiple-byte-sized data elements by Sven Fischer
|
||||||
|
*
|
||||||
|
* 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.portaudio.com
|
||||||
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file
|
||||||
|
@ingroup common_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "pa_ringbuffer.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include "pa_memorybarrier.h"
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Initialize FIFO.
|
||||||
|
* elementCount must be power of 2, returns -1 if not.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementSizeBytes, ring_buffer_size_t elementCount, void *dataPtr )
|
||||||
|
{
|
||||||
|
if( ((elementCount-1) & elementCount) != 0) return -1; /* Not Power of two. */
|
||||||
|
rbuf->bufferSize = elementCount;
|
||||||
|
rbuf->buffer = (char *)dataPtr;
|
||||||
|
PaUtil_FlushRingBuffer( rbuf );
|
||||||
|
rbuf->bigMask = (elementCount*2)-1;
|
||||||
|
rbuf->smallMask = (elementCount)-1;
|
||||||
|
rbuf->elementSizeBytes = elementSizeBytes;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Return number of elements available for reading. */
|
||||||
|
ring_buffer_size_t PaUtil_GetRingBufferReadAvailable( PaUtilRingBuffer *rbuf )
|
||||||
|
{
|
||||||
|
PaUtil_ReadMemoryBarrier();
|
||||||
|
return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );
|
||||||
|
}
|
||||||
|
/***************************************************************************
|
||||||
|
** Return number of elements available for writing. */
|
||||||
|
ring_buffer_size_t PaUtil_GetRingBufferWriteAvailable( PaUtilRingBuffer *rbuf )
|
||||||
|
{
|
||||||
|
/* Since we are calling PaUtil_GetRingBufferReadAvailable, we don't need an aditional MB */
|
||||||
|
return ( rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Clear buffer. Should only be called when buffer is NOT being read. */
|
||||||
|
void PaUtil_FlushRingBuffer( PaUtilRingBuffer *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 elementCount, whichever is smaller.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount,
|
||||||
|
void **dataPtr1, ring_buffer_size_t *sizePtr1,
|
||||||
|
void **dataPtr2, ring_buffer_size_t *sizePtr2 )
|
||||||
|
{
|
||||||
|
ring_buffer_size_t index;
|
||||||
|
ring_buffer_size_t available = PaUtil_GetRingBufferWriteAvailable( rbuf );
|
||||||
|
if( elementCount > available ) elementCount = available;
|
||||||
|
/* Check to see if write is not contiguous. */
|
||||||
|
index = rbuf->writeIndex & rbuf->smallMask;
|
||||||
|
if( (index + elementCount) > rbuf->bufferSize )
|
||||||
|
{
|
||||||
|
/* Write data in two blocks that wrap the buffer. */
|
||||||
|
ring_buffer_size_t firstHalf = rbuf->bufferSize - index;
|
||||||
|
*dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
|
||||||
|
*sizePtr1 = firstHalf;
|
||||||
|
*dataPtr2 = &rbuf->buffer[0];
|
||||||
|
*sizePtr2 = elementCount - firstHalf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
|
||||||
|
*sizePtr1 = elementCount;
|
||||||
|
*dataPtr2 = NULL;
|
||||||
|
*sizePtr2 = 0;
|
||||||
|
}
|
||||||
|
return elementCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount )
|
||||||
|
{
|
||||||
|
/* we need to ensure that previous writes are seen before we update the write index */
|
||||||
|
PaUtil_WriteMemoryBarrier();
|
||||||
|
return rbuf->writeIndex = (rbuf->writeIndex + elementCount) & rbuf->bigMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** 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 elementCount, whichever is smaller.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount,
|
||||||
|
void **dataPtr1, ring_buffer_size_t *sizePtr1,
|
||||||
|
void **dataPtr2, ring_buffer_size_t *sizePtr2 )
|
||||||
|
{
|
||||||
|
ring_buffer_size_t index;
|
||||||
|
ring_buffer_size_t available = PaUtil_GetRingBufferReadAvailable( rbuf );
|
||||||
|
if( elementCount > available ) elementCount = available;
|
||||||
|
/* Check to see if read is not contiguous. */
|
||||||
|
index = rbuf->readIndex & rbuf->smallMask;
|
||||||
|
if( (index + elementCount) > rbuf->bufferSize )
|
||||||
|
{
|
||||||
|
/* Write data in two blocks that wrap the buffer. */
|
||||||
|
ring_buffer_size_t firstHalf = rbuf->bufferSize - index;
|
||||||
|
*dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
|
||||||
|
*sizePtr1 = firstHalf;
|
||||||
|
*dataPtr2 = &rbuf->buffer[0];
|
||||||
|
*sizePtr2 = elementCount - firstHalf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*dataPtr1 = &rbuf->buffer[index*rbuf->elementSizeBytes];
|
||||||
|
*sizePtr1 = elementCount;
|
||||||
|
*dataPtr2 = NULL;
|
||||||
|
*sizePtr2 = 0;
|
||||||
|
}
|
||||||
|
return elementCount;
|
||||||
|
}
|
||||||
|
/***************************************************************************
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount )
|
||||||
|
{
|
||||||
|
/* we need to ensure that previous writes are always seen before updating the index. */
|
||||||
|
PaUtil_WriteMemoryBarrier();
|
||||||
|
return rbuf->readIndex = (rbuf->readIndex + elementCount) & rbuf->bigMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Return elements written. */
|
||||||
|
ring_buffer_size_t PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, ring_buffer_size_t elementCount )
|
||||||
|
{
|
||||||
|
ring_buffer_size_t size1, size2, numWritten;
|
||||||
|
void *data1, *data2;
|
||||||
|
numWritten = PaUtil_GetRingBufferWriteRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 );
|
||||||
|
if( size2 > 0 )
|
||||||
|
{
|
||||||
|
|
||||||
|
memcpy( data1, data, size1*rbuf->elementSizeBytes );
|
||||||
|
data = ((char *)data) + size1*rbuf->elementSizeBytes;
|
||||||
|
memcpy( data2, data, size2*rbuf->elementSizeBytes );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy( data1, data, size1*rbuf->elementSizeBytes );
|
||||||
|
}
|
||||||
|
PaUtil_AdvanceRingBufferWriteIndex( rbuf, numWritten );
|
||||||
|
return numWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
** Return elements read. */
|
||||||
|
ring_buffer_size_t PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, ring_buffer_size_t elementCount )
|
||||||
|
{
|
||||||
|
ring_buffer_size_t size1, size2, numRead;
|
||||||
|
void *data1, *data2;
|
||||||
|
numRead = PaUtil_GetRingBufferReadRegions( rbuf, elementCount, &data1, &size1, &data2, &size2 );
|
||||||
|
if( size2 > 0 )
|
||||||
|
{
|
||||||
|
memcpy( data, data1, size1*rbuf->elementSizeBytes );
|
||||||
|
data = ((char *)data) + size1*rbuf->elementSizeBytes;
|
||||||
|
memcpy( data, data2, size2*rbuf->elementSizeBytes );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy( data, data1, size1*rbuf->elementSizeBytes );
|
||||||
|
}
|
||||||
|
PaUtil_AdvanceRingBufferReadIndex( rbuf, numRead );
|
||||||
|
return numRead;
|
||||||
|
}
|
|
@ -0,0 +1,233 @@
|
||||||
|
#ifndef PA_RINGBUFFER_H
|
||||||
|
#define PA_RINGBUFFER_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_ringbuffer.h 1421 2009-11-18 16:09:05Z bjornroche $
|
||||||
|
* Portable Audio I/O Library
|
||||||
|
* 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.
|
||||||
|
* modified for multiple-byte-sized data elements by Sven Fischer
|
||||||
|
*
|
||||||
|
* 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.portaudio.com
|
||||||
|
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files
|
||||||
|
* (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge,
|
||||||
|
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
* and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
@brief Single-reader single-writer lock-free ring buffer
|
||||||
|
|
||||||
|
PaUtilRingBuffer is a ring buffer used to transport samples between
|
||||||
|
different execution contexts (threads, OS callbacks, interrupt handlers)
|
||||||
|
without requiring the use of any locks. This only works when there is
|
||||||
|
a single reader and a single writer (ie. one thread or callback writes
|
||||||
|
to the ring buffer, another thread or callback reads from it).
|
||||||
|
|
||||||
|
The PaUtilRingBuffer structure manages a ring buffer containing N
|
||||||
|
elements, where N must be a power of two. An element may be any size
|
||||||
|
(specified in bytes).
|
||||||
|
|
||||||
|
The memory area used to store the buffer elements must be allocated by
|
||||||
|
the client prior to calling PaUtil_InitializeRingBuffer() and must outlive
|
||||||
|
the use of the ring buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
#include <sys/types.h>
|
||||||
|
typedef int32_t ring_buffer_size_t;
|
||||||
|
#elif defined( __GNUC__ )
|
||||||
|
typedef long ring_buffer_size_t;
|
||||||
|
#elif (_MSC_VER >= 1400)
|
||||||
|
typedef long ring_buffer_size_t;
|
||||||
|
#elif defined(_MSC_VER) || defined(__BORLANDC__)
|
||||||
|
typedef long ring_buffer_size_t;
|
||||||
|
#else
|
||||||
|
typedef long ring_buffer_size_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
|
||||||
|
typedef struct PaUtilRingBuffer
|
||||||
|
{
|
||||||
|
ring_buffer_size_t bufferSize; /**< Number of elements in FIFO. Power of 2. Set by PaUtil_InitRingBuffer. */
|
||||||
|
ring_buffer_size_t writeIndex; /**< Index of next writable element. Set by PaUtil_AdvanceRingBufferWriteIndex. */
|
||||||
|
ring_buffer_size_t readIndex; /**< Index of next readable element. Set by PaUtil_AdvanceRingBufferReadIndex. */
|
||||||
|
ring_buffer_size_t bigMask; /**< Used for wrapping indices with extra bit to distinguish full/empty. */
|
||||||
|
ring_buffer_size_t smallMask; /**< Used for fitting indices to buffer. */
|
||||||
|
ring_buffer_size_t elementSizeBytes; /**< Number of bytes per element. */
|
||||||
|
char *buffer; /**< Pointer to the buffer containing the actual data. */
|
||||||
|
}PaUtilRingBuffer;
|
||||||
|
|
||||||
|
/** Initialize Ring Buffer.
|
||||||
|
|
||||||
|
@param rbuf The ring buffer.
|
||||||
|
|
||||||
|
@param elementSizeBytes The size of a single data element in bytes.
|
||||||
|
|
||||||
|
@param elementCount The number of elements in the buffer (must be power of 2).
|
||||||
|
|
||||||
|
@param dataPtr A pointer to a previously allocated area where the data
|
||||||
|
will be maintained. It must be elementCount*elementSizeBytes long.
|
||||||
|
|
||||||
|
@return -1 if elementCount is not a power of 2, otherwise 0.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_InitializeRingBuffer( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementSizeBytes, ring_buffer_size_t elementCount, void *dataPtr );
|
||||||
|
|
||||||
|
/** Clear buffer. Should only be called when buffer is NOT being read.
|
||||||
|
|
||||||
|
@param rbuf The ring buffer.
|
||||||
|
*/
|
||||||
|
void PaUtil_FlushRingBuffer( PaUtilRingBuffer *rbuf );
|
||||||
|
|
||||||
|
/** Retrieve the number of elements available in the ring buffer for writing.
|
||||||
|
|
||||||
|
@param rbuf The ring buffer.
|
||||||
|
|
||||||
|
@return The number of elements available for writing.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_GetRingBufferWriteAvailable( PaUtilRingBuffer *rbuf );
|
||||||
|
|
||||||
|
/** Retrieve the number of elements available in the ring buffer for reading.
|
||||||
|
|
||||||
|
@param rbuf The ring buffer.
|
||||||
|
|
||||||
|
@return The number of elements available for reading.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_GetRingBufferReadAvailable( PaUtilRingBuffer *rbuf );
|
||||||
|
|
||||||
|
/** Write data to the ring buffer.
|
||||||
|
|
||||||
|
@param rbuf The ring buffer.
|
||||||
|
|
||||||
|
@param data The address of new data to write to the buffer.
|
||||||
|
|
||||||
|
@param elementCount The number of elements to be written.
|
||||||
|
|
||||||
|
@return The number of elements written.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_WriteRingBuffer( PaUtilRingBuffer *rbuf, const void *data, ring_buffer_size_t elementCount );
|
||||||
|
|
||||||
|
/** Read data from the ring buffer.
|
||||||
|
|
||||||
|
@param rbuf The ring buffer.
|
||||||
|
|
||||||
|
@param data The address where the data should be stored.
|
||||||
|
|
||||||
|
@param elementCount The number of elements to be read.
|
||||||
|
|
||||||
|
@return The number of elements read.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_ReadRingBuffer( PaUtilRingBuffer *rbuf, void *data, ring_buffer_size_t elementCount );
|
||||||
|
|
||||||
|
/** Get address of region(s) to which we can write data.
|
||||||
|
|
||||||
|
@param rbuf The ring buffer.
|
||||||
|
|
||||||
|
@param elementCount The number of elements desired.
|
||||||
|
|
||||||
|
@param dataPtr1 The address where the first (or only) region pointer will be
|
||||||
|
stored.
|
||||||
|
|
||||||
|
@param sizePtr1 The address where the first (or only) region length will be
|
||||||
|
stored.
|
||||||
|
|
||||||
|
@param dataPtr2 The address where the second region pointer will be stored if
|
||||||
|
the first region is too small to satisfy elementCount.
|
||||||
|
|
||||||
|
@param sizePtr2 The address where the second region length will be stored if
|
||||||
|
the first region is too small to satisfy elementCount.
|
||||||
|
|
||||||
|
@return The room available to be written or elementCount, whichever is smaller.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_GetRingBufferWriteRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount,
|
||||||
|
void **dataPtr1, ring_buffer_size_t *sizePtr1,
|
||||||
|
void **dataPtr2, ring_buffer_size_t *sizePtr2 );
|
||||||
|
|
||||||
|
/** Advance the write index to the next location to be written.
|
||||||
|
|
||||||
|
@param rbuf The ring buffer.
|
||||||
|
|
||||||
|
@param elementCount The number of elements to advance.
|
||||||
|
|
||||||
|
@return The new position.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_AdvanceRingBufferWriteIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount );
|
||||||
|
|
||||||
|
/** Get address of region(s) from which we can write data.
|
||||||
|
|
||||||
|
@param rbuf The ring buffer.
|
||||||
|
|
||||||
|
@param elementCount The number of elements desired.
|
||||||
|
|
||||||
|
@param dataPtr1 The address where the first (or only) region pointer will be
|
||||||
|
stored.
|
||||||
|
|
||||||
|
@param sizePtr1 The address where the first (or only) region length will be
|
||||||
|
stored.
|
||||||
|
|
||||||
|
@param dataPtr2 The address where the second region pointer will be stored if
|
||||||
|
the first region is too small to satisfy elementCount.
|
||||||
|
|
||||||
|
@param sizePtr2 The address where the second region length will be stored if
|
||||||
|
the first region is too small to satisfy elementCount.
|
||||||
|
|
||||||
|
@return The number of elements available for reading.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_GetRingBufferReadRegions( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount,
|
||||||
|
void **dataPtr1, ring_buffer_size_t *sizePtr1,
|
||||||
|
void **dataPtr2, ring_buffer_size_t *sizePtr2 );
|
||||||
|
|
||||||
|
/** Advance the read index to the next location to be read.
|
||||||
|
|
||||||
|
@param rbuf The ring buffer.
|
||||||
|
|
||||||
|
@param elementCount The number of elements to advance.
|
||||||
|
|
||||||
|
@return The new position.
|
||||||
|
*/
|
||||||
|
ring_buffer_size_t PaUtil_AdvanceRingBufferReadIndex( PaUtilRingBuffer *rbuf, ring_buffer_size_t elementCount );
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /* __cplusplus */
|
||||||
|
#endif /* PA_RINGBUFFER_H */
|
|
@ -0,0 +1,818 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_skeleton.c 1339 2008-02-15 07:50:33Z rossb $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Skeleton implementation of support for a host API.
|
||||||
|
|
||||||
|
This file is provided as a starting point for implementing support for
|
||||||
|
a new host API. It provides examples of how the common code can be used.
|
||||||
|
|
||||||
|
@note 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_stream.c 1339 2008-02-15 07:50:33Z rossb $
|
||||||
|
* Portable Audio I/O Library
|
||||||
|
* stream interface
|
||||||
|
*
|
||||||
|
* Based on the Open Source API proposed by Ross Bencina
|
||||||
|
* Copyright (c) 2008 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Stream interfaces, representation structures and helper functions
|
||||||
|
used to interface between pa_front.c host API implementations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -0,0 +1,205 @@
|
||||||
|
#ifndef PA_STREAM_H
|
||||||
|
#define PA_STREAM_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_stream.h 1339 2008-02-15 07:50:33Z rossb $
|
||||||
|
* Portable Audio I/O Library
|
||||||
|
* stream interface
|
||||||
|
*
|
||||||
|
* Based on the Open Source API proposed by Ross Bencina
|
||||||
|
* Copyright (c) 1999-2008 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Stream interfaces, representation structures and helper functions
|
||||||
|
used to interface between pa_front.c host API implementations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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 */
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_trace.c 1339 2008-02-15 07:50:33Z rossb $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Real-time safe event trace logging facility 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 */
|
|
@ -0,0 +1,101 @@
|
||||||
|
#ifndef PA_TRACE_H
|
||||||
|
#define PA_TRACE_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_trace.h 1339 2008-02-15 07:50:33Z rossb $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Real-time safe event trace logging facility for debugging.
|
||||||
|
|
||||||
|
Allows data to be logged to a fixed size trace buffer in a real-time
|
||||||
|
execution context (such as at interrupt time). Each log entry consists
|
||||||
|
of a message comprising a string pointer and an int. The trace buffer
|
||||||
|
may be dumped to stdout later.
|
||||||
|
|
||||||
|
This facility is only active if PA_TRACE_REALTIME_EVENTS is set to 1,
|
||||||
|
otherwise the trace functions expand to no-ops.
|
||||||
|
|
||||||
|
@fn PaUtil_ResetTraceMessages
|
||||||
|
@brief Clear the trace buffer.
|
||||||
|
|
||||||
|
@fn PaUtil_AddTraceMessage
|
||||||
|
@brief Add a message to the trace buffer. A message consists of string and an int.
|
||||||
|
@param msg The string pointer must remain valid until PaUtil_DumpTraceMessages
|
||||||
|
is called. As a result, usually only string literals should be passed as
|
||||||
|
the msg parameter.
|
||||||
|
|
||||||
|
@fn PaUtil_DumpTraceMessages
|
||||||
|
@brief Print all messages in the trace buffer to stdout and clear the trace buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PA_TRACE_REALTIME_EVENTS
|
||||||
|
#define PA_TRACE_REALTIME_EVENTS (0) /**< Set to 1 to enable logging using the trace functions defined below */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PA_MAX_TRACE_RECORDS
|
||||||
|
#define PA_MAX_TRACE_RECORDS (2048) /**< Maximum number of records stored in trace buffer */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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 */
|
|
@ -0,0 +1,107 @@
|
||||||
|
#ifndef PA_TYPES_H
|
||||||
|
#define PA_TYPES_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Portable Audio I/O Library
|
||||||
|
* integer type definitions
|
||||||
|
*
|
||||||
|
* Based on the Open Source API proposed by Ross Bencina
|
||||||
|
* Copyright (c) 1999-2006 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Definition of 16 and 32 bit integer types (PaInt16, PaInt32 etc)
|
||||||
|
|
||||||
|
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 */
|
|
@ -0,0 +1,162 @@
|
||||||
|
#ifndef PA_UTIL_H
|
||||||
|
#define PA_UTIL_H
|
||||||
|
/*
|
||||||
|
* $Id: pa_util.h 1339 2008-02-15 07:50:33Z rossb $
|
||||||
|
* 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-2008 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup common_src
|
||||||
|
|
||||||
|
@brief Prototypes for utility functions used by PortAudio implementations.
|
||||||
|
|
||||||
|
Some functions declared here are defined in pa_front.c while others
|
||||||
|
are implemented separately for each platform.
|
||||||
|
|
||||||
|
@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 );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,140 @@
|
||||||
|
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 us on the PortAudio mailing list.
|
||||||
|
|
||||||
|
|
||||||
|
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 src/common/ and platform specific files from src/os/win/ (for Win32)
|
||||||
|
or src/os/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.de/329+M52087573ab0.html
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
You may also need to adjust your include paths to support inclusion of
|
||||||
|
header files from the above directories.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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 compilers 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
---
|
Binary file not shown.
Binary file not shown.
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,196 @@
|
||||||
|
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 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).
|
||||||
|
|
||||||
|
Additionally, the user may define a "channel mapping" by calling
|
||||||
|
paSetupMacCoreChannelMap() on their stream info structure before opening
|
||||||
|
the stream with it. See below for creating a channel map.
|
||||||
|
|
||||||
|
Known issues:
|
||||||
|
|
||||||
|
- Buffering: No buffering beyond that provided by core audio is provided
|
||||||
|
except where absolutely needed for the implementation to work. This may cause
|
||||||
|
issues with large framesPerBuffer settings and it also means that no additional
|
||||||
|
latency will be provided even if a large latency setting is selected.
|
||||||
|
|
||||||
|
- Latency: Latency settings are generally ignored. They may be used as a
|
||||||
|
hint for buffer size in paHostFramesPerBufferUnspecified, or the value may
|
||||||
|
be used in cases where additional buffering is needed, such as doing input and
|
||||||
|
output on seperate devices. 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. In the case of paHostFramesPerBuffer, an
|
||||||
|
appropriate framesPerBuffer value will be used that guarantees minimum
|
||||||
|
requested latency if that's possible.
|
||||||
|
|
||||||
|
- Timing info. It reports on stream time, but I'm probably doing something
|
||||||
|
wrong since patest_sine_time often reports negative latency numbers. Also,
|
||||||
|
there are currently issues with some devices whehn plugging/unplugging
|
||||||
|
devices.
|
||||||
|
|
||||||
|
- 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: should work fine.
|
||||||
|
|
||||||
|
- multichannel: It has been tested successfully on multichannel hardware
|
||||||
|
from MOTU: traveler and 896HD. Also Presonus firepod and others. It is
|
||||||
|
believed to work with all Core Audio devices, including virtual devices
|
||||||
|
such as soundflower.
|
||||||
|
|
||||||
|
- 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 rate conversion quality
|
||||||
|
as "documented" here:
|
||||||
|
http://lists.apple.com/archives/coreaudio-api/2004/Jan/msg00141.html
|
||||||
|
|
||||||
|
- x86/Universal Binary: Universal binaries can be build.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Creating a channel map:
|
||||||
|
|
||||||
|
How to create the map array - Text taken From AUHAL.rtfd :
|
||||||
|
[3] Channel Maps
|
||||||
|
Clients can tell the AUHAL units which channels of the device they are interested in. For example, the client may be processing stereo data, but outputting to a six-channel device. This is done by using the kAudioOutputUnitProperty_ChannelMap property. To use this property:
|
||||||
|
|
||||||
|
For Output:
|
||||||
|
Create an array of SInt32 that is the size of the number of channels of the device (Get the Format of the AUHAL's output Element == 0)
|
||||||
|
Initialize each of the array's values to -1 (-1 indicates that that channel is NOT to be presented in the conversion.)
|
||||||
|
|
||||||
|
Next, for each channel of your app's output, set:
|
||||||
|
channelMapArray[deviceOutputChannel] = desiredAppOutputChannel.
|
||||||
|
|
||||||
|
For example: we have a 6 channel output device and our application has a stereo source it wants to provide to the device. Suppose we want that stereo source to go to the 3rd and 4th channels of the device. The channel map would look like this: { -1, -1, 0, 1, -1, -1 }
|
||||||
|
|
||||||
|
Where the formats are:
|
||||||
|
Input Element == 0: 2 channels (- client format - settable)
|
||||||
|
Output Element == 0: 6 channels (- device format - NOT settable)
|
||||||
|
|
||||||
|
So channel 2 (zero-based) of the device will take the first channel of output and channel 3 will take the second channel of output. (This translates to the 3rd and 4th plugs of the 6 output plugs of the device of course!)
|
||||||
|
|
||||||
|
For Input:
|
||||||
|
Create an array of SInt32 that is the size of the number of channels of the format you require for input. Get (or Set in this case as needed) the AUHAL's output Element == 1.
|
||||||
|
|
||||||
|
Next, for each channel of input you require, set:
|
||||||
|
channelMapArray[desiredAppInputChannel] = deviceOutputChannel;
|
||||||
|
|
||||||
|
For example: we have a 6 channel input device from which we wish to receive stereo input from the 3rd and 4th channels. The channel map looks like this: { 2, 3 }
|
||||||
|
|
||||||
|
Where the formats are:
|
||||||
|
Input Element == 0: 2 channels (- device format - NOT settable)
|
||||||
|
Output Element == 0: 6 channels (- client format - settable)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,592 @@
|
||||||
|
/*
|
||||||
|
* Implementation of the PortAudio API for Apple AUHAL
|
||||||
|
*
|
||||||
|
* PortAudio Portable Real-Time Audio Library
|
||||||
|
* Latest Version at: http://www.portaudio.com
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file
|
||||||
|
@ingroup hostapi_src
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Same as computeSampleSizeFromFormat, except that if
|
||||||
|
* the size is not a power of two, it returns the next power of two up
|
||||||
|
*/
|
||||||
|
static size_t computeSampleSizeFromFormatPow2( PaSampleFormat format )
|
||||||
|
{
|
||||||
|
switch( format ) {
|
||||||
|
case paFloat32: return 4;
|
||||||
|
case paInt32: return 4;
|
||||||
|
case paInt24: return 4;
|
||||||
|
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;
|
||||||
|
OSStatus err;
|
||||||
|
|
||||||
|
/* 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->ringBufferFrames = ringBufferSize;
|
||||||
|
blio->inputSampleFormat = inputSampleFormat;
|
||||||
|
blio->inputSampleSizeActual = computeSampleSizeFromFormat(inputSampleFormat);
|
||||||
|
blio->inputSampleSizePow2 = computeSampleSizeFromFormatPow2(inputSampleFormat);
|
||||||
|
blio->outputSampleFormat = outputSampleFormat;
|
||||||
|
blio->outputSampleSizeActual = computeSampleSizeFromFormat(outputSampleFormat);
|
||||||
|
blio->outputSampleSizePow2 = computeSampleSizeFromFormatPow2(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->inputSampleSizePow2*inChan );
|
||||||
|
if( !data )
|
||||||
|
{
|
||||||
|
result = paInsufficientMemory;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = PaUtil_InitializeRingBuffer(
|
||||||
|
&blio->inputRingBuffer,
|
||||||
|
1, ringBufferSize*blio->inputSampleSizePow2*inChan,
|
||||||
|
data );
|
||||||
|
assert( !err );
|
||||||
|
}
|
||||||
|
if( outChan ) {
|
||||||
|
data = calloc( ringBufferSize, blio->outputSampleSizePow2*outChan );
|
||||||
|
if( !data )
|
||||||
|
{
|
||||||
|
result = paInsufficientMemory;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = PaUtil_InitializeRingBuffer(
|
||||||
|
&blio->outputRingBuffer,
|
||||||
|
1, ringBufferSize*blio->outputSampleSizePow2*outChan,
|
||||||
|
data );
|
||||||
|
assert( !err );
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ) {
|
||||||
|
PaUtil_FlushRingBuffer( &blio->outputRingBuffer );
|
||||||
|
bzero( blio->outputRingBuffer.buffer,
|
||||||
|
blio->outputRingBuffer.bufferSize );
|
||||||
|
/* Advance buffer */
|
||||||
|
PaUtil_AdvanceRingBufferWriteIndex( &blio->outputRingBuffer, blio->ringBufferFrames*blio->outputSampleSizeActual*blio->outChan );
|
||||||
|
//PaUtil_AdvanceRingBufferWriteIndex( &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 ) {
|
||||||
|
PaUtil_FlushRingBuffer( &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;
|
||||||
|
long read;
|
||||||
|
long written;
|
||||||
|
|
||||||
|
/* set flags returned by OS: */
|
||||||
|
OSAtomicOr32( statusFlags, &blio->statusFlags ) ;
|
||||||
|
|
||||||
|
/* --- Handle Input Buffer --- */
|
||||||
|
if( blio->inChan ) {
|
||||||
|
avail = PaUtil_GetRingBufferWriteAvailable( &blio->inputRingBuffer );
|
||||||
|
|
||||||
|
/* check for underflow */
|
||||||
|
if( avail < frameCount * blio->inputSampleSizeActual * blio->inChan )
|
||||||
|
OSAtomicOr32( paInputOverflow, &blio->statusFlags );
|
||||||
|
|
||||||
|
toRead = MIN( avail, frameCount * blio->inputSampleSizeActual * blio->inChan );
|
||||||
|
|
||||||
|
/* copy the data */
|
||||||
|
/*printf( "reading %d\n", toRead );*/
|
||||||
|
read = PaUtil_WriteRingBuffer( &blio->inputRingBuffer, input, toRead );
|
||||||
|
assert( toRead == read );
|
||||||
|
#ifdef PA_MAC__BLIO_MUTEX
|
||||||
|
/* Priority inversion. See notes below. */
|
||||||
|
blioSetIsInputEmpty( blio, false );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* --- Handle Output Buffer --- */
|
||||||
|
if( blio->outChan ) {
|
||||||
|
avail = PaUtil_GetRingBufferReadAvailable( &blio->outputRingBuffer );
|
||||||
|
|
||||||
|
/* check for underflow */
|
||||||
|
if( avail < frameCount * blio->outputSampleSizeActual * blio->outChan )
|
||||||
|
OSAtomicOr32( paOutputUnderflow, &blio->statusFlags );
|
||||||
|
|
||||||
|
toWrite = MIN( avail, frameCount * blio->outputSampleSizeActual * blio->outChan );
|
||||||
|
|
||||||
|
if( toWrite != frameCount * blio->outputSampleSizeActual * blio->outChan )
|
||||||
|
bzero( ((char *)output)+toWrite,
|
||||||
|
frameCount * blio->outputSampleSizeActual * blio->outChan - toWrite );
|
||||||
|
/* copy the data */
|
||||||
|
/*printf( "writing %d\n", toWrite );*/
|
||||||
|
written = PaUtil_ReadRingBuffer( &blio->outputRingBuffer, output, toWrite );
|
||||||
|
assert( toWrite == written );
|
||||||
|
#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 = PaUtil_GetRingBufferReadAvailable( &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->inputSampleSizeActual * blio->inChan );
|
||||||
|
toRead -= toRead % blio->inputSampleSizeActual * blio->inChan ;
|
||||||
|
PaUtil_ReadRingBuffer( &blio->inputRingBuffer, (void *)cbuf, toRead );
|
||||||
|
cbuf += toRead;
|
||||||
|
frames -= toRead / ( blio->inputSampleSizeActual * 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( PaUtil_GetRingBufferReadAvailable( &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( (uint32_t)(~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 = PaUtil_GetRingBufferWriteAvailable( &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->outputSampleSizeActual * blio->outChan );
|
||||||
|
toWrite -= toWrite % blio->outputSampleSizeActual * blio->outChan ;
|
||||||
|
PaUtil_WriteRingBuffer( &blio->outputRingBuffer, (void *)cbuf, toWrite );
|
||||||
|
cbuf += toWrite;
|
||||||
|
frames -= toWrite / ( blio->outputSampleSizeActual * 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( PaUtil_GetRingBufferWriteAvailable( &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( (uint32_t)(~paOutputUnderflow), &blio->statusFlags );
|
||||||
|
ret = paOutputUnderflowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void waitUntilBlioWriteBufferIsFlushed( PaMacBlio *blio )
|
||||||
|
{
|
||||||
|
if( blio->outputRingBuffer.buffer ) {
|
||||||
|
long avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
|
||||||
|
while( avail != blio->outputRingBuffer.bufferSize ) {
|
||||||
|
if( avail == 0 )
|
||||||
|
Pa_Sleep( PA_MAC_BLIO_BUSY_WAIT_SLEEP_INTERVAL );
|
||||||
|
avail = PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
signed long GetStreamReadAvailable( PaStream* stream )
|
||||||
|
{
|
||||||
|
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
|
||||||
|
VVDBUG(("GetStreamReadAvailable()\n"));
|
||||||
|
|
||||||
|
return PaUtil_GetRingBufferReadAvailable( &blio->inputRingBuffer )
|
||||||
|
/ ( blio->inputSampleSizeActual * blio->inChan );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
signed long GetStreamWriteAvailable( PaStream* stream )
|
||||||
|
{
|
||||||
|
PaMacBlio *blio = & ((PaMacCoreStream*)stream) -> blio;
|
||||||
|
VVDBUG(("GetStreamWriteAvailable()\n"));
|
||||||
|
|
||||||
|
return PaUtil_GetRingBufferWriteAvailable( &blio->outputRingBuffer )
|
||||||
|
/ ( blio->outputSampleSizeActual * blio->outChan );
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Internal blocking interfaces for PortAudio Apple AUHAL implementation
|
||||||
|
*
|
||||||
|
* PortAudio Portable Real-Time Audio Library
|
||||||
|
* Latest Version at: http://www.portaudio.com
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file
|
||||||
|
@ingroup hostapi_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PA_MAC_CORE_BLOCKING_H_
|
||||||
|
#define PA_MAC_CORE_BLOCKING_H_
|
||||||
|
|
||||||
|
#include "pa_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 {
|
||||||
|
PaUtilRingBuffer inputRingBuffer;
|
||||||
|
PaUtilRingBuffer outputRingBuffer;
|
||||||
|
size_t ringBufferFrames;
|
||||||
|
PaSampleFormat inputSampleFormat;
|
||||||
|
size_t inputSampleSizeActual;
|
||||||
|
size_t inputSampleSizePow2;
|
||||||
|
PaSampleFormat outputSampleFormat;
|
||||||
|
size_t outputSampleSizeActual;
|
||||||
|
size_t outputSampleSizePow2;
|
||||||
|
|
||||||
|
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_*/
|
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* Internal interfaces for PortAudio Apple AUHAL implementation
|
||||||
|
*
|
||||||
|
* PortAudio Portable Real-Time Audio Library
|
||||||
|
* Latest Version at: http://www.portaudio.com
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file pa_mac_core
|
||||||
|
@ingroup hostapi_src
|
||||||
|
@author Bjorn Roche
|
||||||
|
@brief AUHAL implementation of PortAudio
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PA_MAC_CORE_INTERNAL_H__
|
||||||
|
#define PA_MAC_CORE_INTERNAL_H__
|
||||||
|
|
||||||
|
#include <CoreAudio/CoreAudio.h>
|
||||||
|
#include <CoreServices/CoreServices.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 "pa_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. */
|
||||||
|
PaUtilRingBuffer 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;
|
||||||
|
/* FIXME: instead of volatile, these should be properly memory barriered */
|
||||||
|
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
|
||||||
|
because the user has called StopStream.
|
||||||
|
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__ */
|
|
@ -0,0 +1,913 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_mac_core_old.c 1083 2006-08-23 07:30:49Z rossb $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
|
@ -0,0 +1,733 @@
|
||||||
|
/*
|
||||||
|
* Helper and utility functions for pa_mac_core.c (Apple AUHAL implementation)
|
||||||
|
*
|
||||||
|
* PortAudio Portable Real-Time Audio Library
|
||||||
|
* Latest Version at: http://www.portaudio.com
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file
|
||||||
|
@ingroup hostapi_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pa_mac_core_utilities.h"
|
||||||
|
#include "pa_mac_core_internal.h"
|
||||||
|
#include <libkern/OSAtomic.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/time.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";
|
||||||
|
|
||||||
|
char str[20];
|
||||||
|
// see if it appears to be a 4-char-code
|
||||||
|
*(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error);
|
||||||
|
if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4]))
|
||||||
|
{
|
||||||
|
str[0] = str[5] = '\'';
|
||||||
|
str[6] = '\0';
|
||||||
|
} else {
|
||||||
|
// no, format it as an integer
|
||||||
|
sprintf(str, "%d", (int)error);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG(("%s on line %d: err='%s', msg=%s\n", errorType, line, str, 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 could be used to with a condition variable.
|
||||||
|
* to prevent propertychanges from happening until the last property
|
||||||
|
* change is acknowledged. Instead, I implemented a busy-wait, which is simpler
|
||||||
|
* to implement b/c in second round of testing (nov '09) property changes occured
|
||||||
|
* quickly and so there was no real way to test the condition variable implementation.
|
||||||
|
* therefore, this function is not used, but it is aluded to in commented code below,
|
||||||
|
* since it represents a theoretically better implementation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
OSStatus propertyProc(
|
||||||
|
AudioDeviceID inDevice,
|
||||||
|
UInt32 inChannel,
|
||||||
|
Boolean isInput,
|
||||||
|
AudioDevicePropertyID inPropertyID,
|
||||||
|
void* inClientData )
|
||||||
|
{
|
||||||
|
// this is where we would set the condition variable
|
||||||
|
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.
|
||||||
|
whether or not the call succeeds, if the data is successfully read,
|
||||||
|
it is returned in outPropertyData. If it is not read successfully,
|
||||||
|
outPropertyData is zeroed, which may or may not be useful in
|
||||||
|
determining if the property was read. */
|
||||||
|
PaError AudioDeviceSetPropertyNowAndWaitForChange(
|
||||||
|
AudioDeviceID inDevice,
|
||||||
|
UInt32 inChannel,
|
||||||
|
Boolean isInput,
|
||||||
|
AudioDevicePropertyID inPropertyID,
|
||||||
|
UInt32 inPropertyDataSize,
|
||||||
|
const void *inPropertyData,
|
||||||
|
void *outPropertyData )
|
||||||
|
{
|
||||||
|
OSStatus macErr;
|
||||||
|
UInt32 outPropertyDataSize = inPropertyDataSize;
|
||||||
|
|
||||||
|
/* First, see if it already has that value. If so, return. */
|
||||||
|
macErr = AudioDeviceGetProperty( inDevice, inChannel,
|
||||||
|
isInput, inPropertyID,
|
||||||
|
&outPropertyDataSize, outPropertyData );
|
||||||
|
if( macErr ) {
|
||||||
|
memset( outPropertyData, 0, inPropertyDataSize );
|
||||||
|
goto failMac;
|
||||||
|
}
|
||||||
|
if( inPropertyDataSize!=outPropertyDataSize )
|
||||||
|
return paInternalError;
|
||||||
|
if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) )
|
||||||
|
return paNoError;
|
||||||
|
|
||||||
|
/* Ideally, we'd use a condition variable to determine changes.
|
||||||
|
we could set that up here. */
|
||||||
|
|
||||||
|
/* If we were using a cond variable, we'd do something useful here,
|
||||||
|
but for now, this is just to make 10.6 happy. */
|
||||||
|
macErr = AudioDeviceAddPropertyListener( inDevice, inChannel, isInput,
|
||||||
|
inPropertyID, propertyProc,
|
||||||
|
NULL );
|
||||||
|
if( macErr )
|
||||||
|
/* we couldn't add a listener. */
|
||||||
|
goto failMac;
|
||||||
|
|
||||||
|
/* set property */
|
||||||
|
macErr = AudioDeviceSetProperty( inDevice, NULL, inChannel,
|
||||||
|
isInput, inPropertyID,
|
||||||
|
inPropertyDataSize, inPropertyData );
|
||||||
|
if( macErr )
|
||||||
|
goto failMac;
|
||||||
|
|
||||||
|
/* busy-wait up to 30 seconds for the property to change */
|
||||||
|
/* busy-wait is justified here only because the correct alternative (condition variable)
|
||||||
|
was hard to test, since most of the waiting ended up being for setting rather than
|
||||||
|
getting in OS X 10.5. This was not the case in earlier OS versions. */
|
||||||
|
struct timeval tv1, tv2;
|
||||||
|
gettimeofday( &tv1, NULL );
|
||||||
|
memcpy( &tv2, &tv1, sizeof( struct timeval ) );
|
||||||
|
while( tv2.tv_sec - tv1.tv_sec < 30 ) {
|
||||||
|
/* now read the property back out */
|
||||||
|
macErr = AudioDeviceGetProperty( inDevice, inChannel,
|
||||||
|
isInput, inPropertyID,
|
||||||
|
&outPropertyDataSize, outPropertyData );
|
||||||
|
if( macErr ) {
|
||||||
|
memset( outPropertyData, 0, inPropertyDataSize );
|
||||||
|
goto failMac;
|
||||||
|
}
|
||||||
|
/* and compare... */
|
||||||
|
if( 0==memcmp( outPropertyData, inPropertyData, outPropertyDataSize ) ) {
|
||||||
|
AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc );
|
||||||
|
return paNoError;
|
||||||
|
}
|
||||||
|
/* No match yet, so let's sleep and try again. */
|
||||||
|
Pa_Sleep( 100 );
|
||||||
|
gettimeofday( &tv2, NULL );
|
||||||
|
}
|
||||||
|
DBUG( ("Timeout waiting for device setting.\n" ) );
|
||||||
|
|
||||||
|
AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc );
|
||||||
|
return paNoError;
|
||||||
|
|
||||||
|
failMac:
|
||||||
|
AudioDeviceRemovePropertyListener( inDevice, inChannel, isInput, inPropertyID, propertyProc );
|
||||||
|
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 )
|
||||||
|
{
|
||||||
|
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 -- */
|
||||||
|
srate = 0;
|
||||||
|
err = AudioDeviceSetPropertyNowAndWaitForChange(
|
||||||
|
device, 0, isInput,
|
||||||
|
kAudioDevicePropertyNominalSampleRate,
|
||||||
|
propsize, &desiredSrate, &srate );
|
||||||
|
|
||||||
|
/* -- if the rate agrees, and was changed, we are done -- */
|
||||||
|
if( srate != 0 && srate == desiredSrate )
|
||||||
|
return paNoError;
|
||||||
|
/* -- 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 );
|
||||||
|
srate = 0;
|
||||||
|
err = AudioDeviceSetPropertyNowAndWaitForChange(
|
||||||
|
device, 0, isInput,
|
||||||
|
kAudioDevicePropertyNominalSampleRate,
|
||||||
|
propsize, &best, &srate );
|
||||||
|
|
||||||
|
/* -- if the set rate matches, we are done -- */
|
||||||
|
if( srate != 0 && srate == best )
|
||||||
|
return paNoError;
|
||||||
|
|
||||||
|
if( err )
|
||||||
|
return ERR( err );
|
||||||
|
|
||||||
|
/* -- 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,
|
||||||
|
UInt32 requestedFramesPerBuffer,
|
||||||
|
UInt32 *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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
*
|
||||||
|
* XRun stuff
|
||||||
|
*
|
||||||
|
**********************/
|
||||||
|
|
||||||
|
struct PaMacXRunListNode_s {
|
||||||
|
PaMacCoreStream *stream;
|
||||||
|
struct PaMacXRunListNode_s *next;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
typedef struct PaMacXRunListNode_s PaMacXRunListNode;
|
||||||
|
|
||||||
|
/** Always empty, so that it can always be the one returned by
|
||||||
|
addToXRunListenerList. note that it's not a pointer. */
|
||||||
|
static PaMacXRunListNode firstXRunListNode;
|
||||||
|
static int xRunListSize;
|
||||||
|
static pthread_mutex_t xrunMutex;
|
||||||
|
|
||||||
|
OSStatus xrunCallback(
|
||||||
|
AudioDeviceID inDevice,
|
||||||
|
UInt32 inChannel,
|
||||||
|
Boolean isInput,
|
||||||
|
AudioDevicePropertyID inPropertyID,
|
||||||
|
void* inClientData)
|
||||||
|
{
|
||||||
|
PaMacXRunListNode *node = (PaMacXRunListNode *) inClientData;
|
||||||
|
|
||||||
|
int ret = pthread_mutex_trylock( &xrunMutex ) ;
|
||||||
|
|
||||||
|
if( ret == 0 ) {
|
||||||
|
|
||||||
|
node = node->next ; //skip the first node
|
||||||
|
|
||||||
|
for( ; node; node=node->next ) {
|
||||||
|
PaMacCoreStream *stream = node->stream;
|
||||||
|
|
||||||
|
if( stream->state != ACTIVE )
|
||||||
|
continue; //if the stream isn't active, we don't care if the device is dropping
|
||||||
|
|
||||||
|
if( isInput ) {
|
||||||
|
if( stream->inputDevice == inDevice )
|
||||||
|
OSAtomicOr32( paInputOverflow, (uint32_t *)&(stream->xrunFlags) );
|
||||||
|
} else {
|
||||||
|
if( stream->outputDevice == inDevice )
|
||||||
|
OSAtomicOr32( paOutputUnderflow, (uint32_t *)&(stream->xrunFlags) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock( &xrunMutex );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int initializeXRunListenerList()
|
||||||
|
{
|
||||||
|
xRunListSize = 0;
|
||||||
|
bzero( (void *) &firstXRunListNode, sizeof(firstXRunListNode) );
|
||||||
|
return pthread_mutex_init( &xrunMutex, NULL );
|
||||||
|
}
|
||||||
|
int destroyXRunListenerList()
|
||||||
|
{
|
||||||
|
PaMacXRunListNode *node;
|
||||||
|
node = firstXRunListNode.next;
|
||||||
|
while( node ) {
|
||||||
|
PaMacXRunListNode *tmp = node;
|
||||||
|
node = node->next;
|
||||||
|
free( tmp );
|
||||||
|
}
|
||||||
|
xRunListSize = 0;
|
||||||
|
return pthread_mutex_destroy( &xrunMutex );
|
||||||
|
}
|
||||||
|
|
||||||
|
void *addToXRunListenerList( void *stream )
|
||||||
|
{
|
||||||
|
pthread_mutex_lock( &xrunMutex );
|
||||||
|
PaMacXRunListNode *newNode;
|
||||||
|
// setup new node:
|
||||||
|
newNode = (PaMacXRunListNode *) malloc( sizeof( PaMacXRunListNode ) );
|
||||||
|
newNode->stream = (PaMacCoreStream *) stream;
|
||||||
|
newNode->next = firstXRunListNode.next;
|
||||||
|
// insert:
|
||||||
|
firstXRunListNode.next = newNode;
|
||||||
|
pthread_mutex_unlock( &xrunMutex );
|
||||||
|
|
||||||
|
return &firstXRunListNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
int removeFromXRunListenerList( void *stream )
|
||||||
|
{
|
||||||
|
pthread_mutex_lock( &xrunMutex );
|
||||||
|
PaMacXRunListNode *node, *prev;
|
||||||
|
prev = &firstXRunListNode;
|
||||||
|
node = firstXRunListNode.next;
|
||||||
|
while( node ) {
|
||||||
|
if( node->stream == stream ) {
|
||||||
|
//found it:
|
||||||
|
--xRunListSize;
|
||||||
|
prev->next = node->next;
|
||||||
|
free( node );
|
||||||
|
pthread_mutex_unlock( &xrunMutex );
|
||||||
|
return xRunListSize;
|
||||||
|
}
|
||||||
|
prev = prev->next;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock( &xrunMutex );
|
||||||
|
// failure
|
||||||
|
return xRunListSize;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
/*
|
||||||
|
* Helper and utility functions for pa_mac_core.c (Apple AUHAL implementation)
|
||||||
|
*
|
||||||
|
* PortAudio Portable Real-Time Audio Library
|
||||||
|
* Latest Version at: http://www.portaudio.com
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file
|
||||||
|
@ingroup hostapi_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 );
|
||||||
|
|
||||||
|
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,
|
||||||
|
UInt32 requestedFramesPerBuffer,
|
||||||
|
UInt32 *actualFramesPerBuffer );
|
||||||
|
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
*
|
||||||
|
* xrun handling
|
||||||
|
*
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
OSStatus xrunCallback(
|
||||||
|
AudioDeviceID inDevice,
|
||||||
|
UInt32 inChannel,
|
||||||
|
Boolean isInput,
|
||||||
|
AudioDevicePropertyID inPropertyID,
|
||||||
|
void* inClientData ) ;
|
||||||
|
|
||||||
|
/** returns zero on success or a unix style error code. */
|
||||||
|
int initializeXRunListenerList();
|
||||||
|
/** returns zero on success or a unix style error code. */
|
||||||
|
int destroyXRunListenerList();
|
||||||
|
|
||||||
|
/**Returns the list, so that it can be passed to CorAudio.*/
|
||||||
|
void *addToXRunListenerList( void *stream );
|
||||||
|
/**Returns the number of Listeners in the list remaining.*/
|
||||||
|
int removeFromXRunListenerList( void *stream );
|
||||||
|
|
||||||
|
#endif /* PA_MAC_CORE_UTILITIES_H__*/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,180 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file
|
||||||
|
@ingroup hostapi_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "pa_win_ds_dynlink.h"
|
||||||
|
|
||||||
|
PaWinDsDSoundEntryPoints paWinDsDSoundEntryPoints = { 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
|
||||||
|
static HRESULT WINAPI DummyDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv)
|
||||||
|
{
|
||||||
|
(void)rclsid; /* unused parameter */
|
||||||
|
(void)riid; /* unused parameter */
|
||||||
|
(void)ppv; /* unused parameter */
|
||||||
|
return CLASS_E_CLASSNOTAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.DllGetClassObject =
|
||||||
|
(HRESULT (WINAPI *)(REFCLSID, REFIID , LPVOID *))
|
||||||
|
GetProcAddress( paWinDsDSoundEntryPoints.hInstance_, "DllGetClassObject" );
|
||||||
|
if( paWinDsDSoundEntryPoints.DllGetClassObject == NULL )
|
||||||
|
paWinDsDSoundEntryPoints.DllGetClassObject = DummyDllGetClassObject;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@file
|
||||||
|
@ingroup hostapi_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INCLUDED_PA_DSOUND_DYNLINK_H
|
||||||
|
#define INCLUDED_PA_DSOUND_DYNLINK_H
|
||||||
|
|
||||||
|
/* 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 *DllGetClassObject)(REFCLSID , REFIID , LPVOID *);
|
||||||
|
|
||||||
|
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 */
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -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 );
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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).
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_unix_hostapis.c 1413 2009-05-24 17:00:36Z aknudsen $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup unix_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 );
|
||||||
|
PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
|
||||||
|
|
||||||
|
/** Note that on Linux, ALSA is placed before OSS so that the former is preferred over the latter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PaUtilHostApiInitializer *paHostApiInitializers[] =
|
||||||
|
{
|
||||||
|
#ifdef __linux__
|
||||||
|
|
||||||
|
#ifdef PA_USE_ALSA
|
||||||
|
PaAlsa_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PA_USE_OSS
|
||||||
|
PaOSS_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* __linux__ */
|
||||||
|
|
||||||
|
#ifdef PA_USE_OSS
|
||||||
|
PaOSS_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PA_USE_ALSA
|
||||||
|
PaAlsa_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#ifdef PA_USE_COREAUDIO
|
||||||
|
PaMacCore_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PA_USE_SKELETON
|
||||||
|
PaSkeleton_Initialize,
|
||||||
|
#endif
|
||||||
|
|
||||||
|
0 /* NULL terminated array */
|
||||||
|
};
|
||||||
|
|
||||||
|
int paDefaultHostApiIndex = 0;
|
|
@ -0,0 +1,693 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_unix_util.c 1419 2009-10-22 17:28:35Z bjornroche $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup unix_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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>
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && !defined(HAVE_MACH_ABSOLUTE_TIME)
|
||||||
|
#define HAVE_MACH_ABSOLUTE_TIME
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_MACH_ABSOLUTE_TIME
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "pa_util.h"
|
||||||
|
#include "pa_unix_util.h"
|
||||||
|
#include "pa_debugprint.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
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_MACH_ABSOLUTE_TIME
|
||||||
|
/*
|
||||||
|
Discussion on the CoreAudio mailing list suggests that calling
|
||||||
|
gettimeofday (or anything else in the BSD layer) is not real-time
|
||||||
|
safe, so we use mach_absolute_time on OSX. This implementation is
|
||||||
|
based on these two links:
|
||||||
|
|
||||||
|
Technical Q&A QA1398 - Mach Absolute Time Units
|
||||||
|
http://developer.apple.com/mac/library/qa/qa2004/qa1398.html
|
||||||
|
|
||||||
|
Tutorial: Performance and Time.
|
||||||
|
http://www.macresearch.org/tutorial_performance_and_time
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Scaler to convert the result of mach_absolute_time to seconds */
|
||||||
|
static double machSecondsConversionScaler_ = 0.0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void PaUtil_InitializeClock( void )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_MACH_ABSOLUTE_TIME
|
||||||
|
mach_timebase_info_data_t info;
|
||||||
|
kern_return_t err = mach_timebase_info( &info );
|
||||||
|
if( err == 0 )
|
||||||
|
machSecondsConversionScaler_ = 1e-9 * (double) info.numer / (double) info.denom;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PaTime PaUtil_GetTime( void )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_MACH_ABSOLUTE_TIME
|
||||||
|
return mach_absolute_time() * machSecondsConversionScaler_;
|
||||||
|
#elif defined(HAVE_CLOCK_GETTIME)
|
||||||
|
struct timespec tp;
|
||||||
|
clock_gettime(CLOCK_REALTIME, &tp);
|
||||||
|
return (PaTime)(tp.tv_sec + tp.tv_nsec * 1e-9);
|
||||||
|
#else
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday( &tv, NULL );
|
||||||
|
return (PaTime) tv.tv_usec * 1e-6 + 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PaError BoostPriority( PaUnixThread* self )
|
||||||
|
{
|
||||||
|
PaError result = paNoError;
|
||||||
|
struct sched_param spm = { 0 };
|
||||||
|
/* Priority should only matter between contending FIFO threads? */
|
||||||
|
spm.sched_priority = 1;
|
||||||
|
|
||||||
|
assert( self );
|
||||||
|
|
||||||
|
if( pthread_setschedparam( self->thread, 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild,
|
||||||
|
int rtSched )
|
||||||
|
{
|
||||||
|
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 */
|
||||||
|
|
||||||
|
/* Temporarily disabled since we should test during configuration for presence of required mman.h header */
|
||||||
|
#if 0
|
||||||
|
#if defined _POSIX_MEMLOCK && (_POSIX_MEMLOCK != -1)
|
||||||
|
if( 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
|
||||||
|
#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( rtSched )
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
if( self->useWatchdog )
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct sched_param wdSpm = { 0 };
|
||||||
|
/* Launch watchdog, watchdog sets callback thread priority */
|
||||||
|
int prio = PA_MIN( self->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( &self->watchdogThread, &attr, &WatchdogFunc, self )) )
|
||||||
|
{
|
||||||
|
PA_UNLESS( err == EPERM, paInternalError );
|
||||||
|
/* Permission error, go on without realtime privileges */
|
||||||
|
PA_DEBUG(( "Failed bumping priority\n" ));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int policy;
|
||||||
|
self->watchdogRunning = 1;
|
||||||
|
PA_ENSURE_SYSTEM( pthread_getschedparam( self->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
|
||||||
|
#endif
|
||||||
|
PA_ENSURE( BoostPriority( self ) );
|
||||||
|
|
||||||
|
{
|
||||||
|
int policy;
|
||||||
|
struct sched_param spm;
|
||||||
|
pthread_getschedparam(self->thread, &policy, &spm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
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 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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#endif
|
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_unix_util.h 1241 2007-07-23 20:08:31Z aknudsen $
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup unix_src
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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.
|
||||||
|
* @param rtSched: Enable realtime scheduling?
|
||||||
|
* @return: If timed out waiting on child, paTimedOut.
|
||||||
|
*/
|
||||||
|
PaError PaUnixThread_New( PaUnixThread* self, void* (*threadFunc)( void* ), void* threadArg, PaTime waitForChild,
|
||||||
|
int rtSched );
|
||||||
|
|
||||||
|
/** 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
|
|
@ -0,0 +1,100 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_win_hostapis.c 1339 2008-02-15 07:50:33Z rossb $
|
||||||
|
* Portable Audio I/O Library Windows initialization table
|
||||||
|
*
|
||||||
|
* Based on the Open Source API proposed by Ross Bencina
|
||||||
|
* Copyright (c) 1999-2008 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup win_src
|
||||||
|
|
||||||
|
@brief 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;
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* $Id: pa_win_util.c 1437 2009-12-10 08:10:08Z rossb $
|
||||||
|
* Portable Audio I/O Library
|
||||||
|
* Win32 platform-specific support functions
|
||||||
|
*
|
||||||
|
* Based on the Open Source API proposed by Ross Bencina
|
||||||
|
* Copyright (c) 1999-2008 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The text above constitutes the entire PortAudio license; however,
|
||||||
|
* the PortAudio community also makes the following non-binding requests:
|
||||||
|
*
|
||||||
|
* 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. It is also
|
||||||
|
* requested that these non-binding requests be included along with the
|
||||||
|
* license above.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file
|
||||||
|
@ingroup win_src
|
||||||
|
|
||||||
|
@brief Win32 implementation of platform-specific PaUtil 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"
|
||||||
|
|
||||||
|
#if (defined(WIN32) && (defined(_MSC_VER) && (_MSC_VER >= 1200))) && !defined(_WIN32_WCE) /* MSC version 6 and above */
|
||||||
|
#pragma comment( lib, "winmm.lib" )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
{
|
||||||
|
#ifndef UNDER_CE
|
||||||
|
return timeGetTime() * .001;
|
||||||
|
#else
|
||||||
|
return GetTickCount() * .001;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue