moved pateam to tags/unknown-was-pateam and added a README.txt for the folder.
This commit is contained in:
parent
ecc345dde9
commit
a58a6c257b
82 changed files with 2277 additions and 9227 deletions
65
LICENSE.txt
65
LICENSE.txt
|
|
@ -1,65 +0,0 @@
|
|||
Portable header file to contain:
|
||||
/*
|
||||
* PortAudio Portable Real-Time Audio Library
|
||||
* PortAudio API Header File
|
||||
* Latest version available at: http://www.audiomulch.com/portaudio/
|
||||
*
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
Implementation files to contain:
|
||||
/*
|
||||
* PortAudio Portable Real-Time Audio Library
|
||||
* Latest version at: http://www.audiomulch.com/portaudio/
|
||||
* <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.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
95
Makefile.in
95
Makefile.in
|
|
@ -1,95 +0,0 @@
|
|||
#
|
||||
# PortAudio Makefile.in
|
||||
#
|
||||
# Dominic Mazzoni
|
||||
#
|
||||
|
||||
PREFIX = @prefix@
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@ -Ipa_common
|
||||
LIBS = @LIBS@
|
||||
AR = @AR@
|
||||
RANLIB = @RANLIB@
|
||||
INSTALL = @INSTALL@
|
||||
SHARED_FLAGS = @SHARED_FLAGS@
|
||||
DLL_LIBS = @DLL_LIBS@
|
||||
|
||||
OTHER_OBJS = @OTHER_OBJS@
|
||||
|
||||
PALIB = libportaudio.a
|
||||
PADLL = @PADLL@
|
||||
PADLLV = $(PADLL).0.0.18
|
||||
PAINC = pa_common/portaudio.h
|
||||
|
||||
COMMON_OBJS = \
|
||||
pa_common/pa_convert.o \
|
||||
pa_common/pa_lib.o
|
||||
|
||||
TESTS = \
|
||||
bin/patest_buffer \
|
||||
bin/patest_clip \
|
||||
bin/patest_dither \
|
||||
bin/patest_hang \
|
||||
bin/patest_latency \
|
||||
bin/patest_leftright \
|
||||
bin/patest_longsine \
|
||||
bin/patest_many \
|
||||
bin/patest_maxsines \
|
||||
bin/patest_multi_sine \
|
||||
bin/patest_pink \
|
||||
bin/patest_record \
|
||||
bin/patest_ringmix \
|
||||
bin/patest_saw \
|
||||
bin/patest_sine8 \
|
||||
bin/patest_sine \
|
||||
bin/patest_sine_formats \
|
||||
bin/patest_sine_time \
|
||||
bin/patest_stop \
|
||||
bin/patest_sync \
|
||||
bin/patest_toomanysines \
|
||||
bin/patest_underflow \
|
||||
bin/patest_wire
|
||||
|
||||
OBJS = $(COMMON_OBJS) $(OTHER_OBJS)
|
||||
|
||||
all: lib/$(PALIB) lib/$(PADLLV) tests
|
||||
|
||||
tests: bin/ $(TESTS)
|
||||
|
||||
lib/$(PALIB): lib/ $(OBJS) Makefile $(PAINC)
|
||||
$(AR) ruv lib/$(PALIB) $(OBJS)
|
||||
$(RANLIB) lib/$(PALIB)
|
||||
|
||||
lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC)
|
||||
$(CC) $(SHARED_FLAGS) -o lib/$(PADLLV) $(OBJS) $(DLL_LIBS)
|
||||
|
||||
$(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c
|
||||
$(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS)
|
||||
|
||||
install: lib/$(PALIB) lib/$(PADLLV)
|
||||
$(INSTALL) -m 644 lib/$(PADLLV) $(PREFIX)/lib/$(PADLLV)
|
||||
$(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB)
|
||||
cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL)
|
||||
$(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h
|
||||
@echo ""
|
||||
@echo "------------------------------------------------------------"
|
||||
@echo "PortAudio was successfully installed."
|
||||
@echo ""
|
||||
@echo "On some systems (e.g. Linux) you should run 'ldconfig' now"
|
||||
@echo "to make the shared object available. You may also need to"
|
||||
@echo "modify your LD_LIBRARY_PATH environment variable to include"
|
||||
@echo "the directory $(PREFIX)/lib"
|
||||
@echo "------------------------------------------------------------"
|
||||
@echo ""
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(TESTS) lib/$(PALIB)
|
||||
|
||||
%.o: %.c Makefile $(PAINC)
|
||||
$(CC) -c $(CFLAGS) $< -o $@
|
||||
|
||||
bin:
|
||||
mkdir bin
|
||||
|
||||
lib:
|
||||
mkdir lib
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
# Make PortAudio for Linux
|
||||
# Updated 2001/08/25 Bill Eldridge bill@rfa.org
|
||||
# Updated 2001/10/16, philburk@softsynth.com, s/unix_oss/unix_oss/
|
||||
# Updated 2002/04/30 Bill Eldridge bill@rfa.org
|
||||
# Made the libinstall and tests compile a bit cleaner
|
||||
|
||||
# A pretty bare makefile, that figures out all the test files
|
||||
# and compiles them against the library in the pa_unix_oss directory.
|
||||
|
|
@ -21,34 +19,23 @@ CFLAGS = -g
|
|||
LIBINST = /usr/local/lib
|
||||
|
||||
TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c)
|
||||
TESTO:= $(wildcard pa_tests/pa*.o pa_tests/debug*.o)
|
||||
|
||||
LIBFILES:= ./pa_common/pa_lib.c ./pa_unix_oss/pa_unix_oss.c
|
||||
|
||||
#all: sharedlib libinstall tests
|
||||
all: sharedlib libinstall testo testq
|
||||
|
||||
.c.o:
|
||||
-gcc -c -I./pa_common $< -o $*.o
|
||||
|
||||
.o:
|
||||
-gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio
|
||||
|
||||
#.c.o:
|
||||
# -gcc -c -I./pa_common $< -o $*.o
|
||||
# -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio
|
||||
|
||||
all: sharedlib tests
|
||||
|
||||
sharedlib: $(LIBFILES:.c=.o)
|
||||
gcc -shared -o ./pa_unix_oss/libportaudio.so ./pa_common/pa_lib.o ./pa_unix_oss/pa_unix_oss.o
|
||||
|
||||
libinstall: ./pa_unix_oss/libportaudio.so
|
||||
@cp -f ./pa_unix_oss/libportaudio.so $(LIBINST)
|
||||
@/sbin/ldconfig
|
||||
@/sbin/ldconfig -v
|
||||
|
||||
testo: $(TESTS:.c=.o)
|
||||
|
||||
testq: $(TESTO:.o=)
|
||||
tests: $(TESTS:.c=.o)
|
||||
|
||||
clean:
|
||||
-@rm -f $(TESTS:.c=.o)
|
||||
|
|
|
|||
|
|
@ -1,57 +0,0 @@
|
|||
|
||||
# Makefile for PortAudio on mingw (http://mingw.sourceforge.net)
|
||||
|
||||
# Contributed by Bill Eldridge, bill@rfa.org, Radio Free Asia
|
||||
# Copyright 2002/02/20, GPL
|
||||
|
||||
# Uses a common mingw32 cross-compiler that defaults
|
||||
# to everything in /usr/local/cross-tools
|
||||
|
||||
# First edit your path with
|
||||
# export PATH=/usr/local/cross-tools/bin:$PATH
|
||||
|
||||
# Usage: make -f Makefile.mingw all
|
||||
# or make -f Makefile.mingw sharedlib
|
||||
# make -f Makefile.mingw tests
|
||||
#
|
||||
# Then copy executables & portaudio.dll to your Windows machine
|
||||
#
|
||||
# To make work with pa_win_ds, you'll have to substitue
|
||||
# all the pa_win_wmme files with pa_win_ds files, no biggie.
|
||||
|
||||
CC= i586-mingw32msvc-gcc
|
||||
DLLTOOL= i586-mingw32msvc-dlltool
|
||||
DLLWRAP= i586-mingw32msvc-dllwrap
|
||||
|
||||
ARCH= pa_win_wmme
|
||||
|
||||
TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c)
|
||||
|
||||
.c.o:
|
||||
-$(CC) -c -I./pa_common $< -o $*.o
|
||||
-$(CC) $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm
|
||||
|
||||
all: sharedlib tests
|
||||
|
||||
sharedlib: ./pa_common/pa_lib.c
|
||||
$(CC) -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o
|
||||
$(CC) -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o
|
||||
$(CC) -shared -mthreads -o portaudio.dll pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm
|
||||
$(DLLWRAP) --export-all --output-def=libportaudio.def --output-lib=libportaudio.a --dllname=portaudio.dll --drivername=i586-mingw32msvc-gcc pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm
|
||||
$(CC) -shared -Wl,--enable-auto-image-base -o portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm
|
||||
|
||||
|
||||
tests: $(TESTS:.c=.o)
|
||||
|
||||
sine:
|
||||
$(CC) -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o
|
||||
$(CC) pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm
|
||||
|
||||
clean:
|
||||
-rm ./pa_tests/*.exe
|
||||
-rm ./pa_tests/*.o
|
||||
|
||||
nothing:
|
||||
$(CC) pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm
|
||||
|
||||
|
||||
82
README.txt
82
README.txt
|
|
@ -1,81 +1 @@
|
|||
README for PortAudio
|
||||
Implementations for PC DirectSound and Mac SoundManager
|
||||
|
||||
/*
|
||||
* PortAudio Portable Real-Time Audio Library
|
||||
* Latest Version at: http://www.portaudio.com//
|
||||
*
|
||||
* Copyright (c) 1999-2000 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.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
PortAudio is a portable audio I/O library designed for cross-platform
|
||||
support of audio. It uses a callback mechanism to request audio processing.
|
||||
Audio can be generated in various formats, including 32 bit floating point,
|
||||
and will be converted to the native format internally.
|
||||
|
||||
Documentation:
|
||||
See "pa_common/portaudio.h" for API spec.
|
||||
See docs folder for a tutorial.
|
||||
Also see http://www.portaudio.com/docs/
|
||||
And see "pa_tests/patest_saw.c" for an example.
|
||||
|
||||
For information on compiling programs with PortAudio, please see the
|
||||
tutorial at:
|
||||
|
||||
http://www.portaudio.com/docs/pa_tutorial.html
|
||||
|
||||
Important Files and Folders:
|
||||
pa_common/ = platform independant code
|
||||
pa_common/portaudio.h = header file for PortAudio API. Specifies API.
|
||||
pa_common/pa_lib.c = host independant code for all implementations.
|
||||
|
||||
pablio = simple blocking read/write interface
|
||||
|
||||
Platform Implementations
|
||||
pa_asio = ASIO for Windows and Macintosh
|
||||
pa_beos = BeOS
|
||||
pa_mac = Macintosh Sound Manager for OS 8,9 and Carbon
|
||||
pa_mac_core = Macintosh Core Audio for OS X
|
||||
pa_sgi = Silicon Graphics AL
|
||||
pa_unix_oss = OSS implementation for various Unixes
|
||||
pa_win_ds = Windows Direct Sound
|
||||
pa_win_wmme = Windows MME (most widely supported)
|
||||
|
||||
Test Programs
|
||||
pa_tests/pa_fuzz.c = guitar fuzz box
|
||||
pa_tests/pa_devs.c = print a list of available devices
|
||||
pa_tests/pa_minlat.c = determine minimum latency for your machine
|
||||
pa_tests/paqa_devs.c = self test that opens all devices
|
||||
pa_tests/paqa_errs.c = test error detection and reporting
|
||||
pa_tests/patest_clip.c = hear a sine wave clipped and unclipped
|
||||
pa_tests/patest_dither.c = hear effects of dithering (extremely subtle)
|
||||
pa_tests/patest_pink.c = fun with pink noise
|
||||
pa_tests/patest_record.c = record and playback some audio
|
||||
pa_tests/patest_maxsines.c = how many sine waves can we play? Tests Pa_GetCPULoad().
|
||||
pa_tests/patest_sine.c = output a sine wave in a simple PA app
|
||||
pa_tests/patest_sync.c = test syncronization of audio and video
|
||||
pa_tests/patest_wire.c = pass input to output, wire simulator
|
||||
This folder may have had something to do with the original CVS import. No one else on the mailing list knew what it was either, but it was decided that we aught to keep it in tags, rather than branges, where it was originally. It was originally called "pateam" and before I touched it it was last touched by "anonymous" in 2002ish. -Bjorn Roche
|
||||
|
|
|
|||
BIN
config.guess
vendored
BIN
config.guess
vendored
Binary file not shown.
BIN
config.sub
vendored
BIN
config.sub
vendored
Binary file not shown.
BIN
configure
vendored
BIN
configure
vendored
Binary file not shown.
81
configure.in
81
configure.in
|
|
@ -1,81 +0,0 @@
|
|||
dnl
|
||||
dnl PortAudio configure.in script
|
||||
dnl
|
||||
dnl Dominic Mazzoni
|
||||
dnl
|
||||
|
||||
dnl Require autoconf >= 2.13
|
||||
AC_PREREQ(2.13)
|
||||
|
||||
dnl Init autoconf and make sure configure is being called
|
||||
dnl from the right directory
|
||||
AC_INIT([pa_common/portaudio.h])
|
||||
|
||||
dnl Checks for programs
|
||||
AC_PROG_CC
|
||||
AC_PROG_RANLIB
|
||||
AC_PROG_INSTALL
|
||||
AC_PATH_PROG(AR, ar, no)
|
||||
if [[ $AR = "no" ]] ; then
|
||||
AC_MSG_ERROR("Could not find ar - needed to create a library");
|
||||
fi
|
||||
|
||||
dnl Extra variables we want to substitute
|
||||
AC_SUBST(OTHER_OBJS)
|
||||
AC_SUBST(PADLL)
|
||||
AC_SUBST(SHARED_FLAGS)
|
||||
AC_SUBST(DLL_LIBS)
|
||||
|
||||
dnl Determine the host operating system / platform
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
case "${host_os}" in
|
||||
darwin* )
|
||||
dnl Mac OS X configuration
|
||||
|
||||
OTHER_OBJS="pa_mac_core/pa_mac_core.o";
|
||||
LIBS="-framework CoreAudio -lm";
|
||||
PADLL="libportaudio.dylib";
|
||||
SHARED_FLAGS="-framework CoreAudio -dynamiclib";
|
||||
;;
|
||||
|
||||
mingw* )
|
||||
dnl MingW configuration
|
||||
|
||||
OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
|
||||
LIBS="-lwinmm -lm";
|
||||
PADLL="portaudio.dll";
|
||||
SHARED_FLAGS="-shared -mthreads";
|
||||
DLL_LIBS="-lwinmm";
|
||||
;;
|
||||
|
||||
cygwin* )
|
||||
dnl Cygwin configuration
|
||||
|
||||
OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
|
||||
LIBS="-lwinmm -lm";
|
||||
PADLL="portaudio.dll";
|
||||
SHARED_FLAGS="-shared -mthreads";
|
||||
DLL_LIBS="-lwinmm";
|
||||
;;
|
||||
|
||||
*)
|
||||
dnl Unix OSS configuration
|
||||
|
||||
AC_CHECK_LIB(pthread, pthread_create,
|
||||
,
|
||||
AC_MSG_ERROR([libpthread not found!]))
|
||||
|
||||
OTHER_OBJS="pa_unix_oss/pa_unix_oss.o";
|
||||
LIBS="-lm -lpthread";
|
||||
PADLL="libportaudio.so";
|
||||
SHARED_FLAGS="-shared";
|
||||
esac
|
||||
|
||||
AC_OUTPUT([Makefile])
|
||||
|
||||
echo ""
|
||||
echo "Finished configure."
|
||||
|
||||
echo ""
|
||||
echo "Type 'make' to build PortAudio and examples."
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="PortAudio Docs, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Docs</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Documentation</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<p>Copyright 2000 Phil Burk and Ross Bencina
|
||||
<h3>
|
||||
<a href="pa_tutorial.html">Tutorial</a></h3>
|
||||
|
||||
<dl>
|
||||
<dl>Describes how to write audio programs using the PortAudio API.</dl>
|
||||
|
||||
<h3>
|
||||
<a href="portaudio_h.txt">API Reference</a></h3>
|
||||
|
||||
<dl>The Application Programmer Interface is documented in "portaudio.h".</dl>
|
||||
|
||||
<h3>
|
||||
<a href="releases.html">Release Notes</a></h3>
|
||||
|
||||
<dl>What changed since the last release?</dl>
|
||||
</dl>
|
||||
|
||||
<h3>
|
||||
<a href="pa_impl_guide.html">Implementation Guide</a></h3>
|
||||
|
||||
<blockquote>Describes how to write an implementation of PortAudio for a
|
||||
new computer platform.</blockquote>
|
||||
|
||||
<h3>
|
||||
<a href="portaudio_icmc2001.pdf">Paper Presented at ICMC2001</a> (PDF)</h3>
|
||||
|
||||
<blockquote>Describes the PortAudio API and discusses implementation issues.
|
||||
Written July 2001.</blockquote>
|
||||
|
||||
<h3>
|
||||
<a href="latency.html">Improving Latency</a></h3>
|
||||
|
||||
<blockquote>How to tune your computer to achieve the lowest possible audio
|
||||
delay.</blockquote>
|
||||
|
||||
<h3>
|
||||
<a href="proposals.html">Proposed Changes</a></h3>
|
||||
|
||||
<blockquote>Describes API changes being considered by the developer community.
|
||||
Feedback welcome.</blockquote>
|
||||
<a href="http://www.portaudio.com/">Return to PortAudio Home Page</a>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Internal docs. How a stream is started or stopped.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Implementation - Start/Stop</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
<a href="http://www.portaudio.com">PortAudio</a> Latency</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<p>This page discusses the issues of audio latency for <a href="http://www.portaudio.com">PortAudio</a>
|
||||
. It offers suggestions on how to lower latency to improve the responsiveness
|
||||
of applications.
|
||||
<blockquote><b><a href="#what">What is Latency?</a></b>
|
||||
<br><b><a href="#portaudio">PortAudio and Latency</a></b>
|
||||
<br><b><a href="#macintosh">Macintosh</a></b>
|
||||
<br><b><a href="#unix">Unix</a></b>
|
||||
<br><b><a href="#windows">WIndows</a></b></blockquote>
|
||||
By Phil Burk, Copyright 2002 Phil Burk and Ross Bencina
|
||||
<h2>
|
||||
<a NAME="what"></a>What is Latency?</h2>
|
||||
Latency is basically longest time that you have to wait before you obtain
|
||||
a desired result. For digital audio output it is the time between making
|
||||
a sound in software and finally hearing it.
|
||||
<p>Consider the example of pressing a key on the ASCII keyboard to play
|
||||
a note. There are several stages in this process which each contribute
|
||||
their own latency. First the operating system must respond to the keypress.
|
||||
Then the audio signal generated must work its way through the PortAudio
|
||||
buffers. Then it must work its way through the audio card hardware. Then
|
||||
it must go through the audio amplifier which is very quick and then travel
|
||||
through the air. Sound travels at abous one foot per millisecond through
|
||||
air so placing speakers across the room can add 5-20 msec of delay.
|
||||
<p>The reverse process occurs when recording or responding to audio input.
|
||||
If you are processing audio, for example if you implement a software guitar
|
||||
fuzz box, then you have both the audio input and audio output latencies
|
||||
added together.
|
||||
<p>The audio buffers are used to prevent glitches in the audio stream.
|
||||
The user software writes audio into the output buffers. That audio is read
|
||||
by the low level audio driver or by DMA and sent to the DAC. If the computer
|
||||
gets busy doing something like reading the disk or redrawing the screen,
|
||||
then it may not have time to fill the audio buffer. The audio hardware
|
||||
then runs out of audio data, which causes a glitch. By using a large enough
|
||||
buffer we can ensure that there is always enough audio data for the audio
|
||||
hardware to play. But if the buffer is too large then the latency is high
|
||||
and the system feels sluggish. If you play notes on the keyboard then the
|
||||
"instrument" will feel unresponsive. So you want the buffers to be as small
|
||||
as possible without glitching.
|
||||
<h2>
|
||||
<a NAME="portaudio"></a>PortAudio and Latency</h2>
|
||||
The only delay that PortAudio can control is the total length of its buffers.
|
||||
The Pa_OpenStream() call takes two parameters: numBuffers and framesPerBuffer.
|
||||
The latency is also affected by the sample rate which we will call framesPerSecond.
|
||||
A frame is a set of samples that occur simultaneously. For a stereo stream,
|
||||
a frame is two samples.
|
||||
<p>The latency in milliseconds due to this buffering is:
|
||||
<blockquote><tt>latency_msec = 1000 * numBuffers * framesPerBuffer / framesPerSecond</tt></blockquote>
|
||||
This is not the total latency, as we have seen, but it is the part we can
|
||||
control.
|
||||
<p>If you call Pa_OpenStream() with numBuffers equal to zero, then PortAudio
|
||||
will select a conservative number that will prevent audio glitches. If
|
||||
you still get glitches, then you can pass a larger value for numBuffers
|
||||
until the glitching stops. if you try to pass a numBuffers value that is
|
||||
too small, then PortAudio will use its own idea of the minimum value.
|
||||
<p>PortAudio decides on the minimum number of buffers in a conservative
|
||||
way based on the frameRate, operating system and other variables. You can
|
||||
query the value that PortAudio will use by calling:
|
||||
<blockquote><tt>int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate
|
||||
);</tt></blockquote>
|
||||
On some systems you can override the PortAudio minimum if you know your
|
||||
system can handle a lower value. You do this by setting an environment
|
||||
variable called PA_MIN_LATENCY_MSEC which is read by PortAudio when it
|
||||
starts up. This is supported on the PortAudio implementations for Windows
|
||||
MME, Windows DirectSound, and Unix OSS.
|
||||
<h2>
|
||||
<a NAME="macintosh"></a>Macintosh</h2>
|
||||
The best thing you can do to improve latency on Mac OS 8 and 9 is to turn
|
||||
off Virtual Memory. PortAudio V18 will detect that Virtual Memory is turned
|
||||
off and use a very low latency.
|
||||
<p>For Mac OS X the latency is very low because Apple Core Audio is so
|
||||
well written. You can set the PA_MIN_LATENCY_MSEC variable using:
|
||||
<blockquote><tt>setenv PA_MIN_LATENCY_MSEC 4</tt></blockquote>
|
||||
|
||||
<h2>
|
||||
<a NAME="unix"></a>Unix</h2>
|
||||
PortAudio under Unix currently uses a backgroud thread that reads and writes
|
||||
to OSS. This gives you decent but not great latency. But if you raise the
|
||||
priority of the background thread to a very priority then you can get under
|
||||
10 milliseconds latency. In order to raise your priority you must run the
|
||||
PortAudio program as root! You must also set PA_MIN_LATENCY_MSEC using
|
||||
the appropriate command for your shell.
|
||||
<h2>
|
||||
<a NAME="windows"></a>Windows</h2>
|
||||
Latency under Windows is a complex issue because of all the alternative
|
||||
operating system versions and device drivers. I have seen latency range
|
||||
from 8 milliseconds to 400 milliseconds. The worst case is when using Windows
|
||||
NT. Windows 98 is a little better, and Windows XP can be quite good if
|
||||
properly tuned.
|
||||
<p>The underlying audio API also makes a lot of difference. If the audio
|
||||
device has its own DirectSound driver then DirectSound can often provide
|
||||
better latency than WMME. But if a real DirectSound driver is not available
|
||||
for your device then it is emulated using WMME and the latency can be very
|
||||
high. That's where I saw the 400 millisecond latency. The ASIO implementation
|
||||
is generally very good and will give the lowest latency if available.
|
||||
<p>You can set the PA_MIN_LATENCY_MSEC variable to 50, for example, by
|
||||
entering in MS-DOS:
|
||||
<blockquote><tt>set PA_MIN_LATENCY_MSEC=50</tt></blockquote>
|
||||
If you enter this in a DOS window then you must run the PortAudio program
|
||||
from that same window for the variable to have an effect. You can add that
|
||||
line to your C:\AUTOEXEC.BAT file and reboot if you want it to affect any
|
||||
PortAudio based program.
|
||||
<p>For Windows XP, you can set environment variables as follows:
|
||||
<ol>
|
||||
<li>
|
||||
Select "Control Panel" from the "Start Menu".</li>
|
||||
|
||||
<li>
|
||||
Launch the "System" Control Panel</li>
|
||||
|
||||
<li>
|
||||
Click on the "Advanced" tab.</li>
|
||||
|
||||
<li>
|
||||
Click on the "Environment Variables" button.</li>
|
||||
|
||||
<li>
|
||||
Click "New" button under User Variables.</li>
|
||||
|
||||
<li>
|
||||
Enter PA_MIN_LATENCY_MSEC for the name and some optimistic number for the
|
||||
value.</li>
|
||||
|
||||
<li>
|
||||
Click OK, OK, OK.</li>
|
||||
</ol>
|
||||
|
||||
<h3>
|
||||
Improving Latency on Windows</h3>
|
||||
There are several steps you can take to improve latency under windows.
|
||||
<ol>
|
||||
<li>
|
||||
Avoid reading or writng to disk when doing audio.</li>
|
||||
|
||||
<li>
|
||||
Turn off all automated background tasks such as email clients, virus scanners,
|
||||
backup programs, FTP servers, web servers, etc. when doing audio.</li>
|
||||
|
||||
<li>
|
||||
Disconnect from the network to prevent network traffic from interrupting
|
||||
your CPU.</li>
|
||||
</ol>
|
||||
<b>Important: </b>Windows XP users can also tune the OS to favor background
|
||||
tasks, such as audio, over foreground tasks, such as word processing. I
|
||||
lowered my latency from 40 to 10 milliseconds using this simple technique.
|
||||
<ol>
|
||||
<li>
|
||||
Select "Control Panel" from the "Start Menu".</li>
|
||||
|
||||
<li>
|
||||
Launch the "System" Control Panel</li>
|
||||
|
||||
<li>
|
||||
Click on the "Advanced" tab.</li>
|
||||
|
||||
<li>
|
||||
Click on the "Settings" button in the Performance area.</li>
|
||||
|
||||
<li>
|
||||
Click on the "Advanced" tab.</li>
|
||||
|
||||
<li>
|
||||
Select "Background services" in the Processor Scheduling area.</li>
|
||||
|
||||
<li>
|
||||
Click OK, OK.</li>
|
||||
</ol>
|
||||
Please let us know if you have others sugestions for lowering latency.
|
||||
<br>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Internal docs. How a stream is started or stopped.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Implementation - Start/Stop</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
<a href="http://www.portaudio.com">PortAudio</a> Implementation Guide</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<p>This document describes how to implement the PortAudio API on a new
|
||||
computer platform. Implementing PortAudio on a new platform, makes it possible
|
||||
to port many existing audio applications to that platform.
|
||||
<p>By Phil Burk
|
||||
<br>Copyright 2000 Phil Burk and Ross Bencina
|
||||
<p>Note that the license says: <b>"Any person wishing to distribute modifications
|
||||
to the Software is requested to send the modifications to the original
|
||||
developer so that they can be incorporated into the canonical version."</b>.
|
||||
So when you have finished a new implementation, please send it back to
|
||||
us at "<a href="http://www.portaudio.com">http://www.portaudio.com</a>"
|
||||
so that we can make it available for other users. Thank you!
|
||||
<h2>
|
||||
Download the Latest PortAudio Implementation</h2>
|
||||
Always start with the latest implementation available at "<a href="http://www.portaudio.com">http://www.portaudio.com</a>".
|
||||
Look for the nightly snapshot under the CVS section.
|
||||
<h2>
|
||||
Select an Existing Implementation as a Basis</h2>
|
||||
The fastest way to get started is to take an existing implementation and
|
||||
translate it for your new platform. Choose an implementation whose architecture
|
||||
is as close as possible to your target.
|
||||
<ul>
|
||||
<li>
|
||||
DirectSound Implementation - pa_win_ds - Uses a timer callback for the
|
||||
background "thread". Polls a circular buffer and writes blocks of data
|
||||
to keep it full.</li>
|
||||
|
||||
<li>
|
||||
Windows MME - pa_win_wmme - Spawns an actual Win32 thread. Writes blocks
|
||||
of data to the HW device and waits for events that signal buffer completion.</li>
|
||||
|
||||
<li>
|
||||
Linux OSS - pa_linux - Spawns a real thread that writes to the "/dev/dsp"
|
||||
stream using blocking I/O calls.</li>
|
||||
</ul>
|
||||
When you write a new implementation, you will be using some code that is
|
||||
in common with all implementations. This code is in the folder "pa_common".
|
||||
It provides various functions such as parameter checking, error code to
|
||||
text conversion, sample format conversion, clipping and dithering, etc.
|
||||
<p>The code that you write will go into a separate folder called "pa_{os}_{api}".
|
||||
For example, code specific to the DirectSound interface for Windows goes
|
||||
in "pa_win_ds".
|
||||
<h2>
|
||||
Read Docs and Code</h2>
|
||||
Famialiarize yourself with the system by reading the documentation provided.
|
||||
here is a suggested order:
|
||||
<ol>
|
||||
<li>
|
||||
User Programming <a href="pa_tutorial.html">Tutorial</a></li>
|
||||
|
||||
<li>
|
||||
Header file "pa_common/portaudio.h" which defines API.</li>
|
||||
|
||||
<li>
|
||||
Header file "pa_common/pa_host.h" for host dependant code. This definces
|
||||
the routine you will need to provide.</li>
|
||||
|
||||
<li>
|
||||
Shared code in "pa_common/pa_lib.c".</li>
|
||||
|
||||
<li>
|
||||
Docs on Implementation of <a href="pa_impl_startstop.html">Start/Stop</a>
|
||||
code.</li>
|
||||
</ol>
|
||||
|
||||
<h2>
|
||||
Implement Output to Default Device</h2>
|
||||
Now we are ready to crank some code. For instant gratification, let's try
|
||||
to play a sine wave.
|
||||
<ol>
|
||||
<li>
|
||||
Link the test program "pa_tests/patest_sine.c" with the file "pa_lib.c"
|
||||
and the implementation specific file you are creating.</li>
|
||||
|
||||
<li>
|
||||
For now, just stub out the device query code and the audio input code.</li>
|
||||
|
||||
<li>
|
||||
Modify PaHost_OpenStream() to open your default target device and get everything
|
||||
setup.</li>
|
||||
|
||||
<li>
|
||||
Modify PaHost_StartOutput() to start playing audio.</li>
|
||||
|
||||
<li>
|
||||
Modify PaHost_StopOutput() to stop audio.</li>
|
||||
|
||||
<li>
|
||||
Modify PaHost_CloseStream() to clean up. Free all memory that you allocated
|
||||
in PaHost_OpenStream().</li>
|
||||
|
||||
<li>
|
||||
Keep cranking until you can play a sine wave using "patest_sine.c".</li>
|
||||
|
||||
<li>
|
||||
Once that works, try "patest_pink.c", "patest_clip.c", "patest_sine8.c".</li>
|
||||
|
||||
<li>
|
||||
To test your Open and Close code, try "patest_many.c".</li>
|
||||
|
||||
<li>
|
||||
Now test to make sure that the three modes of stopping are properly supported
|
||||
by running "patest_stop.c".</li>
|
||||
|
||||
<li>
|
||||
Test your implementation of time stamping with "patest_sync.c".</li>
|
||||
</ol>
|
||||
|
||||
<h2>
|
||||
Implement Device Queries</h2>
|
||||
Now that output is working, lets implement the code for querying what devices
|
||||
are available to the user. Run "pa_tests/pa_devs.c". It should print all
|
||||
of the devices available and their characteristics.
|
||||
<h2>
|
||||
Implement Input</h2>
|
||||
Implement audio input and test it with:
|
||||
<ol>
|
||||
<li>
|
||||
patest_record.c - record in half duplex, play back as recorded.</li>
|
||||
|
||||
<li>
|
||||
patest_wire.c - full duplex, copies input to output. Note that some HW
|
||||
may not support full duplex.</li>
|
||||
|
||||
<li>
|
||||
patest_fuzz.c - plug in your guitar and get a feel for why latency is an
|
||||
important issue in computer music.</li>
|
||||
|
||||
<li>
|
||||
paqa_devs.c - try to open every device and use it with every possible format</li>
|
||||
</ol>
|
||||
|
||||
<h2>
|
||||
Debugging Tools</h2>
|
||||
You generally cannot use printf() calls to debug real-time processes because
|
||||
they disturb the timing. Also calling printf() from your background thread
|
||||
or interrupt could crash the machine. So PA includes a tool for capturing
|
||||
events and storing the information while it is running. It then prints
|
||||
the events when Pa_Terminate() is called.
|
||||
<ol>
|
||||
<li>
|
||||
To enable trace mode, change TRACE_REALTIME_EVENTS in "pa_common/pa_trace.h"
|
||||
from a (0) to a (1).</li>
|
||||
|
||||
<li>
|
||||
Link with "pa_common/pa_trace.c".</li>
|
||||
|
||||
<li>
|
||||
Add trace messages to your code by calling:</li>
|
||||
|
||||
<br><tt> void AddTraceMessage( char *msg, int data );</tt>
|
||||
<br><tt>for example</tt>
|
||||
<br><tt> AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ",
|
||||
past->past_NumCallbacks );</tt>
|
||||
<li>
|
||||
Run your program. You will get a dump of events at the end.</li>
|
||||
|
||||
<li>
|
||||
You can leave the trace messages in your code. They will turn to NOOPs
|
||||
when you change TRACE_REALTIME_EVENTS back to (0).</li>
|
||||
</ol>
|
||||
|
||||
<h2>
|
||||
Delivery</h2>
|
||||
Please send your new code along with notes on the implementation back to
|
||||
us at "<a href="http://www.portaudio.com">http://www.portaudio.com</a>".
|
||||
We will review the implementation and post it with your name. If you had
|
||||
to make any modifications to the code in "pa_common" or "pa_tests" <b>please</b>
|
||||
send us those modifications and your notes. We will try to merge your changes
|
||||
so that the "pa_common" code works with <b>all</b> implementations.
|
||||
<p>If you have suggestions for how to make future implementations easier,
|
||||
please let us know.
|
||||
<br>THANKS!
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,190 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.75 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Internal docs. How a stream is started or stopped.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Implementation - Start/Stop</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Implementation</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Starting and Stopping Streams</h2>
|
||||
PortAudio is generally executed in two "threads". The foreground thread
|
||||
is the application thread. The background "thread" may be implemented as
|
||||
an actual thread, an interrupt handler, or a callback from a timer thread.
|
||||
<p>There are three ways that PortAudio can stop a stream. In each case
|
||||
we look at the sequence of events and the messages sent between the two
|
||||
threads. The following variables are contained in the internalPortAudioStream.
|
||||
<blockquote><tt>int past_IsActive;
|
||||
/* Background is still playing. */</tt>
|
||||
<br><tt>int past_StopSoon; /* Stop
|
||||
when last buffer done. */</tt>
|
||||
<br><tt>int past_StopNow; /*
|
||||
Stop IMMEDIATELY. */</tt></blockquote>
|
||||
|
||||
<h3>
|
||||
Pa_AbortStream()</h3>
|
||||
This function causes the background thread to terminate as soon as possible
|
||||
and audio I/O to stop abruptly.
|
||||
<br>
|
||||
<table BORDER COLS=2 WIDTH="60%" >
|
||||
<tr>
|
||||
<td><b>Foreground Thread</b></td>
|
||||
|
||||
<td><b>Background Thread</b></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>sets <tt>StopNow</tt></td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
<td>sees <tt>StopNow</tt>, </td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
<td>clears IsActive, stops thread</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>waits for thread to exit</td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>turns off audio I/O</td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>
|
||||
Pa_StopStream()</h3>
|
||||
This function stops the user callback function from being called and then
|
||||
waits for all audio data written to the output buffer to be played. In
|
||||
a system with very low latency, you may not hear any difference between
|
||||
<br>
|
||||
<table BORDER COLS=2 WIDTH="60%" >
|
||||
<tr>
|
||||
<td><b>Foreground Thread</b></td>
|
||||
|
||||
<td><b>Background Thread</b></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>sets StopSoon</td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
<td>stops calling user callback</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
<td>continues until output buffer empty</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
<td>clears IsActive, stops thread</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>waits for thread to exit</td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>turns off audio I/O</td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>
|
||||
User callback returns one.</h3>
|
||||
If the user callback returns one then the user callback function will no
|
||||
longer be called. Audio output will continue until all audio data written
|
||||
to the output buffer has been played. Then the audio I/O is stopped, the
|
||||
background thread terminates, and the stream becomes inactive.
|
||||
<br>
|
||||
<table BORDER COLS=2 WIDTH="60%" >
|
||||
<tr>
|
||||
<td><b>Foreground Thread</b></td>
|
||||
|
||||
<td><b>Background Thread</b></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
<td>callback returns 1</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
<td>sets StopSoon</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
<td>stops calling user callback</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
<td>continues until output buffer empty</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
|
||||
<td>clears IsActive, stops thread</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>waits for thread to exit</td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>turns off audio I/O</td>
|
||||
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Compiling for ASIO (Windows or Macintosh)</h2>
|
||||
|
||||
<blockquote>ASIO is a low latency audio API from Steinberg. To compile
|
||||
an ASIO application, you must first <a href="http://www.steinberg.net/developers/ASIO2SDKAbout.phtml">download
|
||||
the ASIO SDK</a> from Steinberg. You also need to obtain ASIO drivers for
|
||||
your audio device.
|
||||
<p>Note: I am using '/' as a file separator below. On Macintosh replace
|
||||
'/' with ':'. On Windows, replace '/' with '\'.
|
||||
<p> To use ASIO with the PortAudio library add the following source
|
||||
files to your project:
|
||||
<blockquote>
|
||||
<pre>pa_asio/pa_asio.cpp</pre>
|
||||
</blockquote>
|
||||
and also these files from the ASIO SDK:
|
||||
<blockquote>
|
||||
<pre>common/asio.cpp
|
||||
host/asiodrivers.cpp
|
||||
host/asiolist.cpp</pre>
|
||||
</blockquote>
|
||||
and add these directories to the path for include files
|
||||
<blockquote>
|
||||
<pre>asiosdk2/host/pc (for Windows)
|
||||
asiosdk2/common
|
||||
asiosdk2/host</pre>
|
||||
</blockquote>
|
||||
You may try compiling the "pa_tests/patest_saw.c" file first because it
|
||||
is the simplest.</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> |
|
||||
<a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_over.html">previous</a> | <a href="pa_tut_callback.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Writing a Callback Function</h2>
|
||||
|
||||
<blockquote>To write a program using PortAudio, you must include the "portaudio.h"
|
||||
include file. You may wish to read "<a href="portaudio_h.txt">portaudio.h</a>"
|
||||
because it contains a complete description of the PortAudio functions and
|
||||
constants.
|
||||
<blockquote>
|
||||
<pre>#include "portaudio.h"</pre>
|
||||
</blockquote>
|
||||
The next task is to write your custom callback function. It is a function
|
||||
that is called by the PortAudio engine whenever it has captured audio data,
|
||||
or when it needs more audio data for output.
|
||||
<p>Your callback function is often called by an interrupt, or low level
|
||||
process so you should not do any complex system activities like allocating
|
||||
memory, or reading or writing files, or printf(). Just crunch numbers and
|
||||
generate audio signals. What is safe or not safe will vary from platform
|
||||
to platform. On the Macintosh, for example, you can only call "interrupt
|
||||
safe" routines. Also do not call any PortAudio functions in the callback
|
||||
except for Pa_StreamTime() and Pa_GetCPULoad().
|
||||
<p>Your callback function must return an int and accept the exact parameters
|
||||
specified in this typedef:
|
||||
<blockquote>
|
||||
<pre>typedef int (PortAudioCallback)(
|
||||
void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData );</pre>
|
||||
</blockquote>
|
||||
Here is an example callback function from the test file "patests/patest_saw.c".
|
||||
It calculates a simple left and right sawtooth signal and writes it to
|
||||
the output buffer. Notice that in this example, the signals are of <tt>float</tt>
|
||||
data type. The signals must be between -1.0 and +1.0. You can also use
|
||||
16 bit integers or other formats which are specified during setup. You
|
||||
can pass a pointer to your data structure through PortAudio which will
|
||||
appear as <tt>userData</tt>.
|
||||
<blockquote>
|
||||
<pre>int patestCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
unsigned int i;
|
||||
/* Cast data passed through stream to our structure type. */
|
||||
paTestData *data = (paTestData*)userData;
|
||||
float *out = (float*)outputBuffer;
|
||||
|
||||
for( i=0; i<framesPerBuffer; i++ )
|
||||
{
|
||||
/* Stereo channels are interleaved. */
|
||||
*out++ = data->left_phase; /* left */
|
||||
*out++ = data->right_phase; /* right */
|
||||
|
||||
/* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
|
||||
data->left_phase += 0.01f;
|
||||
/* When signal reaches top, drop back down. */
|
||||
if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
|
||||
|
||||
/* higher pitch so we can distinguish left and right. */
|
||||
data->right_phase += 0.03f;
|
||||
if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
|
||||
}
|
||||
return 0;
|
||||
}</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> |
|
||||
<a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_over.html">previous</a> | <a href="pa_tut_init.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.75 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Querying for Available Devices</h2>
|
||||
|
||||
<blockquote>There are often several different audio devices available in
|
||||
a computer with different capabilities. They can differ in the sample rates
|
||||
supported, bit widths, etc. PortAudio provides a simple way to query for
|
||||
the available devices, and then pass the selected device to Pa_OpenStream().
|
||||
For an example, see the file "pa_tests/pa_devs.c".
|
||||
<p>To determine the number of devices:
|
||||
<blockquote>
|
||||
<pre>numDevices = Pa_CountDevices();</pre>
|
||||
</blockquote>
|
||||
You can then query each device in turn by calling Pa_GetDeviceInfo() with
|
||||
an index.
|
||||
<blockquote>
|
||||
<pre>for( i=0; i<numDevices; i++ ) {
|
||||
pdi = Pa_GetDeviceInfo( i );</pre>
|
||||
</blockquote>
|
||||
It will return a pointer to a <tt>PaDeviceInfo</tt> structure which is
|
||||
defined as:
|
||||
<blockquote>
|
||||
<pre>typedef struct{
|
||||
int structVersion;
|
||||
const char *name;
|
||||
int maxInputChannels;
|
||||
int maxOutputChannels;
|
||||
/* Number of discrete rates, or -1 if range supported. */
|
||||
int numSampleRates;
|
||||
/* Array of supported sample rates, or {min,max} if range supported. */
|
||||
const double *sampleRates;
|
||||
PaSampleFormat nativeSampleFormat;
|
||||
}PaDeviceInfo;</pre>
|
||||
</blockquote>
|
||||
If the device supports a continuous range of sample rates, then numSampleRates
|
||||
will equal -1, and the sampleRates array will have two values, the minimum
|
||||
and maximum rate.
|
||||
<p>The device information is allocated by Pa_Initialize() and freed by
|
||||
Pa_Terminate() so you do not have to free() the structure returned by Pa_GetDeviceInfo().</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> |
|
||||
<a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_util.html">previous</a> | <a href="pa_tut_rw.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Exploring PortAudio</h2>
|
||||
|
||||
<blockquote>Now that you have a good idea of how PortAudio works, you can
|
||||
try out the test programs.
|
||||
<ul>
|
||||
<li>
|
||||
For an example of playing a sine wave, see "pa_tests/patest_sine.c".</li>
|
||||
|
||||
<li>
|
||||
For an example of recording and playing back a sound, see "pa_tests/patest_record.c".</li>
|
||||
</ul>
|
||||
I also encourage you to examine the source for the PortAudio libraries.
|
||||
If you have suggestions on ways to improve them, please let us know. if
|
||||
you want to implement PortAudio on a new platform, please let us know as
|
||||
well so we can coordinate people's efforts.</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_rw.html">previous</a> | next</font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Initializing PortAudio</h2>
|
||||
|
||||
<blockquote>Before making any other calls to PortAudio, you must call <tt>Pa_Initialize</tt>().
|
||||
This will trigger a scan of available devices which can be queried later.
|
||||
Like most PA functions, it will return a result of type <tt>paError</tt>.
|
||||
If the result is not <tt>paNoError</tt>, then an error has occurred.
|
||||
<blockquote>
|
||||
<pre>err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;</pre>
|
||||
</blockquote>
|
||||
You can get a text message that explains the error message by passing it
|
||||
to
|
||||
<blockquote>
|
||||
<pre>printf( "PortAudio error: %s\n", Pa_GetErrorText( err ) );</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_callback.html">previous</a> | <a href="pa_tut_open.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Compiling for Macintosh</h2>
|
||||
|
||||
<blockquote>To compile a Macintosh application with the PortAudio library,
|
||||
add the following source files to your project:
|
||||
<blockquote>
|
||||
<pre>pa_mac:pa_mac.c
|
||||
pa_common:pa_lib.c
|
||||
pa_common:portaudio.h
|
||||
pa_common:pa_host.h</pre>
|
||||
</blockquote>
|
||||
Also add the Apple <b>SoundLib</b> to your project.
|
||||
<p>You may try compiling the "pa_tests:patest_saw.c" file first because
|
||||
it is the simplest.</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> |
|
||||
<a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_over.html">previous</a> | <a href="pa_tut_callback.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Compiling for Macintosh OS X</h2>
|
||||
|
||||
<blockquote>To compile a Macintosh OS X CoreAudio application with the
|
||||
PortAudio library:
|
||||
<p>Create a new ProjectBuilder project. You can use a "Tool" project to
|
||||
run the PortAudio examples.
|
||||
<p>Add the following source files to your Project:
|
||||
<blockquote>
|
||||
<pre>pa_mac_core/pa_mac_core.c
|
||||
pa_common/pa_lib.c
|
||||
pa_common/portaudio.h
|
||||
pa_common/pa_host.h
|
||||
pa_common/pa_convert.c</pre>
|
||||
</blockquote>
|
||||
Add the Apple CoreAudio.framework to your project by selecting "Add FrameWorks..."
|
||||
from the Project menu.
|
||||
<p>Compile and run the "pa_tests:patest_saw.c" file first because it is
|
||||
the simplest.</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> |
|
||||
<a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_over.html">previous</a> | <a href="pa_tut_callback.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Opening a Stream using Defaults</h2>
|
||||
|
||||
<blockquote>The next step is to open a stream which is similar to opening
|
||||
a file. You can specify whether you want audio input and/or output, how
|
||||
many channels, the data format, sample rate, etc. There are two calls for
|
||||
opening streams, <tt>Pa_OpenStream</tt>() and <tt>Pa_OpenDefaultStream</tt>().
|
||||
<p><tt>Pa_OpenStream()</tt> takes extra parameters which give you
|
||||
more control. You can normally just use <tt>Pa_OpenDefaultStream</tt>()
|
||||
which just calls <tt>Pa_OpenStream()</tt> <tt>with</tt> some reasonable
|
||||
default values. Let's open a stream for stereo output, using floating
|
||||
point data, at 44100 Hz.
|
||||
<blockquote>
|
||||
<pre>err = Pa_OpenDefaultStream(
|
||||
&stream, /* passes back stream pointer */
|
||||
0, /* no input channels */
|
||||
2, /* stereo output */
|
||||
paFloat32, /* 32 bit floating point output */
|
||||
44100, /* sample rate */
|
||||
256, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
patestCallback, /* specify our custom callback */
|
||||
&data ); /* pass our data through to callback */</pre>
|
||||
</blockquote>
|
||||
If you want to use 16 bit integer data, pass <tt>paInt16</tt> instead of
|
||||
<tt>paFloat32</tt>.</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_init.html">previous</a> | <a href="pa_tut_run.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Compiling for Unix OSS</h2>
|
||||
|
||||
<blockquote>[Skip this page if you are not using Unix and OSS]
|
||||
<p>We currently support the <a href="http://www.opensound.com/">OSS</a>
|
||||
audio drivers for Linux, Solaris, and FreeBSD. We hope to someday support
|
||||
the newer ALSA drivers.
|
||||
<ol>
|
||||
<li>
|
||||
cd to pa_unix_oss directory</li>
|
||||
|
||||
<li>
|
||||
Edit the Makefile and uncomment one of the tests. You may try compiling
|
||||
the "patest_sine.c" file first because it is very simple.</li>
|
||||
|
||||
<li>
|
||||
gmake run</li>
|
||||
</ol>
|
||||
</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> |
|
||||
<a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_pc.html">previous</a> | <a href="pa_tut_callback.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Overview of PortAudio</h2>
|
||||
|
||||
<blockquote>PortAudio is a library that provides streaming audio input
|
||||
and output. It is a cross-platform API (Application Programming Interface)
|
||||
that works on Windows, Macintosh, Unix running OSS, SGI, BeOS, and perhaps
|
||||
other platforms by the time you read this. This means that you can write
|
||||
a simple 'C' program to process or generate an audio signal, and that program
|
||||
can run on several different types of computer just by recompiling the
|
||||
source code.
|
||||
<p>Here are the steps to writing a PortAudio application:
|
||||
<ol>
|
||||
<li>
|
||||
Write a callback function that will be called by PortAudio when audio processing
|
||||
is needed.</li>
|
||||
|
||||
<li>
|
||||
Initialize the PA library and open a stream for audio I/O.</li>
|
||||
|
||||
<li>
|
||||
Start the stream. Your callback function will be now be called repeatedly
|
||||
by PA in the background.</li>
|
||||
|
||||
<li>
|
||||
In your callback you can read audio data from the inputBuffer and/or write
|
||||
data to the outputBuffer.</li>
|
||||
|
||||
<li>
|
||||
Stop the stream by returning 1 from your callback, or by calling a stop
|
||||
function.</li>
|
||||
|
||||
<li>
|
||||
Close the stream and terminate the library.</li>
|
||||
</ol>
|
||||
</blockquote>
|
||||
|
||||
<blockquote>There is also <a href="pa_tut_rw.html">another interface</a>
|
||||
provided that allows you to generate audio in the foreground. You then
|
||||
simply write data to the stream and the tool will not return until it is
|
||||
ready to accept more data. This interface is simpler to use but is usually
|
||||
not preferred for large applications because it requires that you launch
|
||||
a thread to perform the synthesis. Launching a thread may be difficult
|
||||
on non-multi-tasking systems such as the Macintosh prior to MacOS X.
|
||||
<p>Let's continue by building a simple application that will play a sawtooth
|
||||
wave.
|
||||
<p>Please select the page for the specific implementation you would like
|
||||
to use:
|
||||
<ul>
|
||||
<li>
|
||||
<a href="pa_tut_pc.html">Windows (WMME or DirectSound)</a></li>
|
||||
|
||||
<li>
|
||||
<a href="pa_tut_mac.html">Macintosh SoundManager for OS 7,8,9</a></li>
|
||||
|
||||
<li>
|
||||
<a href="pa_tut_mac_osx.html">Macintosh CoreAudio for OS X</a></li>
|
||||
|
||||
<li>
|
||||
<a href="pa_tut_asio.html">ASIO on Windows or Macintosh</a></li>
|
||||
|
||||
<li>
|
||||
<a href="pa_tut_oss.html">Unix OSS</a></li>
|
||||
</ul>
|
||||
or continue with the <a href="pa_tut_callback.html">next page of the programming
|
||||
tutorial</a>.</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> |
|
||||
<a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tutorial.html">previous</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Compiling for Windows (WMME or DirectSound)</h2>
|
||||
|
||||
<blockquote>To compile PortAudio for Windows, you can choose between two
|
||||
options. One implementation uses the DirectSound API. The other uses the
|
||||
Windows MultiMedia Extensions API (aka WMME or WAVE).
|
||||
<p>Some advantages of using DirectSound are that DirectSound may have lower
|
||||
latency than WMME, and supports effects processing plugins. But one disadvantage
|
||||
is that DirectSound is not installed on all PCs, and is not well supported
|
||||
under Windows NT. So WMME is the best choice for most projects.
|
||||
<p>For either implementation add the following source files to your project:
|
||||
<blockquote>
|
||||
<pre><b>pa_common\pa_lib.c
|
||||
pa_common\portaudio.h
|
||||
pa_common\pa_host.h</b></pre>
|
||||
</blockquote>
|
||||
Link with the system library "<b>winmm.lib</b>". For Visual C++:
|
||||
<ol>
|
||||
<li>
|
||||
select "Settings..." from the "Project" menu,</li>
|
||||
|
||||
<li>
|
||||
select the project name in the tree on the left,</li>
|
||||
|
||||
<li>
|
||||
choose "All Configurations" in the popup menu above the tree,</li>
|
||||
|
||||
<li>
|
||||
select the "Link" tab,</li>
|
||||
|
||||
<li>
|
||||
enter "winmm.lib", without quotes, as the first item in the "Object/library
|
||||
modules:" field.</li>
|
||||
</ol>
|
||||
<b>WMME</b> - To use the WMME implementation, add the following source
|
||||
files to your project:
|
||||
<blockquote><b><tt>pa_win_wmme/pa_win_wmme.c</tt></b></blockquote>
|
||||
<b>DirectSound</b> - If you want to use the DirectSound implementation
|
||||
of PortAudio then you must have a recent copy of the free
|
||||
<a href="http://www.microsoft.com/directx/download.asp">DirectX</a>
|
||||
SDK for Developers from Microsoft installed on your computer. To compile
|
||||
an application add the following source files to your project:
|
||||
<blockquote>
|
||||
<pre><b>pa_win_ds\dsound_wrapper.c
|
||||
pa_win_ds\pa_dsound.c</b></pre>
|
||||
</blockquote>
|
||||
Link with the system library "<b>dsound.lib</b>" using the procedure described
|
||||
above for "winmm.lib".</blockquote>
|
||||
|
||||
<blockquote>You might try compiling the "pa_tests\patest_saw.c" file first
|
||||
because it is the simplest.</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> |
|
||||
<a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_over.html">previous</a> | <a href="pa_tut_callback.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Starting and Stopping a Stream</h2>
|
||||
|
||||
<blockquote>The stream will not start running until you call Pa_StartStream().
|
||||
Then it will start calling your callback function to perform the audio
|
||||
processing.
|
||||
<blockquote>
|
||||
<pre>err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;</pre>
|
||||
</blockquote>
|
||||
At this point, audio is being generated. You can communicate to your callback
|
||||
routine through the data structure you passed in on the open call, or through
|
||||
global variables, or using other interprocess communication techniques.
|
||||
Please be aware that your callback function may be called at interrupt
|
||||
time when your foreground process is least expecting it. So avoid sharing
|
||||
complex data structures that are easily corrupted like double linked lists.
|
||||
<p>In many of the tests we simply sleep for a few seconds so we can hear
|
||||
the sound. This is easy to do with Pa_Sleep() which will sleep for some
|
||||
number of milliseconds. Do not rely on this function for accurate scheduling.
|
||||
it is mostly for writing examples.
|
||||
<blockquote>
|
||||
<pre>/* Sleep for several seconds. */
|
||||
Pa_Sleep(NUM_SECONDS*1000);</pre>
|
||||
</blockquote>
|
||||
When you are through, you can stop the stream from the foreground.
|
||||
<blockquote>
|
||||
<pre>err = Pa_StopStream( stream );
|
||||
if( err != paNoError ) goto error;</pre>
|
||||
</blockquote>
|
||||
You can also stop the stream by returning 1 from your custom callback function.</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_open.html">previous</a> | <a href="pa_tut_term.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Blocking Read/Write Functions</h2>
|
||||
|
||||
<blockquote>[Note: These functions are not part of the official PortAudio
|
||||
API. They are simply built on top of PortAudio as an extra utility. Also
|
||||
note that they are under evaluation and their definition may change.]
|
||||
<p>There are two fundamentally different ways to design an audio API. One
|
||||
is to use callback functions the way we have already shown. The callback
|
||||
function operates under an interrupt or background thread This leaves the
|
||||
foreground application free to do other things while the audio just runs
|
||||
in the background. But this can sometimes be awkward.
|
||||
<p>So we have provided an alternative technique that lets a program generate
|
||||
audio in the foreground and then just write it to the audio stream as if
|
||||
it was a file. If there is not enough room in the audio buffer for more
|
||||
data, then the write function will just block until more room is available.
|
||||
This can make it very easy to write an audio example. To use this tool,
|
||||
you must add the files "pablio/pablio.c" and "pablio/ringbuffer.c" to your
|
||||
project. You must also:
|
||||
<blockquote>
|
||||
<pre>#include "pablio.h"</pre>
|
||||
</blockquote>
|
||||
Here is a short excerpt of a program that opens a stream for input and
|
||||
output. It then reads a block of samples from input, and writes them to
|
||||
output, in a loop. The complete example can be found in "pablio/test_rw.c".
|
||||
<blockquote>
|
||||
<pre> #define SAMPLES_PER_FRAME (2)
|
||||
#define FRAMES_PER_BLOCK (1024)
|
||||
SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK];
|
||||
PaError err;
|
||||
PABLIO_Stream *aStream;
|
||||
|
||||
/* Open simplified blocking I/O layer on top of PortAudio. */
|
||||
err = OpenAudioStream( &rwbl, SAMPLE_RATE, paFloat32,
|
||||
(PABLIO_READ_WRITE | PABLIO_STEREO) );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
/* Process samples in the foreground. */
|
||||
for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ )
|
||||
{
|
||||
/* Read one block of data into sample array from audio input. */
|
||||
ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK );
|
||||
/*
|
||||
** At this point you could process the data in samples array,
|
||||
** and write the result back to the same samples array.
|
||||
*/
|
||||
/* Write that same frame of data to output. */
|
||||
WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK );
|
||||
}
|
||||
|
||||
CloseAudioStream( aStream );</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> |
|
||||
<a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_devs.html">previous</a> | <a href="pa_tut_explore.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Terminating PortAudio</h2>
|
||||
|
||||
<blockquote>You can start and stop a stream as many times as you like.
|
||||
But when you are done using it, you should close it by calling:</blockquote>
|
||||
|
||||
<blockquote>
|
||||
<blockquote>
|
||||
<pre>err = Pa_CloseStream( stream );
|
||||
if( err != paNoError ) goto error;</pre>
|
||||
</blockquote>
|
||||
Then when you are done using PortAudio, you should terminate the whole
|
||||
system by calling:
|
||||
<blockquote>
|
||||
<pre>Pa_Terminate();</pre>
|
||||
</blockquote>
|
||||
That's basically it. You can now write an audio program in 'C' that will
|
||||
run on multiple platforms, for example PCs and Macintosh.
|
||||
<p>In the rest of the tutorial we will look at some additional utility
|
||||
functions, and a different way of using PortAudio that does not require
|
||||
the use of a callback function.</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
|
||||
| <a href="pa_tut_run.html">previous</a> | <a href="pa_tut_util.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.75 [en]C-gatewaynet (Win98; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<h2>
|
||||
Utility Functions</h2>
|
||||
|
||||
<blockquote>Here are several more functions that are not critical, but
|
||||
may be handy when using PortAudio.
|
||||
<p>Pa_StreamActive() returns one when the stream in playing audio, zero
|
||||
when not playing, or a negative error number if the stream is invalid.
|
||||
The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
|
||||
but may also become inactive if the callback returns a non-zero value.
|
||||
In the latter case, the stream is considered inactive after the last buffer
|
||||
has finished playing.
|
||||
<blockquote>
|
||||
<pre>PaError Pa_StreamActive( PortAudioStream *stream );</pre>
|
||||
</blockquote>
|
||||
Pa_StreamTime() returns the number of samples that have been generated.
|
||||
PaTimeStamp is a double precision number which is a convenient way to pass
|
||||
big numbers around even though we only need integers.
|
||||
<blockquote>
|
||||
<pre>PaTimestamp Pa_StreamTime( PortAudioStream *stream );</pre>
|
||||
</blockquote>
|
||||
The "CPU Load" is a fraction of total CPU time consumed by the stream's
|
||||
audio processing. A value of 0.5 would imply that PortAudio and the sound
|
||||
generating callback was consuming roughly 50% of the available CPU time.
|
||||
This function may be called from the callback function or the application.
|
||||
<blockquote>
|
||||
<pre>double Pa_GetCPULoad( PortAudioStream* stream );</pre>
|
||||
</blockquote>
|
||||
</blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> |
|
||||
<a href="pa_tutorial.html">contents</a> | <a href="pa_tut_term.html">previous</a>
|
||||
| <a href="pa_tut_devs.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Tutorial</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio Tutorial</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<p>Copyright 2000 Phil Burk and Ross Bencina
|
||||
<h2>
|
||||
Table of Contents</h2>
|
||||
|
||||
<blockquote><a href="pa_tut_over.html">Overview of PortAudio</a>
|
||||
<br><a href="pa_tut_mac.html">Compiling for Macintosh OS 7,8,9</a>
|
||||
<br><a href="pa_tut_mac_osx.html">Compiling for Macintosh OS X</a>
|
||||
<br><a href="pa_tut_pc.html">Compiling for Windows (DirectSound and WMME)</a>
|
||||
<br><a href="pa_tut_asio.html">Compiling for ASIO on Windows or Mac OS
|
||||
8,9</a>
|
||||
<br><a href="pa_tut_oss.html">Compiling for Unix OSS</a>
|
||||
<br><a href="pa_tut_callback.html">Writing a Callback Function</a>
|
||||
<br><a href="pa_tut_init.html">Initializing PortAudio</a>
|
||||
<br><a href="pa_tut_open.html">Opening a Stream using Defaults</a>
|
||||
<br><a href="pa_tut_run.html">Starting and Stopping a Stream</a>
|
||||
<br><a href="pa_tut_term.html">Cleaning Up</a>
|
||||
<br><a href="pa_tut_util.html">Utilities</a>
|
||||
<br><a href="pa_tut_devs.html">Querying for Devices</a>
|
||||
<br><a href="pa_tut_rw.html">Blocking Read/Write Functions</a>
|
||||
<br><a href="pa_tut_explore.html">Exploring the PortAudio Package</a></blockquote>
|
||||
<font size=+2><a href="http://www.portaudio.com/">home</a> | contents |
|
||||
previous | <a href="pa_tut_over.html">next</a></font>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -1,425 +0,0 @@
|
|||
#ifndef PORT_AUDIO_H
|
||||
#define PORT_AUDIO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/*
|
||||
* PortAudio Portable Real-Time Audio Library
|
||||
* PortAudio API Header File
|
||||
* Latest version available at: http://www.audiomulch.com/portaudio/
|
||||
*
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
typedef int PaError;
|
||||
typedef enum {
|
||||
paNoError = 0,
|
||||
|
||||
paHostError = -10000,
|
||||
paInvalidChannelCount,
|
||||
paInvalidSampleRate,
|
||||
paInvalidDeviceId,
|
||||
paInvalidFlag,
|
||||
paSampleFormatNotSupported,
|
||||
paBadIODeviceCombination,
|
||||
paInsufficientMemory,
|
||||
paBufferTooBig,
|
||||
paBufferTooSmall,
|
||||
paNullCallback,
|
||||
paBadStreamPtr,
|
||||
paTimedOut,
|
||||
paInternalError
|
||||
} PaErrorNum;
|
||||
|
||||
/*
|
||||
Pa_Initialize() is the library initialisation function - call this before
|
||||
using the library.
|
||||
*/
|
||||
|
||||
PaError Pa_Initialize( void );
|
||||
|
||||
/*
|
||||
Pa_Terminate() is the library termination function - call this after
|
||||
using the library.
|
||||
*/
|
||||
|
||||
PaError Pa_Terminate( void );
|
||||
|
||||
/*
|
||||
Return host specific error.
|
||||
This can be called after receiving a paHostError.
|
||||
*/
|
||||
long Pa_GetHostError( void );
|
||||
|
||||
/*
|
||||
Translate the error number into a human readable message.
|
||||
*/
|
||||
const char *Pa_GetErrorText( PaError errnum );
|
||||
|
||||
/*
|
||||
Sample formats
|
||||
|
||||
These are formats used to pass sound data between the callback and the
|
||||
stream. Each device has a "native" format which may be used when optimum
|
||||
efficiency or control over conversion is required.
|
||||
|
||||
Formats marked "always available" are supported (emulated) by all devices.
|
||||
|
||||
The floating point representation uses +1.0 and -1.0 as the respective
|
||||
maximum and minimum.
|
||||
|
||||
*/
|
||||
|
||||
typedef unsigned long PaSampleFormat;
|
||||
#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
|
||||
#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
|
||||
#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
|
||||
#define paInt24 ((PaSampleFormat) (1<<3))
|
||||
#define paPackedInt24 ((PaSampleFormat) (1<<4))
|
||||
#define paInt8 ((PaSampleFormat) (1<<5))
|
||||
#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */
|
||||
#define paCustomFormat ((PaSampleFormat) (1<<16))
|
||||
|
||||
/*
|
||||
Device enumeration mechanism.
|
||||
|
||||
Device ids range from 0 to Pa_CountDevices()-1.
|
||||
|
||||
Devices may support input, output or both. Device 0 is always the "default"
|
||||
device and should support at least stereo in and out if that is available
|
||||
on the taget platform _even_ if this involves kludging an input/output
|
||||
device on platforms that usually separate input from output. Other platform
|
||||
specific devices are specified by positive device ids.
|
||||
*/
|
||||
|
||||
typedef int PaDeviceID;
|
||||
#define paNoDevice -1
|
||||
|
||||
typedef struct{
|
||||
int structVersion;
|
||||
const char *name;
|
||||
int maxInputChannels;
|
||||
int maxOutputChannels;
|
||||
/* Number of discrete rates, or -1 if range supported. */
|
||||
int numSampleRates;
|
||||
/* Array of supported sample rates, or {min,max} if range supported. */
|
||||
const double *sampleRates;
|
||||
PaSampleFormat nativeSampleFormats;
|
||||
} PaDeviceInfo;
|
||||
|
||||
|
||||
int Pa_CountDevices();
|
||||
/*
|
||||
Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID()
|
||||
|
||||
Return the default device ID or paNoDevice if there is no devices.
|
||||
The result can be passed to Pa_OpenStream().
|
||||
|
||||
On the PC, the user can specify a default device by
|
||||
setting an environment variable. For example, to use device #1.
|
||||
|
||||
set PA_RECOMMENDED_OUTPUT_DEVICE=1
|
||||
|
||||
The user should first determine the available device ID by using
|
||||
the supplied application "pa_devs".
|
||||
*/
|
||||
PaDeviceID Pa_GetDefaultInputDeviceID( void );
|
||||
PaDeviceID Pa_GetDefaultOutputDeviceID( void );
|
||||
|
||||
/*
|
||||
PaTimestamp is used to represent a continuous sample clock with arbitrary
|
||||
start time useful for syncronisation. The type is used in the outTime
|
||||
argument to the callback function and the result of Pa_StreamTime()
|
||||
*/
|
||||
|
||||
typedef double PaTimestamp;
|
||||
|
||||
/*
|
||||
Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
|
||||
referring to the device specified by id.
|
||||
If id is out of range the function returns NULL.
|
||||
|
||||
The returned structure is owned by the PortAudio implementation and must
|
||||
not be manipulated or freed. The pointer is guaranteed to be valid until
|
||||
between calls to Pa_Initialize() and Pa_Terminate().
|
||||
*/
|
||||
|
||||
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID );
|
||||
|
||||
/*
|
||||
PortAudioCallback is implemented by clients of the portable audio api.
|
||||
|
||||
inputBuffer and outputBuffer are arrays of interleaved samples,
|
||||
the format, packing and number of channels used by the buffers are
|
||||
determined by parameters to Pa_OpenStream() (see below).
|
||||
|
||||
framesPerBuffer is the number of sample frames to be processed by the callback.
|
||||
|
||||
outTime is the time in samples when the buffer(s) processed by
|
||||
this callback will begin being played at the audio output.
|
||||
See also Pa_StreamTime()
|
||||
|
||||
userData is the value of a user supplied pointer passed to Pa_OpenStream()
|
||||
intended for storing synthesis data etc.
|
||||
|
||||
return value:
|
||||
The callback can return a nonzero value to stop the stream. This may be
|
||||
useful in applications such as soundfile players where a specific duration
|
||||
of output is required. However, it is not necessary to utilise this mechanism
|
||||
as StopStream() will also terminate the stream. A callback returning a
|
||||
nonzero value must fill the entire outputBuffer.
|
||||
|
||||
NOTE: None of the other stream functions may be called from within the
|
||||
callback function except for Pa_GetCPULoad().
|
||||
|
||||
*/
|
||||
|
||||
typedef int (PortAudioCallback)(
|
||||
void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData );
|
||||
|
||||
|
||||
/*
|
||||
Stream flags
|
||||
|
||||
These flags may be supplied (ored together) in the streamFlags argument to
|
||||
the Pa_OpenStream() function.
|
||||
|
||||
[ suggestions? ]
|
||||
*/
|
||||
|
||||
#define paNoFlag (0)
|
||||
#define paClipOff (1<<0) /* disable defult clipping of out of range samples */
|
||||
#define paDitherOff (1<<1) /* disable default dithering */
|
||||
#define paPlatformSpecificFlags (0x00010000)
|
||||
typedef unsigned long PaStreamFlags;
|
||||
|
||||
/*
|
||||
A single PortAudioStream provides multiple channels of real-time
|
||||
input and output audio streaming to a client application.
|
||||
Pointers to PortAudioStream objects are passed between PortAudio functions.
|
||||
*/
|
||||
|
||||
typedef void PortAudioStream;
|
||||
#define PaStream PortAudioStream
|
||||
|
||||
/*
|
||||
Pa_OpenStream() opens a stream for either input, output or both.
|
||||
|
||||
stream is the address of a PortAudioStream pointer which will receive
|
||||
a pointer to the newly opened stream.
|
||||
|
||||
inputDevice is the id of the device used for input (see PaDeviceID above.)
|
||||
inputDevice may be paNoDevice to indicate that an input device is not required.
|
||||
|
||||
numInputChannels is the number of channels of sound to be delivered to the
|
||||
callback. It can range from 1 to the value of maxInputChannels in the
|
||||
device input record for the device specified in the inputDevice parameter.
|
||||
If inputDevice is paNoDevice numInputChannels is ignored.
|
||||
|
||||
inputSampleFormat is the format of inputBuffer provided to the callback
|
||||
function. inputSampleFormat may be any of the formats described by the
|
||||
PaSampleFormat enumeration (see above). PortAudio guarantees support for
|
||||
the sound devices native formats (nativeSampleFormats in the device info
|
||||
record) and additionally 16 and 32 bit integer and 32 bit floating point
|
||||
formats. Support for other formats is implementation defined.
|
||||
|
||||
inputDriverInfo is a pointer to an optional driver specific data structure
|
||||
containing additional information for device setup or stream processing.
|
||||
inputDriverInfo is never required for correct operation. If not used
|
||||
inputDriverInfo should be NULL.
|
||||
|
||||
outputDevice is the id of the device used for output (see PaDeviceID above.)
|
||||
outputDevice may be paNoDevice to indicate that an output device is not required.
|
||||
|
||||
numOutputChannels is the number of channels of sound to be supplied by the
|
||||
callback. See the definition of numInputChannels above for more details.
|
||||
|
||||
outputSampleFormat is the sample format of the outputBuffer filled by the
|
||||
callback function. See the definition of inputSampleFormat above for more
|
||||
details.
|
||||
|
||||
outputDriverInfo is a pointer to an optional driver specific data structure
|
||||
containing additional information for device setup or stream processing.
|
||||
outputDriverInfo is never required for correct operation. If not used
|
||||
outputDriverInfo should be NULL.
|
||||
|
||||
sampleRate is the desired sampleRate for input and output
|
||||
|
||||
framesPerBuffer is the length in sample frames of all internal sample buffers
|
||||
used for communication with platform specific audio routines. Wherever
|
||||
possible this corresponds to the framesPerBuffer parameter passed to the
|
||||
callback function.
|
||||
|
||||
numberOfBuffers is the number of buffers used for multibuffered
|
||||
communication with the platform specific audio routines. This parameter is
|
||||
provided only as a guide - and does not imply that an implementation must
|
||||
use multibuffered i/o when reliable double buffering is available (such as
|
||||
SndPlayDoubleBuffer() on the Macintosh.)
|
||||
|
||||
streamFlags may contain a combination of flags ORed together.
|
||||
These flags modify the behavior of the
|
||||
streaming process. Some flags may only be relevant to certain buffer formats.
|
||||
|
||||
callback is a pointer to a client supplied function that is responsible
|
||||
for processing and filling input and output buffers (see above for details.)
|
||||
|
||||
userData is a client supplied pointer which is passed to the callback
|
||||
function. It could for example, contain a pointer to instance data necessary
|
||||
for processing the audio buffers.
|
||||
|
||||
return value:
|
||||
Apon success Pa_OpenStream() returns PaNoError and places a pointer to a
|
||||
valid PortAudioStream in the stream argument. The stream is inactive (stopped).
|
||||
If a call to Pa_OpenStream() fails a nonzero error code is returned (see
|
||||
PAError above) and the value of stream is invalid.
|
||||
|
||||
*/
|
||||
|
||||
PaError Pa_OpenStream( PortAudioStream** stream,
|
||||
PaDeviceID inputDevice,
|
||||
int numInputChannels,
|
||||
PaSampleFormat inputSampleFormat,
|
||||
void *inputDriverInfo,
|
||||
PaDeviceID outputDevice,
|
||||
int numOutputChannels,
|
||||
PaSampleFormat outputSampleFormat,
|
||||
void *outputDriverInfo,
|
||||
double sampleRate,
|
||||
unsigned long framesPerBuffer,
|
||||
unsigned long numberOfBuffers,
|
||||
PaStreamFlags streamFlags,
|
||||
PortAudioCallback *callback,
|
||||
void *userData );
|
||||
|
||||
|
||||
/*
|
||||
Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that
|
||||
opens the default input and/or ouput devices. Most parameters have
|
||||
identical meaning to their Pa_OpenStream() counterparts, with the following
|
||||
exceptions:
|
||||
|
||||
If either numInputChannels or numOutputChannels is 0 the respective device
|
||||
is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() )
|
||||
|
||||
sampleFormat applies to both the input and output buffers.
|
||||
*/
|
||||
|
||||
PaError Pa_OpenDefaultStream( PortAudioStream** stream,
|
||||
int numInputChannels,
|
||||
int numOutputChannels,
|
||||
PaSampleFormat sampleFormat,
|
||||
double sampleRate,
|
||||
unsigned long framesPerBuffer,
|
||||
unsigned long numberOfBuffers,
|
||||
PortAudioCallback *callback,
|
||||
void *userData );
|
||||
|
||||
/*
|
||||
Pa_CloseStream() closes an audio stream, flushing any pending buffers.
|
||||
*/
|
||||
|
||||
PaError Pa_CloseStream( PortAudioStream* );
|
||||
|
||||
/*
|
||||
Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
|
||||
Pa_StopStream() waits until all pending audio buffers have been played.
|
||||
Pa_AbortStream() stops playing immediately without waiting for pending
|
||||
buffers to complete.
|
||||
*/
|
||||
|
||||
PaError Pa_StartStream( PortAudioStream *stream );
|
||||
|
||||
PaError Pa_StopStream( PortAudioStream *stream );
|
||||
|
||||
PaError Pa_AbortStream( PortAudioStream *stream );
|
||||
|
||||
/*
|
||||
Pa_StreamActive() returns one when the stream is playing audio,
|
||||
zero when not playing, or a negative error number if the
|
||||
stream is invalid.
|
||||
The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
|
||||
but may also become inactive if the callback returns a non-zero value.
|
||||
In the latter case, the stream is considered inactive after the last
|
||||
buffer has finished playing.
|
||||
*/
|
||||
|
||||
PaError Pa_StreamActive( PortAudioStream *stream );
|
||||
|
||||
/*
|
||||
Pa_StreamTime() returns the current output time for the stream in samples.
|
||||
This time may be used as a time reference (for example syncronising audio to
|
||||
MIDI).
|
||||
*/
|
||||
|
||||
PaTimestamp Pa_StreamTime( PortAudioStream *stream );
|
||||
|
||||
/*
|
||||
The "CPU Load" is a fraction of total CPU time consumed by the
|
||||
stream's audio processing.
|
||||
A value of 0.5 would imply that PortAudio and the sound generating
|
||||
callback was consuming roughly 50% of the available CPU time.
|
||||
This function may be called from the callback function or the application.
|
||||
*/
|
||||
double Pa_GetCPULoad( PortAudioStream* stream );
|
||||
|
||||
/*
|
||||
Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for
|
||||
the current host based on minimum latency.
|
||||
On the PC, for the DirectSound implementation, latency can be optionally set
|
||||
by user by setting an environment variable.
|
||||
For example, to set latency to 200 msec, put:
|
||||
|
||||
set PA_MIN_LATENCY_MSEC=200
|
||||
|
||||
in the AUTOEXEC.BAT file and reboot.
|
||||
If the environment variable is not set, then the latency will be determined
|
||||
based on the OS. Windows NT has higher latency than Win95.
|
||||
*/
|
||||
|
||||
int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
|
||||
|
||||
/*
|
||||
Sleep for at least 'msec' milliseconds.
|
||||
You may sleep longer than the requested time so don't rely
|
||||
on this for accurate musical timing.
|
||||
*/
|
||||
void Pa_Sleep( long msec );
|
||||
|
||||
/*
|
||||
Return size in bytes of a single sample in a given PaSampleFormat
|
||||
or paSampleFormatNotSupported.
|
||||
*/
|
||||
PaError Pa_GetSampleSize( PaSampleFormat format );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* PORT_AUDIO_H */
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,339 +0,0 @@
|
|||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
|
||||
<meta name="Author" content="Phil Burk">
|
||||
<meta name="Description" content="PortAudio is a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
|
||||
<meta name="KeyWords" content="audio, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
|
||||
<title>PortAudio Release Notes</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
|
||||
<tr>
|
||||
<td>
|
||||
<center>
|
||||
<h1>
|
||||
PortAudio - Release Notes</h1></center>
|
||||
</td>
|
||||
</tr>
|
||||
</table></center>
|
||||
|
||||
<p>Link to <a href="http://www.portaudio.com">PortAudio Home Page</a>
|
||||
<h2>
|
||||
<b>V18 - 5/6/02</b></h2>
|
||||
|
||||
<blockquote>All source code and documentation now under <a href="http://www.portaudio.com/usingcvs.html">CVS</a>.
|
||||
<p>Ran most of the code through <a href="http://astyle.sourceforge.net/">AStyle</a>
|
||||
to cleanup ragged indentation caused by using different editors. Used this
|
||||
command:
|
||||
<br><tt> astyle --style=ansi -c -o --convert-tabs --indent-preprocessor
|
||||
*.c</tt></blockquote>
|
||||
|
||||
<blockquote>Added "pa_common/pa_convert.c" for Mac OS X. Start of new conversion
|
||||
utilities.
|
||||
<p><b>ASIO</b>
|
||||
<ul>
|
||||
<li>
|
||||
New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables,</li>
|
||||
|
||||
<li>
|
||||
Cleanup of Pa_ASIO_Callback_Input</li>
|
||||
|
||||
<li>
|
||||
Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo</li>
|
||||
|
||||
<li>
|
||||
Deallocate all resources in PaHost_Term for cases where Pa_CloseStream
|
||||
is not called properly</li>
|
||||
|
||||
<li>
|
||||
New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows.
|
||||
Allows use by multiple threads.</li>
|
||||
|
||||
<li>
|
||||
Correct error code management in PaHost_Term, removed various compiler
|
||||
warning</li>
|
||||
|
||||
<li>
|
||||
Add Mac includes for <Devices.h> and <Timer.h></li>
|
||||
|
||||
<li>
|
||||
Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better
|
||||
error handling</li>
|
||||
</ul>
|
||||
<b>Mac OS X</b>
|
||||
<ul>
|
||||
<li>
|
||||
Major cleanup and improvements.</li>
|
||||
|
||||
<li>
|
||||
Fixed device queries for numChannels and sampleRates,</li>
|
||||
|
||||
<li>
|
||||
Audio input works if using same CoreAudio device (some HW devices make
|
||||
separate CoreAudio devices).</li>
|
||||
|
||||
<li>
|
||||
Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file.</li>
|
||||
|
||||
<li>
|
||||
Return error if opened in mono mode cuz not supported.</li>
|
||||
|
||||
<li>
|
||||
Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally.</li>
|
||||
|
||||
<li>
|
||||
Use getrusage() instead of gettimeofday() for CPU Load calculation.</li>
|
||||
</ul>
|
||||
<b>Windows MME</b>
|
||||
<ul>
|
||||
<li>
|
||||
Fixed bug that caused TIMEOUT in Pa_StopStream(). Added check for past_StopSoon()
|
||||
in Pa_TimeSlice(). Thanks Julien Maillard.</li>
|
||||
|
||||
<li>
|
||||
Detect Win XP versus NT, use lower latency.</li>
|
||||
|
||||
<li>
|
||||
Fix DBUG typo;</li>
|
||||
|
||||
<li>
|
||||
removed init of CurrentCount which was not compiling on Borland</li>
|
||||
|
||||
<li>
|
||||
general cleanup, factored streamData alloc and cpu usage initialization</li>
|
||||
|
||||
<li>
|
||||
stopped counting WAVE_MAPPER when there were no audio cards plugged in</li>
|
||||
</ul>
|
||||
<b>Windows DirectSound</b>
|
||||
<ul>
|
||||
<li>
|
||||
Detect Win XP and Win 2K properly when determining latency.</li>
|
||||
</ul>
|
||||
<b>Unix OSS</b>
|
||||
<ul>
|
||||
<li>
|
||||
Use high real-time priority if app is running with root priveledges. Lowers
|
||||
latency.</li>
|
||||
|
||||
<li>
|
||||
Added watch dog thread that prevents real-time thread from hogging CPU
|
||||
and hanging the computer.</li>
|
||||
|
||||
<li>
|
||||
Check error return from read() and write().</li>
|
||||
|
||||
<li>
|
||||
Check CPU endianness instead of assuming Little Endian.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<h2>
|
||||
<b>V17 - 10/15/01</b></h2>
|
||||
|
||||
<blockquote><b>Unix OSS</b>
|
||||
<ul>
|
||||
<li>
|
||||
Set num channels back to two after device query for ALSA. This fixed a
|
||||
bug in V16 that sometimes caused a failure when querying for the sample
|
||||
rates. Thanks Stweart Greenhill.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<blockquote>
|
||||
<h4>
|
||||
<b>Macintosh Sound Manager</b></h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Use NewSndCallBackUPP() for CARBON compatibility.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<h2>
|
||||
<b>V16 - 9/27/01</b></h2>
|
||||
|
||||
<blockquote><b>Added Alpha implementations for ASIO, SGI, and BeOS!</b>
|
||||
<br>
|
||||
<li>
|
||||
CPULoad is now calculated based on the time spent to generate a known number
|
||||
of frames. This is more accurate than a simple percentage of real-time.
|
||||
Implemented in pa_unix_oss, pa_win_wmme and pa_win_ds.</li>
|
||||
|
||||
<li>
|
||||
Fix dither and shift for recording PaUInt8 format data.</li>
|
||||
|
||||
<li>
|
||||
Added "patest_maxsines.c" which tests <tt>Pa_GetCPULoad().</tt></li>
|
||||
</blockquote>
|
||||
|
||||
<blockquote>
|
||||
<h4>
|
||||
Windows WMME</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
sDevicePtrs now allocated using <tt>GlobalAlloc()</tt>. This prevents a
|
||||
crash in Pa_Terminate() on Win2000. Thanks Mike Berry for finding this.
|
||||
Thanks Mike Berry.</li>
|
||||
|
||||
<li>
|
||||
Pass process instead of thread to <tt>SetPriorityClass</tt>(). This fixes
|
||||
a bug that caused the priority to not be increased. Thanks to Alberto di
|
||||
Bene for spotting this.</li>
|
||||
</ul>
|
||||
|
||||
<h4>
|
||||
Windows DirectSound</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Casts for compiling with __MWERKS__ CodeWarrior.</li>
|
||||
</ul>
|
||||
|
||||
<h4>
|
||||
UNIX OSS</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Derived from Linux OSS implementation.</li>
|
||||
|
||||
<li>
|
||||
Numerous patches from Heiko Purnhagen, Stephen Brandon, etc.</li>
|
||||
|
||||
<li>
|
||||
Improved query mechanism which often bailed out unnecessarily.</li>
|
||||
|
||||
<li>
|
||||
Removed sNumDevices and potential related bugs,</li>
|
||||
|
||||
<li>
|
||||
Use <tt>getenv("PA_MIN_LATENCY_MSEC")</tt> in code to set desired latency.
|
||||
User can set by entering:</li>
|
||||
|
||||
<br> <tt>export PA_MIN_LATENCY_MSEC=40</tt></ul>
|
||||
|
||||
<h4>
|
||||
Macintosh Sound Manager</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
Pass unused event to WaitNextEvent instead of NULL to prevent Mac OSX crash.
|
||||
Thanks Dominic Mazzoni.</li>
|
||||
|
||||
<li>
|
||||
Use requested number of input channels.</li>
|
||||
|
||||
<br> </ul>
|
||||
</blockquote>
|
||||
|
||||
<h2>
|
||||
<b>V15 - 5/29/01</b></h2>
|
||||
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li>
|
||||
<b>New Linux OSS Beta</b></li>
|
||||
</ul>
|
||||
|
||||
<h4>
|
||||
Windows WMME</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
sDevicePtrs now allocated based on sizeof(pointer). Was allocating
|
||||
too much space.</li>
|
||||
|
||||
<li>
|
||||
Check for excessive numbers of channels. Some drivers reported bogus
|
||||
numbers.</li>
|
||||
|
||||
<li>
|
||||
Apply Mike Berry's changes for CodeWarrior on PC including condition including
|
||||
of memory.h, and explicit typecasting on memory allocation.</li>
|
||||
</ul>
|
||||
|
||||
<h4>
|
||||
Macintosh Sound Manager</h4>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID.</li>
|
||||
|
||||
<li>
|
||||
Device Scan was crashing for anything other than siBadSoundInDevice, but
|
||||
some Macs may return other errors! Caused failure to init on some G4s under
|
||||
OS9.</li>
|
||||
|
||||
<li>
|
||||
Fix TIMEOUT in record mode.</li>
|
||||
|
||||
<li>
|
||||
Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<h2>
|
||||
<b>V14 - 2/6/01</b></h2>
|
||||
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li>
|
||||
Added implementation for Windows MultiMedia Extensions (WMME) by Ross and
|
||||
Phil</li>
|
||||
|
||||
<li>
|
||||
Changed Pa_StopStream() so that it waits for the buffers to drain.</li>
|
||||
|
||||
<li>
|
||||
Added Pa_AbortStream() that stops immediately without waiting.</li>
|
||||
|
||||
<li>
|
||||
Added new test: patest_stop.c to test above two mods.</li>
|
||||
|
||||
<li>
|
||||
Fixed Pa_StreamTime() so that it returns current play position instead
|
||||
of the write position. Added "patest_sync.c" to demo audio/video sync.</li>
|
||||
|
||||
<li>
|
||||
Improved stability of Macintosh implementation. Added timeouts to prevent
|
||||
hangs.</li>
|
||||
|
||||
<li>
|
||||
Added Pa_GetSampleSize( PaSampleFormat format );</li>
|
||||
|
||||
<li>
|
||||
Changes some "int"s to "long"s so that PA works properly on Macintosh which
|
||||
often compiles using 16 bit ints.</li>
|
||||
|
||||
<li>
|
||||
Added Implementation Guide</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<h2>
|
||||
<b>V12 - 1/9/01</b></h2>
|
||||
|
||||
<blockquote>
|
||||
<ul>
|
||||
<li>
|
||||
Mac now scans for and queries all devices. But it does not yet support
|
||||
selecting any other than the default device.</li>
|
||||
|
||||
<li>
|
||||
Blocking I/O calls renamed to separate them from the PortAudio API.</li>
|
||||
|
||||
<li>
|
||||
Cleaned up indentation problems with tabs versus spaces.</li>
|
||||
|
||||
<li>
|
||||
Now attempts to correct bogus sample rate info returned from DirectSound
|
||||
device queries.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
156
docs/style.html
156
docs/style.html
|
|
@ -1,156 +0,0 @@
|
|||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Coding Style Guidelines for PortAudio Implementors</TITLE>
|
||||
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
|
||||
<META content="Phil Burk, Ross Bencina" name=Author>
|
||||
<META content="coding and design style guide" name=Description>
|
||||
<META
|
||||
content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, synthesis, coding, style"
|
||||
name=KeyWords>
|
||||
</HEAD>
|
||||
<BODY LINK="#0000ff" VLINK="#800080">
|
||||
<CENTER>
|
||||
<TABLE bgColor=#fada7a cols=1 width="100%">
|
||||
<TBODY>
|
||||
<TR>
|
||||
<TD>
|
||||
<CENTER>
|
||||
<H1>Coding Style Guidelines for PortAudio Implementors</H1>
|
||||
</CENTER>
|
||||
</TD></TR></TBODY></TABLE></CENTER>
|
||||
<P><A href="http://www.portaudio.com/">PortAudio Home Page</A></P>
|
||||
|
||||
<P>Updated: June 12, 2002 </P>
|
||||
|
||||
<H2>Introduction</H2>
|
||||
<P>
|
||||
This document provides coding guidelines for PortAudio implementors. Some of the guildelines pertain to mechanical style, others to quality of implementation issues. Since the PortAudio code is commonly edited on many different platforms using different editors these guideline should be followed to improve readability and consistency.
|
||||
</P>
|
||||
|
||||
<H2>PortAudio API Design Guidelines</H2>
|
||||
<P>
|
||||
The design guidelines of the PortAudio project are stated here
|
||||
as some of them apply to implementation as well as to API design.
|
||||
</P>
|
||||
<ul>
|
||||
<li>
|
||||
Implementation should be possible on all common computer
|
||||
music platforms.
|
||||
</li>
|
||||
<li>
|
||||
Clients of PortAudio should be able to gain efficient,
|
||||
and ideally optimal use of the audio services
|
||||
on all target platforms.
|
||||
</li>
|
||||
<li>
|
||||
The API should be simple enough to be used by music
|
||||
students with minimal experience in C programming.
|
||||
</li>
|
||||
<li>
|
||||
The API should seek to provide only low-level audio
|
||||
services, and to only support those services directly
|
||||
available on the host platform.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<P>
|
||||
Note that the final guideline has been bent with regard to audio
|
||||
sample formats and user buffer sizes - PortAudio can convert between
|
||||
a number of sample formats and can adapt to the user's buffer size requirements.
|
||||
</P>
|
||||
|
||||
<H2>Formatting Conventions</H2>
|
||||
|
||||
<P>
|
||||
The following formatting conventions should be adhered to in all PortAudio code:
|
||||
</P>
|
||||
|
||||
<UL>
|
||||
<LI>TABs should not be used in .c and .h files; instead 4 spaces should be used. Makefiles should continue to use TABs since this is required by Make </LI>
|
||||
<LI>Line-emd characters will be consistent with the platform on which the source has been checked out of CVS (CVS handles this.)</LI>
|
||||
<LI>Brace placement will follow ANSI style, eg:
|
||||
<PRE>
|
||||
if( aCondition )
|
||||
{
|
||||
DoSomething();
|
||||
}
|
||||
else
|
||||
{
|
||||
DoSomethingElse();
|
||||
}
|
||||
</PRE>
|
||||
</LI>
|
||||
</UL>
|
||||
|
||||
<P>AStyle ( <A HREF="http://astyle.sourceforge.net/">http://astyle.sourceforge.net/</A> ) has been proposed as helpful tool for cleaning code, however we don't intend to use it on an ongoing basis. It is expected that contributors of each implementation will take responsibility for keeping their code clean.</P>
|
||||
|
||||
|
||||
<H2>Quality of Implementation Guidelines</H2>
|
||||
|
||||
<P>The following coding guidelines should be followed in order to establish a quality baseline for our implementations:</P>
|
||||
|
||||
<UL>
|
||||
<LI>All code should be written in C++-compatible plain ANSI-C (i.e. no // comments). It has been suggested that all implementations should compile silently with both "gcc -ansi -pedantic -Wall" and "g++ -ansi -pedantic -Wall" </LI>
|
||||
<LI>Think of PortAudio as a heavyweight library rather than a lightweight wrapper. Always code defensively. Efficiency is important where it matters (eg in real-time callbacks) but safety is important everywhere. </LI>
|
||||
<LI>All parameters passed to PortAudio by the user should be validated, and error codes returned where necessary. All reasonable efforts should be made to minimise the risk of a crash resulting from passing incorrect parameters to PortAudio. </LI>
|
||||
<LI>Error handling should be complete. Every host function that can return an error condition should have its status checked. PortAudio may attempt to recover from errors in some cases, but generally error codes should be returned to the client. </LI>
|
||||
<LI>In almost all cases, a PortAudio error code should be preferred to returning PaHostError. If a new PortAudio error code is needed it should be discussed with the maintainer to coordinate updating portaudio.h </LI>
|
||||
<LI>PortAudio code should not cause resource leaks. After Pa_Terminate() is called, implementations should guarantee that all dynamically allocated resources have been freed. </LI>
|
||||
<LI>The definition of the PortAudio API should minimise "implementation defined behaviour". For example, calling functions such as Pa_Initialize() after PortAudio is initialised, or Pa_Terminate() after PortAudio has been terminated has well defined behaviour.</LI>
|
||||
<LI>Minimise dependence on ANSI C runtime on platforms where it would have to be loaded separately (eg on Win32 prefer Win32 API functions such as GlobalAlloc() to ANSI C functions such as malloc().) <I></LI></UL>
|
||||
|
||||
</I><P>It has been suggested that we make an effort to minimise the use of global and static data in PortAudio implementations. Another related goal is to reduce name pollution in the global scope. Some possible guidelines in this regard are:</P>
|
||||
|
||||
<UL>
|
||||
<LI>Implementations should avoid exporting any symbols except where absolutely necessary. Specifically, global data must be declared statically. The next section documents naming conventions for all PortAudio symbols.</LI>
|
||||
<LI>Implementations should minimise their use of static data. </LI></UL>
|
||||
|
||||
<H2>Naming Conventions</H2>
|
||||
|
||||
<ul>
|
||||
<li>All #defines begin with PA_</li>
|
||||
<li>All #defines local to a file end with _</li>
|
||||
<li>All global utility variables begin with paUtil</li>
|
||||
<li>All global utility types begin with PaUtil (including function types)</li>
|
||||
<li>All global utility functions begin with PaUtil_</li>
|
||||
<li>All static variables end with _</li>
|
||||
<li>All static constants begin with const and end with _ (eg: constMyMagicNumber_)</li>
|
||||
<li>All static funtions have no special prefix/suffix</li>
|
||||
<li>
|
||||
Platform-specific shared functions should begin with Pa<PN>_ where PN is the
|
||||
platform name. eg. PaWin_ for windows, PaUnix_ for unix.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
In general, implementations should declare all of their members static,
|
||||
except for their initializer which should be exported. All exported names
|
||||
should be preceeded by Pa<MN>_ where <MN> is the module name, for example
|
||||
the windows mme initializer should be named PaWinMme_Initialize().
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If it is necessary for implementations to define non-static symbols, they should
|
||||
use the following naming conventions, where <MN> is the module name such as WinMme.
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>global variables should begin with pa<MN></li>
|
||||
<li>global types should begin with Pa<MN></li>
|
||||
<li>global utility functions should begin with Pa<MN>_</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Two utilities for debug messages are provided. The PA_DEBUG macro defined in
|
||||
pa_implementation.h provides a simple way to print debug messages to stderr.
|
||||
Due to real-time performance issues, PA_DEBUG may not be suitable for use
|
||||
within the portaudio processing callback, or in other threads. In such cases
|
||||
the event tracing facility provided in pa_trace.h may be more appropriate.
|
||||
</p>
|
||||
<p>
|
||||
If PA_LOG_API_CALLS is defined, all calls to the public PortAudio API
|
||||
will be logged to stderr along with parameter and return values.
|
||||
</p>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
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
|
||||
89
index.html
89
index.html
|
|
@ -1,89 +0,0 @@
|
|||
<!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>Last updated 5/6/02.
|
||||
<p>PortAudio is a cross platform, <a href="#License">open-source</a>, audio
|
||||
I/O library proposed by <b>Ross Bencina</b> to the <a href="http://shoko.calarts.edu/~glmrboy/musicdsp/music-dsp.html">music-dsp</a>
|
||||
mailing list. It lets you write simple audio programs in 'C' that will
|
||||
compile and run on <b>Windows, Macintosh, Unix, BeOS</b>. PortAudio is
|
||||
intended to promote the exchange of audio synthesis software between developers
|
||||
on different platforms.
|
||||
<p>For complete information on PortAudio and to download the latest releases,
|
||||
please visit "<b><font size=+2><a href="http://www.portaudio.com">http://www.portaudio.com</a></font></b>".
|
||||
<br>
|
||||
<br>
|
||||
<center>
|
||||
<h2>
|
||||
<b><a href="docs/index.html">Click here for Documentation</a></b></h2></center>
|
||||
|
||||
<h2>
|
||||
<b><font size=+2></font></b></h2>
|
||||
|
||||
<h2>
|
||||
<b><font size=+2>Contacts and E-Mail List</font></b></h2>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
If you are using or implementing PortAudio then please join the <b><font size=+1><a href="http://techweb.rfa.org/mailman/listinfo/portaudio">PortAudio
|
||||
mail list</a></font><font size=+2> </font></b>generously administered by
|
||||
<b>Bill
|
||||
Eldridge</b>.</li>
|
||||
|
||||
<li>
|
||||
If you find bugs in one of these implementations, or have suggestions,
|
||||
please e-mail them to <a href="mailto:philburk@softsynth.com">Phil Burk</a>.</li>
|
||||
|
||||
<li>
|
||||
If you make improvements to the library, please send them to us so we can
|
||||
incorporate the improvements.</li>
|
||||
</ul>
|
||||
|
||||
<h2>
|
||||
<a NAME="License"></a>License</h2>
|
||||
PortAudio Portable Real-Time Audio Library
|
||||
<br>Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
<p>Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following conditions:
|
||||
<ul>
|
||||
<li>
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.</li>
|
||||
|
||||
<li>
|
||||
Any person wishing to distribute modifications to the Software is requested
|
||||
to send the modifications to the original developer so that they can be
|
||||
incorporated into the canonical version.</li>
|
||||
</ul>
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND ON INFRINGEMENT.
|
||||
<br>IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
||||
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
||||
THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
||||
BIN
install-sh
BIN
install-sh
Binary file not shown.
|
|
@ -1,6 +0,0 @@
|
|||
Steinberg's ASIO 2 SDK will compile but crash on
|
||||
initialization if compiled with a Borland compiler.
|
||||
|
||||
The problem is described, and a solution provided on
|
||||
the following page:
|
||||
http://www.audiomulch.com/~rossb/code/calliasio
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,25 +0,0 @@
|
|||
There is a bug in the ASIO SDK that causes the Macintosh version to often fail during initialization. Here is a patch that you can apply.
|
||||
|
||||
In codefragments.cpp replace getFrontProcessDirectory function with
|
||||
the following one (GetFrontProcess replaced by GetCurrentProcess)
|
||||
|
||||
|
||||
bool CodeFragments::getFrontProcessDirectory(void *specs)
|
||||
{
|
||||
FSSpec *fss = (FSSpec *)specs;
|
||||
ProcessInfoRec pif;
|
||||
ProcessSerialNumber psn;
|
||||
|
||||
memset(&psn,0,(long)sizeof(ProcessSerialNumber));
|
||||
// if(GetFrontProcess(&psn) == noErr) // wrong !!!
|
||||
if(GetCurrentProcess(&psn) == noErr) // correct !!!
|
||||
{
|
||||
pif.processName = 0;
|
||||
pif.processAppSpec = fss;
|
||||
pif.processInfoLength = sizeof(ProcessInfoRec);
|
||||
if(GetProcessInformation(&psn, &pif) == noErr)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1,402 +0,0 @@
|
|||
/*
|
||||
* pa_conversions.c
|
||||
* portaudio
|
||||
*
|
||||
* Created by Phil Burk on Mon Mar 18 2002.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "portaudio.h"
|
||||
#include "pa_host.h"
|
||||
|
||||
#define CLIP( val, min, max ) { val = ((val) < (min)) ? min : (((val) < (max)) ? (max) : (val)); }
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Float32_Int16(
|
||||
float *sourceBuffer, int sourceStride,
|
||||
short *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
short samp = (short) (*sourceBuffer * (32767.0f));
|
||||
*targetBuffer = samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Float32_Int16_Clip(
|
||||
float *sourceBuffer, int sourceStride,
|
||||
short *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
long samp = (long) (*sourceBuffer * (32767.0f));
|
||||
CLIP( samp, -0x8000, 0x7FFF );
|
||||
*targetBuffer = (short) samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Float32_Int16_ClipDither(
|
||||
float *sourceBuffer, int sourceStride,
|
||||
short *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
// use smaller scaler to prevent overflow when we add the dither
|
||||
float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
|
||||
float dithered = (*sourceBuffer * (32766.0f)) + dither;
|
||||
long samp = (long) dithered;
|
||||
CLIP( samp, -0x8000, 0x7FFF );
|
||||
*targetBuffer = (short) samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Float32_Int16_Dither(
|
||||
float *sourceBuffer, int sourceStride,
|
||||
short *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
// use smaller scaler to prevent overflow when we add the dither
|
||||
float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
|
||||
float dithered = (*sourceBuffer * (32766.0f)) + dither;
|
||||
*targetBuffer = (short) dithered;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Int16_Float32(
|
||||
short *sourceBuffer, int sourceStride,
|
||||
float *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
float samp = *sourceBuffer * (1.0f / 32768.0f);
|
||||
*targetBuffer = samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Float32_Int8(
|
||||
float *sourceBuffer, int sourceStride,
|
||||
char *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
char samp = (char) (*sourceBuffer * (127.0));
|
||||
*targetBuffer = samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Float32_Int8_Clip(
|
||||
float *sourceBuffer, int sourceStride,
|
||||
char *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
long samp = *sourceBuffer * 127.0f;
|
||||
CLIP( samp, -0x80, 0x7F );
|
||||
*targetBuffer = (char) samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Float32_Int8_ClipDither(
|
||||
float *sourceBuffer, int sourceStride,
|
||||
char *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
// use smaller scaler to prevent overflow when we add the dither
|
||||
float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
|
||||
float dithered = (*sourceBuffer * (126.0f)) + dither;
|
||||
long samp = (long) dithered;
|
||||
CLIP( samp, -0x80, 0x7F );
|
||||
*targetBuffer = (char) samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Float32_Int8_Dither(
|
||||
float *sourceBuffer, int sourceStride,
|
||||
char *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
// use smaller scaler to prevent overflow when we add the dither
|
||||
float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE; //FIXME
|
||||
float dithered = (*sourceBuffer * (126.0f)) + dither;
|
||||
long samp = (long) dithered;
|
||||
*targetBuffer = (char) samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Int8_Float32(
|
||||
char *sourceBuffer, int sourceStride,
|
||||
float *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
float samp = *sourceBuffer * (1.0f / 128.0f);
|
||||
*targetBuffer = samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_Float32_UInt8(
|
||||
float *sourceBuffer, int sourceStride,
|
||||
unsigned char *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
unsigned char samp = 128 + (unsigned char) (*sourceBuffer * (127.0));
|
||||
*targetBuffer = samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
static void PaConvert_UInt8_Float32(
|
||||
unsigned char *sourceBuffer, int sourceStride,
|
||||
float *targetBuffer, int targetStride,
|
||||
int numSamples )
|
||||
{
|
||||
int i;
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
float samp = (*sourceBuffer - 128) * (1.0f / 128.0f);
|
||||
*targetBuffer = samp;
|
||||
sourceBuffer += sourceStride;
|
||||
targetBuffer += targetStride;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
static PortAudioConverter *PaConvert_SelectProc( PaSampleFormat sourceFormat,
|
||||
PaSampleFormat targetFormat, int ifClip, int ifDither )
|
||||
{
|
||||
PortAudioConverter *proc = NULL;
|
||||
switch( sourceFormat )
|
||||
{
|
||||
case paUInt8:
|
||||
switch( targetFormat )
|
||||
{
|
||||
case paFloat32:
|
||||
proc = (PortAudioConverter *) PaConvert_UInt8_Float32;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case paInt8:
|
||||
switch( targetFormat )
|
||||
{
|
||||
case paFloat32:
|
||||
proc = (PortAudioConverter *) PaConvert_Int8_Float32;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case paInt16:
|
||||
switch( targetFormat )
|
||||
{
|
||||
case paFloat32:
|
||||
proc = (PortAudioConverter *) PaConvert_Int16_Float32;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case paFloat32:
|
||||
switch( targetFormat )
|
||||
{
|
||||
case paUInt8:
|
||||
proc = (PortAudioConverter *) PaConvert_Float32_UInt8;
|
||||
break;
|
||||
case paInt8:
|
||||
if( ifClip && ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_ClipDither;
|
||||
else if( ifClip ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_Clip;
|
||||
else if( ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_Dither;
|
||||
else proc = (PortAudioConverter *) PaConvert_Float32_Int8;
|
||||
break;
|
||||
case paInt16:
|
||||
if( ifClip && ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_ClipDither;
|
||||
else if( ifClip ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_Clip;
|
||||
else if( ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_Dither;
|
||||
else proc = (PortAudioConverter *) PaConvert_Float32_Int16;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return proc;
|
||||
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
PaError PaConvert_SetupInput( internalPortAudioStream *past,
|
||||
PaSampleFormat nativeInputSampleFormat )
|
||||
{
|
||||
past->past_NativeInputSampleFormat = nativeInputSampleFormat;
|
||||
past->past_InputConversionSourceStride = 1;
|
||||
past->past_InputConversionTargetStride = 1;
|
||||
|
||||
if( nativeInputSampleFormat != past->past_InputSampleFormat )
|
||||
{
|
||||
int ifDither = (past->past_Flags & paDitherOff) == 0;
|
||||
past->past_InputConversionProc = PaConvert_SelectProc( nativeInputSampleFormat,
|
||||
past->past_InputSampleFormat, 0, ifDither );
|
||||
if( past->past_InputConversionProc == NULL ) return paSampleFormatNotSupported;
|
||||
}
|
||||
else
|
||||
{
|
||||
past->past_InputConversionProc = NULL; /* no conversion necessary */
|
||||
}
|
||||
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
PaError PaConvert_SetupOutput( internalPortAudioStream *past,
|
||||
PaSampleFormat nativeOutputSampleFormat )
|
||||
{
|
||||
|
||||
past->past_NativeOutputSampleFormat = nativeOutputSampleFormat;
|
||||
past->past_OutputConversionSourceStride = 1;
|
||||
past->past_OutputConversionTargetStride = 1;
|
||||
|
||||
if( nativeOutputSampleFormat != past->past_OutputSampleFormat )
|
||||
{
|
||||
int ifDither = (past->past_Flags & paDitherOff) == 0;
|
||||
int ifClip = (past->past_Flags & paClipOff) == 0;
|
||||
|
||||
past->past_OutputConversionProc = PaConvert_SelectProc( past->past_OutputSampleFormat,
|
||||
nativeOutputSampleFormat, ifClip, ifDither );
|
||||
if( past->past_OutputConversionProc == NULL ) return paSampleFormatNotSupported;
|
||||
}
|
||||
else
|
||||
{
|
||||
past->past_OutputConversionProc = NULL; /* no conversion necessary */
|
||||
}
|
||||
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
** Called by host code.
|
||||
** Convert input from native format to user format,
|
||||
** call user code,
|
||||
** then convert output to native format.
|
||||
** Returns result from user callback.
|
||||
*/
|
||||
long PaConvert_Process( internalPortAudioStream *past,
|
||||
void *nativeInputBuffer,
|
||||
void *nativeOutputBuffer )
|
||||
{
|
||||
int userResult;
|
||||
void *inputBuffer = NULL;
|
||||
void *outputBuffer = NULL;
|
||||
|
||||
/* Get native input data. */
|
||||
if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
|
||||
{
|
||||
if( past->past_InputSampleFormat == past->past_NativeInputSampleFormat )
|
||||
{
|
||||
/* Already in native format so just read directly from native buffer. */
|
||||
inputBuffer = nativeInputBuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
inputBuffer = past->past_InputBuffer;
|
||||
/* Convert input data to user format. */
|
||||
(*past->past_InputConversionProc)(nativeInputBuffer, past->past_InputConversionSourceStride,
|
||||
inputBuffer, past->past_InputConversionTargetStride,
|
||||
past->past_FramesPerUserBuffer * past->past_NumInputChannels );
|
||||
}
|
||||
}
|
||||
|
||||
/* Are we doing output? */
|
||||
if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
|
||||
{
|
||||
outputBuffer = (past->past_OutputConversionProc == NULL) ?
|
||||
nativeOutputBuffer : past->past_OutputBuffer;
|
||||
}
|
||||
/*
|
||||
AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
|
||||
AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
|
||||
*/
|
||||
/* Call user callback routine. */
|
||||
userResult = past->past_Callback(
|
||||
inputBuffer,
|
||||
outputBuffer,
|
||||
past->past_FramesPerUserBuffer,
|
||||
past->past_FrameCount,
|
||||
past->past_UserData );
|
||||
|
||||
/* Advance frame counter for timestamp. */
|
||||
past->past_FrameCount += past->past_FramesPerUserBuffer; // FIXME - should this be in here?
|
||||
|
||||
/* Convert to native format if necessary. */
|
||||
if( (past->past_OutputConversionProc != NULL ) && (outputBuffer != NULL) )
|
||||
{
|
||||
(*past->past_OutputConversionProc)( outputBuffer, past->past_OutputConversionSourceStride,
|
||||
nativeOutputBuffer, past->past_OutputConversionTargetStride,
|
||||
past->past_FramesPerUserBuffer * past->past_NumOutputChannels );
|
||||
}
|
||||
|
||||
return userResult;
|
||||
}
|
||||
|
|
@ -36,8 +36,6 @@
|
|||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "portaudio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
|
|
@ -61,12 +59,6 @@ extern "C"
|
|||
typedef unsigned short uint16;
|
||||
#endif
|
||||
|
||||
/* Used to convert between various sample formats. */
|
||||
typedef void (PortAudioConverter)(
|
||||
void *inputBuffer, int inputStride,
|
||||
void *outputBuffer, int outputStride,
|
||||
int numSamples );
|
||||
|
||||
#define PA_MAGIC (0x18273645)
|
||||
|
||||
/************************************************************************************/
|
||||
|
|
@ -84,9 +76,7 @@ typedef struct internalPortAudioStream
|
|||
int past_NumOutputChannels;
|
||||
PaDeviceID past_InputDeviceID;
|
||||
PaDeviceID past_OutputDeviceID;
|
||||
PaSampleFormat past_NativeInputSampleFormat;
|
||||
PaSampleFormat past_InputSampleFormat;
|
||||
PaSampleFormat past_NativeOutputSampleFormat;
|
||||
PaSampleFormat past_OutputSampleFormat;
|
||||
void *past_DeviceData;
|
||||
PortAudioCallback *past_Callback;
|
||||
|
|
@ -109,19 +99,11 @@ typedef struct internalPortAudioStream
|
|||
double past_AverageTotalCount;
|
||||
double past_Usage;
|
||||
int past_IfLastExitValid;
|
||||
/* Format Conversion */
|
||||
/* These are setup by PaConversion_Setup() */
|
||||
PortAudioConverter *past_InputConversionProc;
|
||||
int past_InputConversionSourceStride;
|
||||
int past_InputConversionTargetStride;
|
||||
PortAudioConverter *past_OutputConversionProc;
|
||||
int past_OutputConversionSourceStride;
|
||||
int past_OutputConversionTargetStride;
|
||||
}
|
||||
internalPortAudioStream;
|
||||
|
||||
/************************************************************************************/
|
||||
/******** These functions must be provided by a platform implementation. ************/
|
||||
/****************** Prototypes ******************************************************/
|
||||
/************************************************************************************/
|
||||
|
||||
PaError PaHost_Init( void );
|
||||
|
|
@ -138,46 +120,21 @@ PaError PaHost_StartEngine( internalPortAudioStream *past );
|
|||
PaError PaHost_StopEngine( internalPortAudioStream *past, int abort );
|
||||
PaError PaHost_StreamActive( internalPortAudioStream *past );
|
||||
|
||||
void *PaHost_AllocateFastMemory( long numBytes );
|
||||
void PaHost_FreeFastMemory( void *addr, long numBytes );
|
||||
|
||||
/* This only called if PA_VALIDATE_RATE IS CALLED. */
|
||||
PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
|
||||
double *closestFrameRatePtr );
|
||||
|
||||
/**********************************************************************/
|
||||
/************ Common Utility Routines provided by PA ******************/
|
||||
/**********************************************************************/
|
||||
|
||||
/* PaHost_IsInitialized() returns non-zero if PA is initialized, 0 otherwise */
|
||||
int PaHost_IsInitialized( void );
|
||||
|
||||
internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream );
|
||||
|
||||
int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable,
|
||||
int numRates, double frameRate );
|
||||
|
||||
long Pa_CallConvertInt16( internalPortAudioStream *past,
|
||||
short *nativeInputBuffer,
|
||||
short *nativeOutputBuffer );
|
||||
|
||||
/* Calculate 2 LSB dither signal with a triangular distribution.
|
||||
** Ranged properly for adding to a 32 bit 1.31 fixed point value prior to >>15.
|
||||
** Range of output is +/- 65535
|
||||
** Multiply by PA_DITHER_SCALE to get a float between -2.0 and 2.0. */
|
||||
#define PA_DITHER_BITS (15)
|
||||
#define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
|
||||
long PaConvert_TriangularDither( void );
|
||||
|
||||
PaError PaConvert_SetupInput( internalPortAudioStream *past,
|
||||
PaSampleFormat nativeInputSampleFormat );
|
||||
long Pa_CallConvertFloat32( internalPortAudioStream *past,
|
||||
float *nativeInputBuffer,
|
||||
float *nativeOutputBuffer );
|
||||
|
||||
PaError PaConvert_SetupOutput( internalPortAudioStream *past,
|
||||
PaSampleFormat nativeOutputSampleFormat );
|
||||
void *PaHost_AllocateFastMemory( long numBytes );
|
||||
void PaHost_FreeFastMemory( void *addr, long numBytes );
|
||||
|
||||
long PaConvert_Process( internalPortAudioStream *past,
|
||||
void *nativeInputBuffer,
|
||||
void *nativeOutputBuffer );
|
||||
PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
|
||||
double *closestFrameRatePtr );
|
||||
int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable,
|
||||
int numRates, double frameRate );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,8 +70,8 @@ O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for c
|
|||
|
||||
#define PRINT(x) { printf x; fflush(stdout); }
|
||||
#define ERR_RPT(x) PRINT(x)
|
||||
#define DBUG(x) /* PRINT(x) /**/
|
||||
#define DBUGX(x) /* PRINT(x) /**/
|
||||
#define DBUG(x) /* PRINT(x) */
|
||||
#define DBUGX(x) /* PRINT(x) */
|
||||
|
||||
static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */
|
||||
|
||||
|
|
@ -152,10 +152,10 @@ PaError Pa_OpenStream(
|
|||
int bitsPerInputSample;
|
||||
int bitsPerOutputSample;
|
||||
/* Print passed parameters. */
|
||||
DBUG(("Pa_OpenStream( %p, dev=%d, numChan=%d, format=%d, info=%p, /* input */ \n",
|
||||
DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n",
|
||||
streamPtrPtr, inputDeviceID, numInputChannels,
|
||||
inputSampleFormat, inputDriverInfo ));
|
||||
DBUG((" dev=%d, numChan=%d, format=%d, info=%p, /* output */\n",
|
||||
DBUG((" %d, %d, %d, %p, /* output */\n",
|
||||
outputDeviceID, numOutputChannels,
|
||||
outputSampleFormat, outputDriverInfo ));
|
||||
DBUG((" %g, %d, %d, 0x%x, , %p )\n",
|
||||
|
|
@ -217,7 +217,7 @@ PaError Pa_OpenStream(
|
|||
|
||||
past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */
|
||||
past->past_FramesPerUserBuffer = framesPerBuffer;
|
||||
past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() MUST CHECK FOR ZERO! */
|
||||
past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() NMUST CHECK FOR ZERO! */
|
||||
past->past_Callback = callback;
|
||||
past->past_UserData = userData;
|
||||
past->past_OutputSampleFormat = outputSampleFormat;
|
||||
|
|
@ -248,7 +248,7 @@ PaError Pa_OpenStream(
|
|||
#else
|
||||
past->past_SampleRate = sampleRate;
|
||||
#endif
|
||||
/* Allocate single Input buffer for passing formatted samples to user callback. */
|
||||
/* Allocate single Input buffer. */
|
||||
past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8);
|
||||
past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize);
|
||||
if( past->past_InputBuffer == NULL )
|
||||
|
|
@ -478,25 +478,13 @@ double Pa_GetCPULoad( PortAudioStream* stream)
|
|||
return past->past_Usage;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream )
|
||||
{
|
||||
internalPortAudioStream* result = (internalPortAudioStream*) stream;
|
||||
|
||||
if( result == NULL || result->past_Magic != PA_MAGIC )
|
||||
return NULL;
|
||||
else
|
||||
return result;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
** Calculate 2 LSB dither signal with a triangular distribution.
|
||||
** Ranged properly for adding to a 32 bit integer prior to >>15.
|
||||
** Range of output is +/- 32767
|
||||
*/
|
||||
#define PA_DITHER_BITS (15)
|
||||
#define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
|
||||
long PaConvert_TriangularDither( void )
|
||||
#define DITHER_BITS (15)
|
||||
#define DITHER_SCALE (1.0f / ((1<<DITHER_BITS)-1))
|
||||
static long Pa_TriangularDither( void )
|
||||
{
|
||||
static unsigned long previous = 0;
|
||||
static unsigned long randSeed1 = 22222;
|
||||
|
|
@ -505,12 +493,8 @@ long PaConvert_TriangularDither( void )
|
|||
/* Generate two random numbers. */
|
||||
randSeed1 = (randSeed1 * 196314165) + 907633515;
|
||||
randSeed2 = (randSeed2 * 196314165) + 907633515;
|
||||
/* Generate triangular distribution about 0.
|
||||
* Shift before adding to prevent overflow which would skew the distribution.
|
||||
* Also shift an extra bit for the high pass filter.
|
||||
*/
|
||||
#define DITHER_SHIFT ((32 - PA_DITHER_BITS) + 1)
|
||||
current = (((long)randSeed1)>>DITHER_SHIFT) + (((long)randSeed2)>>DITHER_SHIFT);
|
||||
/* Generate triangular distribution about 0. */
|
||||
current = (((long)randSeed1)>>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS));
|
||||
/* High pass filter to reduce audibility. */
|
||||
highPass = current - previous;
|
||||
previous = current;
|
||||
|
|
@ -529,6 +513,8 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
|
|||
short *nativeOutputBuffer )
|
||||
{
|
||||
long temp;
|
||||
long bytesEmpty = 0;
|
||||
long bytesFilled = 0;
|
||||
int userResult;
|
||||
unsigned int i;
|
||||
void *inputBuffer = NULL;
|
||||
|
|
@ -590,7 +576,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
|
|||
for( i=0; i<samplesPerBuffer; i++ )
|
||||
{
|
||||
temp = nativeInputBuffer[i];
|
||||
temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
|
||||
temp += Pa_TriangularDither() >> 8; /* PLB20010820 */
|
||||
temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
|
||||
inBufPtr[i] = (char)(temp >> 8);
|
||||
}
|
||||
|
|
@ -616,7 +602,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
|
|||
for( i=0; i<samplesPerBuffer; i++ )
|
||||
{
|
||||
temp = nativeInputBuffer[i];
|
||||
temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
|
||||
temp += Pa_TriangularDither() >> 8; /* PLB20010820 */
|
||||
temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
|
||||
inBufPtr[i] = (unsigned char)((temp>>8) + 0x80); /* PLB20010820 */
|
||||
}
|
||||
|
|
@ -683,7 +669,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
|
|||
/* If you dither then you have to clip because dithering could push the signal out of range! */
|
||||
for( i=0; i<samplesPerBuffer; i++ )
|
||||
{
|
||||
float dither = PaConvert_TriangularDither()*PA_DITHER_SCALE;
|
||||
float dither = Pa_TriangularDither()*DITHER_SCALE;
|
||||
float dithered = (outBufPtr[i] * (32767.0f)) + dither;
|
||||
temp = (long) (dithered);
|
||||
*nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
|
||||
|
|
@ -707,7 +693,7 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
|
|||
for( i=0; i<samplesPerBuffer; i++ )
|
||||
{
|
||||
/* Shift one bit down before dithering so that we have room for overflow from add. */
|
||||
temp = (outBufPtr[i] >> 1) + PaConvert_TriangularDither();
|
||||
temp = (outBufPtr[i] >> 1) + Pa_TriangularDither();
|
||||
temp = temp >> 15;
|
||||
*nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
|
||||
}
|
||||
|
|
@ -744,6 +730,55 @@ long Pa_CallConvertInt16( internalPortAudioStream *past,
|
|||
return userResult;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
** Called by host code.
|
||||
** Convert input from Float32, call user code, then convert output
|
||||
** to Float32 format for native use.
|
||||
** Assumes host native format is Float32.
|
||||
** Returns result from user callback.
|
||||
** FIXME - Unimplemented for formats other than paFloat32!!!!
|
||||
*/
|
||||
long Pa_CallConvertFloat32( internalPortAudioStream *past,
|
||||
float *nativeInputBuffer,
|
||||
float *nativeOutputBuffer )
|
||||
{
|
||||
long bytesEmpty = 0;
|
||||
long bytesFilled = 0;
|
||||
int userResult;
|
||||
void *inputBuffer = NULL;
|
||||
void *outputBuffer = NULL;
|
||||
|
||||
/* Get native data from DirectSound. */
|
||||
if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
|
||||
{
|
||||
inputBuffer = nativeInputBuffer; /* FIXME */
|
||||
}
|
||||
|
||||
/* Are we doing output time? */
|
||||
if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
|
||||
{
|
||||
/* May already be in native format so just write directly to native buffer. */
|
||||
outputBuffer = (past->past_OutputSampleFormat == paFloat32) ?
|
||||
nativeOutputBuffer : past->past_OutputBuffer;
|
||||
}
|
||||
/*
|
||||
AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
|
||||
AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
|
||||
*/
|
||||
/* Call user callback routine. */
|
||||
userResult = past->past_Callback(
|
||||
inputBuffer,
|
||||
outputBuffer,
|
||||
past->past_FramesPerUserBuffer,
|
||||
past->past_FrameCount,
|
||||
past->past_UserData );
|
||||
|
||||
past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
|
||||
|
||||
/* Convert to native format if necessary. */ /* FIXME */
|
||||
return userResult;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
PaError Pa_Initialize( void )
|
||||
{
|
||||
|
|
@ -765,11 +800,6 @@ PaError Pa_Terminate( void )
|
|||
return result;
|
||||
}
|
||||
|
||||
int PaHost_IsInitialized()
|
||||
{
|
||||
return gInitCount;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
PaError Pa_GetSampleSize( PaSampleFormat format )
|
||||
{
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ typedef enum {
|
|||
/*
|
||||
Pa_Initialize() is the library initialisation function - call this before
|
||||
using the library.
|
||||
|
||||
*/
|
||||
|
||||
PaError Pa_Initialize( void );
|
||||
|
|
@ -71,25 +70,19 @@ PaError Pa_Initialize( void );
|
|||
/*
|
||||
Pa_Terminate() is the library termination function - call this after
|
||||
using the library.
|
||||
|
||||
*/
|
||||
|
||||
PaError Pa_Terminate( void );
|
||||
|
||||
/*
|
||||
Pa_GetHostError() returns a host specific error code.
|
||||
This can be called after receiving a PortAudio error code of paHostError.
|
||||
|
||||
Return host specific error.
|
||||
This can be called after receiving a paHostError.
|
||||
*/
|
||||
|
||||
long Pa_GetHostError( void );
|
||||
|
||||
/*
|
||||
Pa_GetErrorText() translates the supplied PortAudio error number
|
||||
into a human readable message.
|
||||
|
||||
Translate the error number into a human readable message.
|
||||
*/
|
||||
|
||||
const char *Pa_GetErrorText( PaError errnum );
|
||||
|
||||
/*
|
||||
|
|
@ -99,14 +92,11 @@ const char *Pa_GetErrorText( PaError errnum );
|
|||
stream. Each device has a "native" format which may be used when optimum
|
||||
efficiency or control over conversion is required.
|
||||
|
||||
Formats marked "always available" are supported (emulated) by all
|
||||
PortAudio implementations.
|
||||
Formats marked "always available" are supported (emulated) by all devices.
|
||||
|
||||
The floating point representation uses +1.0 and -1.0 as the respective
|
||||
maximum and minimum.
|
||||
|
||||
The floating point representation (paFloat32) uses +1.0 and -1.0 as the
|
||||
maximum and minimum respectively.
|
||||
|
||||
paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
|
||||
|
||||
*/
|
||||
|
||||
typedef unsigned long PaSampleFormat;
|
||||
|
|
@ -116,23 +106,24 @@ typedef unsigned long PaSampleFormat;
|
|||
#define paInt24 ((PaSampleFormat) (1<<3))
|
||||
#define paPackedInt24 ((PaSampleFormat) (1<<4))
|
||||
#define paInt8 ((PaSampleFormat) (1<<5))
|
||||
#define paUInt8 ((PaSampleFormat) (1<<6))
|
||||
#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */
|
||||
#define paCustomFormat ((PaSampleFormat) (1<<16))
|
||||
|
||||
/*
|
||||
Device enumeration mechanism.
|
||||
|
||||
Device ids range from 0 to Pa_CountDevices()-1.
|
||||
Device ids range from 0 to Pa_CountDevices()-1.
|
||||
|
||||
Devices may support input, output or both.
|
||||
|
||||
Devices may support input, output or both. Device 0 is always the "default"
|
||||
device and should support at least stereo in and out if that is available
|
||||
on the taget platform _even_ if this involves kludging an input/output
|
||||
device on platforms that usually separate input from output. Other platform
|
||||
specific devices are specified by positive device ids.
|
||||
*/
|
||||
|
||||
typedef int PaDeviceID;
|
||||
#define paNoDevice -1
|
||||
|
||||
int Pa_CountDevices( void );
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int structVersion;
|
||||
|
|
@ -147,10 +138,12 @@ typedef struct
|
|||
}
|
||||
PaDeviceInfo;
|
||||
|
||||
|
||||
int Pa_CountDevices();
|
||||
/*
|
||||
Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() return the
|
||||
default device ids for input and output respectively, or paNoDevice if
|
||||
no device is available.
|
||||
Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID()
|
||||
|
||||
Return the default device ID or paNoDevice if there is no devices.
|
||||
The result can be passed to Pa_OpenStream().
|
||||
|
||||
On the PC, the user can specify a default device by
|
||||
|
|
@ -158,40 +151,34 @@ PaDeviceInfo;
|
|||
|
||||
set PA_RECOMMENDED_OUTPUT_DEVICE=1
|
||||
|
||||
The user should first determine the available device ids by using
|
||||
The user should first determine the available device ID by using
|
||||
the supplied application "pa_devs".
|
||||
|
||||
*/
|
||||
|
||||
PaDeviceID Pa_GetDefaultInputDeviceID( void );
|
||||
PaDeviceID Pa_GetDefaultOutputDeviceID( void );
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
|
||||
for the device specified.
|
||||
If the device parameter is out of range the function returns NULL.
|
||||
|
||||
PortAudio manages the memory referenced by the returned pointer, the client
|
||||
must not manipulate or free the memory. The pointer is only guaranteed to be
|
||||
valid between calls to Pa_Initialize() and Pa_Terminate().
|
||||
|
||||
*/
|
||||
|
||||
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID device );
|
||||
|
||||
/*
|
||||
PaTimestamp is used to represent a continuous sample clock with arbitrary
|
||||
start time that can be used for syncronization. The type is used for the
|
||||
outTime argument to the PortAudioCallback and as the result of Pa_StreamTime()
|
||||
|
||||
start time useful for syncronisation. The type is used in the outTime
|
||||
argument to the callback function and the result of Pa_StreamTime()
|
||||
*/
|
||||
|
||||
typedef double PaTimestamp;
|
||||
|
||||
/*
|
||||
PortAudioCallback is implemented by PortAudio clients.
|
||||
Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
|
||||
referring to the device specified by id.
|
||||
If id is out of range the function returns NULL.
|
||||
|
||||
The returned structure is owned by the PortAudio implementation and must
|
||||
not be manipulated or freed. The pointer is only guaranteed to be valid
|
||||
between calls to Pa_Initialize() and Pa_Terminate().
|
||||
*/
|
||||
|
||||
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID );
|
||||
|
||||
/*
|
||||
PortAudioCallback is implemented by clients of the portable audio api.
|
||||
|
||||
inputBuffer and outputBuffer are arrays of interleaved samples,
|
||||
the format, packing and number of channels used by the buffers are
|
||||
|
|
@ -207,15 +194,15 @@ typedef double PaTimestamp;
|
|||
intended for storing synthesis data etc.
|
||||
|
||||
return value:
|
||||
The callback can return a non-zero value to stop the stream. This may be
|
||||
The callback can return a nonzero value to stop the stream. This may be
|
||||
useful in applications such as soundfile players where a specific duration
|
||||
of output is required. However, it is not necessary to utilise this mechanism
|
||||
as StopStream() will also terminate the stream. A callback returning a
|
||||
non-zero value must fill the entire outputBuffer.
|
||||
nonzero value must fill the entire outputBuffer.
|
||||
|
||||
NOTE: None of the other stream functions may be called from within the
|
||||
callback function except for Pa_GetCPULoad().
|
||||
|
||||
|
||||
*/
|
||||
|
||||
typedef int (PortAudioCallback)(
|
||||
|
|
@ -229,11 +216,12 @@ typedef int (PortAudioCallback)(
|
|||
|
||||
These flags may be supplied (ored together) in the streamFlags argument to
|
||||
the Pa_OpenStream() function.
|
||||
|
||||
|
||||
[ suggestions? ]
|
||||
*/
|
||||
|
||||
#define paNoFlag (0)
|
||||
#define paClipOff (1<<0) /* disable default clipping of out of range samples */
|
||||
#define paClipOff (1<<0) /* disable defult clipping of out of range samples */
|
||||
#define paDitherOff (1<<1) /* disable default dithering */
|
||||
#define paPlatformSpecificFlags (0x00010000)
|
||||
typedef unsigned long PaStreamFlags;
|
||||
|
|
@ -258,15 +246,15 @@ typedef void PortAudioStream;
|
|||
|
||||
numInputChannels is the number of channels of sound to be delivered to the
|
||||
callback. It can range from 1 to the value of maxInputChannels in the
|
||||
PaDeviceInfo record for the device specified by the inputDevice parameter.
|
||||
device input record for the device specified in the inputDevice parameter.
|
||||
If inputDevice is paNoDevice numInputChannels is ignored.
|
||||
|
||||
inputSampleFormat is the sample format of inputBuffer provided to the callback
|
||||
inputSampleFormat is the format of inputBuffer provided to the callback
|
||||
function. inputSampleFormat may be any of the formats described by the
|
||||
PaSampleFormat enumeration (see above). PortAudio guarantees support for
|
||||
the device's native formats (nativeSampleFormats in the device info record)
|
||||
and additionally 16 and 32 bit integer and 32 bit floating point formats.
|
||||
Support for other formats is implementation defined.
|
||||
the sound devices native formats (nativeSampleFormats in the device info
|
||||
record) and additionally 16 and 32 bit integer and 32 bit floating point
|
||||
formats. Support for other formats is implementation defined.
|
||||
|
||||
inputDriverInfo is a pointer to an optional driver specific data structure
|
||||
containing additional information for device setup or stream processing.
|
||||
|
|
@ -288,24 +276,24 @@ typedef void PortAudioStream;
|
|||
outputDriverInfo is never required for correct operation. If not used
|
||||
outputDriverInfo should be NULL.
|
||||
|
||||
sampleRate is the desired sampleRate. For full-duplex streams it is the
|
||||
sample rate for both input and output
|
||||
sampleRate is the desired sampleRate for input and output
|
||||
|
||||
framesPerBuffer is the length in sample frames of all internal sample buffers
|
||||
used for communication with platform specific audio routines. Wherever
|
||||
possible this corresponds to the framesPerBuffer parameter passed to the
|
||||
callback function.
|
||||
|
||||
numberOfBuffers is the number of buffers used for multibuffered communication
|
||||
with the platform specific audio routines. If you pass zero, then an optimum
|
||||
value will be chosen for you internally. This parameter is provided only
|
||||
as a guide - and does not imply that an implementation must use multibuffered
|
||||
i/o when reliable double buffering is available (such as SndPlayDoubleBuffer()
|
||||
on the Macintosh.)
|
||||
numberOfBuffers is the number of buffers used for
|
||||
multibuffered communication with the platform specific audio
|
||||
routines. If you pass zero, then an optimum value will be
|
||||
chosen for you internally. This parameter is provided only
|
||||
as a guide - and does not imply that an implementation must
|
||||
use multibuffered i/o when reliable double buffering is
|
||||
available (such as SndPlayDoubleBuffer() on the Macintosh.)
|
||||
|
||||
streamFlags may contain a combination of flags ORed together.
|
||||
These flags modify the behaviour of the streaming process. Some flags may only
|
||||
be relevant to certain buffer formats.
|
||||
These flags modify the behavior of the
|
||||
streaming process. Some flags may only be relevant to certain buffer formats.
|
||||
|
||||
callback is a pointer to a client supplied function that is responsible
|
||||
for processing and filling input and output buffers (see above for details.)
|
||||
|
|
@ -315,10 +303,10 @@ typedef void PortAudioStream;
|
|||
for processing the audio buffers.
|
||||
|
||||
return value:
|
||||
Upon success Pa_OpenStream() returns PaNoError and places a pointer to a
|
||||
Apon success Pa_OpenStream() returns PaNoError and places a pointer to a
|
||||
valid PortAudioStream in the stream argument. The stream is inactive (stopped).
|
||||
If a call to Pa_OpenStream() fails a non-zero error code is returned (see
|
||||
PaError above) and the value of stream is invalid.
|
||||
If a call to Pa_OpenStream() fails a nonzero error code is returned (see
|
||||
PAError above) and the value of stream is invalid.
|
||||
|
||||
*/
|
||||
|
||||
|
|
@ -340,16 +328,15 @@ PaError Pa_OpenStream( PortAudioStream** stream,
|
|||
|
||||
|
||||
/*
|
||||
Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that opens
|
||||
the default input and/or output devices. Most parameters have identical meaning
|
||||
to their Pa_OpenStream() counterparts, with the following exceptions:
|
||||
Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that
|
||||
opens the default input and/or ouput devices. Most parameters have
|
||||
identical meaning to their Pa_OpenStream() counterparts, with the following
|
||||
exceptions:
|
||||
|
||||
If either numInputChannels or numOutputChannels is 0 the respective device
|
||||
is not opened. This has the same effect as passing paNoDevice in the device
|
||||
arguments to Pa_OpenStream().
|
||||
is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() )
|
||||
|
||||
sampleFormat applies to both the input and output buffers.
|
||||
|
||||
*/
|
||||
|
||||
PaError Pa_OpenDefaultStream( PortAudioStream** stream,
|
||||
|
|
@ -364,17 +351,15 @@ PaError Pa_OpenDefaultStream( PortAudioStream** stream,
|
|||
|
||||
/*
|
||||
Pa_CloseStream() closes an audio stream, flushing any pending buffers.
|
||||
|
||||
*/
|
||||
|
||||
PaError Pa_CloseStream( PortAudioStream* );
|
||||
|
||||
/*
|
||||
Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
|
||||
Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
|
||||
Pa_StopStream() waits until all pending audio buffers have been played.
|
||||
Pa_AbortStream() stops playing immediately without waiting for pending
|
||||
buffers to complete.
|
||||
|
||||
Pa_AbortStream() stops playing immediately without waiting for pending
|
||||
buffers to complete.
|
||||
*/
|
||||
|
||||
PaError Pa_StartStream( PortAudioStream *stream );
|
||||
|
|
@ -384,43 +369,37 @@ PaError Pa_StopStream( PortAudioStream *stream );
|
|||
PaError Pa_AbortStream( PortAudioStream *stream );
|
||||
|
||||
/*
|
||||
Pa_StreamActive() returns one (1) when the stream is active (ie playing
|
||||
or recording audio), zero (0) when not playing, or a negative error number
|
||||
if the stream is invalid.
|
||||
Pa_StreamActive() returns one when the stream is playing audio,
|
||||
zero when not playing, or a negative error number if the
|
||||
stream is invalid.
|
||||
The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
|
||||
but may also become inactive if the callback returns a non-zero value.
|
||||
In the latter case, the stream is considered inactive after the last
|
||||
buffer has finished playing.
|
||||
|
||||
*/
|
||||
|
||||
PaError Pa_StreamActive( PortAudioStream *stream );
|
||||
|
||||
/*
|
||||
Pa_StreamTime() returns the current output time in samples for the stream.
|
||||
This time may be used as a time reference (for example synchronizing audio to
|
||||
Pa_StreamTime() returns the current output time for the stream in samples.
|
||||
This time may be used as a time reference (for example syncronising audio to
|
||||
MIDI).
|
||||
|
||||
*/
|
||||
|
||||
PaTimestamp Pa_StreamTime( PortAudioStream *stream );
|
||||
|
||||
/*
|
||||
Pa_GetCPULoad() returns the CPU Load for the stream.
|
||||
The "CPU Load" is a fraction of total CPU time consumed by the stream's
|
||||
audio processing routines including, but not limited to the client supplied
|
||||
callback.
|
||||
The "CPU Load" is a fraction of total CPU time consumed by the
|
||||
stream's audio processing.
|
||||
A value of 0.5 would imply that PortAudio and the sound generating
|
||||
callback was consuming roughly 50% of the available CPU time.
|
||||
This function may be called from the callback function or the application.
|
||||
|
||||
*/
|
||||
|
||||
double Pa_GetCPULoad( PortAudioStream* stream );
|
||||
|
||||
/*
|
||||
Pa_GetMinNumBuffers() returns the minimum number of buffers required by
|
||||
the current host based on minimum latency.
|
||||
Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for
|
||||
the current host based on minimum latency.
|
||||
On the PC, for the DirectSound implementation, latency can be optionally set
|
||||
by user by setting an environment variable.
|
||||
For example, to set latency to 200 msec, put:
|
||||
|
|
@ -430,33 +409,23 @@ double Pa_GetCPULoad( PortAudioStream* stream );
|
|||
in the AUTOEXEC.BAT file and reboot.
|
||||
If the environment variable is not set, then the latency will be determined
|
||||
based on the OS. Windows NT has higher latency than Win95.
|
||||
|
||||
*/
|
||||
|
||||
int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
|
||||
|
||||
/*
|
||||
Pa_Sleep() puts the caller to sleep for at least 'msec' milliseconds.
|
||||
You may sleep longer than the requested time so don't rely on this for
|
||||
accurate musical timing.
|
||||
|
||||
Pa_Sleep() is provided as a convenience for authors of portable code (such as
|
||||
the tests and examples in the PortAudio distribution.)
|
||||
|
||||
Sleep for at least 'msec' milliseconds.
|
||||
You may sleep longer than the requested time so don't rely
|
||||
on this for accurate musical timing.
|
||||
*/
|
||||
|
||||
void Pa_Sleep( long msec );
|
||||
|
||||
/*
|
||||
Pa_GetSampleSize() returns the size in bytes of a single sample in the
|
||||
supplied PaSampleFormat, or paSampleFormatNotSupported if the format is
|
||||
no supported.
|
||||
|
||||
Return size in bytes of a single sample in a given PaSampleFormat
|
||||
or paSampleFormatNotSupported.
|
||||
*/
|
||||
|
||||
PaError Pa_GetSampleSize( PaSampleFormat format );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
|
|
|||
205
pa_mac/pa_mac.c
205
pa_mac/pa_mac.c
|
|
@ -42,16 +42,7 @@
|
|||
PLB20010907 - Pass unused event to WaitNextEvent to prevent Mac OSX crash. Thanks Dominic Mazzoni.
|
||||
PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni.
|
||||
PLB20011009 - Use NewSndCallBackUPP() for CARBON
|
||||
PLB20020417 - I used to call Pa_GetMinNumBuffers() which doesn't take into account the
|
||||
variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will
|
||||
give lower latency when virtual memory is turned off.
|
||||
Thanks Kristoffer Jensen and Georgios Marentakis for spotting this bug.
|
||||
PLB20020423 - Use new method to calculate CPU load similar to other ports. Based on num frames calculated.
|
||||
Fixed Pa_StreamTime(). Now estimates how many frames have played based on MicroSecond timer.
|
||||
Added PA_MAX_USAGE_ALLOWED to prevent Mac form hanging when CPU load approaches 100%.
|
||||
PLB20020424 - Fixed return value in Pa_StreamTime
|
||||
*/
|
||||
|
||||
/*
|
||||
COMPATIBILITY
|
||||
This Macintosh implementation is designed for use with Mac OS 7, 8 and
|
||||
|
|
@ -81,7 +72,6 @@ O- Determine default devices somehow.
|
|||
#include <string.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Mac specific includes */
|
||||
#include "OSUtils.h"
|
||||
#include <MacTypes.h>
|
||||
|
|
@ -94,7 +84,6 @@ O- Determine default devices somehow.
|
|||
#include <DateTimeUtils.h>
|
||||
#include <Timer.h>
|
||||
#include <Gestalt.h>
|
||||
|
||||
#include "portaudio.h"
|
||||
#include "pa_host.h"
|
||||
#include "pa_trace.h"
|
||||
|
|
@ -104,16 +93,6 @@ O- Determine default devices somehow.
|
|||
#define TRUE (!FALSE)
|
||||
#endif
|
||||
|
||||
/* #define TARGET_API_MAC_CARBON (1) */
|
||||
|
||||
/*
|
||||
* Define maximum CPU load that will be allowed. User callback will
|
||||
* be skipped if load exceeds this limit. This is to prevent the Mac
|
||||
* from hanging when the CPU is hogged by the sound thread.
|
||||
* On my PowerBook G3, the mac hung when I used 94% of CPU ( usage = 0.94 ).
|
||||
*/
|
||||
#define PA_MAX_USAGE_ALLOWED (0.92)
|
||||
|
||||
/* Debugging output macros. */
|
||||
#define PRINT(x) { printf x; fflush(stdout); }
|
||||
#define ERR_RPT(x) PRINT(x)
|
||||
|
|
@ -122,7 +101,7 @@ O- Determine default devices somehow.
|
|||
|
||||
#define MAC_PHYSICAL_FRAMES_PER_BUFFER (512) /* Minimum number of stereo frames per SoundManager double buffer. */
|
||||
#define MAC_VIRTUAL_FRAMES_PER_BUFFER (4096) /* Need this many when using Virtual Memory for recording. */
|
||||
#define PA_MIN_NUM_HOST_BUFFERS (2)
|
||||
#define PA_MIN_NUM_HOST_BUFFERS (2)
|
||||
#define PA_MAX_NUM_HOST_BUFFERS (16) /* Do not exceed!! */
|
||||
#define PA_MAX_DEVICE_INFO (32)
|
||||
|
||||
|
|
@ -147,8 +126,7 @@ MultiBuffer;
|
|||
typedef struct PaHostSoundControl
|
||||
{
|
||||
UInt64 pahsc_EntryCount;
|
||||
double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
|
||||
|
||||
UInt64 pahsc_LastExitCount;
|
||||
/* Use char instead of Boolean for atomic operation. */
|
||||
volatile char pahsc_IsRecording; /* Recording in progress. Set by foreground. Cleared by background. */
|
||||
volatile char pahsc_StopRecording; /* Signal sent to background. */
|
||||
|
|
@ -156,23 +134,22 @@ typedef struct PaHostSoundControl
|
|||
/* Input */
|
||||
SPB pahsc_InputParams;
|
||||
SICompletionUPP pahsc_InputCompletionProc;
|
||||
MultiBuffer pahsc_InputMultiBuffer;
|
||||
int32 pahsc_BytesPerInputHostBuffer;
|
||||
MultiBuffer pahsc_InputMultiBuffer;
|
||||
int32 pahsc_BytesPerInputHostBuffer;
|
||||
int32 pahsc_InputRefNum;
|
||||
/* Output */
|
||||
CmpSoundHeader pahsc_SoundHeaders[PA_MAX_NUM_HOST_BUFFERS];
|
||||
int32 pahsc_BytesPerOutputHostBuffer;
|
||||
SndChannelPtr pahsc_Channel;
|
||||
SndChannelPtr pahsc_Channel;
|
||||
SndCallBackUPP pahsc_OutputCompletionProc;
|
||||
int32 pahsc_NumOutsQueued;
|
||||
int32 pahsc_NumOutsPlayed;
|
||||
PaTimestamp pahsc_NumFramesDone;
|
||||
UInt64 pahsc_WhenFramesDoneIncremented;
|
||||
/* Init Time -------------- */
|
||||
int32 pahsc_NumHostBuffers;
|
||||
int32 pahsc_FramesPerHostBuffer;
|
||||
int32 pahsc_UserBuffersPerHostBuffer;
|
||||
int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */
|
||||
int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */
|
||||
}
|
||||
PaHostSoundControl;
|
||||
|
||||
|
|
@ -200,8 +177,7 @@ static int sDefaultInputDeviceID;
|
|||
/************************************************************************************/
|
||||
static PaError PaMac_TimeSlice( internalPortAudioStream *past, int16 *macOutputBufPtr );
|
||||
static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr );
|
||||
static PaError PaMac_RecordNext( internalPortAudioStream *past );
|
||||
static void PaMac_StartLoadCalculation( internalPortAudioStream *past );
|
||||
static PaError PaMac_RecordNext( internalPortAudioStream *past );static void StartLoadCalculation( internalPortAudioStream *past );
|
||||
static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerBuffer, double sampleRate );
|
||||
static double *PaMac_GetSampleRatesFromHandle ( int numRates, Handle h );
|
||||
static PaError PaMac_ScanInputDevices( void );
|
||||
|
|
@ -720,8 +696,8 @@ PaDeviceID Pa_GetDefaultOutputDeviceID( void )
|
|||
return sDefaultOutputDeviceID;
|
||||
}
|
||||
|
||||
/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
|
||||
static void PaMac_StartLoadCalculation( internalPortAudioStream *past )
|
||||
/**************************************************************************/
|
||||
static void StartLoadCalculation( internalPortAudioStream *past )
|
||||
{
|
||||
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
UnsignedWide widePad;
|
||||
|
|
@ -731,36 +707,38 @@ static void PaMac_StartLoadCalculation( internalPortAudioStream *past )
|
|||
pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad );
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
** Measure fractional CPU load based on real-time it took to calculate
|
||||
** buffers worth of output.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
static void PaMac_EndLoadCalculation( internalPortAudioStream *past )
|
||||
{
|
||||
UnsignedWide widePad;
|
||||
UInt64 currentCount;
|
||||
long usecsElapsed;
|
||||
double newUsage;
|
||||
UInt64 CurrentCount;
|
||||
long InsideCount;
|
||||
long TotalCount;
|
||||
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
if( pahsc == NULL ) return;
|
||||
|
||||
/* Measure CPU utilization during this callback. Note that this calculation
|
||||
** assumes that we had the processor the whole time.
|
||||
*/
|
||||
#define LOWPASS_COEFFICIENT_0 (0.95)
|
||||
#define LOWPASS_COEFFICIENT_0 (0.9)
|
||||
#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
|
||||
Microseconds( &widePad );
|
||||
currentCount = UnsignedWideToUInt64( widePad );
|
||||
|
||||
usecsElapsed = (long) U64Subtract(currentCount, pahsc->pahsc_EntryCount);
|
||||
|
||||
/* Use inverse because it is faster than the divide. */
|
||||
newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer;
|
||||
|
||||
past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
|
||||
(LOWPASS_COEFFICIENT_1 * newUsage);
|
||||
|
||||
CurrentCount = UnsignedWideToUInt64( widePad );
|
||||
if( past->past_IfLastExitValid )
|
||||
{
|
||||
InsideCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_EntryCount);
|
||||
TotalCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_LastExitCount);
|
||||
/* Low pass filter the result because sometimes we get called several times in a row.
|
||||
* That can cause the TotalCount to be very low which can cause the usage to appear
|
||||
* unnaturally high. So we must filter numerator and denominator separately!!!
|
||||
*/
|
||||
past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
|
||||
(LOWPASS_COEFFICIENT_1 * InsideCount));
|
||||
past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
|
||||
(LOWPASS_COEFFICIENT_1 * TotalCount));
|
||||
past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
|
||||
}
|
||||
pahsc->pahsc_LastExitCount = CurrentCount;
|
||||
past->past_IfLastExitValid = 1;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
@ -851,14 +829,6 @@ static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHead
|
|||
sndHeader->format = kSoundNotCompressed;
|
||||
}
|
||||
|
||||
static void SetFramesDone( PaHostSoundControl *pahsc, PaTimestamp framesDone )
|
||||
{
|
||||
UnsignedWide now;
|
||||
Microseconds( &now );
|
||||
pahsc->pahsc_NumFramesDone = framesDone;
|
||||
pahsc->pahsc_WhenFramesDoneIncremented = UnsignedWideToUInt64( now );
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
PaError PaHost_StartOutput( internalPortAudioStream *past )
|
||||
{
|
||||
|
|
@ -874,8 +844,7 @@ PaError PaHost_StartOutput( internalPortAudioStream *past )
|
|||
past->past_IsActive = 1;
|
||||
pahsc->pahsc_NumOutsQueued = 0;
|
||||
pahsc->pahsc_NumOutsPlayed = 0;
|
||||
|
||||
SetFramesDone( pahsc, 0.0 );
|
||||
pahsc->pahsc_NumFramesDone = 0.0;
|
||||
|
||||
/* Pause channel so it does not do back ground processing while we are still filling the queue. */
|
||||
pauseCommand.cmd = pauseCmd;
|
||||
|
|
@ -888,7 +857,7 @@ PaError PaHost_StartOutput( internalPortAudioStream *past )
|
|||
{
|
||||
PaMac_PlayNext( past, i );
|
||||
}
|
||||
|
||||
|
||||
/* Resume channel now that the queue is full. */
|
||||
resumeCommand.cmd = resumeCmd;
|
||||
resumeCommand.param1 = resumeCommand.param2 = 0;
|
||||
|
|
@ -973,8 +942,8 @@ int Mac_IsVirtualMemoryOn( void )
|
|||
}
|
||||
|
||||
/*******************************************************************
|
||||
* Determine number of host Buffers
|
||||
* and how many User Buffers we can put into each host buffer.
|
||||
* Determine number of WAVE Buffers
|
||||
* and how many User Buffers we can put into each WAVE buffer.
|
||||
*/
|
||||
static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
|
||||
{
|
||||
|
|
@ -985,23 +954,16 @@ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
|
|||
int32 userBuffersPerHostBuffer;
|
||||
int32 framesPerHostBuffer;
|
||||
int32 numHostBuffers;
|
||||
|
||||
/* Calculate minimum and maximum sizes based on timing and sample rate. */
|
||||
minFramesPerHostBuffer = pahsc->pahsc_MinFramesPerHostBuffer;
|
||||
minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
|
||||
DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
|
||||
|
||||
/* Determine number of user buffers based on minimum latency. */
|
||||
/* PLB20020417 I used to call Pa_GetMinNumBuffers() which doesn't take into account the
|
||||
** variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will
|
||||
** gove lower latency when virtual memory is turned off. */
|
||||
/* minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); WRONG */
|
||||
minNumBuffers = PaMac_GetMinNumBuffers( minFramesPerHostBuffer, past->past_FramesPerUserBuffer, past->past_SampleRate );
|
||||
|
||||
minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
|
||||
past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers;
|
||||
DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
|
||||
minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer;
|
||||
|
||||
/* We cannot make the buffers too small because they may not get serviced quickly enough. */
|
||||
/* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */
|
||||
if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer )
|
||||
{
|
||||
userBuffersPerHostBuffer =
|
||||
|
|
@ -1013,17 +975,16 @@ static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
|
|||
userBuffersPerHostBuffer = 1;
|
||||
}
|
||||
framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
|
||||
|
||||
/* Calculate number of host buffers needed. Round up to cover minTotalFrames. */
|
||||
/* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */
|
||||
numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
|
||||
/* Make sure we have enough host buffers. */
|
||||
/* Make sure we have anough WAVE buffers. */
|
||||
if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS)
|
||||
{
|
||||
numHostBuffers = PA_MIN_NUM_HOST_BUFFERS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If we have too many host buffers, try to put more user buffers in a host buffer. */
|
||||
/* If we have too many WAVE buffers, try to put more user buffers in a wave buffer. */
|
||||
while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS)
|
||||
{
|
||||
userBuffersPerHostBuffer += 1;
|
||||
|
|
@ -1067,9 +1028,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
|
|||
}
|
||||
|
||||
PaHost_CalcNumHostBuffers( past );
|
||||
|
||||
/* Setup constants for CPU load measurement. */
|
||||
pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer);
|
||||
|
||||
/* ------------------ OUTPUT */
|
||||
if( past->past_NumOutputChannels > 0 )
|
||||
|
|
@ -1261,9 +1219,6 @@ PaError PaHost_CloseStream( internalPortAudioStream *past )
|
|||
/*************************************************************************/
|
||||
int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate )
|
||||
{
|
||||
/* We use the MAC_VIRTUAL_FRAMES_PER_BUFFER because we might be recording.
|
||||
** This routine doesn't have enough information to determine the best value
|
||||
** and is being depracated. */
|
||||
return PaMac_GetMinNumBuffers( MAC_VIRTUAL_FRAMES_PER_BUFFER, framesPerUserBuffer, sampleRate );
|
||||
}
|
||||
/*************************************************************************/
|
||||
|
|
@ -1343,37 +1298,11 @@ void PaHost_FreeFastMemory( void *addr, long numBytes )
|
|||
/*************************************************************************/
|
||||
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
|
||||
{
|
||||
PaTimestamp framesDone1;
|
||||
PaTimestamp framesDone2;
|
||||
UInt64 whenIncremented;
|
||||
UnsignedWide now;
|
||||
UInt64 now64;
|
||||
long microsElapsed;
|
||||
long framesElapsed;
|
||||
|
||||
PaHostSoundControl *pahsc;
|
||||
internalPortAudioStream *past = (internalPortAudioStream *) stream;
|
||||
if( past == NULL ) return paBadStreamPtr;
|
||||
pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
|
||||
/* Capture information from audio thread.
|
||||
* We have to be careful that we don't get interrupted in the middle.
|
||||
* So we grab the pahsc_NumFramesDone twice and make sure it didn't change.
|
||||
*/
|
||||
do
|
||||
{
|
||||
framesDone1 = pahsc->pahsc_NumFramesDone;
|
||||
whenIncremented = pahsc->pahsc_WhenFramesDoneIncremented;
|
||||
framesDone2 = pahsc->pahsc_NumFramesDone;
|
||||
} while( framesDone1 != framesDone2 );
|
||||
|
||||
/* Calculate how many microseconds have elapsed and convert to frames. */
|
||||
Microseconds( &now );
|
||||
now64 = UnsignedWideToUInt64( now );
|
||||
microsElapsed = U64Subtract( now64, whenIncremented );
|
||||
framesElapsed = microsElapsed * past->past_SampleRate * 0.000001;
|
||||
|
||||
return framesDone1 + framesElapsed;
|
||||
return pahsc->pahsc_NumFramesDone;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
|
|
@ -1411,8 +1340,7 @@ pascal void PaMac_InputCompletionProc(SPBPtr recParams)
|
|||
*/
|
||||
if(past->past_NumOutputChannels == 0)
|
||||
{
|
||||
SetFramesDone( pahsc,
|
||||
pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
|
||||
pahsc->pahsc_NumFramesDone += pahsc->pahsc_FramesPerHostBuffer; // Advance for recording
|
||||
result = PaMac_CallUserLoop( past, NULL );
|
||||
}
|
||||
|
||||
|
|
@ -1443,7 +1371,6 @@ static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPt
|
|||
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
int16 *inPtr = NULL;
|
||||
int i;
|
||||
|
||||
|
||||
/* Advance read index for sound input FIFO here, independantly of record/write process. */
|
||||
if(past->past_NumInputChannels > 0)
|
||||
|
|
@ -1458,33 +1385,22 @@ static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPt
|
|||
/* Call user code enough times to fill buffer. */
|
||||
if( (inPtr != NULL) || (outPtr != NULL) )
|
||||
{
|
||||
PaMac_StartLoadCalculation( past ); /* CPU usage */
|
||||
StartLoadCalculation( past ); /* CPU usage */
|
||||
|
||||
for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
|
||||
{
|
||||
result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr );
|
||||
if( result != 0)
|
||||
{
|
||||
/* Recording might be in another process, so tell it to stop with a flag. */
|
||||
pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording;
|
||||
break;
|
||||
}
|
||||
/* Advance sample pointers. */
|
||||
if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels;
|
||||
if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
|
||||
}
|
||||
|
||||
#ifdef PA_MAX_USAGE_ALLOWED
|
||||
/* If CPU usage exceeds limit, skip user callback to prevent hanging CPU. */
|
||||
if( past->past_Usage > PA_MAX_USAGE_ALLOWED )
|
||||
{
|
||||
past->past_FrameCount += (PaTimestamp) pahsc->pahsc_FramesPerHostBuffer;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
|
||||
for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
|
||||
{
|
||||
result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr );
|
||||
if( result != 0)
|
||||
{
|
||||
/* Recording might be in another process, so tell it to stop with a flag. */
|
||||
pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording;
|
||||
break;
|
||||
}
|
||||
/* Advance sample pointers. */
|
||||
if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels;
|
||||
if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
|
||||
}
|
||||
}
|
||||
|
||||
PaMac_EndLoadCalculation( past );
|
||||
}
|
||||
return result;
|
||||
|
|
@ -1571,10 +1487,8 @@ static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndComm
|
|||
|
||||
pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
pahsc->pahsc_NumOutsPlayed += 1;
|
||||
pahsc->pahsc_NumFramesDone += pahsc->pahsc_FramesPerHostBuffer;
|
||||
|
||||
SetFramesDone( pahsc,
|
||||
pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
|
||||
|
||||
PaMac_BackgroundManager( past, theCallBackCmd->param1 );
|
||||
}
|
||||
|
||||
|
|
@ -1626,19 +1540,16 @@ static void PaMac_PlayNext ( internalPortAudioStream *past, int index )
|
|||
|
||||
/* If this was the last buffer, or abort requested, then just be done. */
|
||||
if ( past->past_StopSoon ) goto done;
|
||||
|
||||
/* Load buffer with sound. */
|
||||
result = PaMac_FillNextOutputBuffer ( past, index );
|
||||
if( result > 0 ) past->past_StopSoon = 1; /* Stop generating audio but wait until buffers play. */
|
||||
else if( result < 0 ) goto done;
|
||||
|
||||
/* Play the next buffer. */
|
||||
playCmd.cmd = bufferCmd;
|
||||
playCmd.param1 = 0;
|
||||
playCmd.param2 = (long) &pahsc->pahsc_SoundHeaders[ index ];
|
||||
error = SndDoCommand (pahsc->pahsc_Channel, &playCmd, true );
|
||||
if( error != noErr ) goto gotError;
|
||||
|
||||
/* Ask for a callback when it is done. */
|
||||
callbackCmd.cmd = callBackCmd;
|
||||
callbackCmd.param1 = index;
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
Notes on Core Audio Implementation of PortAudio
|
||||
|
||||
by Phil Burk and Darren Gibbs
|
||||
|
||||
Document 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
|
||||
BuiltIn 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
|
|
@ -1,6 +1,5 @@
|
|||
# Make PortAudio for Silicon Graphics IRIX 6.2 - 6.5.
|
||||
# Pieter suurmond, july 4, 2002. (for PA v18.)
|
||||
# Based on SGI-specific sproc()-method to spawn children, not on POSIX-threads.
|
||||
# Make PortAudio for Silicon Graphics IRIX (6.2)
|
||||
# Pieter suurmond, august 17, 2001. (v15 pa_sgi sub-version #0.04)
|
||||
|
||||
# Instead of "-lpthread", as with linux,
|
||||
# just the audio- and math-library for SGI:
|
||||
|
|
@ -15,36 +14,36 @@ CFLAGS = -O2
|
|||
PASRC = ../pa_common/pa_lib.c pa_sgi.c
|
||||
PAINC = ../pa_common/portaudio.h
|
||||
|
||||
# Tests that work (on SGI Indy with R5000 @ 180MHz running IRIX 6.2):
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_record.c # TODO probably ok.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_many.c # v18 ok (with PA_MIN_LATENCY_MSEC=250).
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_latency.c # v18 ok (with PA_MIN_LATENCY_MSEC=250) patest_latency.c contained //
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # v18 ok (with PA_MIN_LATENCY_MSEC=250).
|
||||
|
||||
TESTC = $(PASRC) ../pa_tests/patest_saw.c # v18 ok (with PA_MIN_LATENCY_MSEC=250).
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_wire.c # v18 seems ok.
|
||||
|
||||
#TESTC = $(PASRC) ../pa_tests/pa_devs.c # TODO probably ok.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sine.c # TODO probably ok.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # TODO probably ok.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # TODO probably ok.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # TODO probably ok.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_pink.c # TODO probably ok.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_clip.c # TODO probably ok.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_stop.c # TODO probably ok.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_dither.c # TODO probably ok.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore with v15.
|
||||
|
||||
# Tests that were not yet performed:
|
||||
#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # test??
|
||||
#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # test??
|
||||
#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # test??
|
||||
# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2).
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK
|
||||
TESTC = $(PASRC) ../pa_tests/patest_record.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?).
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore.
|
||||
|
||||
# Tests that do not yet work.
|
||||
#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default
|
||||
#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default
|
||||
#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-(
|
||||
# PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH.
|
||||
# OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON???
|
||||
# HMMM I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS!
|
||||
TESTH = $(PAINC)
|
||||
|
||||
all: patest
|
||||
|
||||
# "cc" for the MIPSpro compiler, may be changed to "gcc":
|
||||
#(cc may be changed to gcc)
|
||||
patest: $(TESTC) $(TESTH) Makefile
|
||||
cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest
|
||||
|
||||
|
|
|
|||
1055
pa_sgi/pa_sgi.c
1055
pa_sgi/pa_sgi.c
File diff suppressed because it is too large
Load diff
|
|
@ -1,52 +0,0 @@
|
|||
# Make PortAudio for Silicon Graphics IRIX (6.2)
|
||||
# Pieter suurmond, september 22, 2001. (v15 pa_sgi sub-version #0.18)
|
||||
|
||||
# pthread, math (as with linux) and SGI audio library:
|
||||
# SGI-books say -lpthread should be the last on the line.
|
||||
LIBS = -lm -laudio -lpthread
|
||||
|
||||
CDEFINES = -I../pa_common
|
||||
|
||||
# Possible CFLAGS with MIPSpro compiler are: -32, -o32, -n32, -64,
|
||||
# -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging.
|
||||
# And use for example -O2 or -O3 for better optimization:
|
||||
CFLAGS = -O2
|
||||
PASRC = ../pa_common/pa_lib.c pa_sgi.c
|
||||
PAINC = ../pa_common/portaudio.h
|
||||
|
||||
# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2).
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_record.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches.
|
||||
TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?).
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore.
|
||||
|
||||
# Tests that do not yet work.
|
||||
#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default
|
||||
#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default
|
||||
#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS FUZZ CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-(
|
||||
# PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH.
|
||||
# OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON???
|
||||
# ANYWAY, I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS!
|
||||
TESTH = $(PAINC)
|
||||
|
||||
all: patest
|
||||
|
||||
# "cc" for the MIPSpro compiler, may be changed to "gcc":
|
||||
patest: $(TESTC) $(TESTH) Makefile
|
||||
cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest
|
||||
|
||||
run: patest
|
||||
./patest
|
||||
|
||||
|
|
@ -1,908 +0,0 @@
|
|||
/*
|
||||
* PortAudio Portable Real-Time Audio Library
|
||||
* Latest Version at: http://www.portaudio.com
|
||||
* SGI IRIX implementation by Pieter Suurmond, september 22, 2001 (#0.18).
|
||||
*
|
||||
* Copyright (c) 1999-2001 Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
Modfication History:
|
||||
8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2.
|
||||
8/17/2001 - alpha release with IRIX sproc()-method, may sometimes let IRIX6.2 crash at closing audiostream.
|
||||
9/22/2001 - #0.18 pthread starts to work a bit:
|
||||
BUT UNDER IRIX6.2, I DON'T GET IT TO WORK REALLY CORRECTLY,
|
||||
this POSIX-attempt,
|
||||
DON'T USE THIS FILE FOR RELIABLE OPERATION, IT IS HERE JUST
|
||||
FOR DOCUMENTATION/ARCHIVE... OR FOR ANYONE WHO WANTS TO FIX......
|
||||
TODO:
|
||||
- Test under IRIX 6.5.
|
||||
- Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion),
|
||||
and maybe also the other natively supported formats? (might increase performance)
|
||||
- Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet,
|
||||
seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?)
|
||||
- The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4.
|
||||
REFERENCES:
|
||||
- IRIX 6.2 man pages regarding SGI AL library.
|
||||
- IRIS Digital MediaProgramming Guide (online books as well as man-pages come with IRIX 6.2 and
|
||||
may not be publically available on the internet).
|
||||
*/
|
||||
|
||||
#include <stdio.h> /* Standard libraries. */
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../pa_common/portaudio.h" /* Portaudio headers. */
|
||||
#include "../pa_common/pa_host.h"
|
||||
#include "../pa_common/pa_trace.h"
|
||||
|
||||
/*
|
||||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
#include <sys/prctl.h> Not needed
|
||||
#include <sys/types.h>
|
||||
#include <sys/schedctl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h> Needed?
|
||||
#include <sys/time.h>
|
||||
#include <sched.h> sched_param struct and related functions
|
||||
used in setting thread priorities.
|
||||
#include <limits.h> Some POSIX constants such as _POSIX_THREAD_THREADS_MAX
|
||||
*/
|
||||
|
||||
#include <pthread.h> /* Pthreads are supported by IRIX 6.2 after */
|
||||
/* patches 1361, 1367, and 1429 are applied. */
|
||||
|
||||
#include <fcntl.h> /* fcntl.h needed for "O_RDONLY". */
|
||||
#include <unistd.h> /* For usleep() and constants used when calling sysconf() */
|
||||
/* to query POSIX limits (see the sysconf(3) ref. page. */
|
||||
|
||||
#include <dmedia/audio.h> /* SGI-specific audio library. */
|
||||
|
||||
|
||||
/*--------------------------------------------*/
|
||||
#define PRINT(x) { printf x; fflush(stdout); }
|
||||
#define ERR_RPT(x) PRINT(x)
|
||||
#define DBUG(x) PRINT(x)
|
||||
#define DBUGX(x) /* PRINT(x) */
|
||||
|
||||
#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */
|
||||
#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */
|
||||
|
||||
typedef struct internalPortAudioDevice /* IRIX specific device info: */
|
||||
{
|
||||
PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */
|
||||
long pad_ALdevice; /* SGI-number! */
|
||||
double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */
|
||||
char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */
|
||||
PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */
|
||||
/* int structVersion; */
|
||||
/* const char* name; */
|
||||
/* int maxInputChannels, maxOutputChannels; */
|
||||
/* int numSampleRates; Num rates, or -1 if range supprtd. */
|
||||
/* const double* sampleRates; Array of supported sample rates, */
|
||||
/* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */
|
||||
struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */
|
||||
} internalPortAudioDevice;
|
||||
|
||||
typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */
|
||||
{
|
||||
ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */
|
||||
pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */
|
||||
pthread_t pahsc_ThreadPID;
|
||||
short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */
|
||||
*pahsc_NativeOutputBuffer;
|
||||
unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */
|
||||
pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */
|
||||
unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */
|
||||
pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */
|
||||
struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */
|
||||
pahsc_LastExitTime;
|
||||
long pahsc_InsideCountSum,
|
||||
pahsc_TotalCountSum;
|
||||
} PaHostSoundControl;
|
||||
|
||||
/*----------------------------- Shared Data ------------------------------------------------------*/
|
||||
static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */
|
||||
static int sPaHostError = 0; /* Maybe more than one process writing errs!? */
|
||||
|
||||
long Pa_GetHostError(void)
|
||||
{
|
||||
return (long)sPaHostError;
|
||||
}
|
||||
|
||||
/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/
|
||||
/* (copied from source pa_linux_oss/pa_linux_oss.c) */
|
||||
static void Pa_StartUsageCalculation( internalPortAudioStream *past )
|
||||
{
|
||||
struct itimerval itimer;
|
||||
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
if( pahsc == NULL ) return;
|
||||
/* Query system timer for usage analysis and to prevent overuse of CPU. */
|
||||
getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime );
|
||||
}
|
||||
|
||||
static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB )
|
||||
{
|
||||
long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec;
|
||||
long usecs = secs * 1000000;
|
||||
usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec);
|
||||
return usecs;
|
||||
}
|
||||
|
||||
static void Pa_EndUsageCalculation( internalPortAudioStream *past )
|
||||
{
|
||||
struct itimerval currentTime;
|
||||
long insideCount;
|
||||
long totalCount; /* Measure CPU utilization during this callback. */
|
||||
|
||||
#define LOWPASS_COEFFICIENT_0 (0.95)
|
||||
#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
|
||||
|
||||
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
if (pahsc == NULL)
|
||||
return;
|
||||
if (getitimer( ITIMER_REAL, ¤tTime ) == 0 )
|
||||
{
|
||||
if (past->past_IfLastExitValid)
|
||||
{
|
||||
insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, ¤tTime );
|
||||
pahsc->pahsc_InsideCountSum += insideCount;
|
||||
totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, ¤tTime );
|
||||
pahsc->pahsc_TotalCountSum += totalCount;
|
||||
/* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */
|
||||
/* Low pass filter the result because sometimes we get called several times in a row. */
|
||||
/* That can cause the TotalCount to be very low which can cause the usage to appear */
|
||||
/* unnaturally high. So we must filter numerator and denominator separately!!! */
|
||||
if (pahsc->pahsc_InsideCountSum > 0)
|
||||
{
|
||||
past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
|
||||
(LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum));
|
||||
past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
|
||||
(LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum));
|
||||
past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
|
||||
pahsc->pahsc_InsideCountSum = 0;
|
||||
pahsc->pahsc_TotalCountSum = 0;
|
||||
}
|
||||
}
|
||||
past->past_IfLastExitValid = 1;
|
||||
}
|
||||
pahsc->pahsc_LastExitTime.it_value.tv_sec = 100;
|
||||
pahsc->pahsc_LastExitTime.it_value.tv_usec = 0;
|
||||
setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL );
|
||||
past->past_IfLastExitValid = 1;
|
||||
} /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------------------*/
|
||||
PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */
|
||||
{ /* call to report via ERR_RPT(), yields a PaError-num. */
|
||||
const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */
|
||||
switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */
|
||||
{
|
||||
case AL_BAD_OUT_OF_MEM:
|
||||
ERR_RPT(("%sout of memory.\n", a));
|
||||
return paInsufficientMemory; /* Known PaError. */
|
||||
case AL_BAD_CONFIG:
|
||||
ERR_RPT(("%sconfiguration invalid or NULL.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_CHANNELS:
|
||||
ERR_RPT(("%schannels not 1,2 or 4.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_NO_PORTS:
|
||||
ERR_RPT(("%sout of audio ports.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_DEVICE:
|
||||
ERR_RPT(("%swrong device number.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_DEVICE_ACCESS:
|
||||
ERR_RPT(("%swrong device access.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_DIRECTION:
|
||||
ERR_RPT(("%sinvalid direction.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_SAMPFMT:
|
||||
ERR_RPT(("%sdoesn't accept sampleformat.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_FLOATMAX:
|
||||
ERR_RPT(("%smax float value is zero.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_WIDTH:
|
||||
ERR_RPT(("%sunsupported samplewidth.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_QSIZE:
|
||||
ERR_RPT(("%sinvalid queue size.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_PVBUFFER:
|
||||
ERR_RPT(("%sPVbuffer null.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_BUFFERLENGTH_NEG:
|
||||
ERR_RPT(("%snegative bufferlength.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_BUFFERLENGTH_ODD:
|
||||
ERR_RPT(("%sodd bufferlength.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
case AL_BAD_PARAM:
|
||||
ERR_RPT(("%sparameter not valid for device.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
default:
|
||||
ERR_RPT(("%sunknown error.\n", a));
|
||||
return paHostError; /* Generic PaError. */
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------------------*/
|
||||
/* Tries to set various rates and formats and fill in the device info structure. */
|
||||
static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */
|
||||
PaDeviceID id, /* (DefaultI|ODeviceID()) */
|
||||
char* name, /* (for example "SGI AL") */
|
||||
internalPortAudioDevice* pad) /* Result written to pad. */
|
||||
{
|
||||
int format;
|
||||
long min, max; /* To catch hardware characteristics. */
|
||||
ALseterrorhandler(0); /* 0 = turn off the default error handler. */
|
||||
/*--------------------------------------------------------------------------------------*/
|
||||
pad->pad_ALdevice = ALdev; /* Set the AL device number. */
|
||||
pad->pad_DeviceID = id; /* Set the PA device number. */
|
||||
if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */
|
||||
{
|
||||
ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name));
|
||||
return paHostError;
|
||||
}
|
||||
strcpy(pad->pad_DeviceName, name); /* Write name-string. */
|
||||
pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */
|
||||
/*--------------------------------- natively supported sample formats: -----------------*/
|
||||
pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */
|
||||
/* Then also choose other CallConvertXX()! */
|
||||
/*--------------------------------- number of available i/o channels: ------------------*/
|
||||
if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max))
|
||||
return translateSGIerror();
|
||||
pad->pad_Info.maxInputChannels = max;
|
||||
DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels))
|
||||
if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max))
|
||||
return translateSGIerror();
|
||||
pad->pad_Info.maxOutputChannels = max;
|
||||
DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels))
|
||||
/*--------------------------------- supported samplerates: ----------------------*/
|
||||
pad->pad_Info.numSampleRates = 7;
|
||||
pad->pad_Info.sampleRates = pad->pad_SampleRates;
|
||||
pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */
|
||||
pad->pad_SampleRates[1] = (double)AL_RATE_11025;
|
||||
pad->pad_SampleRates[2] = (double)AL_RATE_16000;
|
||||
pad->pad_SampleRates[3] = (double)AL_RATE_22050;
|
||||
pad->pad_SampleRates[4] = (double)AL_RATE_32000;
|
||||
pad->pad_SampleRates[5] = (double)AL_RATE_44100;
|
||||
pad->pad_SampleRates[6] = (double)AL_RATE_48000;
|
||||
if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */
|
||||
return translateSGIerror(); /* double -> long. */
|
||||
if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */
|
||||
goto weird;
|
||||
if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */
|
||||
return translateSGIerror();
|
||||
if (max != (long)(0.5 + pad->pad_SampleRates[6]))
|
||||
{
|
||||
weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max));
|
||||
return paHostError; /* Or make it a warning and just carry on... */
|
||||
}
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------------*/
|
||||
int Pa_CountDevices() /* Name of this function suggests it only counts and */
|
||||
{ /* is NOT destructive, it however resets whole PA ! */
|
||||
int numDevices = 0; /* Let 's not do that here. */
|
||||
internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */
|
||||
#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */
|
||||
if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */
|
||||
Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */
|
||||
#endif /* friendly to clients that forgot to initialize PA. */
|
||||
while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */
|
||||
{
|
||||
numDevices++;
|
||||
currentDevice = currentDevice->pad_Next;
|
||||
}
|
||||
return numDevices;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id)
|
||||
{
|
||||
int numDevices = 0;
|
||||
internalPortAudioDevice *res = (internalPortAudioDevice*)NULL;
|
||||
internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */
|
||||
while (pad) /* pad may be NULL, that's ok, return 0. */
|
||||
{ /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */
|
||||
if (pad->pad_DeviceID == id) /* This the device we were looking for? */
|
||||
res = pad; /* But keep on(!) counting so we don't */
|
||||
numDevices++; /* have to call Pa_CountDevices() later. */
|
||||
pad = pad->pad_Next; /* Advance to the next device or NULL. */
|
||||
} /* No assumptions about order of ID's in */
|
||||
if (!res) /* the list. */
|
||||
ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id));
|
||||
if ((id < 0) || (id >= numDevices))
|
||||
{
|
||||
ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id));
|
||||
#if 1 /* Be strict, even when found, */
|
||||
res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */
|
||||
#endif
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------*/
|
||||
const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id)
|
||||
{
|
||||
PaDeviceInfo* res = (PaDeviceInfo*)NULL;
|
||||
internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */
|
||||
if (pad)
|
||||
res = &pad->pad_Info; /* Not finding the specified ID is not */
|
||||
if (!res) /* the same as &pad->pad_Info == NULL. */
|
||||
ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id));
|
||||
return res; /* So (maybe) a second/third ERR_RPT(). */
|
||||
}
|
||||
|
||||
/*------------------------------------------------*/
|
||||
PaDeviceID Pa_GetDefaultInputDeviceID(void)
|
||||
{
|
||||
return 0; /* 0 is the default device ID. */
|
||||
}
|
||||
/*------------------------------------------------*/
|
||||
PaDeviceID Pa_GetDefaultOutputDeviceID(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------------------------------*/
|
||||
/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */
|
||||
PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */
|
||||
{
|
||||
internalPortAudioDevice* pad;
|
||||
PaError r = paNoError;
|
||||
int audioLibFileID; /* To test for the presence of audio. */
|
||||
|
||||
if (sDeviceList) /* Allow re-init, only warn, no error. */
|
||||
{
|
||||
ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n"));
|
||||
return r;
|
||||
}
|
||||
/*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/
|
||||
audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */
|
||||
if (audioLibFileID < 0) /* IO port. On failure, machine */
|
||||
{ /* has no audio ability. */
|
||||
ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n"));
|
||||
return paHostError;
|
||||
}
|
||||
close(audioLibFileID); /* Allocate fast mem to hold device info. */
|
||||
pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice));
|
||||
if (pad == NULL)
|
||||
return paInsufficientMemory;
|
||||
memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */
|
||||
r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */
|
||||
Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */
|
||||
"AL default", /* A suitable name. */
|
||||
pad); /* Write args and queried info into pad. */
|
||||
if (r != paNoError)
|
||||
{
|
||||
ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r));
|
||||
PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */
|
||||
}
|
||||
else
|
||||
sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */
|
||||
/*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/
|
||||
/*---------------------------------------------------------------------------------------------*/
|
||||
return r;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------------------------*/
|
||||
static PaError Pa_SgiAudioProcess(internalPortAudioStream *past) /* Spawned by PaHost_StartEngine(). */
|
||||
{
|
||||
PaError result = paNoError;
|
||||
PaHostSoundControl *pahsc;
|
||||
|
||||
if (!past)
|
||||
return paBadStreamPtr;
|
||||
pahsc = (PaHostSoundControl*)past->past_DeviceData;
|
||||
if (!pahsc)
|
||||
return paInternalError;
|
||||
past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */
|
||||
DBUG(("entering thread.\n"));
|
||||
|
||||
while (!past->past_StopSoon) /* OR-ing StopSoon and StopNow here gives problems! */
|
||||
{
|
||||
/*---------------------------------------- INPUT: ------------------------------------*/
|
||||
if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */
|
||||
{
|
||||
while (ALgetfilled(pahsc->pahsc_ALportIN) < pahsc->pahsc_SamplesPerInputBuffer)
|
||||
{
|
||||
/* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */
|
||||
if (past->past_StopNow) /* Don't let ALreadsamps() block */
|
||||
goto done;
|
||||
}
|
||||
if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer,
|
||||
pahsc->pahsc_SamplesPerInputBuffer)) /* Number of samples instead */
|
||||
{ /* of number of frames. */
|
||||
ERR_RPT(("ALreadsamps() failed.\n"));
|
||||
result = paInternalError;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------- USER CALLBACK ROUTINE: ----------*/
|
||||
/* DBUG(("Calling Pa_CallConvertInt16()...\n")); */
|
||||
Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */
|
||||
result = Pa_CallConvertInt16(past, /* user data and call user routine. */
|
||||
pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_NativeOutputBuffer);
|
||||
Pa_EndUsageCalculation(past);
|
||||
if (result)
|
||||
{
|
||||
DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result));
|
||||
goto done; /* This is apparently NOT an error! */
|
||||
} /* Just letting the userCallBack stop us. */
|
||||
/*---------------------------------------- OUTPUT: ------------------------------------*/
|
||||
if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */
|
||||
{
|
||||
while (ALgetfillable(pahsc->pahsc_ALportOUT) < pahsc->pahsc_SamplesPerOutputBuffer)
|
||||
{
|
||||
/* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */
|
||||
if (past->past_StopNow) /* Don't let ALwritesamps() block */
|
||||
goto done;
|
||||
}
|
||||
if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer,
|
||||
pahsc->pahsc_SamplesPerOutputBuffer))
|
||||
{
|
||||
ERR_RPT(("ALwritesamps() failed.\n"));
|
||||
result = paInternalError;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/*-------------------------------------------------------------------------------------*/
|
||||
}
|
||||
done:
|
||||
/* pahsc->pahsc_ThreadPID = -1; Hu? doesn't help!! (added by Pieter) */
|
||||
past->past_IsActive = 0;
|
||||
DBUG(("leaving thread.\n"));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------------------*/
|
||||
PaError PaHost_OpenStream(internalPortAudioStream *past)
|
||||
{
|
||||
PaError result = paNoError;
|
||||
PaHostSoundControl *pahsc;
|
||||
unsigned int minNumBuffers;
|
||||
internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */
|
||||
ALconfig sgiALconfig = NULL; /* IRIX-datatype. */
|
||||
long pvbuf[8]; /* To get/set hardware configs. */
|
||||
long sr, ALqsize;
|
||||
DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */
|
||||
if (!past)
|
||||
{
|
||||
ERR_RPT(("Streampointer NULL!\n"));
|
||||
result = paBadStreamPtr; goto done;
|
||||
}
|
||||
pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
|
||||
if (pahsc == NULL)
|
||||
{
|
||||
ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */
|
||||
result = paInsufficientMemory; goto done; /* code (nothing will be freed). */
|
||||
}
|
||||
memset(pahsc, 0, sizeof(PaHostSoundControl));
|
||||
/* pahsc->pahsc_threadPID = -1; Should pahsc_threadPID be inited to */
|
||||
past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */
|
||||
/*--------------------------------------------------- Allocate native buffers: --------*/
|
||||
pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */
|
||||
past->past_NumInputChannels; /* audio-thread. */
|
||||
pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short);
|
||||
if (past->past_NumInputChannels > 0) /* Assumes short = 16 bits! */
|
||||
{
|
||||
pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer);
|
||||
if( pahsc->pahsc_NativeInputBuffer == NULL )
|
||||
{
|
||||
ERR_RPT(("Fast memory allocation for input-buffer failed.\n"));
|
||||
result = paInsufficientMemory; goto done;
|
||||
}
|
||||
}
|
||||
pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */
|
||||
past->past_NumOutputChannels; /* audio-thread. */
|
||||
pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short);
|
||||
if (past->past_NumOutputChannels > 0) /* Assumes short = 16 bits! */
|
||||
{
|
||||
pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer);
|
||||
if (pahsc->pahsc_NativeOutputBuffer == NULL)
|
||||
{
|
||||
ERR_RPT(("Fast memory allocation for output-buffer failed.\n"));
|
||||
result = paInsufficientMemory; goto done;
|
||||
}
|
||||
}
|
||||
/*------------------------------------------ Manipulate hardware if necessary and allowed: --*/
|
||||
ALseterrorhandler(0); /* 0 = turn off the default error handler. */
|
||||
pvbuf[0] = AL_INPUT_RATE;
|
||||
pvbuf[2] = AL_INPUT_COUNT;
|
||||
pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */
|
||||
pvbuf[6] = AL_OUTPUT_COUNT;
|
||||
sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */
|
||||
if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */
|
||||
{ /* sponding native AL-number(s). */
|
||||
padIN = Pa_GetInternalDevice(past->past_InputDeviceID);
|
||||
if (!padIN)
|
||||
{
|
||||
ERR_RPT(("Pa_GetInternalDevice() for input failed.\n"));
|
||||
result = paHostError; goto done;
|
||||
}
|
||||
if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */
|
||||
goto sgiError; /* the same AL-device, the AL-library might */
|
||||
if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */
|
||||
{ /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */
|
||||
if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */
|
||||
{
|
||||
ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \
|
||||
another process is currently using input at %ld kHz.\n", sr, pvbuf[1]));
|
||||
result = paHostError; goto done;
|
||||
}
|
||||
pvbuf[1] = sr; /* Then set input-rate. */
|
||||
if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2))
|
||||
goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */
|
||||
} /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */
|
||||
}
|
||||
if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */
|
||||
{ /* We use padOUT/IN later on, or at least 1 of both. */
|
||||
padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID);
|
||||
if (!padOUT)
|
||||
{
|
||||
ERR_RPT(("Pa_GetInternalDevice() for output failed.\n"));
|
||||
result = paHostError; goto done;
|
||||
}
|
||||
if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4))
|
||||
goto sgiError;
|
||||
if ((past->past_NumOutputChannels > 0) && (pvbuf[5] != sr))
|
||||
{ /* Output needed and rate different from current harware-rate. */
|
||||
if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */
|
||||
{
|
||||
ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \
|
||||
another process is currently using output at %ld kHz.\n", sr, pvbuf[5]));
|
||||
result = paHostError; goto done; /* Will free again the inputbuffer */
|
||||
} /* that was just created above. */
|
||||
pvbuf[5] = sr; /* Then set output-rate. */
|
||||
if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2))
|
||||
goto sgiError;
|
||||
}
|
||||
}
|
||||
/*------------------------------------------ Construct an audio-port-configuration ----------*/
|
||||
sgiALconfig = ALnewconfig(); /* Change the SGI-AL-default-settings. */
|
||||
if (sgiALconfig == (ALconfig)0) /* sgiALconfig is released here after use! */
|
||||
goto sgiError; /* See that sgiALconfig is NOT released! */
|
||||
if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */
|
||||
goto sgiError;
|
||||
if (ALsetwidth (sgiALconfig, AL_SAMPLE_16)) /* Only meaningful when sample format for */
|
||||
goto sgiError; /* config is set to two's complement format. */
|
||||
/************************ Future versions might (dynamically) switch to 32-bit floats? *******
|
||||
if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.)
|
||||
goto sgiError;
|
||||
if (ALsetfloatmax (sgiALconfig, 1.0)) Only meaningful when sample format for config
|
||||
goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */
|
||||
/*---------- ?? --------------------*/
|
||||
/* DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); */
|
||||
minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, past->past_SampleRate);
|
||||
past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ?
|
||||
minNumBuffers : past->past_NumUserBuffers;
|
||||
/*------------------------------------------------ Set internal AL queuesize (in samples) ----*/
|
||||
if (pahsc->pahsc_SamplesPerInputBuffer >= pahsc->pahsc_SamplesPerOutputBuffer)
|
||||
ALqsize = (long)pahsc->pahsc_SamplesPerInputBuffer;
|
||||
else /* Take the largest of the two amounts. */
|
||||
ALqsize = (long)pahsc->pahsc_SamplesPerOutputBuffer;
|
||||
ALqsize *= 4; /* 4 times as large as amount per transfer! */
|
||||
if (ALsetqueuesize(sgiALconfig, ALqsize)) /* Or should we use past_NumUserBuffers here? */
|
||||
goto sgiError; /* Using 2 times may give glitches... */
|
||||
/* Have to work on ALsetqueuesize() above. */
|
||||
|
||||
/* Do ALsetchannels() later, apart per input and/or output. */
|
||||
/*----------------------------------------------- OPEN 1 OR 2 AL-DEVICES: --------------------*/
|
||||
if (past->past_OutputDeviceID == past->past_InputDeviceID) /* Who SETS these devive-numbers? */
|
||||
{
|
||||
if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0))
|
||||
{
|
||||
DBUG(("PaHost_OpenStream: opening both input and output channels.\n"));
|
||||
/*------------------------- open output port: ----------------------------------*/
|
||||
if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels)))
|
||||
goto sgiError; /* Returns 0 on success, -1 on failure. */
|
||||
pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig);
|
||||
if (pahsc->pahsc_ALportOUT == (ALport)0)
|
||||
goto sgiError;
|
||||
/*------------------------- open input port: -----------------------------------*/
|
||||
if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels)))
|
||||
goto sgiError; /* Returns 0 on success, -1 on failure. */
|
||||
pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig);
|
||||
if (pahsc->pahsc_ALportIN == (ALport)0)
|
||||
goto sgiError; /* For some reason the "patest_wire.c"-test crashes! */
|
||||
} /* Probably due to too small buffersizes?.... */
|
||||
else
|
||||
{
|
||||
ERR_RPT(("Cannot setup bidirectional stream between different devices.\n"));
|
||||
result = paHostError;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else /* (OutputDeviceID != InputDeviceID) */
|
||||
{
|
||||
if (past->past_NumOutputChannels > 0) /* WRITE-ONLY: */
|
||||
{
|
||||
/*------------------------- open output port: ----------------------------------*/
|
||||
DBUG(("PaHost_OpenStream: opening %d output channel(s) on %s.\n",
|
||||
past->past_NumOutputChannels, padOUT->pad_DeviceName));
|
||||
if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels)))
|
||||
goto sgiError; /* Returns 0 on success, -1 on failure. */
|
||||
pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig);
|
||||
if (pahsc->pahsc_ALportOUT == (ALport)0)
|
||||
goto sgiError;
|
||||
}
|
||||
if (past->past_NumInputChannels > 0) /* READ-ONLY: */
|
||||
{
|
||||
/*------------------------- open input port: -----------------------------------*/
|
||||
DBUG(("PaHost_OpenStream: opening %d input channel(s) on %s.\n",
|
||||
past->past_NumInputChannels, padIN->pad_DeviceName));
|
||||
if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels)))
|
||||
goto sgiError; /* Returns 0 on success, -1 on failure. */
|
||||
pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig);
|
||||
if (pahsc->pahsc_ALportIN == (ALport)0)
|
||||
goto sgiError;
|
||||
}
|
||||
}
|
||||
DBUG(("PaHost_OpenStream() succeeded.\n"));
|
||||
goto done; /* (no errors occured) */
|
||||
sgiError:
|
||||
result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
|
||||
done:
|
||||
if (sgiALconfig)
|
||||
ALfreeconfig(sgiALconfig); /* We don't need that struct anymore. */
|
||||
if (result != paNoError)
|
||||
PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */
|
||||
return result;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*/
|
||||
PaError PaHost_StartOutput(internalPortAudioStream *past)
|
||||
{
|
||||
return paNoError; /* Hmm, not implemented yet? */
|
||||
}
|
||||
PaError PaHost_StartInput(internalPortAudioStream *past)
|
||||
{
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
PaError PaHost_StartEngine(internalPortAudioStream *past)
|
||||
{
|
||||
PaHostSoundControl *pahsc;
|
||||
int hres;
|
||||
PaError result = paNoError;
|
||||
|
||||
if (!past) /* Test argument. */
|
||||
{
|
||||
ERR_RPT(("PaHost_StartEngine(NULL)!\n"));
|
||||
return paBadStreamPtr;
|
||||
}
|
||||
pahsc = (PaHostSoundControl*)past->past_DeviceData;
|
||||
if (!pahsc)
|
||||
{
|
||||
ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData == NULL!\n"));
|
||||
return paHostError;
|
||||
}
|
||||
past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */
|
||||
past->past_StopNow = 0;
|
||||
past->past_IsActive = 1;
|
||||
DBUG(("PaHost_StartEngine() called.\n"));
|
||||
/* Use pthread_create() instead of __clone() because: */
|
||||
/* - pthread_create also works for other UNIX systems like Solaris, */
|
||||
/* - Java HotSpot VM crashes in pthread_setcanceltype() when using __clone(). */
|
||||
hres = pthread_create(&(pahsc->pahsc_ThreadPID), /* SPAWN AUDIO-CHILD. */
|
||||
NULL, /* pthread_attr_t * attr */
|
||||
(void*)Pa_SgiAudioProcess,
|
||||
past);
|
||||
if (hres)
|
||||
{
|
||||
result = paHostError;
|
||||
sPaHostError = hres;
|
||||
ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n"));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
PaError PaHost_StopEngine(internalPortAudioStream *past, int abort)
|
||||
{
|
||||
int hres;
|
||||
PaError result = paNoError;
|
||||
PaHostSoundControl *pahsc;
|
||||
|
||||
DBUG(("PaHost_StopEngine() called.\n"));
|
||||
if (!past)
|
||||
return paBadStreamPtr;
|
||||
pahsc = (PaHostSoundControl*)past->past_DeviceData;
|
||||
if (pahsc == NULL)
|
||||
return result; /* paNoError (already stopped, no err?). */
|
||||
past->past_StopSoon = 1; /* Tell background thread to stop generating */
|
||||
if (abort) /* more and to let current data play out. If */
|
||||
past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */
|
||||
if (pahsc->pahsc_ThreadPID != -1) /* Join thread to recover memory resources. */
|
||||
{
|
||||
DBUG(("pthread_join() called.\n"));
|
||||
hres = pthread_join(pahsc->pahsc_ThreadPID, NULL);
|
||||
if (hres)
|
||||
{
|
||||
result = paHostError;
|
||||
sPaHostError = hres;
|
||||
ERR_RPT(("PaHost_StopEngine() failed pthread_join().\n"));
|
||||
}
|
||||
pahsc->pahsc_ThreadPID = -1;
|
||||
}
|
||||
past->past_IsActive = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
PaError PaHost_StopOutput(internalPortAudioStream *past, int abort)
|
||||
{
|
||||
return paNoError; /* Not implemented yet? */
|
||||
}
|
||||
PaError PaHost_StopInput(internalPortAudioStream *past, int abort )
|
||||
{
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
PaError PaHost_CloseStream(internalPortAudioStream *past)
|
||||
{
|
||||
PaHostSoundControl *pahsc;
|
||||
PaError result = paNoError;
|
||||
|
||||
DBUG(("PaHost_CloseStream() called.\n"));
|
||||
if (past == NULL)
|
||||
return paBadStreamPtr;
|
||||
pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
if (pahsc == NULL) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */
|
||||
return result; /* This test prevents from freeing NULL-pointers. */
|
||||
|
||||
if (pahsc->pahsc_ALportIN)
|
||||
{
|
||||
if (ALcloseport(pahsc->pahsc_ALportIN))
|
||||
result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
|
||||
else /* But go on anyway... to release other stuff... */
|
||||
pahsc->pahsc_ALportIN = (ALport)0;
|
||||
}
|
||||
if (pahsc->pahsc_ALportOUT)
|
||||
{
|
||||
if (ALcloseport(pahsc->pahsc_ALportOUT))
|
||||
result = translateSGIerror();
|
||||
else
|
||||
pahsc->pahsc_ALportOUT = (ALport)0;
|
||||
}
|
||||
if (pahsc->pahsc_NativeInputBuffer)
|
||||
{
|
||||
PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer);
|
||||
pahsc->pahsc_NativeInputBuffer = NULL;
|
||||
}
|
||||
if (pahsc->pahsc_NativeOutputBuffer)
|
||||
{
|
||||
PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer);
|
||||
pahsc->pahsc_NativeOutputBuffer = NULL;
|
||||
}
|
||||
PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl));
|
||||
past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST. */
|
||||
return result;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
** Determine minimum number of buffers required for this host based
|
||||
** on minimum latency. Latency can be optionally set by user by setting
|
||||
** an environment variable. For example, to set latency to 200 msec, put:
|
||||
** set PA_MIN_LATENCY_MSEC=200
|
||||
** in the AUTOEXEC.BAT file and reboot.
|
||||
** If the environment variable is not set, then the latency will be
|
||||
** determined based on the OS. Windows NT has higher latency than Win95.
|
||||
*/
|
||||
#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
|
||||
|
||||
int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */
|
||||
/* Do we HAVE to do it this way under IRIX???.... */
|
||||
/*--------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */
|
||||
{ /* Called by Pa_Terminate() from pa_lib.c. */
|
||||
internalPortAudioDevice *pad = sDeviceList,
|
||||
*nxt;
|
||||
while (pad)
|
||||
{
|
||||
DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName));
|
||||
nxt = pad->pad_Next;
|
||||
PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice));
|
||||
pad = nxt; /* PaHost_Init allocated this FAST MEM.*/
|
||||
}
|
||||
sDeviceList = (internalPortAudioDevice*)NULL;
|
||||
return 0; /* Got rid of sNumDevices=0; */
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */
|
||||
{
|
||||
#if 0
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = msec / 1000;
|
||||
timeout.tv_usec = (msec % 1000) * 1000;
|
||||
select(0, NULL, NULL, NULL, &timeout);
|
||||
#else
|
||||
long usecs = msec * 1000;
|
||||
usleep( usecs );
|
||||
#endif
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------------*/
|
||||
/* Allocate memory that can be accessed in real-time. This may need to be held in physi- */
|
||||
/* cal memory so that it is not paged to virtual memory. This call MUST be balanced with */
|
||||
/* a call to PaHost_FreeFastMemory(). */
|
||||
void *PaHost_AllocateFastMemory(long numBytes)
|
||||
{
|
||||
void *addr = malloc(numBytes);
|
||||
if (addr)
|
||||
memset(addr, 0, numBytes);
|
||||
return addr;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------------------*/
|
||||
/* Free memory that could be accessed in real-time. This call MUST be balanced with a */
|
||||
/* call to PaHost_AllocateFastMemory(). */
|
||||
void PaHost_FreeFastMemory(void *addr, long numBytes)
|
||||
{
|
||||
if (addr)
|
||||
free(addr);
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------*/
|
||||
PaError PaHost_StreamActive (internalPortAudioStream *past)
|
||||
{
|
||||
PaHostSoundControl *pahsc;
|
||||
if (past == NULL)
|
||||
return paBadStreamPtr;
|
||||
pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
if (pahsc == NULL)
|
||||
return paInternalError;
|
||||
return (PaError)(past->past_IsActive != 0);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
|
||||
{
|
||||
internalPortAudioStream *past = (internalPortAudioStream *) stream;
|
||||
/* FIXME - return actual frames played, not frames generated.
|
||||
** Need to query the output device somehow.
|
||||
*/
|
||||
return past->past_FrameCount;
|
||||
}
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
* Convert tagged values.
|
||||
*
|
||||
* Author: Phil Burk <philburk@softsynth.com>
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
|
||||
//#define OUTPUT_DEVICE (11)
|
||||
#define NUM_SECONDS (8)
|
||||
#define SLEEP_DUR (800)
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
|
||||
#define NUM_BUFFERS (0)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int framesToGo;
|
||||
}
|
||||
paTestData;
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
*/
|
||||
static int patestCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
short *out = (short*)outputBuffer;
|
||||
int i;
|
||||
int finished = 0;
|
||||
(void) outTime; /* Prevent unused variable warnings. */
|
||||
(void) inputBuffer;
|
||||
|
||||
if( data->framesToGo < framesPerBuffer ) finished = 1;
|
||||
|
||||
for( i=0; i<framesPerBuffer; i++ )
|
||||
{
|
||||
*out++ = 0x0000 + i; /* left */
|
||||
*out++ = 0x1000 + i; /* right */
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
paTestData data;
|
||||
int i;
|
||||
int totalSamps;
|
||||
printf("PortAudio Test: output debug values\n" );
|
||||
data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
|
||||
printf("totalSamps = %d\n", totalSamps );
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE );
|
||||
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice,
|
||||
0, /* no input */
|
||||
paFloat32, /* 32 bit floating point input */
|
||||
NULL,
|
||||
OUTPUT_DEVICE,
|
||||
2, /* stereo output */
|
||||
paInt16, /* 32 bit floating point output */
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER,
|
||||
NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
patestCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
printf("Is callback being called?\n");
|
||||
for( i=0; i<((NUM_SECONDS+1)*1000); i+=SLEEP_DUR )
|
||||
{
|
||||
printf("data.framesToGo = %d\n", data.framesToGo ); fflush(stdout);
|
||||
Pa_Sleep( SLEEP_DUR );
|
||||
}
|
||||
/* Stop sound until ENTER hit. */
|
||||
printf("Call Pa_StopStream()\n");
|
||||
err = Pa_StopStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
Pa_Terminate();
|
||||
printf("Test finished.\n");
|
||||
return err;
|
||||
error:
|
||||
Pa_Terminate();
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
fprintf( stderr, "Error number: %d\n", err );
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
* Test Dither calculations.
|
||||
*
|
||||
* Author: Phil Burk http://www.softsynth.com
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
#include "pa_host.h"
|
||||
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
long max,min;
|
||||
int i;
|
||||
|
||||
for( i=0; i<10000; i++ )
|
||||
{
|
||||
long dither = PaConvert_TriangularDither();
|
||||
// printf("dither = 0x%08X\n", dither );
|
||||
if( dither < min ) min = dither;
|
||||
else if( dither > max ) max = dither;
|
||||
}
|
||||
printf("min = 0x%08X = %d, max = 0x%08X = %d\n", min, min, max, max );
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
/*
|
||||
* $Id$
|
||||
* debug_multi_out.c
|
||||
* Play a different sine wave on each channels,
|
||||
* debug_multi.c
|
||||
* Play a sine wave on each of multiple channels,
|
||||
* using the Portable Audio api.
|
||||
* Hacked test for debugging PA.
|
||||
*
|
||||
* Author: Phil Burk http://www.softsynth.com
|
||||
*
|
||||
|
|
@ -37,24 +38,28 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
|
||||
#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
|
||||
#define NUM_CHANNELS (8)
|
||||
// #define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
|
||||
#define OUTPUT_DEVICE (18)
|
||||
#define NUM_SECONDS (NUM_CHANNELS*4)
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_CHANNEL (SAMPLE_RATE/2)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
#define FREQ_INCR (300.0 / SAMPLE_RATE)
|
||||
#define MAX_CHANNELS (64)
|
||||
|
||||
#define MIN_LATENCY_MSEC (400)
|
||||
#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265)
|
||||
#endif
|
||||
|
||||
#define TABLE_SIZE (800)
|
||||
typedef struct
|
||||
{
|
||||
int numChannels;
|
||||
double phases[MAX_CHANNELS];
|
||||
float sine[TABLE_SIZE];
|
||||
int phase;
|
||||
int liveChannel;
|
||||
int count;
|
||||
unsigned int sampsToGo;
|
||||
}
|
||||
paTestData;
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
|
|
@ -65,25 +70,38 @@ static int patestCallback( void *inputBuffer, void *outputBuffer,
|
|||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
float *out = (float*)outputBuffer;
|
||||
int frameIndex, channelIndex;
|
||||
int i, j;
|
||||
int finished = 0;
|
||||
(void) outTime; /* Prevent unused variable warnings. */
|
||||
(void) inputBuffer;
|
||||
|
||||
for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
|
||||
if( data->sampsToGo < framesPerBuffer )
|
||||
{
|
||||
for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
|
||||
{
|
||||
/* Output sine wave on every channel. */
|
||||
*out++ = (float) sin(data->phases[channelIndex]);
|
||||
|
||||
/* Play each channel at a higher frequency. */
|
||||
data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
|
||||
if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
|
||||
}
|
||||
finished = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
for( i=0; i<(int)framesPerBuffer; i++ )
|
||||
{
|
||||
for( j=0; j<NUM_CHANNELS; j++ )
|
||||
{
|
||||
/* Output sine wave only on live channel. */
|
||||
*out++ = (j==data->liveChannel) ? data->sine[data->phase] : 0.0f;
|
||||
/* Play each channel at a higher frequency. */
|
||||
data->phase += 1 + data->liveChannel;
|
||||
if( data->phase >= TABLE_SIZE ) data->phase -= TABLE_SIZE;
|
||||
}
|
||||
/* Switch channels every so often. */
|
||||
if( --data->count <= 0 )
|
||||
{
|
||||
data->count = FRAMES_PER_CHANNEL;
|
||||
data->liveChannel += 1;
|
||||
if( data->liveChannel >= NUM_CHANNELS ) data->liveChannel = 0;
|
||||
}
|
||||
}
|
||||
data->sampsToGo -= framesPerBuffer;
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
|
|
@ -91,18 +109,21 @@ int main(void)
|
|||
{
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
const PaDeviceInfo *pdi;
|
||||
paTestData data = {0};
|
||||
printf("PortAudio Test: output sine wave on each channel.\n" );
|
||||
|
||||
paTestData data;
|
||||
int i;
|
||||
int totalSamps;
|
||||
printf("PortAudio Test: output sine wave. %d buffers\n", NUM_BUFFERS );
|
||||
/* initialise sinusoidal wavetable */
|
||||
for( i=0; i<TABLE_SIZE; i++ )
|
||||
{
|
||||
data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
|
||||
}
|
||||
data.phase = 0;
|
||||
data.count = FRAMES_PER_CHANNEL;
|
||||
data.liveChannel = 0;
|
||||
data.sampsToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE );
|
||||
data.numChannels = pdi->maxOutputChannels;
|
||||
if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS;
|
||||
printf("Number of Channels = %d\n", data.numChannels );
|
||||
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice, /* default input device */
|
||||
|
|
@ -110,27 +131,27 @@ int main(void)
|
|||
paFloat32, /* 32 bit floating point input */
|
||||
NULL,
|
||||
OUTPUT_DEVICE,
|
||||
data.numChannels,
|
||||
NUM_CHANNELS,
|
||||
paFloat32, /* 32 bit floating point output */
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
patestCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Hit ENTER to stop sound.\n");
|
||||
fflush(stdout);
|
||||
getchar();
|
||||
|
||||
printf("Is callback being called?\n");
|
||||
for( i=0; i<NUM_SECONDS; i++ )
|
||||
{
|
||||
printf("data.sampsToGo = %d\n", data.sampsToGo );
|
||||
Pa_Sleep( 1000 );
|
||||
}
|
||||
/* Stop sound until ENTER hit. */
|
||||
err = Pa_StopStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
Pa_CloseStream( stream );
|
||||
Pa_Terminate();
|
||||
printf("Test finished.\n");
|
||||
|
|
|
|||
|
|
@ -42,23 +42,20 @@
|
|||
#define SAMPLE_RATE (22050)
|
||||
#define NUM_SECONDS (10)
|
||||
#define SLEEP_DUR_MSEC (200)
|
||||
#define FRAMES_PER_BUFFER (1<<10)
|
||||
#define REC_BUF_FRAMES (1<<10)
|
||||
#define NUM_REC_BUFS (0)
|
||||
|
||||
#if 1
|
||||
#if 0
|
||||
#define PA_SAMPLE_TYPE paFloat32
|
||||
typedef float SAMPLE;
|
||||
#else
|
||||
#define PA_SAMPLE_TYPE paInt16
|
||||
typedef short SAMPLE;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long frameIndex; /* Index into sample array. */
|
||||
long maxFrameIndex;
|
||||
long samplesPerFrame;
|
||||
long numSamples;
|
||||
SAMPLE *recordedSamples;
|
||||
}
|
||||
paTestData;
|
||||
|
|
@ -156,19 +153,41 @@ static int playCallback( void *inputBuffer, void *outputBuffer,
|
|||
}
|
||||
return finished;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
PaError TestRecording( paTestData *dataPtr )
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
int i;
|
||||
paTestData data;
|
||||
long totalFrames;
|
||||
long numSamples;
|
||||
long numBytes;
|
||||
long i;
|
||||
printf("patest_record.c\n"); fflush(stdout);
|
||||
|
||||
data.frameIndex = 0;
|
||||
data.samplesPerFrame = 2;
|
||||
data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE;
|
||||
|
||||
printf("totalFrames = %d\n", totalFrames ); fflush(stdout);
|
||||
numSamples = totalFrames * data.samplesPerFrame;
|
||||
numBytes = numSamples * sizeof(SAMPLE);
|
||||
data.recordedSamples = (SAMPLE *) malloc( numBytes );
|
||||
if( data.recordedSamples == NULL )
|
||||
{
|
||||
printf("Could not allocate record array.\n");
|
||||
exit(1);
|
||||
}
|
||||
for( i=0; i<numSamples; i++ ) data.recordedSamples[i] = 0;
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
/* Record some audio. */
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
Pa_GetDefaultInputDeviceID(),
|
||||
dataPtr->samplesPerFrame, /* stereo input */
|
||||
data.samplesPerFrame, /* stereo input */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
paNoDevice,
|
||||
|
|
@ -176,15 +195,14 @@ PaError TestRecording( paTestData *dataPtr )
|
|||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
REC_BUF_FRAMES, /* frames per buffer */
|
||||
NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
recordCallback,
|
||||
dataPtr );
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Now recording!\n"); fflush(stdout);
|
||||
for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
|
||||
{
|
||||
|
|
@ -193,28 +211,54 @@ PaError TestRecording( paTestData *dataPtr )
|
|||
printf("Stream inactive!\n");
|
||||
break;
|
||||
}
|
||||
if( dataPtr->maxFrameIndex <= dataPtr->frameIndex )
|
||||
if( data.maxFrameIndex <= data.frameIndex )
|
||||
{
|
||||
printf("Buffer recording complete.\n");
|
||||
break;
|
||||
}
|
||||
Pa_Sleep(100);
|
||||
printf("index = %d\n", dataPtr->frameIndex ); fflush(stdout);
|
||||
printf("index = %d\n", data.frameIndex );
|
||||
}
|
||||
err = Pa_CloseStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
/* Playback recorded data. */
|
||||
data.frameIndex = 0;
|
||||
printf("Begin playback.\n"); fflush(stdout);
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice,
|
||||
0, /* NO input */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
Pa_GetDefaultOutputDeviceID(),
|
||||
data.samplesPerFrame, /* stereo output */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
1024, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
playCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
printf("Waiting for playback to finish.\n"); fflush(stdout);
|
||||
for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
|
||||
{
|
||||
Pa_Sleep(100);
|
||||
printf("index = %d\n", data.frameIndex );
|
||||
}
|
||||
|
||||
printf("Finished loop. Close stream.\n"); fflush(stdout);
|
||||
|
||||
err = Pa_CloseStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Done.\n"); fflush(stdout);
|
||||
{
|
||||
SAMPLE max = 0;
|
||||
SAMPLE posVal;
|
||||
int i;
|
||||
for( i=0; i<dataPtr->numSamples; i++ )
|
||||
for( i=0; i<numSamples; i++ )
|
||||
{
|
||||
posVal = dataPtr->recordedSamples[i];
|
||||
posVal = data.recordedSamples[i];
|
||||
if( posVal < 0 ) posVal = -posVal;
|
||||
if( posVal > max ) max = posVal;
|
||||
}
|
||||
|
|
@ -231,101 +275,15 @@ PaError TestRecording( paTestData *dataPtr )
|
|||
}
|
||||
else
|
||||
{
|
||||
fwrite( dataPtr->recordedSamples, dataPtr->samplesPerFrame * sizeof(SAMPLE), totalFrames, fid );
|
||||
fwrite( data.recordedSamples, data.samplesPerFrame * sizeof(SAMPLE), totalFrames, fid );
|
||||
fclose( fid );
|
||||
printf("Wrote data to 'recorded.raw'\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
PaError TestPlayback( paTestData *dataPtr )
|
||||
{
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
int i;
|
||||
|
||||
/* Playback recorded data. */
|
||||
dataPtr->frameIndex = 0;
|
||||
printf("Begin playback.\n"); fflush(stdout);
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice,
|
||||
0, /* NO input */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
Pa_GetDefaultOutputDeviceID(),
|
||||
dataPtr->samplesPerFrame, /* stereo output */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
playCallback,
|
||||
dataPtr );
|
||||
if( err != paNoError ) goto error;
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
printf("Waiting for playback to finish.\n"); fflush(stdout);
|
||||
for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
|
||||
{
|
||||
Pa_Sleep(100);
|
||||
printf("index = %d\n", dataPtr->frameIndex );
|
||||
}
|
||||
err = Pa_CloseStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
PaError err;
|
||||
paTestData data;
|
||||
long totalFrames;
|
||||
long numBytes;
|
||||
long i;
|
||||
printf("patest_record.c\n"); fflush(stdout);
|
||||
|
||||
data.frameIndex = 0;
|
||||
data.samplesPerFrame = 2;
|
||||
data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE;
|
||||
|
||||
printf("totalFrames = %d\n", totalFrames ); fflush(stdout);
|
||||
data.numSamples = totalFrames * data.samplesPerFrame;
|
||||
|
||||
numBytes = data.numSamples * sizeof(SAMPLE);
|
||||
data.recordedSamples = (SAMPLE *) malloc( numBytes );
|
||||
if( data.recordedSamples == NULL )
|
||||
{
|
||||
printf("Could not allocate record array.\n");
|
||||
exit(1);
|
||||
}
|
||||
for( i=0; i<data.numSamples; i++ ) data.recordedSamples[i] = 0;
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
for( i=0; i<2; i++ )
|
||||
{
|
||||
err = TestRecording( &data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = TestPlayback( &data );
|
||||
if( err != paNoError ) goto error;
|
||||
}
|
||||
|
||||
free( data.recordedSamples );
|
||||
Pa_Terminate();
|
||||
return 0;
|
||||
|
||||
error:
|
||||
Pa_Terminate();
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
|
|
|
|||
|
|
@ -1,351 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
* debug_record_reuse.c
|
||||
* Record input into an array.
|
||||
* Save array to a file.
|
||||
* Based on patest_record.c but with various ugly debug hacks thrown in.
|
||||
* Loop twice and reuse same streams.
|
||||
*
|
||||
* Author: Phil Burk http://www.softsynth.com
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include "portaudio.h"
|
||||
#define SAMPLE_RATE (22050)
|
||||
#define NUM_SECONDS (4)
|
||||
#define SLEEP_DUR_MSEC (200)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
#define NUM_REC_BUFS (0)
|
||||
|
||||
#if 1
|
||||
#define PA_SAMPLE_TYPE paFloat32
|
||||
typedef float SAMPLE;
|
||||
#else
|
||||
#define PA_SAMPLE_TYPE paInt16
|
||||
typedef short SAMPLE;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long frameIndex; /* Index into sample array. */
|
||||
long maxFrameIndex;
|
||||
long samplesPerFrame;
|
||||
long numSamples;
|
||||
PortAudioStream *outputStream;
|
||||
PortAudioStream *inputStream;
|
||||
SAMPLE *recordedSamples;
|
||||
}
|
||||
paTestData;
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may be called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
*/
|
||||
static int recordCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
SAMPLE *rptr = (SAMPLE*)inputBuffer;
|
||||
SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
|
||||
long framesToCalc;
|
||||
unsigned long i;
|
||||
int finished;
|
||||
unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
|
||||
|
||||
(void) outputBuffer; /* Prevent unused variable warnings. */
|
||||
(void) outTime;
|
||||
|
||||
if( framesLeft < framesPerBuffer )
|
||||
{
|
||||
framesToCalc = framesLeft;
|
||||
finished = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
framesToCalc = framesPerBuffer;
|
||||
finished = 0;
|
||||
}
|
||||
if( inputBuffer == NULL )
|
||||
{
|
||||
for( i=0; i<framesToCalc; i++ )
|
||||
{
|
||||
*wptr++ = 0; /* left */
|
||||
*wptr++ = 0; /* right */
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i=0; i<framesToCalc; i++ )
|
||||
{
|
||||
*wptr++ = *rptr++; /* left */
|
||||
*wptr++ = *rptr++; /* right */
|
||||
}
|
||||
}
|
||||
data->frameIndex += framesToCalc;
|
||||
return finished;
|
||||
}
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may be called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
*/
|
||||
static int playCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
|
||||
SAMPLE *wptr = (SAMPLE*)outputBuffer;
|
||||
unsigned long i;
|
||||
int finished;
|
||||
unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;
|
||||
if( outputBuffer == NULL ) return 0;
|
||||
(void) inputBuffer; /* Prevent unused variable warnings. */
|
||||
(void) outTime;
|
||||
|
||||
if( framesLeft < framesPerBuffer )
|
||||
{
|
||||
/* final buffer... */
|
||||
for( i=0; i<framesLeft; i++ )
|
||||
{
|
||||
*wptr++ = *rptr++; /* left */
|
||||
*wptr++ = *rptr++; /* right */
|
||||
}
|
||||
for( ; i<framesPerBuffer; i++ )
|
||||
{
|
||||
*wptr++ = 0; /* left */
|
||||
*wptr++ = 0; /* right */
|
||||
}
|
||||
data->frameIndex += framesLeft;
|
||||
finished = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( i=0; i<framesPerBuffer; i++ )
|
||||
{
|
||||
*wptr++ = *rptr++; /* left */
|
||||
*wptr++ = *rptr++; /* right */
|
||||
}
|
||||
data->frameIndex += framesPerBuffer;
|
||||
finished = 0;
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
PaError TestRecording( paTestData *dataPtr )
|
||||
{
|
||||
PaError err;
|
||||
int i;
|
||||
int lastIndex = 0;
|
||||
|
||||
/* Open input stream if not already open. */
|
||||
if( dataPtr->inputStream == NULL )
|
||||
{
|
||||
/* Record some audio. */
|
||||
err = Pa_OpenStream(
|
||||
&dataPtr->inputStream,
|
||||
Pa_GetDefaultInputDeviceID(),
|
||||
dataPtr->samplesPerFrame, /* stereo input */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
paNoDevice,
|
||||
0,
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
recordCallback,
|
||||
dataPtr );
|
||||
if( err != paNoError ) goto error;
|
||||
}
|
||||
|
||||
dataPtr->frameIndex = 0;
|
||||
|
||||
err = Pa_StartStream( dataPtr->inputStream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Now recording!\n"); fflush(stdout);
|
||||
for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
|
||||
{
|
||||
int frameIndex, delta;
|
||||
Pa_Sleep(SLEEP_DUR_MSEC);
|
||||
|
||||
frameIndex = dataPtr->frameIndex;
|
||||
if( Pa_StreamActive( dataPtr->inputStream ) <= 0)
|
||||
{
|
||||
printf("Stream inactive!\n");
|
||||
break;
|
||||
}
|
||||
if( dataPtr->maxFrameIndex <= frameIndex )
|
||||
{
|
||||
printf("Buffer recording complete.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
delta = frameIndex - lastIndex;
|
||||
lastIndex = frameIndex;
|
||||
printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout);
|
||||
}
|
||||
|
||||
err = Pa_StopStream( dataPtr->inputStream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Done.\n"); fflush(stdout);
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
PaError TestPlayback( paTestData *dataPtr )
|
||||
{
|
||||
PaError err;
|
||||
int i;
|
||||
int lastIndex = 0;
|
||||
|
||||
/* Playback recorded data. */
|
||||
dataPtr->frameIndex = 0;
|
||||
printf("Begin playback.\n"); fflush(stdout);
|
||||
|
||||
/* Open output stream if not already open. */
|
||||
if( dataPtr->outputStream == NULL )
|
||||
{
|
||||
err = Pa_OpenStream(
|
||||
&dataPtr->outputStream,
|
||||
paNoDevice,
|
||||
0, /* NO input */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
Pa_GetDefaultOutputDeviceID(),
|
||||
dataPtr->samplesPerFrame, /* stereo output */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
playCallback,
|
||||
dataPtr );
|
||||
if( err != paNoError ) goto error;
|
||||
}
|
||||
|
||||
err = Pa_StartStream( dataPtr->outputStream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Waiting for playback to finish.\n"); fflush(stdout);
|
||||
for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
|
||||
{
|
||||
int frameIndex, delta;
|
||||
Pa_Sleep(SLEEP_DUR_MSEC);
|
||||
frameIndex = dataPtr->frameIndex;
|
||||
delta = frameIndex - lastIndex;
|
||||
lastIndex = frameIndex;
|
||||
printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout);
|
||||
}
|
||||
|
||||
err = Pa_StopStream( dataPtr->outputStream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
PaError err;
|
||||
paTestData data = { 0 };
|
||||
long totalFrames;
|
||||
long numBytes;
|
||||
long i;
|
||||
printf("patest_record.c\n"); fflush(stdout);
|
||||
|
||||
/* Set up test data structure and sample array. */
|
||||
data.frameIndex = 0;
|
||||
data.samplesPerFrame = 2;
|
||||
data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE;
|
||||
|
||||
printf("totalFrames = %d\n", totalFrames ); fflush(stdout);
|
||||
data.numSamples = totalFrames * data.samplesPerFrame;
|
||||
|
||||
numBytes = data.numSamples * sizeof(SAMPLE);
|
||||
data.recordedSamples = (SAMPLE *) malloc( numBytes );
|
||||
if( data.recordedSamples == NULL )
|
||||
{
|
||||
printf("Could not allocate record array.\n");
|
||||
exit(1);
|
||||
}
|
||||
for( i=0; i<data.numSamples; i++ ) data.recordedSamples[i] = 0;
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
/* Record and playback multiple times. */
|
||||
for( i=0; i<2; i++ )
|
||||
{
|
||||
err = TestRecording( &data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = TestPlayback( &data );
|
||||
if( err != paNoError ) goto error;
|
||||
}
|
||||
|
||||
/* Clean up. */
|
||||
err = Pa_CloseStream( data.inputStream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_CloseStream( data.outputStream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
free( data.recordedSamples );
|
||||
Pa_Terminate();
|
||||
|
||||
printf("Test complete.\n"); fflush(stdout);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
Pa_Terminate();
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
fprintf( stderr, "Error number: %d\n", err );
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
if( err == paHostError )
|
||||
{
|
||||
fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
#define SLEEP_DUR (800)
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
#if 0
|
||||
#if 1
|
||||
#define MIN_LATENCY_MSEC (200)
|
||||
#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
* Play a different sine wave on each channels,
|
||||
* using the Portable Audio api.
|
||||
* Allos amplitude to be set interactively.
|
||||
*
|
||||
* Author: Phil Burk http://www.softsynth.com
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
|
||||
#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
#define FREQ_INCR (300.0 / SAMPLE_RATE)
|
||||
#define MAX_CHANNELS (64)
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int numChannels;
|
||||
double phases[MAX_CHANNELS];
|
||||
float amplitude;
|
||||
}
|
||||
paTestData;
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
*/
|
||||
static int patestCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
float *out = (float*)outputBuffer;
|
||||
int frameIndex, channelIndex;
|
||||
(void) outTime; /* Prevent unused variable warnings. */
|
||||
(void) inputBuffer;
|
||||
|
||||
for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
|
||||
{
|
||||
for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
|
||||
{
|
||||
/* Output sine wave on every channel. */
|
||||
*out++ = (float) ( data->amplitude * sin(data->phases[channelIndex]) );
|
||||
|
||||
/* Play each channel at a higher frequency. */
|
||||
data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
|
||||
if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
char pad[256];
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
const PaDeviceInfo *pdi;
|
||||
paTestData data = {0};
|
||||
printf("PortAudio Test: output sine wave on each channel.\n" );
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE );
|
||||
data.numChannels = pdi->maxOutputChannels;
|
||||
if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS;
|
||||
printf("Number of Channels = %d\n", data.numChannels );
|
||||
data.amplitude = 1.0;
|
||||
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice, /* default input device */
|
||||
0, /* no input */
|
||||
paFloat32, /* 32 bit floating point input */
|
||||
NULL,
|
||||
OUTPUT_DEVICE,
|
||||
data.numChannels,
|
||||
paFloat32, /* 32 bit floating point output */
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
patestCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
do
|
||||
{
|
||||
printf("Current amplitude = %f\n", data.amplitude );
|
||||
printf("Enter new amplitude or 'q' to quit.\n");
|
||||
fflush(stdout);
|
||||
gets( pad );
|
||||
if( pad[0] != 'q' )
|
||||
{
|
||||
// I tried to use atof but it seems to be broken on Mac OS X 10.1
|
||||
float amp;
|
||||
sscanf( pad, "%f", & );
|
||||
data.amplitude = amp;
|
||||
}
|
||||
} while( pad[0] != 'q' );
|
||||
|
||||
err = Pa_StopStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
Pa_CloseStream( stream );
|
||||
Pa_Terminate();
|
||||
printf("Test finished.\n");
|
||||
return err;
|
||||
error:
|
||||
Pa_Terminate();
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
fprintf( stderr, "Error number: %d\n", err );
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
* patest_sine_formats.c
|
||||
* Play a sine wave using the Portable Audio api for several seconds.
|
||||
* Test various data formats.
|
||||
*
|
||||
* Author: Phil Burk
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.audiomulch.com/portaudio/
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
|
||||
#define NUM_SECONDS (10)
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
|
||||
#define LEFT_FREQ (SAMPLE_RATE/512.0) /* So we hit 1.0 */
|
||||
#define RIGHT_FREQ (500.0)
|
||||
|
||||
#define AMPLITUDE (1.0)
|
||||
|
||||
/* Select ONE format for testing. */
|
||||
#define TEST_UINT8 (1)
|
||||
#define TEST_INT8 (0)
|
||||
#define TEST_INT16 (0)
|
||||
#define TEST_FLOAT32 (0)
|
||||
|
||||
#if TEST_UINT8
|
||||
#define TEST_FORMAT paUInt8
|
||||
typedef unsigned char SAMPLE_t;
|
||||
#define SAMPLE_ZERO (0x80)
|
||||
#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
|
||||
#define FORMAT_NAME "Unsigned 8 Bit"
|
||||
|
||||
#elif TEST_INT8
|
||||
#define TEST_FORMAT paInt8
|
||||
typedef char SAMPLE_t;
|
||||
#define SAMPLE_ZERO (0)
|
||||
#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
|
||||
#define FORMAT_NAME "Signed 8 Bit"
|
||||
|
||||
#elif TEST_INT16
|
||||
#define TEST_FORMAT paInt16
|
||||
typedef short SAMPLE_t;
|
||||
#define SAMPLE_ZERO (0)
|
||||
#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x)))
|
||||
#define FORMAT_NAME "Signed 16 Bit"
|
||||
|
||||
#elif TEST_FLOAT32
|
||||
#define TEST_FORMAT paFloat32
|
||||
typedef float SAMPLE_t;
|
||||
#define SAMPLE_ZERO (0.0)
|
||||
#define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x))
|
||||
#define FORMAT_NAME "Float 32 Bit"
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265)
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double left_phase;
|
||||
double right_phase;
|
||||
unsigned int framesToGo;
|
||||
}
|
||||
paTestData;
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
*/
|
||||
static int patestCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
SAMPLE_t *out = (SAMPLE_t *)outputBuffer;
|
||||
SAMPLE_t sample;
|
||||
int i;
|
||||
int framesToCalc;
|
||||
int finished = 0;
|
||||
(void) outTime; /* Prevent unused variable warnings. */
|
||||
(void) inputBuffer;
|
||||
|
||||
if( data->framesToGo < framesPerBuffer )
|
||||
{
|
||||
framesToCalc = data->framesToGo;
|
||||
data->framesToGo = 0;
|
||||
finished = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
framesToCalc = framesPerBuffer;
|
||||
data->framesToGo -= framesPerBuffer;
|
||||
}
|
||||
|
||||
for( i=0; i<framesToCalc; i++ )
|
||||
{
|
||||
data->left_phase += (LEFT_FREQ / SAMPLE_RATE);
|
||||
if( data->left_phase > 1.0) data->left_phase -= 1.0;
|
||||
sample = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. ))); /**/
|
||||
*out++ = sample;
|
||||
/* *out++ = sample; /**/
|
||||
/* *out++ = 0; /**/
|
||||
|
||||
data->right_phase += (RIGHT_FREQ / SAMPLE_RATE);
|
||||
if( data->right_phase > 1.0) data->right_phase -= 1.0;
|
||||
*out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. ))); /**/
|
||||
/* *out++ = 0; /* */
|
||||
}
|
||||
/* zero remainder of final buffer */
|
||||
for( ; i<(int)framesPerBuffer; i++ )
|
||||
{
|
||||
*out++ = SAMPLE_ZERO; /* left */
|
||||
*out++ = SAMPLE_ZERO; /* right */
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
paTestData data;
|
||||
int totalSamps;
|
||||
|
||||
printf("PortAudio Test: output " FORMAT_NAME "\n");
|
||||
|
||||
|
||||
data.left_phase = data.right_phase = 0.0;
|
||||
data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice,/* default input device */
|
||||
0, /* no input */
|
||||
TEST_FORMAT,
|
||||
NULL,
|
||||
Pa_GetDefaultOutputDeviceID(), /* default output device */
|
||||
2, /* stereo output */
|
||||
TEST_FORMAT,
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER,
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
patestCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS );
|
||||
while( Pa_StreamActive( stream ) ) Pa_Sleep(10);
|
||||
|
||||
err = Pa_CloseStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
Pa_Terminate();
|
||||
|
||||
printf("PortAudio Test Finished: " FORMAT_NAME "\n");
|
||||
|
||||
return err;
|
||||
error:
|
||||
Pa_Terminate();
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
fprintf( stderr, "Error number: %d\n", err );
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* $Id$
|
||||
* Play a sine then hang audio callback to test watchdog.
|
||||
* debug_sine_wait.c
|
||||
* Play a sine wave using the Portable Audio api until we hit ENTER.
|
||||
*
|
||||
* Authors:
|
||||
* Ross Bencina <rossb@audiomulch.com>
|
||||
|
|
@ -38,18 +39,21 @@
|
|||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
|
||||
|
||||
#define NUM_SECONDS (20)
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_BUFFER (1024)
|
||||
#define FRAMES_PER_BUFFER (64)
|
||||
#define NUM_BUFFERS (16)
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265)
|
||||
#endif
|
||||
#define TWOPI (M_PI * 2.0)
|
||||
|
||||
typedef struct paTestData
|
||||
#define TABLE_SIZE (200)
|
||||
typedef struct
|
||||
{
|
||||
int sleepFor;
|
||||
double phase;
|
||||
float sine[TABLE_SIZE];
|
||||
int left_phase;
|
||||
int right_phase;
|
||||
}
|
||||
paTestData;
|
||||
|
||||
|
|
@ -65,26 +69,17 @@ static int patestCallback( void *inputBuffer, void *outputBuffer,
|
|||
float *out = (float*)outputBuffer;
|
||||
unsigned long i;
|
||||
int finished = 0;
|
||||
double phaseInc = 0.02;
|
||||
double phase = data->phase;
|
||||
|
||||
(void) outTime; /* Prevent unused variable warnings. */
|
||||
(void) inputBuffer;
|
||||
|
||||
for( i=0; i<framesPerBuffer; i++ )
|
||||
{
|
||||
phase += phaseInc;
|
||||
if( phase > TWOPI ) phase -= TWOPI;
|
||||
/* This is not a very efficient way to calc sines. */
|
||||
*out++ = (float) sin( phase ); /* mono */
|
||||
*out++ = data->sine[data->left_phase]; /* left */
|
||||
*out++ = data->sine[data->right_phase]; /* right */
|
||||
data->left_phase += 1;
|
||||
if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
|
||||
data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
|
||||
if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
|
||||
}
|
||||
|
||||
if( data->sleepFor > 0 )
|
||||
{
|
||||
Pa_Sleep( data->sleepFor );
|
||||
}
|
||||
|
||||
data->phase = phase;
|
||||
return finished;
|
||||
}
|
||||
|
||||
|
|
@ -93,16 +88,18 @@ int main(void);
|
|||
int main(void)
|
||||
{
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
int i;
|
||||
paTestData data = {0};
|
||||
|
||||
printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n",
|
||||
SAMPLE_RATE, FRAMES_PER_BUFFER );
|
||||
|
||||
PaError err;
|
||||
paTestData data;
|
||||
int i;
|
||||
printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
|
||||
/* initialise sinusoidal wavetable */
|
||||
for( i=0; i<TABLE_SIZE; i++ )
|
||||
{
|
||||
data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
|
||||
}
|
||||
data.left_phase = data.right_phase = 0;
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice,/* default input device */
|
||||
|
|
@ -110,31 +107,21 @@ int main(void)
|
|||
paFloat32, /* 32 bit floating point input */
|
||||
NULL,
|
||||
Pa_GetDefaultOutputDeviceID(), /* default output device */
|
||||
1, /* mono output */
|
||||
2, /* stereo output */
|
||||
paFloat32, /* 32 bit floating point output */
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
FRAMES_PER_BUFFER,
|
||||
NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
patestCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
printf("Hit ENTER to stop.\n");
|
||||
gets(stdin);
|
||||
|
||||
/* Gradually increase sleep time. */
|
||||
for( i=0; i<10000; i+= 1000 )
|
||||
{
|
||||
printf("Sleep for %d milliseconds in audio callback.\n", i );
|
||||
data.sleepFor = i;
|
||||
Pa_Sleep( ((i<1000) ? 1000 : i) );
|
||||
}
|
||||
|
||||
printf("Suffer for 10 seconds.\n");
|
||||
Pa_Sleep( 10000 );
|
||||
|
||||
err = Pa_StopStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
err = Pa_CloseStream( stream );
|
||||
|
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
* debug_record_reuse.c
|
||||
* Record input into an array.
|
||||
* Save array to a file.
|
||||
* Based on patest_record.c but with various ugly debug hacks thrown in.
|
||||
* Loop twice and reuse same streams.
|
||||
*
|
||||
* Author: Phil Burk http://www.softsynth.com
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include "portaudio.h"
|
||||
|
||||
#define EWS88MT_12_REC (1)
|
||||
#define EWS88MT_12_PLAY (10)
|
||||
#define SBLIVE_REC (2)
|
||||
#define SBLIVE_PLAY (11)
|
||||
|
||||
#if 0
|
||||
#define INPUT_DEVICE_ID Pa_GetDefaultInputDeviceID()
|
||||
#define OUTPUT_DEVICE_ID Pa_GetDefaultOutputDeviceID()
|
||||
#else
|
||||
#define INPUT_DEVICE_ID (EWS88MT_12_REC)
|
||||
#define OUTPUT_DEVICE_ID (SBLIVE_PLAY)
|
||||
#endif
|
||||
|
||||
#define INPUT_SAMPLE_RATE (22050.0)
|
||||
#define OUTPUT_SAMPLE_RATE (22050.0)
|
||||
#define NUM_SECONDS (4)
|
||||
#define SLEEP_DUR_MSEC (1000)
|
||||
#define FRAMES_PER_BUFFER (64)
|
||||
#define NUM_REC_BUFS (0)
|
||||
#define SAMPLES_PER_FRAME (2)
|
||||
|
||||
#define PA_SAMPLE_TYPE paInt16
|
||||
typedef short SAMPLE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
long frameIndex; /* Index into sample array. */
|
||||
}
|
||||
paTestData;
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may be called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
*/
|
||||
static int recordCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
paTestData *data = (paTestData *) userData;
|
||||
(void) outputBuffer; /* Prevent unused variable warnings. */
|
||||
(void) outTime;
|
||||
|
||||
if( inputBuffer != NULL )
|
||||
{
|
||||
data->frameIndex += framesPerBuffer;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may be called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
*/
|
||||
static int playCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
paTestData *data = (paTestData *) userData;
|
||||
(void) inputBuffer; /* Prevent unused variable warnings. */
|
||||
(void) outTime;
|
||||
|
||||
if( outputBuffer != NULL )
|
||||
{
|
||||
data->frameIndex += framesPerBuffer;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
PaError MeasureStreamRate( PortAudioStream *stream, paTestData *dataPtr, double *ratePtr )
|
||||
{
|
||||
PaError err;
|
||||
int i;
|
||||
int totalFrames = 0;
|
||||
int totalMSec = 0;
|
||||
|
||||
dataPtr->frameIndex = 0;
|
||||
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
|
||||
{
|
||||
int delta, endIndex;
|
||||
|
||||
int startIndex = dataPtr->frameIndex;
|
||||
Pa_Sleep(SLEEP_DUR_MSEC);
|
||||
endIndex = dataPtr->frameIndex;
|
||||
|
||||
delta = endIndex - startIndex;
|
||||
totalFrames += delta;
|
||||
totalMSec += SLEEP_DUR_MSEC;
|
||||
|
||||
printf("index = %d, delta = %d\n", endIndex, delta ); fflush(stdout);
|
||||
}
|
||||
|
||||
err = Pa_StopStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
*ratePtr = (totalFrames * 1000.0) / totalMSec;
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
void ReportRate( double measuredRate, double expectedRate )
|
||||
{
|
||||
double error;
|
||||
|
||||
error = (measuredRate - expectedRate) / expectedRate;
|
||||
error = (error < 0 ) ? -error : error;
|
||||
|
||||
printf("Measured rate = %6.1f, expected rate = %6.1f\n",
|
||||
measuredRate, expectedRate );
|
||||
if( error > 0.1 )
|
||||
{
|
||||
printf("ERROR: unexpected rate! --------------------- ERROR!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("SUCCESS: rate within tolerance!\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
PaError err;
|
||||
paTestData data = { 0 };
|
||||
long i;
|
||||
double rate;
|
||||
const PaDeviceInfo *pdi;
|
||||
|
||||
PortAudioStream *outputStream;
|
||||
PortAudioStream *inputStream;
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
|
||||
pdi = Pa_GetDeviceInfo( INPUT_DEVICE_ID );
|
||||
printf("Input device = %s\n", pdi->name );
|
||||
pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE_ID );
|
||||
printf("Output device = %s\n", pdi->name );
|
||||
|
||||
/* Open input stream. */
|
||||
err = Pa_OpenStream(
|
||||
&inputStream,
|
||||
INPUT_DEVICE_ID,
|
||||
SAMPLES_PER_FRAME, /* stereo input */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
paNoDevice,
|
||||
0,
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
INPUT_SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
recordCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_OpenStream(
|
||||
&outputStream,
|
||||
paNoDevice,
|
||||
0, /* NO input */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
OUTPUT_DEVICE_ID,
|
||||
SAMPLES_PER_FRAME, /* stereo output */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
OUTPUT_SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
playCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
/* Record and playback multiple times. */
|
||||
for( i=0; i<2; i++ )
|
||||
{
|
||||
printf("Measuring INPUT ------------------------- \n");
|
||||
err = MeasureStreamRate( inputStream, &data, &rate );
|
||||
if( err != paNoError ) goto error;
|
||||
ReportRate( rate, INPUT_SAMPLE_RATE );
|
||||
|
||||
printf("Measuring OUTPUT ------------------------- \n");
|
||||
err = MeasureStreamRate( outputStream, &data, &rate );
|
||||
if( err != paNoError ) goto error;
|
||||
ReportRate( rate, OUTPUT_SAMPLE_RATE );
|
||||
}
|
||||
|
||||
/* Clean up. */
|
||||
err = Pa_CloseStream( inputStream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_CloseStream( outputStream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
Pa_Terminate();
|
||||
|
||||
printf("Test complete.\n"); fflush(stdout);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
Pa_Terminate();
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
fprintf( stderr, "Error number: %d\n", err );
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
if( err == paHostError )
|
||||
{
|
||||
fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -38,21 +38,18 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265)
|
||||
#endif
|
||||
#define TWOPI (M_PI * 2.0)
|
||||
|
||||
#define DEFAULT_BUFFER_SIZE (64)
|
||||
|
||||
#define DEFAULT_BUFFER_SIZE (128)
|
||||
#define TABLE_SIZE (200)
|
||||
typedef struct
|
||||
{
|
||||
double left_phase;
|
||||
double right_phase;
|
||||
float sine[TABLE_SIZE];
|
||||
int left_phase;
|
||||
int right_phase;
|
||||
}
|
||||
paTestData;
|
||||
|
||||
/* Very simple synthesis routine to generate two sine waves. */
|
||||
static int paminlatCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
|
|
@ -61,25 +58,15 @@ static int paminlatCallback( void *inputBuffer, void *outputBuffer,
|
|||
paTestData *data = (paTestData*)userData;
|
||||
float *out = (float*)outputBuffer;
|
||||
unsigned int i;
|
||||
double left_phaseInc = 0.02;
|
||||
double right_phaseInc = 0.06;
|
||||
|
||||
double left_phase = data->left_phase;
|
||||
double right_phase = data->right_phase;
|
||||
|
||||
for( i=0; i<framesPerBuffer; i++ )
|
||||
{
|
||||
left_phase += left_phaseInc;
|
||||
if( left_phase > TWOPI ) left_phase -= TWOPI;
|
||||
*out++ = (float) sin( left_phase );
|
||||
|
||||
right_phase += right_phaseInc;
|
||||
if( right_phase > TWOPI ) right_phase -= TWOPI;
|
||||
*out++ = (float) sin( right_phase );
|
||||
*out++ = data->sine[data->left_phase]; /* left */
|
||||
*out++ = data->sine[data->right_phase]; /* right */
|
||||
data->left_phase += 1;
|
||||
if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
|
||||
data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
|
||||
if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
|
||||
}
|
||||
|
||||
data->left_phase = left_phase;
|
||||
data->right_phase = right_phase;
|
||||
return 0;
|
||||
}
|
||||
void main( int argc, char **argv );
|
||||
|
|
@ -88,6 +75,7 @@ void main( int argc, char **argv )
|
|||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
paTestData data;
|
||||
int i;
|
||||
int go;
|
||||
int numBuffers = 0;
|
||||
int minBuffers = 0;
|
||||
|
|
@ -103,8 +91,12 @@ void main( int argc, char **argv )
|
|||
/* Get bufferSize from command line. */
|
||||
framesPerBuffer = ( argc > 1 ) ? atol( argv[1] ) : DEFAULT_BUFFER_SIZE;
|
||||
printf("Frames per buffer = %d\n", framesPerBuffer );
|
||||
|
||||
data.left_phase = data.right_phase = 0.0;
|
||||
/* Initialise sinusoidal wavetable. */
|
||||
for( i=0; i<TABLE_SIZE; i++ )
|
||||
{
|
||||
data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
|
||||
}
|
||||
data.left_phase = data.right_phase = 0;
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
/* Ask PortAudio for the recommended minimum number of buffers. */
|
||||
|
|
@ -129,7 +121,7 @@ void main( int argc, char **argv )
|
|||
paFloat32, /* 32 bit floating point output */
|
||||
NULL,
|
||||
sampleRate,
|
||||
framesPerBuffer,
|
||||
framesPerBuffer,/* 46 msec buffers */
|
||||
numBuffers, /* number of buffers */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
paminlatCallback,
|
||||
|
|
|
|||
|
|
@ -270,31 +270,6 @@ static int TestBadOpens( void )
|
|||
QaCallback,
|
||||
&myData )
|
||||
) == paInvalidFlag) );
|
||||
|
||||
#if 0 /* FIXME - this is legal for some implementations. */
|
||||
HOPEFOR( ( /* Use input device as output device. */
|
||||
(result = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice, 0, paFloat32, NULL,
|
||||
Pa_GetDefaultInputDeviceID(), 2, paFloat32, NULL,
|
||||
SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
|
||||
paClipOff,
|
||||
QaCallback,
|
||||
&myData )
|
||||
) == paInvalidDeviceId) );
|
||||
|
||||
HOPEFOR( ( /* Use output device as input device. */
|
||||
(result = Pa_OpenStream(
|
||||
&stream,
|
||||
Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
|
||||
paNoDevice, 0, paFloat32, NULL,
|
||||
SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
|
||||
paClipOff,
|
||||
QaCallback,
|
||||
&myData )
|
||||
) == paInvalidDeviceId) );
|
||||
#endif
|
||||
|
||||
if( stream != NULL ) Pa_CloseStream( stream );
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
* $Id$
|
||||
* patest_dither.c
|
||||
* Attempt to hear difference between dithered and non-dithered signal.
|
||||
* This only has an effect if the native format is 16 bit.
|
||||
*
|
||||
* Author: Phil Burk http://www.softsynth.com
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* $Id$
|
||||
* Hear the latency caused by big buffers.
|
||||
* Hear the latency caused by bug buffers.
|
||||
* Play a sine wave and change frequency based on letter input.
|
||||
*
|
||||
* Author: Phil Burk <philburk@softsynth.com>, and Darren Gibbs
|
||||
* Author: Phil Burk <philburk@softsynth.com>
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
|
|
@ -36,18 +36,15 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
|
||||
#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_BUFFER (64)
|
||||
|
||||
#if 0
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
#if 1
|
||||
#define MIN_LATENCY_MSEC (2000)
|
||||
#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
|
||||
#else
|
||||
#define NUM_BUFFERS (0)
|
||||
#endif
|
||||
|
||||
#define MIN_FREQ (100.0f)
|
||||
#define CalcPhaseIncrement(freq) ((freq)/SAMPLE_RATE)
|
||||
#ifndef M_PI
|
||||
|
|
@ -56,7 +53,7 @@
|
|||
#define TABLE_SIZE (400)
|
||||
typedef struct
|
||||
{
|
||||
float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */
|
||||
float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation
|
||||
float phase_increment;
|
||||
float left_phase;
|
||||
float right_phase;
|
||||
|
|
@ -111,16 +108,15 @@ int main(void)
|
|||
paTestData data;
|
||||
int i;
|
||||
int done = 0;
|
||||
printf("PortAudio Test: enter letter then hit ENTER. numBuffers = %d\n", NUM_BUFFERS );
|
||||
printf("PortAudio Test: output sine sweep. ask for %d buffers\n", NUM_BUFFERS );
|
||||
/* initialise sinusoidal wavetable */
|
||||
for( i=0; i<TABLE_SIZE; i++ )
|
||||
{
|
||||
data.sine[i] = 0.90f * (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
|
||||
data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
|
||||
}
|
||||
data.sine[TABLE_SIZE] = data.sine[0]; /* set guard point */
|
||||
data.sine[TABLE_SIZE] = data.sine[0]; // set guard point
|
||||
data.left_phase = data.right_phase = 0.0;
|
||||
data.phase_increment = CalcPhaseIncrement(MIN_FREQ);
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE );
|
||||
|
|
@ -144,7 +140,6 @@ int main(void)
|
|||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
printf("Play ASCII keyboard. Hit 'q' to stop. (Use RETURN key on Mac)\n");
|
||||
fflush(stdout);
|
||||
while ( !done )
|
||||
{
|
||||
float freq;
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ static int patestCallback( void *inputBuffer, void *outputBuffer,
|
|||
|
||||
return finished;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
|
|
@ -108,21 +107,17 @@ int main(void)
|
|||
paTestData data;
|
||||
int i;
|
||||
int timeout;
|
||||
|
||||
printf("Play different tone sine waves that alternate between left and right channel.\n");
|
||||
printf("The low tone should be on the left channel.\n");
|
||||
|
||||
printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
|
||||
/* initialise sinusoidal wavetable */
|
||||
for( i=0; i<TABLE_SIZE; i++ )
|
||||
{
|
||||
data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
|
||||
}
|
||||
data.left_phase = data.right_phase = data.toggle = 0;
|
||||
data.left_phase = data.right_phase = 0;
|
||||
data.countDown = SAMPLE_RATE;
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice,/* default input device */
|
||||
|
|
@ -140,15 +135,15 @@ int main(void)
|
|||
patestCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Play for several seconds.\n");
|
||||
timeout = NUM_SECONDS * 4;
|
||||
while( timeout > 0 )
|
||||
{
|
||||
Pa_Sleep( 300 );
|
||||
printf("Countdown = %d, Toggle = %d\n", data.countDown, data.toggle );
|
||||
fflush( stdout );
|
||||
Pa_Sleep( 1000/4 );
|
||||
timeout -= 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* $Id$
|
||||
* patest_longsine.c
|
||||
* Play a sine wave using the Portable Audio api until ENTER hit.
|
||||
* Play a sine wave using the Portable Audio api forever.
|
||||
*
|
||||
* Author: Phil Burk http://www.softsynth.com
|
||||
*
|
||||
|
|
@ -36,13 +36,10 @@
|
|||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
|
||||
#define SAMPLE_RATE (44100)
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265)
|
||||
#endif
|
||||
|
||||
#define TABLE_SIZE (200)
|
||||
typedef struct
|
||||
{
|
||||
|
|
@ -51,7 +48,6 @@ typedef struct
|
|||
int right_phase;
|
||||
}
|
||||
paTestData;
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
|
|
@ -76,7 +72,6 @@ static int patestCallback( void *inputBuffer, void *outputBuffer,
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
|
|
@ -86,17 +81,14 @@ int main(void)
|
|||
paTestData data;
|
||||
int i;
|
||||
printf("PortAudio Test: output sine wave.\n");
|
||||
|
||||
/* initialise sinusoidal wavetable */
|
||||
for( i=0; i<TABLE_SIZE; i++ )
|
||||
{
|
||||
data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
|
||||
}
|
||||
data.left_phase = data.right_phase = 0;
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice,/* default input device */
|
||||
|
|
@ -114,20 +106,15 @@ int main(void)
|
|||
patestCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Hit ENTER to stop program.\n");
|
||||
getchar();
|
||||
|
||||
err = Pa_CloseStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
Pa_Terminate();
|
||||
|
||||
printf("Test finished.\n");
|
||||
return err;
|
||||
|
||||
error:
|
||||
Pa_Terminate();
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
|
|
|
|||
|
|
@ -40,44 +40,20 @@
|
|||
#include "portaudio.h"
|
||||
|
||||
#define MAX_SINES (500)
|
||||
#define MAX_USAGE (0.8)
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FREQ_TO_PHASE_INC(freq) (freq/(float)SAMPLE_RATE)
|
||||
|
||||
#define MIN_PHASE_INC FREQ_TO_PHASE_INC(200.0f)
|
||||
#define MAX_PHASE_INC (MIN_PHASE_INC * (1 << 5))
|
||||
|
||||
#define FRAMES_PER_BUFFER (512)
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265)
|
||||
#endif
|
||||
#define TWOPI (M_PI * 2.0)
|
||||
|
||||
#define TABLE_SIZE (512)
|
||||
|
||||
typedef struct paTestData
|
||||
{
|
||||
int numSines;
|
||||
float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */
|
||||
float phases[MAX_SINES];
|
||||
double phases[MAX_SINES];
|
||||
}
|
||||
paTestData;
|
||||
|
||||
/* Convert phase between and 1.0 to sine value
|
||||
* using linear interpolation.
|
||||
*/
|
||||
float LookupSine( paTestData *data, float phase );
|
||||
float LookupSine( paTestData *data, float phase )
|
||||
{
|
||||
float fIndex = phase*TABLE_SIZE;
|
||||
int index = (int) fIndex;
|
||||
float fract = fIndex - index;
|
||||
float lo = data->sine[index];
|
||||
float hi = data->sine[index+1];
|
||||
float val = lo + fract*(hi-lo);
|
||||
return val;
|
||||
}
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
|
|
@ -88,42 +64,34 @@ static int patestCallback( void *inputBuffer, void *outputBuffer,
|
|||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
float *out = (float*)outputBuffer;
|
||||
float outSample;
|
||||
float scaler;
|
||||
int numForScale;
|
||||
unsigned long i;
|
||||
int j;
|
||||
int finished = 0;
|
||||
(void) outTime; /* Prevent unused variable warnings. */
|
||||
(void) inputBuffer;
|
||||
|
||||
/* Detemine amplitude scaling factor */
|
||||
numForScale = data->numSines;
|
||||
if( numForScale < 8 ) numForScale = 8; /* prevent pops at beginning */
|
||||
scaler = 1.0f / numForScale;
|
||||
|
||||
for( i=0; i<framesPerBuffer; i++ )
|
||||
{
|
||||
float output = 0.0;
|
||||
float phaseInc = MIN_PHASE_INC;
|
||||
float phase;
|
||||
double phaseInc = 0.02;
|
||||
double phase;
|
||||
for( j=0; j<data->numSines; j++ )
|
||||
{
|
||||
/* Advance phase of next oscillator. */
|
||||
phase = data->phases[j];
|
||||
phase += phaseInc;
|
||||
if( phase >= 1.0 ) phase -= 1.0;
|
||||
if( phase > TWOPI ) phase -= TWOPI;
|
||||
|
||||
output += LookupSine(data, phase);
|
||||
phaseInc *= 1.02;
|
||||
if( phaseInc > 0.5 ) phaseInc *= 0.5;
|
||||
|
||||
/* This is not a very efficient way to calc sines. */
|
||||
output += (float) sin( phase );
|
||||
data->phases[j] = phase;
|
||||
|
||||
phaseInc *= 1.02f;
|
||||
if( phaseInc > MAX_PHASE_INC ) phaseInc = MIN_PHASE_INC;
|
||||
}
|
||||
|
||||
outSample = (float) (output * scaler);
|
||||
*out++ = outSample; /* Left */
|
||||
*out++ = outSample; /* Right */
|
||||
|
||||
*out++ = (float) (output / data->numSines);
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
|
|
@ -132,34 +100,27 @@ static int patestCallback( void *inputBuffer, void *outputBuffer,
|
|||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
paTestData data = {0};
|
||||
double load;
|
||||
printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
|
||||
|
||||
/* initialise sinusoidal wavetable */
|
||||
for( i=0; i<TABLE_SIZE; i++ )
|
||||
{
|
||||
data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
|
||||
}
|
||||
data.sine[TABLE_SIZE] = data.sine[0]; /* set guard point */
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice,
|
||||
paNoDevice,/* default input device */
|
||||
0, /* no input */
|
||||
paFloat32,
|
||||
paFloat32, /* 32 bit floating point input */
|
||||
NULL,
|
||||
Pa_GetDefaultOutputDeviceID(), /* default output device */
|
||||
2, /* stereo output */
|
||||
1, /* mono output */
|
||||
paFloat32, /* 32 bit floating point output */
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
patestCallback,
|
||||
|
|
@ -168,7 +129,6 @@ int main(void)
|
|||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
/* Play an increasing number of sine waves until we hit MAX_USAGE */
|
||||
do
|
||||
{
|
||||
data.numSines++;
|
||||
|
|
@ -176,9 +136,8 @@ int main(void)
|
|||
|
||||
load = Pa_GetCPULoad( stream );
|
||||
printf("numSines = %d, CPU load = %f\n", data.numSines, load );
|
||||
fflush( stdout );
|
||||
}
|
||||
while( (load < MAX_USAGE) && (data.numSines < MAX_SINES) );
|
||||
while( load < 0.8 );
|
||||
|
||||
err = Pa_StopStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
|
|
|||
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
* patest_multi_out.c
|
||||
* Play a different sine wave on each channels,
|
||||
* using the Portable Audio api.
|
||||
*
|
||||
* Author: Phil Burk http://www.softsynth.com
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.portaudio.com
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
|
||||
#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
#define FREQ_INCR (300.0 / SAMPLE_RATE)
|
||||
#define MAX_CHANNELS (64)
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265)
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int numChannels;
|
||||
double phases[MAX_CHANNELS];
|
||||
}
|
||||
paTestData;
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
*/
|
||||
static int patestCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
float *out = (float*)outputBuffer;
|
||||
int frameIndex, channelIndex;
|
||||
int finished = 0;
|
||||
(void) outTime; /* Prevent unused variable warnings. */
|
||||
(void) inputBuffer;
|
||||
|
||||
for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
|
||||
{
|
||||
for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
|
||||
{
|
||||
/* Output sine wave on every channel. */
|
||||
*out++ = (float) sin(data->phases[channelIndex]);
|
||||
|
||||
/* Play each channel at a higher frequency. */
|
||||
data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
|
||||
if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
const PaDeviceInfo *pdi;
|
||||
paTestData data = {0};
|
||||
printf("PortAudio Test: output sine wave on each channel.\n" );
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE );
|
||||
data.numChannels = pdi->maxOutputChannels;
|
||||
if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS;
|
||||
printf("Number of Channels = %d\n", data.numChannels );
|
||||
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice, /* default input device */
|
||||
0, /* no input */
|
||||
paFloat32, /* 32 bit floating point input */
|
||||
NULL,
|
||||
OUTPUT_DEVICE,
|
||||
data.numChannels,
|
||||
paFloat32, /* 32 bit floating point output */
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
patestCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Hit ENTER to stop sound.\n");
|
||||
getchar();
|
||||
|
||||
err = Pa_StopStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
Pa_CloseStream( stream );
|
||||
Pa_Terminate();
|
||||
printf("Test finished.\n");
|
||||
return err;
|
||||
error:
|
||||
Pa_Terminate();
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
fprintf( stderr, "Error number: %d\n", err );
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
return err;
|
||||
}
|
||||
|
|
@ -42,34 +42,24 @@
|
|||
/* #define SAMPLE_RATE (17932) /* Test failure to open with this value. */
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define NUM_SECONDS (5)
|
||||
#define NUM_CHANNELS (2)
|
||||
/* #define DITHER_FLAG (paDitherOff) /**/
|
||||
#define DITHER_FLAG (0) /**/
|
||||
|
||||
/* Select sample format. */
|
||||
#if 0
|
||||
#define PA_SAMPLE_TYPE paFloat32
|
||||
typedef float SAMPLE;
|
||||
#define SAMPLE_SILENCE (0.0f)
|
||||
#elif 0
|
||||
#define PA_SAMPLE_TYPE paInt16
|
||||
typedef short SAMPLE;
|
||||
#define SAMPLE_SILENCE (0)
|
||||
#elif 0
|
||||
#define PA_SAMPLE_TYPE paInt8
|
||||
typedef char SAMPLE;
|
||||
#define SAMPLE_SILENCE (0)
|
||||
#else
|
||||
#define PA_SAMPLE_TYPE paUInt8
|
||||
typedef unsigned char SAMPLE;
|
||||
#define SAMPLE_SILENCE (128)
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int frameIndex; /* Index into sample array. */
|
||||
int maxFrameIndex;
|
||||
int samplesPerFrame;
|
||||
SAMPLE *recordedSamples;
|
||||
}
|
||||
paTestData;
|
||||
|
|
@ -83,7 +73,7 @@ static int recordCallback( void *inputBuffer, void *outputBuffer,
|
|||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
SAMPLE *rptr = (SAMPLE*)inputBuffer;
|
||||
SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
|
||||
SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
|
||||
long framesToCalc;
|
||||
long i;
|
||||
int finished;
|
||||
|
|
@ -106,8 +96,8 @@ static int recordCallback( void *inputBuffer, void *outputBuffer,
|
|||
{
|
||||
for( i=0; i<framesToCalc; i++ )
|
||||
{
|
||||
*wptr++ = SAMPLE_SILENCE; /* left */
|
||||
if( NUM_CHANNELS == 2 ) *wptr++ = SAMPLE_SILENCE; /* right */
|
||||
*wptr++ = 0; /* left */
|
||||
*wptr++ = 0; /* right */
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -115,7 +105,7 @@ static int recordCallback( void *inputBuffer, void *outputBuffer,
|
|||
for( i=0; i<framesToCalc; i++ )
|
||||
{
|
||||
*wptr++ = *rptr++; /* left */
|
||||
if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
|
||||
*wptr++ = *rptr++; /* right */
|
||||
}
|
||||
}
|
||||
data->frameIndex += framesToCalc;
|
||||
|
|
@ -131,7 +121,7 @@ static int playCallback( void *inputBuffer, void *outputBuffer,
|
|||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
|
||||
SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
|
||||
SAMPLE *wptr = (SAMPLE*)outputBuffer;
|
||||
unsigned int i;
|
||||
int finished;
|
||||
|
|
@ -145,12 +135,12 @@ static int playCallback( void *inputBuffer, void *outputBuffer,
|
|||
for( i=0; i<framesLeft; i++ )
|
||||
{
|
||||
*wptr++ = *rptr++; /* left */
|
||||
if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
|
||||
*wptr++ = *rptr++; /* right */
|
||||
}
|
||||
for( ; i<framesPerBuffer; i++ )
|
||||
{
|
||||
*wptr++ = 0; /* left */
|
||||
if( NUM_CHANNELS == 2 ) *wptr++ = 0; /* right */
|
||||
*wptr++ = 0; /* right */
|
||||
}
|
||||
data->frameIndex += framesLeft;
|
||||
finished = 1;
|
||||
|
|
@ -160,7 +150,7 @@ static int playCallback( void *inputBuffer, void *outputBuffer,
|
|||
for( i=0; i<framesPerBuffer; i++ )
|
||||
{
|
||||
*wptr++ = *rptr++; /* left */
|
||||
if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
|
||||
*wptr++ = *rptr++; /* right */
|
||||
}
|
||||
data->frameIndex += framesPerBuffer;
|
||||
finished = 0;
|
||||
|
|
@ -184,7 +174,8 @@ int main(void)
|
|||
|
||||
data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */
|
||||
data.frameIndex = 0;
|
||||
numSamples = totalFrames * NUM_CHANNELS;
|
||||
data.samplesPerFrame = 2;
|
||||
numSamples = totalFrames * data.samplesPerFrame;
|
||||
|
||||
numBytes = numSamples * sizeof(SAMPLE);
|
||||
data.recordedSamples = (SAMPLE *) malloc( numBytes );
|
||||
|
|
@ -202,7 +193,7 @@ int main(void)
|
|||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
Pa_GetDefaultInputDeviceID(),
|
||||
NUM_CHANNELS, /* stereo input */
|
||||
data.samplesPerFrame, /* stereo input */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
paNoDevice,
|
||||
|
|
@ -212,7 +203,7 @@ int main(void)
|
|||
SAMPLE_RATE,
|
||||
1024, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
0, //paDitherOff, /* flags */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
recordCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
|
@ -243,20 +234,10 @@ int main(void)
|
|||
}
|
||||
average += val;
|
||||
}
|
||||
|
||||
printf("sample max amplitude = %d\n", max );
|
||||
average = average / numSamples;
|
||||
printf("sample average = %d\n", average );
|
||||
|
||||
if( PA_SAMPLE_TYPE == paFloat32 )
|
||||
{
|
||||
printf("sample max amplitude = %f\n", max );
|
||||
printf("sample average = %f\n", average );
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("sample max amplitude = %d\n", max );
|
||||
printf("sample average = %d\n", average );
|
||||
}
|
||||
|
||||
/* Write recorded data to a file. */
|
||||
#if 0
|
||||
{
|
||||
|
|
@ -268,7 +249,7 @@ int main(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid );
|
||||
fwrite( data.recordedSamples, data.samplesPerFrame * sizeof(SAMPLE), totalFrames, fid );
|
||||
fclose( fid );
|
||||
printf("Wrote data to 'recorded.raw'\n");
|
||||
}
|
||||
|
|
@ -285,7 +266,7 @@ int main(void)
|
|||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
Pa_GetDefaultOutputDeviceID(),
|
||||
NUM_CHANNELS, /* stereo output */
|
||||
data.samplesPerFrame, /* stereo output */
|
||||
PA_SAMPLE_TYPE,
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/*
|
||||
* $Id$
|
||||
* $Id$
|
||||
* patest_sine.c
|
||||
* Play a sine wave using the Portable Audio api for several seconds.
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
#define NUM_SECONDS (20)
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_BUFFER (512)
|
||||
#define FRAMES_PER_BUFFER (256)
|
||||
#define LEFT_FREQ (SAMPLE_RATE/256.0) /* So we hit 1.0 */
|
||||
#define RIGHT_FREQ (500.0)
|
||||
#define AMPLITUDE (1.0)
|
||||
|
|
@ -57,22 +57,25 @@ typedef unsigned char SAMPLE_t;
|
|||
#define SAMPLE_ZERO (0x80)
|
||||
#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
|
||||
#define FORMAT_NAME "Unsigned 8 Bit"
|
||||
#endif
|
||||
|
||||
#elif TEST_INT8
|
||||
#if TEST_INT8
|
||||
#define TEST_FORMAT paInt8
|
||||
typedef char SAMPLE_t;
|
||||
#define SAMPLE_ZERO (0)
|
||||
#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
|
||||
#define FORMAT_NAME "Signed 8 Bit"
|
||||
#endif
|
||||
|
||||
#elif TEST_INT16
|
||||
#if TEST_INT16
|
||||
#define TEST_FORMAT paInt16
|
||||
typedef short SAMPLE_t;
|
||||
#define SAMPLE_ZERO (0)
|
||||
#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x)))
|
||||
#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767.0 * (x)))
|
||||
#define FORMAT_NAME "Signed 16 Bit"
|
||||
#endif
|
||||
|
||||
#elif TEST_FLOAT32
|
||||
#if TEST_FLOAT32
|
||||
#define TEST_FORMAT paFloat32
|
||||
typedef float SAMPLE_t;
|
||||
#define SAMPLE_ZERO (0.0)
|
||||
|
|
|
|||
|
|
@ -43,18 +43,16 @@
|
|||
#define NUM_SECONDS (8)
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_BUFFER (64)
|
||||
#define NUM_BUFFERS (0)
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265)
|
||||
#endif
|
||||
#define TABLE_SIZE (200)
|
||||
typedef struct
|
||||
{
|
||||
float sine[TABLE_SIZE];
|
||||
int left_phase;
|
||||
int right_phase;
|
||||
int framesToGo;
|
||||
volatile PaTimestamp outTime;
|
||||
float sine[TABLE_SIZE];
|
||||
int left_phase;
|
||||
int right_phase;
|
||||
int framesToGo;
|
||||
}
|
||||
paTestData;
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
|
|
@ -73,8 +71,6 @@ static int patestCallback( void *inputBuffer, void *outputBuffer,
|
|||
(void) outTime; /* Prevent unused variable warnings. */
|
||||
(void) inputBuffer;
|
||||
|
||||
data->outTime = outTime;
|
||||
|
||||
if( data->framesToGo < framesPerBuffer )
|
||||
{
|
||||
framesToCalc = data->framesToGo;
|
||||
|
|
@ -104,44 +100,23 @@ static int patestCallback( void *inputBuffer, void *outputBuffer,
|
|||
}
|
||||
return finished;
|
||||
}
|
||||
/*******************************************************************/
|
||||
static void ReportStreamTime( PortAudioStream *stream, paTestData *data );
|
||||
static void ReportStreamTime( PortAudioStream *stream, paTestData *data )
|
||||
{
|
||||
PaTimestamp streamTime, latency, outTime;
|
||||
|
||||
streamTime = Pa_StreamTime( stream );
|
||||
outTime = data->outTime;
|
||||
if( outTime < 0.0 )
|
||||
{
|
||||
printf("Stream time = %8.1f\n", streamTime );
|
||||
}
|
||||
else
|
||||
{
|
||||
latency = outTime - streamTime;
|
||||
printf("Stream time = %8.1f, outTime = %8.1f, latency = %8.1f\n",
|
||||
streamTime, outTime, latency );
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
paTestData DATA;
|
||||
paTestData data;
|
||||
int i;
|
||||
int totalSamps;
|
||||
printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
|
||||
/* initialise sinusoidal wavetable */
|
||||
for( i=0; i<TABLE_SIZE; i++ )
|
||||
{
|
||||
DATA.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
|
||||
data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
|
||||
}
|
||||
DATA.left_phase = DATA.right_phase = 0;
|
||||
DATA.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
|
||||
data.left_phase = data.right_phase = 0;
|
||||
data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
err = Pa_OpenStream(
|
||||
|
|
@ -156,41 +131,26 @@ int main(void)
|
|||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
patestCallback,
|
||||
&DATA );
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
DATA.outTime = -1.0; // mark time for callback as undefined
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
/* Watch until sound is halfway finished. */
|
||||
printf("Play for %d seconds.\n", NUM_SECONDS/2 ); fflush(stdout);
|
||||
do
|
||||
{
|
||||
ReportStreamTime( stream, &DATA );
|
||||
Pa_Sleep(100);
|
||||
} while( Pa_StreamTime( stream ) < (totalSamps/2) );
|
||||
|
||||
while( Pa_StreamTime( stream ) < (totalSamps/2) ) Pa_Sleep(10);
|
||||
/* Stop sound until ENTER hit. */
|
||||
err = Pa_StopStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
printf("Pause for 2 seconds.\n"); fflush(stdout);
|
||||
Pa_Sleep( 2000 );
|
||||
|
||||
DATA.outTime = -1.0; // mark time for callback as undefined
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Play until sound is finished.\n"); fflush(stdout);
|
||||
do
|
||||
{
|
||||
ReportStreamTime( stream, &DATA );
|
||||
Pa_Sleep(100);
|
||||
} while( Pa_StreamActive( stream ) );
|
||||
|
||||
while( Pa_StreamActive( stream ) ) Pa_Sleep(10);
|
||||
err = Pa_CloseStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
Pa_Terminate();
|
||||
|
|
|
|||
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
* $Id$
|
||||
* Play more sine waves than we can handle in real time as a stress test,
|
||||
*
|
||||
* Authors:
|
||||
* Ross Bencina <rossb@audiomulch.com>
|
||||
* Phil Burk <philburk@softsynth.com>
|
||||
*
|
||||
* This program uses the PortAudio Portable Audio Library.
|
||||
* For more information see: http://www.audiomulch.com/portaudio/
|
||||
* Copyright (c) 1999-2000 Ross Bencina and Phil Burk
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* Any person wishing to distribute modifications to the Software is
|
||||
* requested to send the modifications to the original developer so that
|
||||
* they can be incorporated into the canonical version.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
|
||||
#define MAX_SINES (500)
|
||||
#define MAX_LOAD (1.2)
|
||||
#define SAMPLE_RATE (44100)
|
||||
#define FRAMES_PER_BUFFER (512)
|
||||
#ifndef M_PI
|
||||
#define M_PI (3.14159265)
|
||||
#endif
|
||||
#define TWOPI (M_PI * 2.0)
|
||||
|
||||
typedef struct paTestData
|
||||
{
|
||||
int numSines;
|
||||
double phases[MAX_SINES];
|
||||
}
|
||||
paTestData;
|
||||
|
||||
/* This routine will be called by the PortAudio engine when audio is needed.
|
||||
** It may called at interrupt level on some machines so don't do anything
|
||||
** that could mess up the system like calling malloc() or free().
|
||||
*/
|
||||
static int patestCallback( void *inputBuffer, void *outputBuffer,
|
||||
unsigned long framesPerBuffer,
|
||||
PaTimestamp outTime, void *userData )
|
||||
{
|
||||
paTestData *data = (paTestData*)userData;
|
||||
float *out = (float*)outputBuffer;
|
||||
unsigned long i;
|
||||
int j;
|
||||
int finished = 0;
|
||||
(void) outTime; /* Prevent unused variable warnings. */
|
||||
(void) inputBuffer;
|
||||
|
||||
for( i=0; i<framesPerBuffer; i++ )
|
||||
{
|
||||
float output = 0.0;
|
||||
double phaseInc = 0.02;
|
||||
double phase;
|
||||
for( j=0; j<data->numSines; j++ )
|
||||
{
|
||||
/* Advance phase of next oscillator. */
|
||||
phase = data->phases[j];
|
||||
phase += phaseInc;
|
||||
if( phase > TWOPI ) phase -= TWOPI;
|
||||
|
||||
phaseInc *= 1.02;
|
||||
if( phaseInc > 0.5 ) phaseInc *= 0.5;
|
||||
|
||||
/* This is not a very efficient way to calc sines. */
|
||||
output += (float) sin( phase );
|
||||
data->phases[j] = phase;
|
||||
}
|
||||
|
||||
|
||||
*out++ = (float) (output / data->numSines);
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
int main(void);
|
||||
int main(void)
|
||||
{
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
int numStress;
|
||||
paTestData data = {0};
|
||||
double load;
|
||||
printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d. MAX_LOAD = %f\n",
|
||||
SAMPLE_RATE, FRAMES_PER_BUFFER, MAX_LOAD );
|
||||
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
paNoDevice,/* default input device */
|
||||
0, /* no input */
|
||||
paFloat32, /* 32 bit floating point input */
|
||||
NULL,
|
||||
Pa_GetDefaultOutputDeviceID(), /* default output device */
|
||||
1, /* mono output */
|
||||
paFloat32, /* 32 bit floating point output */
|
||||
NULL,
|
||||
SAMPLE_RATE,
|
||||
FRAMES_PER_BUFFER, /* frames per buffer */
|
||||
0, /* number of buffers, if zero then use default minimum */
|
||||
paClipOff, /* we won't output out of range samples so don't bother clipping them */
|
||||
patestCallback,
|
||||
&data );
|
||||
if( err != paNoError ) goto error;
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
/* Determine number of sines required to get to 50% */
|
||||
do
|
||||
{
|
||||
data.numSines++;
|
||||
Pa_Sleep( 100 );
|
||||
|
||||
load = Pa_GetCPULoad( stream );
|
||||
printf("numSines = %d, CPU load = %f\n", data.numSines, load );
|
||||
}
|
||||
while( load < 0.5 );
|
||||
|
||||
/* Calculate target stress value then ramp up to that level*/
|
||||
numStress = (int) (2.0 * data.numSines * MAX_LOAD );
|
||||
for( ; data.numSines < numStress; data.numSines++ )
|
||||
{
|
||||
Pa_Sleep( 200 );
|
||||
load = Pa_GetCPULoad( stream );
|
||||
printf("STRESSING: numSines = %d, CPU load = %f\n", data.numSines, load );
|
||||
}
|
||||
|
||||
printf("Suffer for 5 seconds.\n");
|
||||
Pa_Sleep( 5000 );
|
||||
|
||||
printf("Stop stream.\n");
|
||||
err = Pa_StopStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_CloseStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
Pa_Terminate();
|
||||
printf("Test finished.\n");
|
||||
return err;
|
||||
error:
|
||||
Pa_Terminate();
|
||||
fprintf( stderr, "An error occured while using the portaudio stream\n" );
|
||||
fprintf( stderr, "Error number: %d\n", err );
|
||||
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
||||
return err;
|
||||
}
|
||||
|
|
@ -69,6 +69,7 @@ static int wireCallback( void *inputBuffer, void *outputBuffer,
|
|||
SAMPLE *out = (SAMPLE*)outputBuffer;
|
||||
SAMPLE *in = (SAMPLE*)inputBuffer;
|
||||
unsigned int i;
|
||||
int finished = 0;
|
||||
(void) outTime;
|
||||
|
||||
/* This may get called with NULL inputBuffer during initial setup. */
|
||||
|
|
@ -97,12 +98,11 @@ int main(void)
|
|||
{
|
||||
PortAudioStream *stream;
|
||||
PaError err;
|
||||
|
||||
int numDevices = Pa_CountDevices();
|
||||
err = Pa_Initialize();
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("PortAudio Test: input device ID = %d\n", Pa_GetDefaultInputDeviceID() );
|
||||
printf("PortAudio Test: output device ID = %d\n", Pa_GetDefaultOutputDeviceID() );
|
||||
printf("PortAudio Test: input device = %d\n", Pa_GetDefaultInputDeviceID() );
|
||||
printf("PortAudio Test: output device = %d\n", Pa_GetDefaultOutputDeviceID() );
|
||||
err = Pa_OpenStream(
|
||||
&stream,
|
||||
Pa_GetDefaultInputDeviceID(), /* default output device */
|
||||
|
|
@ -120,19 +120,14 @@ int main(void)
|
|||
wireCallback,
|
||||
NULL ); /* no data */
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
err = Pa_StartStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
|
||||
printf("Full duplex sound test in progress.\n");
|
||||
printf("Hit ENTER to exit test.\n"); fflush(stdout);
|
||||
printf("Hit ENTER to exit test.\n");
|
||||
getchar();
|
||||
|
||||
printf("Closing stream.\n");
|
||||
err = Pa_CloseStream( stream );
|
||||
if( err != paNoError ) goto error;
|
||||
Pa_Terminate();
|
||||
|
||||
printf("Full duplex sound test complete.\n"); fflush(stdout);
|
||||
return 0;
|
||||
error:
|
||||
|
|
|
|||
|
|
@ -3,18 +3,15 @@
|
|||
LIBS = -lm -lpthread
|
||||
|
||||
CDEFINES = -I../pa_common
|
||||
CFLAGS = -g -Wall
|
||||
CFLAGS = -g
|
||||
PASRC = ../pa_common/pa_lib.c pa_unix_oss.c
|
||||
PAINC = ../pa_common/portaudio.h
|
||||
|
||||
# Tests that work.
|
||||
TESTC = $(PASRC) ../pa_tests/patest_sine.c
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_longsine.c
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_maxsines.c
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_toomanysines.c
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_underflow.c
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_hang.c
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_stop.c
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_sync.c
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_pink.c
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_leftright.c
|
||||
|
|
@ -28,8 +25,6 @@ TESTC = $(PASRC) ../pa_tests/patest_sine.c
|
|||
#TESTC = $(PASRC) ../pa_tests/paqa_devs.c
|
||||
|
||||
# Tests that do not yet work.
|
||||
# OSS doesn't let us make obscenely huge buffers so the test will seem to fail. But its OK.
|
||||
#TESTC = $(PASRC) ../pa_tests/patest_stop.c
|
||||
|
||||
TESTH = $(PAINC)
|
||||
|
||||
|
|
|
|||
|
|
@ -58,16 +58,9 @@ Modfication History
|
|||
PLB20010927 - Phil - Improved negotiation for numChannels.
|
||||
SG20011005 - Stewart Greenhill - set numChannels back to reasonable value after query.
|
||||
DH20010115 - David Herring - fixed uninitialized handle.
|
||||
|
||||
DM20020218 - Dominic Mazzoni - Try to open in nonblocking mode first, in case
|
||||
the device is already open. New implementation of
|
||||
Pa_StreamTime that uses SNDCTL_DSP_GETOPTR but
|
||||
uses our own counter to avoid wraparound.
|
||||
PLB20020222 - Phil Burk - Added WatchDog proc if audio running at high priority.
|
||||
Check error return from read() and write().
|
||||
Check CPU endianness instead of assuming Little Endian.
|
||||
|
||||
TODO
|
||||
O- change Pa_StreamTime() to query device (patest_sync.c)
|
||||
O- put semaphore lock around shared data?
|
||||
O- handle native formats better
|
||||
O- handle stereo-only device better ???
|
||||
|
|
@ -98,14 +91,17 @@ PaDriverInfo;
|
|||
#include <malloc.h>
|
||||
#include <memory.h>
|
||||
#include <math.h>
|
||||
#include "portaudio.h"
|
||||
#include "pa_host.h"
|
||||
#include "pa_trace.h"
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <linux/soundcard.h>
|
||||
|
|
@ -113,9 +109,13 @@ PaDriverInfo;
|
|||
#include <machine/soundcard.h> /* JH20010905 */
|
||||
#endif
|
||||
|
||||
#include "portaudio.h"
|
||||
#include "pa_host.h"
|
||||
#include "pa_trace.h"
|
||||
#include <sched.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* Some versions of OSS do not define AFMT_S16_NE. Assume little endian. FIXME - check CPU*/
|
||||
#ifndef AFMT_S16_NE
|
||||
#define AFMT_S16_NE AFMT_S16_LE
|
||||
#endif
|
||||
|
||||
#define PRINT(x) { printf x; fflush(stdout); }
|
||||
#define ERR_RPT(x) PRINT(x)
|
||||
|
|
@ -135,9 +135,6 @@ PaDriverInfo;
|
|||
#define DEVICE_NAME_BASE "/dev/audio"
|
||||
#endif
|
||||
|
||||
/* What is a pthread_t anyway? Here is a guess at a value that will never happen in real life. */
|
||||
#define INVALID_THREAD (-1)
|
||||
|
||||
#define MAX_CHARS_DEVNAME (32)
|
||||
#define MAX_SAMPLE_RATES (10)
|
||||
typedef struct internalPortAudioDevice
|
||||
|
|
@ -154,14 +151,7 @@ typedef struct PaHostSoundControl
|
|||
{
|
||||
int pahsc_OutputHandle;
|
||||
int pahsc_InputHandle;
|
||||
int pahsc_AudioPriority; /* priority of background audio thread */
|
||||
pthread_t pahsc_AudioThread; /* background audio thread */
|
||||
pid_t pahsc_AudioThreadPID; /* background audio thread */
|
||||
pthread_t pahsc_WatchDogThread; /* highest priority thread that protects system */
|
||||
int pahsc_WatchDogRun; /* Ask WatchDog to stop. */
|
||||
pthread_t pahsc_CanaryThread; /* low priority thread that detects abuse by audio */
|
||||
struct timeval pahsc_CanaryTime;
|
||||
int pahsc_CanaryRun; /* Ask Canary to stop. */
|
||||
pthread_t pahsc_ThreadPID;
|
||||
short *pahsc_NativeInputBuffer;
|
||||
short *pahsc_NativeOutputBuffer;
|
||||
unsigned int pahsc_BytesPerInputBuffer; /* native buffer size in bytes */
|
||||
|
|
@ -169,30 +159,29 @@ typedef struct PaHostSoundControl
|
|||
/* For measuring CPU utilization. */
|
||||
struct timeval pahsc_EntryTime;
|
||||
double pahsc_InverseMicrosPerBuffer; /* 1/Microseconds of real-time audio per user buffer. */
|
||||
|
||||
/* For calculating stream time */
|
||||
int pahsc_LastPosPtr;
|
||||
double pahsc_LastStreamBytes;
|
||||
}
|
||||
PaHostSoundControl;
|
||||
|
||||
/************************************************* Shared Data ********/
|
||||
/* FIXME - put Mutex around this shared data. */
|
||||
static int sDeviceIndex = 0;
|
||||
static internalPortAudioDevice *sDeviceList = NULL;
|
||||
static int sDefaultInputDeviceID = paNoDevice;
|
||||
static int sDefaultOutputDeviceID = paNoDevice;
|
||||
static int sEnumerationError;
|
||||
static int sPaHostError = 0;
|
||||
|
||||
/************************************************* Prototypes **********/
|
||||
|
||||
static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id );
|
||||
static PaError Pa_QueryDevices( void );
|
||||
static Pa_QueryDevices( void );
|
||||
static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad );
|
||||
static PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleRate );
|
||||
|
||||
/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
|
||||
static void Pa_StartUsageCalculation( internalPortAudioStream *past )
|
||||
{
|
||||
struct itimerval itimer;
|
||||
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
if( pahsc == NULL ) return;
|
||||
/* Query system timer for usage analysis and to prevent overuse of CPU. */
|
||||
|
|
@ -235,21 +224,6 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past )
|
|||
}
|
||||
/****************************************** END CPU UTILIZATION *******/
|
||||
|
||||
#ifndef AFMT_S16_NE
|
||||
#define AFMT_S16_NE Get_AFMT_S16_NE()
|
||||
/*********************************************************************
|
||||
* Some versions of OSS do not define AFMT_S16_NE. So check CPU.
|
||||
* PowerPC is Big Endian. X86 is Little Endian.
|
||||
*/
|
||||
static int Get_AFMT_S16_NE( void )
|
||||
{
|
||||
long testData = 1;
|
||||
char *ptr = (char *) &testData;
|
||||
int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */
|
||||
return isLittle ? AFMT_S16_LE : AFMT_S16_BE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*********************************************************************
|
||||
* Try to open the named device.
|
||||
* If it opens, try to set various rates and formats and fill in
|
||||
|
|
@ -258,6 +232,7 @@ static int Get_AFMT_S16_NE( void )
|
|||
static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad )
|
||||
{
|
||||
int result = paHostError;
|
||||
int numBytes;
|
||||
int tempDevHandle;
|
||||
int numChannels, maxNumChannels;
|
||||
int format;
|
||||
|
|
@ -274,7 +249,7 @@ static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *
|
|||
the correct order for OSS is: format, channels, sample rate
|
||||
|
||||
*/
|
||||
if ( (tempDevHandle = open(deviceName,O_WRONLY|O_NONBLOCK)) == -1 )
|
||||
if ( (tempDevHandle = open(deviceName,O_WRONLY)) == -1 )
|
||||
{
|
||||
DBUG(("Pa_QueryDevice: could not open %s\n", deviceName ));
|
||||
return paHostError;
|
||||
|
|
@ -400,6 +375,7 @@ error:
|
|||
static PaError Pa_QueryDevices( void )
|
||||
{
|
||||
internalPortAudioDevice *pad, *lastPad;
|
||||
int numBytes;
|
||||
int go = 1;
|
||||
int numDevices = 0;
|
||||
PaError testResult;
|
||||
|
|
@ -529,273 +505,55 @@ PaError PaHost_Init( void )
|
|||
return Pa_MaybeQueryDevices();
|
||||
}
|
||||
|
||||
/*******************************************************************************************
|
||||
* The ol' Canary in a Coal Mine trick.
|
||||
* Just update the time periodically.
|
||||
* Runs at low priority so if audio thread runs wild, this thread will get starved
|
||||
* and the watchdog will detect it.
|
||||
*/
|
||||
|
||||
#define SCHEDULER_POLICY SCHED_RR
|
||||
#define WATCHDOG_MAX_SECONDS (3)
|
||||
#define WATCHDOG_INTERVAL_USEC (1000000)
|
||||
|
||||
static int PaHost_CanaryProc( PaHostSoundControl *pahsc )
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
#ifdef GNUSTEP
|
||||
GSRegisterCurrentThread(); /* SB20010904 */
|
||||
#endif
|
||||
|
||||
while( pahsc->pahsc_CanaryRun && ((result = usleep( WATCHDOG_INTERVAL_USEC )) == 0) )
|
||||
{
|
||||
gettimeofday( &pahsc->pahsc_CanaryTime, NULL );
|
||||
}
|
||||
|
||||
DBUG(("PaHost_CanaryProc: exiting.\n"));
|
||||
|
||||
#ifdef GNUSTEP
|
||||
GSUnregisterCurrentThread(); /* SB20010904 */
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*******************************************************************************************
|
||||
* Monitor audio thread and lower its it if it hogs the CPU.
|
||||
* To prevent getting killed, the audio thread must update a
|
||||
* variable with a timer value.
|
||||
* If the value is not recent enough, then the
|
||||
* thread will get killed.
|
||||
*/
|
||||
|
||||
static PaError PaHost_WatchDogProc( PaHostSoundControl *pahsc )
|
||||
{
|
||||
PaError result = 0;
|
||||
struct sched_param schp = { 0 };
|
||||
int maxPri;
|
||||
|
||||
#ifdef GNUSTEP
|
||||
GSRegisterCurrentThread(); /* SB20010904 */
|
||||
#endif
|
||||
|
||||
/* Run at a priority level above audio thread so we can still run if it hangs. */
|
||||
/* Rise more than 1 because of rumored off-by-one scheduler bugs. */
|
||||
schp.sched_priority = pahsc->pahsc_AudioPriority + 4;
|
||||
maxPri = sched_get_priority_max(SCHEDULER_POLICY);
|
||||
if( schp.sched_priority > maxPri ) schp.sched_priority = maxPri;
|
||||
|
||||
if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0)
|
||||
{
|
||||
ERR_RPT(("PaHost_WatchDogProc: cannot set watch dog priority!\n"));
|
||||
goto killAudio;
|
||||
}
|
||||
|
||||
/* Compare watchdog time with audio and canary thread times. */
|
||||
/* Sleep for a while or until thread cancelled. */
|
||||
while( pahsc->pahsc_WatchDogRun && ((result = usleep( WATCHDOG_INTERVAL_USEC )) == 0) )
|
||||
{
|
||||
int delta;
|
||||
struct timeval currentTime;
|
||||
|
||||
gettimeofday( ¤tTime, NULL );
|
||||
|
||||
/* If audio thread is not advancing, then lower its priority. */
|
||||
delta = currentTime.tv_sec - pahsc->pahsc_EntryTime.tv_sec;
|
||||
DBUG(("PaHost_WatchDogProc: audio delta = %d\n", delta ));
|
||||
if( delta > WATCHDOG_MAX_SECONDS )
|
||||
{
|
||||
goto killAudio;
|
||||
}
|
||||
|
||||
/* If canary died, then kill audio and canary. */
|
||||
delta = currentTime.tv_sec - pahsc->pahsc_CanaryTime.tv_sec;
|
||||
if( delta > WATCHDOG_MAX_SECONDS )
|
||||
{
|
||||
ERR_RPT(("PaHost_WatchDogProc: canary died!\n"));
|
||||
goto lowerAudio;
|
||||
}
|
||||
}
|
||||
|
||||
DBUG(("PaHost_WatchDogProc: exiting.\n"));
|
||||
#ifdef GNUSTEP
|
||||
GSUnregisterCurrentThread(); /* SB20010904 */
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
lowerAudio:
|
||||
{
|
||||
struct sched_param schat = { 0 };
|
||||
if( sched_setscheduler(pahsc->pahsc_AudioThreadPID, SCHED_OTHER, &schat) != 0)
|
||||
{
|
||||
ERR_RPT(("PaHost_WatchDogProc: failed to lower audio priority. errno = %d\n", errno ));
|
||||
/* Fall through into killing audio thread. */
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_RPT(("PaHost_WatchDogProc: lowered audio priority to prevent hogging of CPU.\n"));
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
killAudio:
|
||||
ERR_RPT(("PaHost_WatchDogProc: killing hung audio thread!\n"));
|
||||
pthread_kill( pahsc->pahsc_AudioThread, SIGKILL );
|
||||
|
||||
cleanup:
|
||||
pahsc->pahsc_CanaryRun = 0;
|
||||
DBUG(("PaHost_WatchDogProc: cancel Canary\n"));
|
||||
pthread_cancel( pahsc->pahsc_CanaryThread );
|
||||
DBUG(("PaHost_WatchDogProc: join Canary\n"));
|
||||
pthread_join( pahsc->pahsc_CanaryThread, NULL );
|
||||
DBUG(("PaHost_WatchDogProc: forget Canary\n"));
|
||||
pahsc->pahsc_CanaryThread = INVALID_THREAD;
|
||||
|
||||
#ifdef GNUSTEP
|
||||
GSUnregisterCurrentThread(); /* SB20010904 */
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************************/
|
||||
static void PaHost_StopWatchDog( PaHostSoundControl *pahsc )
|
||||
{
|
||||
/* Cancel WatchDog thread if there is one. */
|
||||
if( pahsc->pahsc_WatchDogThread != INVALID_THREAD )
|
||||
{
|
||||
pahsc->pahsc_WatchDogRun = 0;
|
||||
DBUG(("PaHost_StopWatchDog: cancel WatchDog\n"));
|
||||
pthread_cancel( pahsc->pahsc_WatchDogThread );
|
||||
pthread_join( pahsc->pahsc_WatchDogThread, NULL );
|
||||
pahsc->pahsc_WatchDogThread = INVALID_THREAD;
|
||||
}
|
||||
/* Cancel Canary thread if there is one. */
|
||||
if( pahsc->pahsc_CanaryThread != INVALID_THREAD )
|
||||
{
|
||||
pahsc->pahsc_CanaryRun = 0;
|
||||
DBUG(("PaHost_StopWatchDog: cancel Canary\n"));
|
||||
pthread_cancel( pahsc->pahsc_CanaryThread );
|
||||
DBUG(("PaHost_StopWatchDog: join Canary\n"));
|
||||
pthread_join( pahsc->pahsc_CanaryThread, NULL );
|
||||
pahsc->pahsc_CanaryThread = INVALID_THREAD;
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************************/
|
||||
static PaError PaHost_StartWatchDog( PaHostSoundControl *pahsc )
|
||||
{
|
||||
int hres;
|
||||
PaError result = 0;
|
||||
|
||||
/* The watch dog watches for these timer updates */
|
||||
gettimeofday( &pahsc->pahsc_EntryTime, NULL );
|
||||
gettimeofday( &pahsc->pahsc_CanaryTime, NULL );
|
||||
|
||||
/* Launch a canary thread to detect priority abuse. */
|
||||
pahsc->pahsc_CanaryRun = 1;
|
||||
hres = pthread_create(&(pahsc->pahsc_CanaryThread),
|
||||
NULL /*pthread_attr_t * attr*/,
|
||||
(void*)PaHost_CanaryProc, pahsc);
|
||||
if( hres != 0 )
|
||||
{
|
||||
pahsc->pahsc_CanaryThread = INVALID_THREAD;
|
||||
result = paHostError;
|
||||
sPaHostError = hres;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Launch a watchdog thread to prevent runaway audio thread. */
|
||||
pahsc->pahsc_WatchDogRun = 1;
|
||||
hres = pthread_create(&(pahsc->pahsc_WatchDogThread),
|
||||
NULL /*pthread_attr_t * attr*/,
|
||||
(void*)PaHost_WatchDogProc, pahsc);
|
||||
if( hres != 0 )
|
||||
{
|
||||
pahsc->pahsc_WatchDogThread = INVALID_THREAD;
|
||||
result = paHostError;
|
||||
sPaHostError = hres;
|
||||
goto error;
|
||||
}
|
||||
return result;
|
||||
|
||||
error:
|
||||
PaHost_StopWatchDog( pahsc );
|
||||
return result;
|
||||
}
|
||||
|
||||
/*******************************************************************************************
|
||||
* Bump priority of audio thread if running with superuser priveledges.
|
||||
* if priority bumped then launch a watchdog.
|
||||
*/
|
||||
static PaError PaHost_BoostPriority( internalPortAudioStream *past )
|
||||
{
|
||||
PaHostSoundControl *pahsc;
|
||||
PaError result = paNoError;
|
||||
struct sched_param schp = { 0 };
|
||||
|
||||
pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
if( pahsc == NULL ) return paInternalError;
|
||||
|
||||
pahsc->pahsc_AudioThreadPID = getpid();
|
||||
DBUG(("PaHost_BoostPriority: audio PID = %d\n", pahsc->pahsc_AudioThreadPID ));
|
||||
|
||||
/* Choose a priority in the middle of the range. */
|
||||
pahsc->pahsc_AudioPriority = (sched_get_priority_max(SCHEDULER_POLICY) -
|
||||
sched_get_priority_min(SCHEDULER_POLICY)) / 2;
|
||||
schp.sched_priority = pahsc->pahsc_AudioPriority;
|
||||
|
||||
if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0)
|
||||
{
|
||||
PRINT(("PortAudio: only superuser can use real-time priority.\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
PRINT(("PortAudio: audio callback priority set to level %d!\n", schp.sched_priority));
|
||||
/* We are running at high priority so we should have a watchdog in case audio goes wild. */
|
||||
result = PaHost_StartWatchDog( pahsc );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*******************************************************************************************/
|
||||
static PaError Pa_AudioThreadProc( internalPortAudioStream *past )
|
||||
{
|
||||
PaError result;
|
||||
PaError result = 0;
|
||||
PaHostSoundControl *pahsc;
|
||||
ssize_t bytes_read, bytes_written;
|
||||
count_info info;
|
||||
int delta;
|
||||
short bytes_read = 0;
|
||||
|
||||
pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
if( pahsc == NULL ) return paInternalError;
|
||||
|
||||
#ifdef GNUSTEP
|
||||
GSRegisterCurrentThread(); /* SB20010904 */
|
||||
#endif
|
||||
|
||||
result = PaHost_BoostPriority( past );
|
||||
if( result < 0 ) goto error;
|
||||
#if 1
|
||||
{
|
||||
#define SCHEDULER_POLICY SCHED_RR
|
||||
|
||||
struct sched_param schp;
|
||||
memset(&schp, 0, sizeof(schp));
|
||||
schp.sched_priority = sched_get_priority_max(SCHEDULER_POLICY);
|
||||
|
||||
if (sched_setscheduler(0, SCHEDULER_POLICY, &schp) != 0)
|
||||
{
|
||||
perror("sched_setscheduler");
|
||||
printf("PortAudio: only superuser can use real-time priority.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("PortAudio: callback priority set to level %d!\n", schp.sched_priority);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
if( pahsc == NULL ) return paInternalError;
|
||||
|
||||
past->past_IsActive = 1;
|
||||
DBUG(("entering thread.\n"));
|
||||
|
||||
while( (past->past_StopNow == 0) && (past->past_StopSoon == 0) )
|
||||
{
|
||||
|
||||
DBUG(("go!\n"));
|
||||
/* Read data from device */
|
||||
if(pahsc->pahsc_NativeInputBuffer)
|
||||
{
|
||||
DBUG(("Pa_AudioThreadProc: attempt to read %d bytes\n", pahsc->pahsc_BytesPerInputBuffer));
|
||||
bytes_read = read(pahsc->pahsc_InputHandle,
|
||||
(void *)pahsc->pahsc_NativeInputBuffer,
|
||||
pahsc->pahsc_BytesPerInputBuffer);
|
||||
DBUG(("Pa_AudioThreadProc: bytes_read = %d\n", bytes_read));
|
||||
if( bytes_read < pahsc->pahsc_BytesPerInputBuffer )
|
||||
{
|
||||
ERR_RPT(("PortAudio: read interrupted! Only got %d bytes.\n", bytes_read ));
|
||||
break;
|
||||
}
|
||||
|
||||
DBUG(("bytes_read: %d\n", bytes_read));
|
||||
}
|
||||
|
||||
/* Convert 16 bit native data to user data and call user routine. */
|
||||
|
|
@ -816,37 +574,19 @@ static PaError Pa_AudioThreadProc( internalPortAudioStream *past )
|
|||
if( pahsc->pahsc_NativeOutputBuffer )
|
||||
{
|
||||
|
||||
bytes_written = write(pahsc->pahsc_OutputHandle,
|
||||
write(pahsc->pahsc_OutputHandle,
|
||||
(void *)pahsc->pahsc_NativeOutputBuffer,
|
||||
pahsc->pahsc_BytesPerOutputBuffer);
|
||||
if( bytes_written < pahsc->pahsc_BytesPerOutputBuffer )
|
||||
{
|
||||
ERR_RPT(("PortAudio: write interrupted! Only got %d bytes.\n", bytes_written ));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update current stream time (using a double so that
|
||||
we don't wrap around like info.bytes does) */
|
||||
if( pahsc->pahsc_NativeOutputBuffer )
|
||||
ioctl(pahsc->pahsc_OutputHandle, SNDCTL_DSP_GETOPTR, &info);
|
||||
else
|
||||
ioctl(pahsc->pahsc_InputHandle, SNDCTL_DSP_GETIPTR, &info);
|
||||
delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF;
|
||||
pahsc->pahsc_LastStreamBytes += delta;
|
||||
pahsc->pahsc_LastPosPtr = info.bytes;
|
||||
}
|
||||
DBUG(("Pa_AudioThreadProc: left audio loop.\n"));
|
||||
|
||||
|
||||
past->past_IsActive = 0;
|
||||
PaHost_StopWatchDog( pahsc );
|
||||
|
||||
error:
|
||||
DBUG(("leaving audio thread.\n"));
|
||||
DBUG(("leaving thread.\n"));
|
||||
|
||||
#ifdef GNUSTEP
|
||||
GSUnregisterCurrentThread(); /* SB20010904 */
|
||||
#endif
|
||||
return result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************************************/
|
||||
|
|
@ -863,7 +603,7 @@ static PaError Pa_SetupDeviceFormat( int devHandle, int numChannels, int sampleR
|
|||
ERR_RPT(("Pa_SetupDeviceFormat: could not SNDCTL_DSP_SETFMT\n" ));
|
||||
return paHostError;
|
||||
}
|
||||
if( tmp != AFMT_S16_NE )
|
||||
if( tmp != AFMT_S16_NE)
|
||||
{
|
||||
ERR_RPT(("Pa_SetupDeviceFormat: HW does not support AFMT_S16_NE\n" ));
|
||||
return paHostError;
|
||||
|
|
@ -912,7 +652,7 @@ static int CalcHigherLogTwo( int n )
|
|||
static void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, int channelsPerFrame )
|
||||
{
|
||||
int tmp;
|
||||
int bufferSize, powerOfTwo;
|
||||
int numFrames , bufferSize, powerOfTwo;
|
||||
|
||||
/* Increase size of buffers and reduce number of buffers to reduce latency inside driver. */
|
||||
while( numBuffers > 8 )
|
||||
|
|
@ -922,7 +662,7 @@ static void Pa_SetLatency( int devHandle, int numBuffers, int framesPerBuffer, i
|
|||
}
|
||||
|
||||
/* calculate size of buffers in bytes */
|
||||
bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME - other sizes? */
|
||||
bufferSize = framesPerBuffer * channelsPerFrame * sizeof(short); /* FIXME */
|
||||
|
||||
/* Calculate next largest power of two */
|
||||
powerOfTwo = CalcHigherLogTwo( bufferSize );
|
||||
|
|
@ -975,6 +715,9 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
|
|||
{
|
||||
PaError result = paNoError;
|
||||
PaHostSoundControl *pahsc;
|
||||
int tmp;
|
||||
int flags;
|
||||
int numBytes, maxChannels;
|
||||
unsigned int minNumBuffers;
|
||||
internalPortAudioDevice *pad;
|
||||
DBUG(("PaHost_OpenStream() called.\n" ));
|
||||
|
|
@ -991,8 +734,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
|
|||
|
||||
pahsc->pahsc_OutputHandle = BAD_DEVICE_ID; /* No device currently opened. */
|
||||
pahsc->pahsc_InputHandle = BAD_DEVICE_ID;
|
||||
pahsc->pahsc_AudioThread = INVALID_THREAD;
|
||||
pahsc->pahsc_WatchDogThread = INVALID_THREAD;
|
||||
|
||||
/* Allocate native buffers. */
|
||||
pahsc->pahsc_BytesPerInputBuffer = past->past_FramesPerUserBuffer *
|
||||
|
|
@ -1035,18 +776,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
|
|||
{
|
||||
pad = Pa_GetInternalDevice( past->past_OutputDeviceID );
|
||||
DBUG(("PaHost_OpenStream: attempt to open %s for O_RDWR\n", pad->pad_DeviceName ));
|
||||
|
||||
/* dmazzoni: test it first in nonblocking mode to
|
||||
make sure the device is not busy */
|
||||
pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDWR|O_NONBLOCK);
|
||||
if(pahsc->pahsc_InputHandle==-1)
|
||||
{
|
||||
ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDWR\n", pad->pad_DeviceName ));
|
||||
result = paHostError;
|
||||
goto error;
|
||||
}
|
||||
close(pahsc->pahsc_InputHandle);
|
||||
|
||||
pahsc->pahsc_OutputHandle = pahsc->pahsc_InputHandle =
|
||||
open(pad->pad_DeviceName,O_RDWR);
|
||||
if(pahsc->pahsc_InputHandle==-1)
|
||||
|
|
@ -1068,17 +797,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
|
|||
{
|
||||
pad = Pa_GetInternalDevice( past->past_OutputDeviceID );
|
||||
DBUG(("PaHost_OpenStream: attempt to open %s for O_WRONLY\n", pad->pad_DeviceName ));
|
||||
/* dmazzoni: test it first in nonblocking mode to
|
||||
make sure the device is not busy */
|
||||
pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY|O_NONBLOCK);
|
||||
if(pahsc->pahsc_OutputHandle==-1)
|
||||
{
|
||||
ERR_RPT(("PaHost_OpenStream: could not open %s for O_WRONLY\n", pad->pad_DeviceName ));
|
||||
result = paHostError;
|
||||
goto error;
|
||||
}
|
||||
close(pahsc->pahsc_OutputHandle);
|
||||
|
||||
pahsc->pahsc_OutputHandle = open(pad->pad_DeviceName,O_WRONLY);
|
||||
if(pahsc->pahsc_OutputHandle==-1)
|
||||
{
|
||||
|
|
@ -1097,17 +815,6 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
|
|||
{
|
||||
pad = Pa_GetInternalDevice( past->past_InputDeviceID );
|
||||
DBUG(("PaHost_OpenStream: attempt to open %s for O_RDONLY\n", pad->pad_DeviceName ));
|
||||
/* dmazzoni: test it first in nonblocking mode to
|
||||
make sure the device is not busy */
|
||||
pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY|O_NONBLOCK);
|
||||
if(pahsc->pahsc_InputHandle==-1)
|
||||
{
|
||||
ERR_RPT(("PaHost_OpenStream: could not open %s for O_RDONLY\n", pad->pad_DeviceName ));
|
||||
result = paHostError;
|
||||
goto error;
|
||||
}
|
||||
close(pahsc->pahsc_InputHandle);
|
||||
|
||||
pahsc->pahsc_InputHandle = open(pad->pad_DeviceName,O_RDONLY);
|
||||
if(pahsc->pahsc_InputHandle==-1)
|
||||
{
|
||||
|
|
@ -1162,14 +869,13 @@ PaError PaHost_StartEngine( internalPortAudioStream *past )
|
|||
* - pthread_create also works for other UNIX systems like Solaris,
|
||||
* - the Java HotSpot VM crashes in pthread_setcanceltype() when using __clone()
|
||||
*/
|
||||
hres = pthread_create(&(pahsc->pahsc_AudioThread),
|
||||
hres = pthread_create(&(pahsc->pahsc_ThreadPID),
|
||||
NULL /*pthread_attr_t * attr*/,
|
||||
(void*)Pa_AudioThreadProc, past);
|
||||
if( hres != 0 )
|
||||
{
|
||||
result = paHostError;
|
||||
sPaHostError = hres;
|
||||
pahsc->pahsc_AudioThread = INVALID_THREAD;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
|
@ -1181,6 +887,7 @@ error:
|
|||
PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
|
||||
{
|
||||
int hres;
|
||||
long timeOut;
|
||||
PaError result = paNoError;
|
||||
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
|
||||
|
|
@ -1192,12 +899,12 @@ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
|
|||
if( abort ) past->past_StopNow = 1;
|
||||
|
||||
/* Join thread to recover memory resources. */
|
||||
if( pahsc->pahsc_AudioThread != INVALID_THREAD )
|
||||
if( pahsc->pahsc_ThreadPID != -1 )
|
||||
{
|
||||
/* This check is needed for GNUSTEP - SB20010904 */
|
||||
if ( !pthread_equal( pahsc->pahsc_AudioThread, pthread_self() ) )
|
||||
if ( !pthread_equal( pahsc->pahsc_ThreadPID, pthread_self() ) )
|
||||
{
|
||||
hres = pthread_join( pahsc->pahsc_AudioThread, NULL );
|
||||
hres = pthread_join( pahsc->pahsc_ThreadPID, NULL );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1210,7 +917,7 @@ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
|
|||
result = paHostError;
|
||||
sPaHostError = hres;
|
||||
}
|
||||
pahsc->pahsc_AudioThread = INVALID_THREAD;
|
||||
pahsc->pahsc_ThreadPID = -1;
|
||||
}
|
||||
|
||||
past->past_IsActive = 0;
|
||||
|
|
@ -1322,7 +1029,7 @@ void Pa_Sleep( long msec )
|
|||
*/
|
||||
void *PaHost_AllocateFastMemory( long numBytes )
|
||||
{
|
||||
void *addr = malloc( numBytes ); /* FIXME - do we need physical, wired, non-virtual memory? */
|
||||
void *addr = malloc( numBytes ); /* FIXME - do we need physical memory? */
|
||||
if( addr != NULL ) memset( addr, 0, numBytes );
|
||||
return addr;
|
||||
}
|
||||
|
|
@ -1351,23 +1058,11 @@ PaError PaHost_StreamActive( internalPortAudioStream *past )
|
|||
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
|
||||
{
|
||||
internalPortAudioStream *past = (internalPortAudioStream *) stream;
|
||||
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
|
||||
count_info info;
|
||||
int delta;
|
||||
|
||||
/* FIXME - return actual frames played, not frames generated.
|
||||
** Need to query the output device somehow.
|
||||
*/
|
||||
if( past == NULL ) return paBadStreamPtr;
|
||||
|
||||
if( pahsc->pahsc_NativeOutputBuffer ) {
|
||||
ioctl(pahsc->pahsc_OutputHandle, SNDCTL_DSP_GETOPTR, &info);
|
||||
delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF;
|
||||
return (pahsc->pahsc_LastStreamBytes + delta) / (past->past_NumOutputChannels * sizeof(short));
|
||||
}
|
||||
else {
|
||||
ioctl(pahsc->pahsc_InputHandle, SNDCTL_DSP_GETIPTR, &info);
|
||||
delta = (info.bytes - pahsc->pahsc_LastPosPtr) & 0x000FFFFF;
|
||||
return (pahsc->pahsc_LastStreamBytes + delta) / (past->past_NumInputChannels * sizeof(short));
|
||||
|
||||
}
|
||||
return past->past_FrameCount;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@
|
|||
/* Modifications
|
||||
* 7/19/01 Mike Berry - casts for compiling with __MWERKS__ CodeWarrior
|
||||
* 9/27/01 Phil Burk - use number of frames instead of real-time for CPULoad calculation.
|
||||
* 4/19/02 Phil Burk - Check for Win XP for system latency calculation.
|
||||
*/
|
||||
/* Compiler flags:
|
||||
SUPPORT_AUDIO_CAPTURE - define this flag if you want to SUPPORT_AUDIO_CAPTURE
|
||||
|
|
@ -50,12 +49,10 @@
|
|||
#include "pa_host.h"
|
||||
#include "pa_trace.h"
|
||||
#include "dsound_wrapper.h"
|
||||
|
||||
#define PRINT(x) { printf x; fflush(stdout); }
|
||||
#define ERR_RPT(x) PRINT(x)
|
||||
#define DBUG(x) /* PRINT(x) */
|
||||
#define DBUGX(x) /* PRINT(x) */
|
||||
|
||||
#define PA_USE_HIGH_LATENCY (0)
|
||||
#if PA_USE_HIGH_LATENCY
|
||||
#define PA_WIN_9X_LATENCY (500)
|
||||
|
|
@ -64,9 +61,6 @@
|
|||
#define PA_WIN_9X_LATENCY (140)
|
||||
#define PA_WIN_NT_LATENCY (280)
|
||||
#endif
|
||||
|
||||
#define PA_WIN_WDM_LATENCY (120)
|
||||
|
||||
/* Trigger an underflow for testing purposes. Should normally be (0). */
|
||||
#define PA_SIMULATE_UNDERFLOW (0)
|
||||
#if PA_SIMULATE_UNDERFLOW
|
||||
|
|
@ -74,7 +68,6 @@ static gUnderCallbackCounter = 0;
|
|||
#define UNDER_START_GAP (10)
|
||||
#define UNDER_STOP_GAP (UNDER_START_GAP + 4)
|
||||
#endif
|
||||
|
||||
/************************************************* Definitions ********/
|
||||
typedef struct internalPortAudioStream internalPortAudioStream;
|
||||
typedef struct internalPortAudioDevice
|
||||
|
|
@ -85,7 +78,6 @@ typedef struct internalPortAudioDevice
|
|||
PaDeviceInfo pad_Info;
|
||||
}
|
||||
internalPortAudioDevice;
|
||||
|
||||
/* Define structure to contain all DirectSound and Windows specific data. */
|
||||
typedef struct PaHostSoundControl
|
||||
{
|
||||
|
|
@ -101,7 +93,6 @@ typedef struct PaHostSoundControl
|
|||
double pahsc_InverseTicksPerUserBuffer;
|
||||
}
|
||||
PaHostSoundControl;
|
||||
|
||||
/************************************************* Shared Data ********/
|
||||
/* FIXME - put Mutex around this shared data. */
|
||||
static int sNumDevices = 0;
|
||||
|
|
@ -124,7 +115,6 @@ static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID,
|
|||
static Pa_QueryDevices( void );
|
||||
static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg,
|
||||
DWORD dwUser, DWORD dw1, DWORD dw2);
|
||||
|
||||
/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
|
||||
static void Pa_StartUsageCalculation( internalPortAudioStream *past )
|
||||
{
|
||||
|
|
@ -133,7 +123,6 @@ static void Pa_StartUsageCalculation( internalPortAudioStream *past )
|
|||
/* Query system timer for usage analysis and to prevent overuse of CPU. */
|
||||
QueryPerformanceCounter( &pahsc->pahsc_EntryCount );
|
||||
}
|
||||
|
||||
static void Pa_EndUsageCalculation( internalPortAudioStream *past )
|
||||
{
|
||||
LARGE_INTEGER CurrentCount = { 0, 0 };
|
||||
|
|
@ -153,7 +142,6 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past )
|
|||
(LOWPASS_COEFFICIENT_1 * newUsage);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************** END CPU UTILIZATION *******/
|
||||
static PaError Pa_QueryDevices( void )
|
||||
{
|
||||
|
|
@ -885,38 +873,6 @@ PaError PaHost_CloseStream( internalPortAudioStream *past )
|
|||
past->past_DeviceData = NULL;
|
||||
return paNoError;
|
||||
}
|
||||
|
||||
/* Set minimal latency based on whether NT or Win95.
|
||||
* NT has higher latency.
|
||||
*/
|
||||
static int PaHost_GetMinSystemLatency( void )
|
||||
{
|
||||
int minLatencyMsec;
|
||||
/* Set minimal latency based on whether NT or other OS.
|
||||
* NT has higher latency.
|
||||
*/
|
||||
OSVERSIONINFO osvi;
|
||||
osvi.dwOSVersionInfoSize = sizeof( osvi );
|
||||
GetVersionEx( &osvi );
|
||||
DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId ));
|
||||
DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion ));
|
||||
DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion ));
|
||||
/* Check for NT */
|
||||
if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
|
||||
{
|
||||
minLatencyMsec = PA_WIN_NT_LATENCY;
|
||||
}
|
||||
else if(osvi.dwMajorVersion >= 5)
|
||||
{
|
||||
minLatencyMsec = PA_WIN_WDM_LATENCY;
|
||||
}
|
||||
else
|
||||
{
|
||||
minLatencyMsec = PA_WIN_9X_LATENCY;
|
||||
}
|
||||
return minLatencyMsec;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
** Determine minimum number of buffers required for this host based
|
||||
** on minimum latency. Latency can be optionally set by user by setting
|
||||
|
|
@ -932,6 +888,7 @@ static int PaHost_GetMinSystemLatency( void )
|
|||
int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
|
||||
{
|
||||
char envbuf[PA_ENV_BUF_SIZE];
|
||||
DWORD hostVersion;
|
||||
DWORD hresult;
|
||||
int minLatencyMsec = 0;
|
||||
double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate;
|
||||
|
|
@ -944,7 +901,12 @@ int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
|
|||
}
|
||||
else
|
||||
{
|
||||
minLatencyMsec = PaHost_GetMinSystemLatency();
|
||||
/* Set minimal latency based on whether NT or Win95.
|
||||
* NT has higher latency.
|
||||
*/
|
||||
hostVersion = GetVersion();
|
||||
/* High bit clear if NT */
|
||||
minLatencyMsec = ( (hostVersion & 0x80000000) == 0 ) ? PA_WIN_NT_LATENCY : PA_WIN_9X_LATENCY ;
|
||||
#if PA_USE_HIGH_LATENCY
|
||||
PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -44,10 +44,9 @@
|
|||
** 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)
|
||||
#define SAMPLE_RATE (22050)
|
||||
#define NUM_SECONDS (15)
|
||||
#define SAMPLES_PER_FRAME (2)
|
||||
|
||||
/* Select whether we will use floats or shorts. */
|
||||
#if 1
|
||||
|
|
@ -63,7 +62,7 @@ int main(void);
|
|||
int main(void)
|
||||
{
|
||||
int i;
|
||||
SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK];
|
||||
SAMPLE samples[SAMPLES_PER_FRAME];
|
||||
PaError err;
|
||||
PABLIO_Stream *aStream;
|
||||
|
||||
|
|
@ -76,12 +75,13 @@ int main(void)
|
|||
if( err != paNoError ) goto error;
|
||||
|
||||
/* Process samples in the foreground. */
|
||||
for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK )
|
||||
for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ )
|
||||
{
|
||||
/* 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 );
|
||||
/* Read one frame of data into sample array from audio input. */
|
||||
ReadAudioStream( aStream, samples, 1 );
|
||||
/* Write that same frame of data to output. */
|
||||
/* samples[1] = (i&256) * (1.0f/256.0f); /* sawtooth */
|
||||
WriteAudioStream( aStream, samples, 1 );
|
||||
}
|
||||
|
||||
CloseAudioStream( aStream );
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
This is just a dopy little file used to test the CVS repository.
|
||||
Feel free to trash this file.
|
||||
Minor change.
|
||||
Another tweak.
|
||||
philburk tweak
|
||||
stephane test
|
||||
Phil changed this again on 2/21/02. Yawn...
|
||||
pieter test (MacCVS Pro 2.5b2)
|
||||
phil says hi
|
||||
|
|
@ -1 +0,0 @@
|
|||
interesting info
|
||||
Loading…
Reference in a new issue