+++ /dev/null
-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.
- *
- */
\ No newline at end of file
+++ /dev/null
-#
-# 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
# 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.
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
-
-testo: $(TESTS:.c=.o)
+ @/sbin/ldconfig -v
-testq: $(TESTO:.o=)
+tests: $(TESTS:.c=.o)
clean:
-@rm -f $(TESTS:.c=.o)
+++ /dev/null
-
-# 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
-
-
-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
+++ /dev/null
-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."
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-<!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>
+++ /dev/null
-#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 */
+++ /dev/null
-<!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>
+++ /dev/null
-<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>
\ No newline at end of file
+++ /dev/null
-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
+++ /dev/null
-<!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>
+++ /dev/null
-Steinberg's ASIO 2 SDK will compile but crash on
-initialization if compiled with a Borland compiler.
-
-The problem is described, and a solution provided on
-the following page:
-http://www.audiomulch.com/~rossb/code/calliasio
\ No newline at end of file
08-27-01 Implementation of hostBufferSize < userBufferSize case, better management of the ouput buffer when
the stream is stopped : Stephane Letz
08-28-01 Check the stream pointer for null in bufferSwitchTimeInfo, correct bug in bufferSwitchTimeInfo when
- the stream is stopped : Stephane Letz
+ the stream is stopped : Stephane Letz
10-12-01 Correct the PaHost_CalcNumHostBuffers function: computes FramesPerHostBuffer to be the lowest that
- respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz
+ respect requested FramesPerUserBuffer and userBuffersPerHostBuffer : Stephane Letz
10-26-01 Management of hostBufferSize and userBufferSize of any size : Stephane Letz
10-27-01 Improve calculus of hostBufferSize to be multiple or divisor of userBufferSize if possible : Stephane and Phil
10-29-01 Change MAX_INT32_FP to (2147483520.0f) to prevent roundup to 0x80000000 : Phil Burk
10-31-01 Clear the ouput buffer and user buffers in PaHost_StartOutput, correct bug in GetFirstMultiple : Stephane Letz
11-06-01 Rename functions : Stephane Letz
11-08-01 New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables, cleanup of Pa_ASIO_Callback_Input: Stephane Letz
- 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk
- 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz
- 02-01-02 Cleanup, test of multiple-stream opening : Stephane Letz
- 19-02-02 New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows : Stephane Letz
- 09-04-02 Correct error code management in PaHost_Term, removes various compiler warning : Stephane Letz
- 12-04-02 Add Mac includes for <Devices.h> and <Timer.h> : Phil Burk
- 13-04-02 Removes another compiler warning : Stephane Letz
- 30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz
+ 11-29-01 Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo ; Phil Burk
+ 01-03-02 Desallocate all resources in PaHost_Term for cases where Pa_CloseStream is not called properly : Stephane Letz
TO DO :
- Check Pa_StopSteam and Pa_AbortStream
- Optimization for Input only or Ouput only (really necessary ??)
+ - Opening of several streams
*/
#include <stdio.h>
#include <assert.h>
-#include <string.h>
#include "portaudio.h"
#include "pa_host.h"
#include "asio.h"
#include "asiodrivers.h"
-
#if MAC
-#include <Devices.h>
-#include <Timer.h>
#include <Math64.h>
#else
#include <math.h>
//----------------------------------------------------------
+// name of the ASIO device to be used
+#if WINDOWS
+ //#define ASIO_DRIVER_NAME "ASIO Multimedia Driver"
+ #define ASIO_DRIVER_NAME "ASIO Sample"
+#elif MAC
+ //#define ASIO_DRIVER_NAME "Apple Sound Manager"
+ #define ASIO_DRIVER_NAME "ASIO Delta1010"
+ //#define ASIO_DRIVER_NAME "DigiDesign DirectIO"
+#endif
+
#define PRINT(x) { printf x; fflush(stdout); }
#define ERR_RPT(x) PRINT(x)
#endif
// Prototypes
-static void bufferSwitch(long index, ASIOBool processNow);
-static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
-static void sampleRateChanged(ASIOSampleRate sRate);
-static long asioMessages(long selector, long value, void* message, double* opt);
+void bufferSwitch(long index, ASIOBool processNow);
+ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
+void sampleRateChanged(ASIOSampleRate sRate);
+long asioMessages(long selector, long value, void* message, double* opt);
static void Pa_StartUsageCalculation( internalPortAudioStream *past );
static void Pa_EndUsageCalculation( internalPortAudioStream *past );
-static void Pa_ASIO_Convert_Inter_Input(
+void Pa_ASIO_Convert_Inter_Input(
ASIOBufferInfo* nativeBuffer,
void* inputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
+ short NumInputChannels,
+ short NumOuputChannels,
+ short framePerBuffer,
+ short hostFrameOffset,
+ short userFrameOffset,
ASIOSampleType nativeFormat,
PaSampleFormat paFormat,
PaStreamFlags flags,
- long index);
+ short index);
-static void Pa_ASIO_Convert_Inter_Output(
+void Pa_ASIO_Convert_Inter_Output(
ASIOBufferInfo* nativeBuffer,
void* outputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
+ short NumInputChannels,
+ short NumOuputChannels,
+ short framePerBuffer,
+ short hostFrameOffset,
+ short userFrameOffset,
ASIOSampleType nativeFormat,
PaSampleFormat paFormat,
PaStreamFlags flags,
- long index);
+ short index);
-static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer,
+ void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer,
ASIOSampleType nativeFormat,
- long NumInputChannels,
- long NumOuputChannels,
- long index,
- long hostFrameOffset,
- long frames);
+ short NumInputChannels,
+ short NumOuputChannels,
+ int index,
+ int hostFrameOffset,
+ int frames);
-static void Pa_ASIO_Callback_Input(long index);
-static void Pa_ASIO_Callback_Output(long index, long framePerBuffer);
-static void Pa_ASIO_Callback_End();
-static void Pa_ASIO_Clear_User_Buffers();
+void Pa_ASIO_Callback_Input(long index);
+void Pa_ASIO_Callback_Output(long index, long framePerBuffer);
+void Pa_ASIO_Callback_End();
+void Pa_ASIO_Clear_User_Buffers();
// Some external references
extern AsioDrivers* asioDrivers ;
unsigned long get_sys_reference_time();
+// For callback debugging on Mac : to be removed in the final version
+
+/*
+#define MidiSharePPC_68k
+#include <MidiShare.h>
+
+void SendVal (long val)
+{
+ MidiEvPtr ev = MidiNewEv(typeTempo);
+ if (ev) {
+ Tempo(ev) = val;
+ MidiSendIm(0,ev);
+ }
+}
+
+void MidiPrintText ( char * s)
+{
+ MidiEvPtr e;
+ long c = 0;
+
+ if (e = MidiNewEv(typeTextual)){
+ for (c = 0 ; *s ; s++,c++) MidiAddField (e ,*s);
+ MidiSendIm (0, e);
+ }
+}
+*/
+
+
/************************************************************************************/
/****************** Macro ************************************************************/
/************************************************************************************/
#endif
-static bool Pa_ASIO_loadAsioDriver(char *name)
-{
- #ifdef WINDOWS
- CoInitialize(0);
- #endif
- return loadAsioDriver(name);
-}
-
-
-
// Utilities for alignement buffer size computation
-static int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);}
-static int PPCM (int a, int b) {return (a*b) / PGCD (a,b);}
+int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);}
+int PPCM (int a, int b) {return (a*b) / PGCD (a,b);}
// Takes the size of host buffer and user buffer : returns the number of frames needed for buffer alignement
-static int Pa_ASIO_CalcFrameShift (int M, int N)
+int Pa_ASIO_CalcFrameShift (int M, int N)
{
int res = 0;
for (int i = M; i < PPCM (M,N) ; i+=M) { res = max (res, i%N); }
int i;
int numDrivers;
ASIOError asioError;
-
- /* Allocate names */
- for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) {
- names[i] = (char*)PaHost_AllocateFastMemory(32);
- /* check memory */
- if(!names[i]) return paInsufficientMemory;
- }
+
+ /* Allocate names */
+ for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) names[i] = (char*)PaHost_AllocateFastMemory(32);
/* MUST BE CHECKED : to force fragments loading on Mac */
- Pa_ASIO_loadAsioDriver("dummy");
+ loadAsioDriver("dummy");
/* Get names of all available ASIO drivers */
asioDrivers->getDriverNames(names,PA_MAX_DEVICE_INFO);
#endif
/* If the driver can be loaded : */
- if ( !Pa_ASIO_loadAsioDriver(names[driver]) )
+ if ( !loadAsioDriver(names[driver]) )
{
DBUG(("PaASIO_QueryDeviceInfo could not loadAsioDriver %s\n", names[driver]));
}
}
else
{
- /* Gets the name */
- dev = &(ipad[sNumDevices].pad_Info);
+
+ /* Gets the name */
+ dev = &(ipad[driver].pad_Info);
dev->name = names[driver];
names[driver] = 0;
DBUG(("PaASIO_QueryDeviceInfo: OutputChannels = %d\n", OutputChannels ));
/* Make room in case device supports all rates. */
- sampleRates = (double*)PaHost_AllocateFastMemory(MAX_NUMSAMPLINGRATES * sizeof(double));
- /* check memory */
- if (!sampleRates) {
- ASIOExit();
- return paInsufficientMemory;
- }
+ sampleRates = (double*)PaHost_AllocateFastMemory( MAX_NUMSAMPLINGRATES * sizeof(double));
dev->sampleRates = sampleRates;
dev->numSampleRates = 0;
for (int index = 0; index < MAX_NUMSAMPLINGRATES; index++) {
if (ASIOCanSampleRate(possibleSampleRates[index]) != ASE_NoClock) {
DBUG(("PortAudio : possible sample rate = %d\n", (long)possibleSampleRates[index]));
- dev->numSampleRates += 1;
+ dev->numSampleRates+=1;
*sampleRates = possibleSampleRates[index];
sampleRates++;
}
dev->nativeSampleFormats = Pa_ASIO_Convert_SampleFormat(channelInfos.type);
/* unload the driver */
+ ASIODisposeBuffers();
ASIOExit();
+
sNumDevices++;
}
}
//----------------------------------------------------------------------------------
// TAKEN FROM THE ASIO SDK:
-static void sampleRateChanged(ASIOSampleRate sRate)
+void sampleRateChanged(ASIOSampleRate sRate)
{
// do whatever you need to do if the sample rate changed
// usually this only happens during external sync.
#endif
-static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
+ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
{
// the actual processing callback.
// Beware that this is normally in a seperate thread, hence be sure that you take care
// about thread synchronization. This is omitted here for simplicity.
- // static processedSamples = 0;
+ static processedSamples = 0;
int result = 0;
// store the timeInfo for later use
// get the system reference time
#if WINDOWS
return timeGetTime();
- #elif MAC
+ #elif MAC
static const double twoRaisedTo32 = 4294967296.;
UnsignedWide ys;
Microseconds(&ys);
// TO BE COMPLETED WITH ALL SUPPORTED PA SAMPLE TYPES
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+ void Input_Int16_Flot32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
{
long temp;
int i,j;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+ void Input_Int32_Flot32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
{
long temp;
int i,j;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// MUST BE TESTED
-static void Input_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+ void Input_Float32_Flot32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
{
- unsigned long temp;
+ long temp;
int i,j;
for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ float *asioBufPtr = &((float*)nativeBuffer[j].buffers[index])[hostFrameOffset];
float *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
for (i= 0; i < framePerBuffer; i++)
{
- temp = asioBufPtr[i];
+ temp = (long)asioBufPtr[i];
if (swap) temp = SwapLong(temp);
*userBufPtr = (float)temp;
userBufPtr += NumInputChannels;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+ void Input_Int16_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
{
long temp;
int i,j;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+ void Input_Int32_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
{
long temp;
int i,j;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// MUST BE TESTED
-static void Input_Float32_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+ void Input_Float32_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
{
- unsigned long temp;
+ long temp;
int i,j;
for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ float *asioBufPtr = &((float*)nativeBuffer[j].buffers[index])[hostFrameOffset];
long *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
for (i= 0; i < framePerBuffer; i++)
{
- temp = asioBufPtr[i];
+ temp = (long) asioBufPtr[i];
if (swap) temp = SwapLong(temp);
*userBufPtr = (long)((float)temp * MAX_INT32_FP); // Is temp a value between -1.0 and 1.0 ??
userBufPtr += NumInputChannels;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+ void Input_Int16_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
{
long temp;
int i,j;
{
temp = asioBufPtr[i];
if (swap) temp = SwapShort(temp);
- *userBufPtr = (short)temp;
+ *userBufPtr = temp;
userBufPtr += NumInputChannels;
}
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
+ void Input_Int32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
{
long temp;
int i,j;
{
temp = asioBufPtr[i];
if (swap) temp = SwapLong(temp);
- *userBufPtr = (short)(temp>>16);
+ *userBufPtr = temp>>16;
userBufPtr += NumInputChannels;
}
}
temp = (temp >> 1) + Pa_TriangularDither();
temp = temp >> 15;
temp = (short) ClipShort(temp);
- *userBufPtr = (short)temp;
+ *userBufPtr = temp;
userBufPtr += NumInputChannels;
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// MUST BE TESTED
-static void Input_Float32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
+ void Input_Float32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
{
- unsigned long temp;
+ long temp;
int i,j;
if( flags & paDitherOff )
{
for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ float *asioBufPtr = &((float*)nativeBuffer[j].buffers[index])[hostFrameOffset];
short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
for (i= 0; i < framePerBuffer; i++)
{
- temp = asioBufPtr[i];
+ temp = (long)asioBufPtr[i];
if (swap) temp = SwapLong(temp);
*userBufPtr = (short)((float)temp * MAX_INT16_FP); // Is temp a value between -1.0 and 1.0 ??
userBufPtr += NumInputChannels;
else
{
for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ float *asioBufPtr = &((float*)nativeBuffer[j].buffers[index])[hostFrameOffset];
short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
for (i= 0; i < framePerBuffer; i++)
{
float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = asioBufPtr[i];
+ temp = (long)asioBufPtr[i];
if (swap) temp = SwapLong(temp);
temp = (short)(((float)temp * MAX_INT16_FP) + dither);
temp = ClipShort(temp);
- *userBufPtr = (short)temp;
+ *userBufPtr = temp;
userBufPtr += NumInputChannels;
}
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+ void Input_Int16_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
{
long temp;
int i,j;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset, uint32 flags,bool swap)
+ void Input_Int32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset, uint32 flags,bool swap)
{
long temp;
int i,j;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// MUST BE TESTED
-static void Input_Float32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+ void Input_Float32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
{
- unsigned long temp;
+ long temp;
int i,j;
if( flags & paDitherOff )
{
for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
for (i= 0; i < framePerBuffer; i++)
{
else
{
for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
for (i= 0; i < framePerBuffer; i++)
{
if (swap) temp = SwapLong(temp);
temp = (char)(((float)temp * MAX_INT8_FP) + dither);
temp = ClipChar(temp);
- *userBufPtr = (char)temp;
+ *userBufPtr = temp ;
userBufPtr += NumInputChannels;
}
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+ void Input_Int16_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
{
long temp;
int i,j;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
+ void Input_Int32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
{
long temp;
int i,j;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// MUST BE TESTED
-static void Input_Float32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+ void Input_Float32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
{
- unsigned long temp;
+ long temp;
int i,j;
if( flags & paDitherOff )
{
for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ float *asioBufPtr = &((float*)nativeBuffer[j].buffers[index])[hostFrameOffset];
unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
for (i= 0; i < framePerBuffer; i++)
{
- temp = asioBufPtr[i];
+ temp = (float) asioBufPtr[i];
if (swap) temp = SwapLong(temp);
*userBufPtr = (unsigned char)(((float)temp*MAX_INT8_FP) + 0x80);
userBufPtr += NumInputChannels;
else
{
for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
+ float *asioBufPtr = &((float*)nativeBuffer[j].buffers[index])[hostFrameOffset];
unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
for (i= 0; i < framePerBuffer; i++)
{
float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = asioBufPtr[i];
+ temp = (float) asioBufPtr[i];
if (swap) temp = SwapLong(temp);
temp = (char)(((float)temp * MAX_INT8_FP) + dither);
temp = ClipChar(temp);
// OUPUT
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Float32_Int16 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags, bool swap)
+ void Output_Float32_Int16 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags, bool swap)
{
long temp;
int i,j;
{
temp = (short) (*userBufPtr * MAX_INT16_FP);
if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
+ asioBufPtr[i] = temp;
userBufPtr += NumOuputChannels;
}
}
temp = (long) (*userBufPtr * MAX_INT16_FP);
temp = ClipShort(temp);
if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
+ asioBufPtr[i] = temp;
userBufPtr += NumOuputChannels;
}
}
{
/* If you dither then you have to clip because dithering could push the signal out of range! */
for( j=0; j<NumOuputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
-
- for (i= 0; i < framePerBuffer; i++)
- {
- float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = (long) ((*userBufPtr * MAX_INT16_FP) + dither);
- temp = ClipShort(temp);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
+ short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
+ float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
+
+ for (i= 0; i < framePerBuffer; i++)
+ {
+ float dither = Pa_TriangularDither()*DITHER_SCALE;
+ temp = (long) ((*userBufPtr * MAX_INT16_FP) + dither);
+ temp = ClipShort(temp);
+ if (swap) temp = SwapShort(temp);
+ asioBufPtr[i] = temp;
+ userBufPtr += NumOuputChannels;
+ }
}
- }
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Float32_Int32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
+ void Output_Float32_Int32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
{
long temp;
int i,j;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// MUST BE TESTED
- static void Output_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
+ void Output_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
{
long temp;
int i,j;
}
}
-
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int32_Int16(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
+ void Output_Int32_Int16(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
{
long temp;
int i,j;
{
temp = (short) ((*userBufPtr) >> 16);
if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
+ asioBufPtr[i] = temp;
userBufPtr += NumOuputChannels;
}
}
temp = temp >> 15;
temp = (short) ClipShort(temp);
if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
+ asioBufPtr[i] = temp;
userBufPtr += NumOuputChannels;
}
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
+ void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
{
long temp;
int i,j;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// MUST BE CHECKED
-static void Output_Int32_Float32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
+ void Output_Int32_Float32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
{
long temp;
int i,j;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int16_Int16(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,bool swap)
+ void Output_Int16_Int16(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,bool swap)
{
long temp;
int i,j;
{
temp = *userBufPtr;
if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
+ asioBufPtr[i] = temp;
userBufPtr += NumOuputChannels;
}
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int16_Int32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+ void Output_Int16_Int32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
{
long temp;
int i,j;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// MUST BE CHECKED
-static void Output_Int16_Float32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+ void Output_Int16_Float32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
{
long temp;
int i,j;
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int8_Int16(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+ void Output_Int8_Int16(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
{
long temp;
int i,j;
{
temp = (short)(*userBufPtr)<<8;
if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
+ asioBufPtr[i] = temp;
userBufPtr += NumOuputChannels;
}
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int8_Int32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+ void Output_Int8_Int32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
{
long temp;
int i,j;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// MUST BE CHECKED
-static void Output_Int8_Float32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+ void Output_Int8_Float32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
{
long temp;
int i,j;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_IntU8_Int16(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+ void Output_IntU8_Int16(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
{
long temp;
int i,j;
{
temp = ((short)((*userBufPtr) - 0x80)) << 8;
if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
+ asioBufPtr[i] = temp;
userBufPtr += NumOuputChannels;
}
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_IntU8_Int32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+ void Output_IntU8_Int32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
{
long temp;
int i,j;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// MUST BE CHECKED
-static void Output_IntU8_Float32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+ void Output_IntU8_Float32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
{
long temp;
int i,j;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Clear_Output_16 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset)
+ void Pa_ASIO_Clear_Output_16 (ASIOBufferInfo* nativeBuffer, int frames, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset)
{
int i,j;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Clear_Output_32 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset)
+ void Pa_ASIO_Clear_Output_32 (ASIOBufferInfo* nativeBuffer, int frames, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset)
{
int i,j;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Adaptor_Init()
+void Pa_ASIO_Adaptor_Init()
{
if (asioDriverInfo.past->past_FramesPerUserBuffer <= asioDriverInfo.past_FramesPerHostBuffer) {
asioDriverInfo.pahsc_hostOutputBufferFrameOffset = asioDriverInfo.pahsc_OutputBufferOffset;
//-------------------------------------------------------------------------------------------------------------------------------------------------------
// FIXME : optimization for Input only or output only modes (really necessary ??)
-static void Pa_ASIO_Callback_Input( long index)
+void Pa_ASIO_Callback_Input( long index)
{
internalPortAudioStream *past = asioDriverInfo.past;
long framesInputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer; // number of frames available into the host input buffer
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Callback_Output(long index, long framePerBuffer)
+void Pa_ASIO_Callback_Output(long index, long framePerBuffer)
{
internalPortAudioStream *past = asioDriverInfo.past;
}
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Callback_End()
+ void Pa_ASIO_Callback_End()
{
/* Empty ASIO ouput : write offset */
asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0;
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Clear_User_Buffers()
+void Pa_ASIO_Clear_User_Buffers()
{
if( asioDriverInfo.past->past_InputBuffer != NULL )
{
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------
- static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer,
+ void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer,
ASIOSampleType nativeFormat,
- long NumInputChannels,
- long NumOuputChannels,
- long index,
- long hostFrameOffset,
- long frames)
+ short NumInputChannels,
+ short NumOuputChannels,
+ int index,
+ int hostFrameOffset,
+ int frames)
{
switch (nativeFormat) {
//---------------------------------------------------------------------------------------
-static void Pa_ASIO_Convert_Inter_Input(
+void Pa_ASIO_Convert_Inter_Input(
ASIOBufferInfo* nativeBuffer,
void* inputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
+ short NumInputChannels,
+ short NumOuputChannels,
+ short framePerBuffer,
+ short hostFrameOffset,
+ short userFrameOffset,
ASIOSampleType nativeFormat,
PaSampleFormat paFormat,
PaStreamFlags flags,
- long index)
+ short index)
{
if((NumInputChannels > 0) && (nativeBuffer != NULL))
switch (nativeFormat) {
case ASIOSTInt16LSB:
- Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap);
+ Input_Int16_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap);
break;
case ASIOSTInt16MSB:
- Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
+ Input_Int16_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
break;
case ASIOSTInt32LSB:
- Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap);
+ Input_Int32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap);
break;
case ASIOSTInt32MSB:
- Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
+ Input_Int32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
break;
case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap);
+ Input_Float32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap);
break;
case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
+ Input_Float32_Flot32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
break;
case ASIOSTInt24LSB: // used for 20 bits as well
//---------------------------------------------------------------------------------------
-static void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer,
+void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer,
void* outputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
+ short NumInputChannels,
+ short NumOuputChannels,
+ short framePerBuffer,
+ short hostFrameOffset,
+ short userFrameOffset,
ASIOSampleType nativeFormat,
PaSampleFormat paFormat,
PaStreamFlags flags,
- long index)
+ short index)
{
- if((NumOuputChannels > 0) && (nativeBuffer != NULL))
+ if((NumOuputChannels > 0) && (nativeBuffer != NULL))
{
/* Convert from PA format to native format */
{
PaDeviceInfo * dev = &(sDevices[device].pad_Info);
- if (!Pa_ASIO_loadAsioDriver((char *) dev->name)) return paHostError;
+ if (!loadAsioDriver((char *) dev->name)) return paHostError;
if (ASIOInit(&asioDriverInfo.pahsc_driverInfo) != ASE_OK) return paHostError;
if (ASIOGetChannels(&asioDriverInfo.pahsc_NumInputChannels, &asioDriverInfo.pahsc_NumOutputChannels) != ASE_OK) return paHostError;
if (ASIOGetBufferSize(&asioDriverInfo.pahsc_minSize, &asioDriverInfo.pahsc_maxSize, &asioDriverInfo.pahsc_preferredSize, &asioDriverInfo.pahsc_granularity) != ASE_OK) return paHostError;
}
//---------------------------------------------------
-static int GetHighestBitPosition (unsigned long n)
+static int GetHighestBitPosition( unsigned long n )
{
int pos = -1;
while( n != 0 )
return pos;
}
-//------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
static int GetFirstMultiple(long min, long val ){ return ((min + val - 1) / val) * val; }
-//------------------------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
static int GetFirstPossibleDivisor(long max, long val )
{
for (int i = 2; i < 20; i++) {if (((val%i) == 0) && ((val/i) <= max)) return (val/i); }
/***********************************************************************/
PaError PaHost_Init( void )
{
- /* Have we already initialized the device info? */
- PaError err = (PaError) Pa_CountDevices();
- return ( err < 0 ) ? err : paNoError;
+ /* Have we already initialized the device info? */
+ return (Pa_CountDevices() < 0 ) ? paHostError : paNoError;
}
/***********************************************************************/
int i;
PaDeviceInfo *dev;
double *rates;
- PaError result = paNoError;
-
- if (sNumDevices > 0) {
-
- /* Free allocated sample rate arrays and names*/
- for( i=0; i<sNumDevices; i++ ){
- dev = &sDevices[i].pad_Info;
- rates = (double *) dev->sampleRates;
- if ((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double));
- dev->sampleRates = NULL;
- if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32);
- dev->name = NULL;
-
- }
-
- sNumDevices = 0;
-
- /* Dispose : if not done by Pa_CloseStream */
- if(ASIODisposeBuffers() != ASE_OK) result = paHostError;
- if(ASIOExit() != ASE_OK) result = paHostError;
-
- /* remove the loaded ASIO driver */
- asioDrivers->removeCurrentDriver();
- }
+ PaError result = paNoError;
+
+ /* Free allocated sample rate arrays and names*/
+ for( i=0; i<sNumDevices; i++ ){
+ dev = &sDevices[i].pad_Info;
+ rates = (double *) dev->sampleRates;
+ if((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double));
+ dev->sampleRates = NULL;
+ if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32);
+ dev->name = NULL;
+ }
+
+ sNumDevices = 0;
+
+ /* Dispose : if not done by Pa_CloseStream */
+ if(ASIODisposeBuffers() != ASE_OK) result = paHostError;
+ if(ASIOExit() != ASE_OK) result = paHostError;
+
+ /* remove the loaded ASIO driver */
+ asioDrivers->removeCurrentDriver();
return result;
}
ASIOError err;
int32 device;
- /* Check if a stream already runs */
- if (asioDriverInfo.past != NULL) return paHostError;
+ /* TO DO : Check if a stream already runs */
+ //if (asioDriverInfo.past != NULL) return paHostError; (does not work)
/* Check the device number */
if ((past->past_InputDeviceID != paNoDevice)
+++ /dev/null
-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;
-}
-
+++ /dev/null
-/*
- * 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;
-}
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
-
-#include "portaudio.h"
#ifdef __cplusplus
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)
/************************************************************************************/
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;
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 );
PaError PaHost_StopEngine( internalPortAudioStream *past, int abort );
PaError PaHost_StreamActive( internalPortAudioStream *past );
+long Pa_CallConvertInt16( internalPortAudioStream *past,
+ short *nativeInputBuffer,
+ short *nativeOutputBuffer );
+
+long Pa_CallConvertFloat32( internalPortAudioStream *past,
+ float *nativeInputBuffer,
+ float *nativeOutputBuffer );
+
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 );
-
-PaError PaConvert_SetupOutput( internalPortAudioStream *past,
- PaSampleFormat nativeOutputSampleFormat );
-
-long PaConvert_Process( internalPortAudioStream *past,
- void *nativeInputBuffer,
- void *nativeOutputBuffer );
-
#ifdef __cplusplus
}
#endif /* __cplusplus */
#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. */
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",
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;
#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 )
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;
/* 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;
short *nativeOutputBuffer )
{
long temp;
+ long bytesEmpty = 0;
+ long bytesFilled = 0;
int userResult;
unsigned int i;
void *inputBuffer = NULL;
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);
}
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 */
}
/* 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));
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));
}
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 )
{
return result;
}
-int PaHost_IsInitialized()
-{
- return gInitCount;
-}
-
/*************************************************************************/
PaError Pa_GetSampleSize( PaSampleFormat format )
{
/*
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 );
/*
- 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 );
/*
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;
#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;
}
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
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().
-
+ 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()
*/
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID device );
+typedef double PaTimestamp;
/*
- 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()
-
+ 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().
*/
-typedef double PaTimestamp;
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID );
/*
- PortAudioCallback is implemented by PortAudio clients.
+ 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
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)(
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;
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.
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.)
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.
*/
/*
- 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,
/*
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 );
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:
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 */
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
#include <string.h>
#include <memory.h>
#include <math.h>
-
/* Mac specific includes */
#include "OSUtils.h"
#include <MacTypes.h>
#include <DateTimeUtils.h>
#include <Timer.h>
#include <Gestalt.h>
-
#include "portaudio.h"
#include "pa_host.h"
#include "pa_trace.h"
#define TRUE (!FALSE)
#endif
-/* #define TARGET_API_MAC_CARBON (1) */
-
-/*
- * Define maximum CPU load that will be allowed. User callback will
- * be skipped if load exceeds this limit. This is to prevent the Mac
- * from hanging when the CPU is hogged by the sound thread.
- * On my PowerBook G3, the mac hung when I used 94% of CPU ( usage = 0.94 ).
- */
-#define PA_MAX_USAGE_ALLOWED (0.92)
-
/* Debugging output macros. */
#define PRINT(x) { printf x; fflush(stdout); }
#define ERR_RPT(x) PRINT(x)
#define 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)
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. */
/* 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;
/************************************************************************************/
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 );
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;
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;
}
/***********************************************************************
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 )
{
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;
{
PaMac_PlayNext( past, i );
}
-
+
/* Resume channel now that the queue is full. */
resumeCommand.cmd = resumeCmd;
resumeCommand.param1 = resumeCommand.param2 = 0;
}
/*******************************************************************
-* 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 )
{
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 =
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;
}
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 )
/*************************************************************************/
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 );
}
/*************************************************************************/
/*************************************************************************/
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;
}
/**************************************************************************
*/
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 );
}
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)
/* Call user code enough times to fill buffer. */
if( (inPtr != NULL) || (outPtr != NULL) )
{
- PaMac_StartLoadCalculation( past ); /* CPU usage */
-
-#ifdef PA_MAX_USAGE_ALLOWED
- /* If CPU usage exceeds limit, skip user callback to prevent hanging CPU. */
- if( past->past_Usage > PA_MAX_USAGE_ALLOWED )
- {
- past->past_FrameCount += (PaTimestamp) pahsc->pahsc_FramesPerHostBuffer;
- }
- else
-#endif
- {
-
- for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
- {
- result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr );
- if( result != 0)
- {
- /* Recording might be in another process, so tell it to stop with a flag. */
- pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording;
- break;
- }
- /* Advance sample pointers. */
- if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels;
- if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
- }
- }
-
+ 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;
+ }
+
PaMac_EndLoadCalculation( past );
}
return result;
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 );
}
/* 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;
+++ /dev/null
-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.
3.29.2001 - Phil Burk - First pass... converted from Window MME code with help from Darren.
3.30.2001 - Darren Gibbs - Added more support for dynamically querying device info.
12.7.2001 - Gord Peters - Tweaks to compile on PA V17 and OS X 10.1
- 2.7.2002 - Darren and Phil - fixed isInput so GetProperty works better,
- fixed device queries for numChannels and sampleRates,
- one CoreAudio device now maps to separate input and output PaDevices,
- audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices).
- 2.22.2002 - Stephane Letz - Explicit cast needed for compilation with Code Warrior 7
- 3.19.2002 - Phil Burk - Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file.
- Return error if opened in mono mode cuz not supported.
- Add support for Pa_GetCPULoad();
- Fixed timestamp in callback and Pa_StreamTime() (Thanks n++k for the advice!)
- Check for invalid sample rates and return an error.
- Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally.
- Better error checking for invalid channel counts and invalid devices.
- 3.29.2002 - Phil Burk - Fixed Pa_GetCPULoad() for small buffers.
- 3.31.2002 - Phil Burk - Use getrusage() instead of gettimeofday() for CPU Load calculation.
-
-TODO:
-O- how do mono output?
-O- FIFO between input and output callbacks if different devices, like in pa_mac.c
-*/
-
+ */
#include <CoreServices/CoreServices.h>
#include <CoreAudio/CoreAudio.h>
#include <sys/time.h>
-#include <sys/resource.h>
#include <unistd.h>
-
#include "portaudio.h"
#include "pa_host.h"
#include "pa_trace.h"
/************************************************* Constants ********/
+#define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */
+#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */
+
+/* Switches for debugging. */
+#define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */
/* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */
#define PA_TRACE_RUN (0)
#define PA_TRACE_START_STOP (1)
-#define PA_MIN_LATENCY_MSEC (8)
-#define MIN_TIMEOUT_MSEC (1000)
+#define PA_MIN_MSEC_PER_HOST_BUFFER (10)
+#define PA_MAX_MSEC_PER_HOST_BUFFER (100) /* Do not exceed unless user buffer exceeds */
+#define PA_MIN_NUM_HOST_BUFFERS (3)
+#define PA_MAX_NUM_HOST_BUFFERS (16) /* OK to exceed if necessary */
+#define PA_MIN_LATENCY_MSEC (200)
+
+#define MIN_TIMEOUT_MSEC (1000)
#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) */
-// define value of isInput passed to CoreAudio routines
-#define IS_INPUT (true)
-#define IS_OUTPUT (false)
+/************************************************* Definitions ********/
/**************************************************************
* Structure for internal host specific stream data.
*/
typedef struct PaHostSoundControl
{
- AudioDeviceID pahsc_AudioDeviceID; // Must be the same for input and output for now.
/* Input -------------- */
- int pahsc_BytesPerUserNativeInputBuffer; /* native buffer size in bytes per user chunk */
+ int pahsc_BytesPerHostInputBuffer;
+ int pahsc_BytesPerUserInputBuffer; /* native buffer size in bytes */
/* Output -------------- */
- int pahsc_BytesPerUserNativeOutputBuffer; /* native buffer size in bytes per user chunk */
+ AudioDeviceID pahsc_OutputAudioDeviceID;
+ int pahsc_BytesPerHostOutputBuffer;
+ int pahsc_BytesPerUserOutputBuffer; /* native buffer size in bytes */
+ /* Run Time -------------- */
+ PaTimestamp pahsc_FramesPlayed;
+ long pahsc_LastPosition; /* used to track frames played. */
+ /* For measuring CPU utilization. */
+ // LARGE_INTEGER pahsc_EntryCount;
+ // LARGE_INTEGER pahsc_LastExitCount;
/* Init Time -------------- */
+ int pahsc_NumHostBuffers;
int pahsc_FramesPerHostBuffer;
- int pahsc_UserBuffersPerHostBuffer;
- /* For measuring CPU utilization. */
- struct rusage pahsc_EntryRusage;
- double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
-}
-PaHostSoundControl;
+ int pahsc_UserBuffersPerHostBuffer;
+
+ // CRITICAL_SECTION pahsc_StreamLock; /* Mutext to prevent threads from colliding. */
+ int pahsc_StreamLockInited;
-/**************************************************************
- * Structure for internal extended device info.
- * There will be one or two PortAudio devices for each Core Audio device:
- * one input and or one output.
- */
-typedef struct PaHostDeviceInfo
-{
- PaDeviceInfo paInfo;
- AudioDeviceID audioDeviceID;
}
-PaHostDeviceInfo;
+PaHostSoundControl;
/************************************************* Shared Data ********/
/* FIXME - put Mutex around this shared data. */
-static int sNumPaDevices = 0; /* Total number of PaDeviceInfos */
-static int sNumInputDevices = 0; /* Total number of input PaDeviceInfos */
-static int sNumOutputDevices = 0;
-static PaHostDeviceInfo *sDeviceInfos = NULL;
+static int sNumDevices = 0;
+static PaDeviceInfo **sDevicePtrs = NULL;
static int sDefaultInputDeviceID = paNoDevice;
static int sDefaultOutputDeviceID = paNoDevice;
static int sPaHostError = 0;
-
-static int sNumCoreDevices = 0;
-static AudioDeviceID *sCoreDeviceIDs; // Array of Core AudioDeviceIDs
+static AudioDeviceID *sDeviceIDList; // Array of AudioDeviceIDs
static const char sMapperSuffixInput[] = " - Input";
static const char sMapperSuffixOutput[] = " - Output";
-/* We index the input devices first, then the output devices. */
-#define LOWEST_INPUT_DEVID (0)
-#define HIGHEST_INPUT_DEVID (sNumInputDevices - 1)
-#define LOWEST_OUTPUT_DEVID (sNumInputDevices)
-#define HIGHEST_OUTPUT_DEVID (sNumPaDevices - 1)
-
/************************************************* Macros ********/
+/* Convert external PA ID to an internal ID that includes WAVE_MAPPER */
+#define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1))
+
/************************************************* Prototypes **********/
static PaError Pa_QueryDevices( void );
PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past );
-
-static int PaHost_ScanDevices( Boolean isInput );
-static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput );
-
-static PaDeviceID Pa_QueryDefaultInputDevice( void );
-static PaDeviceID Pa_QueryDefaultOutputDevice( void );
-static void PaHost_CalcHostBufferSize( internalPortAudioStream *past );
-
/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
static void Pa_StartUsageCalculation( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return;
- /* Query user CPU timer for usage analysis and to prevent overuse of CPU. */
- getrusage( RUSAGE_SELF, &pahsc->pahsc_EntryRusage );
+ /* Query system timer for usage analysis and to prevent overuse of CPU. */
+ // QueryPerformanceCounter( &pahsc->pahsc_EntryCount );
}
-static long SubtractTime_AminusB( struct timeval *timeA, struct timeval *timeB )
-{
- long secs = timeA->tv_sec - timeB->tv_sec;
- long usecs = secs * 1000000;
- usecs += (timeA->tv_usec - timeB->tv_usec);
- return usecs;
-}
-
-/******************************************************************************
-** Measure fractional CPU load based on real-time it took to calculate
-** buffers worth of output.
-*/
static void Pa_EndUsageCalculation( internalPortAudioStream *past )
{
- struct rusage currentRusage;
- long usecsElapsed;
- double newUsage;
-
-#define LOWPASS_COEFFICIENT_0 (0.95)
+#if 0
+ // LARGE_INTEGER CurrentCount = { 0, 0 };
+ // LONGLONG InsideCount;
+ // LONGLONG TotalCount;
+ /*
+ ** Measure CPU utilization during this callback. Note that this calculation
+ ** assumes that we had the processor the whole time.
+ */
+#define LOWPASS_COEFFICIENT_0 (0.9)
#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return;
-
- if( getrusage( RUSAGE_SELF, ¤tRusage ) == 0 )
- {
- usecsElapsed = SubtractTime_AminusB( ¤tRusage.ru_utime, &pahsc->pahsc_EntryRusage.ru_utime );
-
- /* 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);
- }
-}
-/****************************************** END CPU UTILIZATION *******/
-/************************************************************************/
-static PaDeviceID Pa_QueryDefaultInputDevice( void )
-{
- OSStatus err = noErr;
- UInt32 count;
- int i;
- AudioDeviceID tempDeviceID = kAudioDeviceUnknown;
- PaDeviceID defaultDeviceID = paNoDevice;
-
- // get the default output device for the HAL
- // it is required to pass the size of the data to be returned
- count = sizeof(tempDeviceID);
- err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice, &count, (void *) &tempDeviceID);
- if (err != noErr) goto Bail;
-
- // scan input devices to see which one matches this device
- defaultDeviceID = paNoDevice;
- for( i=LOWEST_INPUT_DEVID; i<=HIGHEST_INPUT_DEVID; i++ )
+ if( QueryPerformanceCounter( &CurrentCount ) )
{
- DBUG(("Pa_QueryDefaultInputDevice: i = %d, aDevId = %d\n", i, sDeviceInfos[i].audioDeviceID ));
- if( sDeviceInfos[i].audioDeviceID == tempDeviceID )
+ if( past->past_IfLastExitValid )
{
- defaultDeviceID = i;
- break;
+ InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart;
+ TotalCount = CurrentCount.QuadPart - pahsc->pahsc_LastExitCount.QuadPart;
+ /* Low pass filter the result because sometimes we get called several times in a row.
+ * That can cause the TotalCount to be very low which can cause the usage to appear
+ * unnaturally high. So we must filter numerator and denominator separately!!!
+ */
+ past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
+ (LOWPASS_COEFFICIENT_1 * InsideCount));
+ past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
+ (LOWPASS_COEFFICIENT_1 * TotalCount));
+ past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
}
+ pahsc->pahsc_LastExitCount = CurrentCount;
+ past->past_IfLastExitValid = 1;
}
-Bail:
- return defaultDeviceID;
+#endif
}
-/************************************************************************/
-static PaDeviceID Pa_QueryDefaultOutputDevice( void )
+static PaDeviceID Pa_QueryDefaultDevice( int deviceEnum )
{
OSStatus err = noErr;
UInt32 count;
int i;
- AudioDeviceID tempDeviceID = kAudioDeviceUnknown;
- PaDeviceID defaultDeviceID = paNoDevice;
+ AudioDeviceID tempDevice = kAudioDeviceUnknown;
+ PaDeviceID defaultDeviceID;
// get the default output device for the HAL
// it is required to pass the size of the data to be returned
- count = sizeof(tempDeviceID);
- err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &tempDeviceID);
+ count = sizeof(AudioDeviceID);
+ err = AudioHardwareGetProperty( deviceEnum, &count, (void *) &tempDevice);
if (err != noErr) goto Bail;
-
- // scan output devices to see which one matches this device
+ // find index of default device
defaultDeviceID = paNoDevice;
- for( i=LOWEST_OUTPUT_DEVID; i<=HIGHEST_OUTPUT_DEVID; i++ )
+ for( i=0; i<sNumDevices; i++ )
{
- DBUG(("Pa_QueryDefaultOutputDevice: i = %d, aDevId = %d\n", i, sDeviceInfos[i].audioDeviceID ));
- if( sDeviceInfos[i].audioDeviceID == tempDeviceID )
+ if( sDeviceIDList[i] == tempDevice )
{
defaultDeviceID = i;
break;
return defaultDeviceID;
}
-/******************************************************************/
+/****************************************** END CPU UTILIZATION *******/
+
static PaError Pa_QueryDevices( void )
{
OSStatus err = noErr;
Boolean outWritable;
int numBytes;
- // find out how many Core Audio devices there are, if any
+ // find out how many audio devices there are, if any
err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &outSize, &outWritable);
if (err != noErr)
ERR_RPT(("Couldn't get info about list of audio devices\n"));
// calculate the number of device available
- sNumCoreDevices = outSize / sizeof(AudioDeviceID);
+ sNumDevices = outSize / sizeof(AudioDeviceID);
// Bail if there aren't any devices
- if (sNumCoreDevices < 1)
+ if (sNumDevices < 1)
ERR_RPT(("No Devices Available\n"));
// make space for the devices we are about to get
- sCoreDeviceIDs = (AudioDeviceID *)malloc(outSize);
+ sDeviceIDList = malloc(outSize);
// get an array of AudioDeviceIDs
- err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &outSize, (void *)sCoreDeviceIDs);
+ err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &outSize, (void *)sDeviceIDList);
if (err != noErr)
ERR_RPT(("Couldn't get list of audio device IDs\n"));
- // Allocate structures to hold device info pointers.
- // There will be a maximum of two Pa devices per Core Audio device, input and/or output.
- numBytes = sNumCoreDevices * 2 * sizeof(PaHostDeviceInfo);
- sDeviceInfos = (PaHostDeviceInfo *) PaHost_AllocateFastMemory( numBytes );
- if( sDeviceInfos == NULL ) return paInsufficientMemory;
+ /* Allocate structures to hold device info pointers. */
+ numBytes = sNumDevices * sizeof(PaDeviceInfo *);
+ sDevicePtrs = PaHost_AllocateFastMemory( numBytes );
+ if( sDevicePtrs == NULL ) return paInsufficientMemory;
- // Scan all the Core Audio devices to see which support input and allocate a
- // PaHostDeviceInfo structure for each one.
- PaHost_ScanDevices( IS_INPUT );
- sNumInputDevices = sNumPaDevices;
- // Now scan all the output devices.
- PaHost_ScanDevices( IS_OUTPUT );
- sNumOutputDevices = sNumPaDevices - sNumInputDevices;
-
- // Figure out which of the devices that we scanned is the default device.
- sDefaultInputDeviceID = Pa_QueryDefaultInputDevice();
- sDefaultOutputDeviceID = Pa_QueryDefaultOutputDevice();
+ sDefaultInputDeviceID = Pa_QueryDefaultDevice( kAudioHardwarePropertyDefaultInputDevice );
+ sDefaultOutputDeviceID = Pa_QueryDefaultDevice( kAudioHardwarePropertyDefaultOutputDevice );
return paNoError;
}
/*************************************************************************/
int Pa_CountDevices()
{
- if( sNumPaDevices <= 0 ) Pa_Initialize();
- return sNumPaDevices;
+ if( sNumDevices <= 0 ) Pa_Initialize();
+ return sNumDevices;
}
/*************************************************************************/
+
/* Allocate a string containing the device name. */
-static char *PaHost_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput )
+char *deviceNameFromID(AudioDeviceID deviceID )
{
OSStatus err = noErr;
UInt32 outSize;
Boolean outWritable;
char *deviceName = nil;
-
// query size of name
- err = AudioDeviceGetPropertyInfo(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
+ err = AudioDeviceGetPropertyInfo(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
if (err == noErr)
{
- deviceName = (char*)malloc( outSize + 1);
+ deviceName = malloc( outSize + 1);
if( deviceName )
{
- err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, deviceName);
- if (err != noErr)
- ERR_RPT(("Couldn't get audio device name.\n"));
+ err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyDeviceName, &outSize, deviceName);
+ // FIXME if (err == noErr)
}
}
return deviceName;
}
+/*************************************************************************/
+
+void deviceDataFormatFromID(AudioDeviceID deviceID , AudioStreamBasicDescription *desc )
+{
+ OSStatus err = noErr;
+ UInt32 outSize;
+
+ outSize = sizeof(*desc);
+ err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyStreamFormat, &outSize, desc);
+}
+
/*************************************************************************/
// An AudioStreamBasicDescription is passed in to query whether or not
// the format is supported. A kAudioDeviceUnsupportedFormatError will
// fields set to 0 will be ignored in the query, but otherwise values
// must match exactly.
-Boolean deviceDoesSupportFormat(AudioDeviceID deviceID, AudioStreamBasicDescription *desc, Boolean isInput )
+Boolean deviceDoesSupportFormat(AudioDeviceID deviceID , AudioStreamBasicDescription *desc )
{
OSStatus err = noErr;
UInt32 outSize;
outSize = sizeof(*desc);
- err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &outSize, desc);
+ err = AudioDeviceGetProperty(deviceID, 0, false, kAudioDevicePropertyStreamFormatSupported, &outSize, desc);
if (err == kAudioHardwareNoError)
return true;
str = "kAudioHardwareIllegalOperationError";
break;
default:
- str = "Unknown CoreAudio Error!";
+ str = "UNKNWON ERROR!";
break;
}
}
/*************************************************************************
-** PaDeviceInfo structures have already been created
-** so just return the pointer.
+** If a PaDeviceInfo structure has not already been created,
+** then allocate one and fill it in for the selected device.
**
+** We create one extra input and one extra output device for the WAVE_MAPPER.
+** [Does anyone know how to query the default device and get its name?]
*/
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
{
- if( id < 0 || id >= sNumPaDevices )
- return NULL;
+#define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */
+#define NUM_CUSTOMSAMPLINGRATES 4 /* must be the same number of elements as in the array below */
+#define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES)
- return &sDeviceInfos[id].paInfo;
-}
+ PaDeviceInfo *deviceInfo;
+ AudioDeviceID devID;
+ double *sampleRates; /* non-const ptr */
+ double possibleSampleRates[] = {8000.0, 11025.0, 22050.0, 44100.0, 48000.0, 88200.0, 96000.0};
+ int index;
+ AudioStreamBasicDescription formatDesc;
+ Boolean result;
-/*************************************************************************
-** Scan all of the Core Audio devices to see which support input or output.
-** Changes sNumDevices, and fills in sDeviceInfos.
-*/
-static int PaHost_ScanDevices( Boolean isInput )
-{
- int coreDeviceIndex;
- int result;
- PaHostDeviceInfo *hostDeviceInfo;
- int numAdded = 0;
+ if( id < 0 || id >= sNumDevices )
+ return NULL;
- for( coreDeviceIndex=0; coreDeviceIndex<sNumCoreDevices; coreDeviceIndex++ )
+ if( sDevicePtrs[ id ] != NULL )
{
- // try to fill in next PaHostDeviceInfo
- hostDeviceInfo = &sDeviceInfos[sNumPaDevices];
- result = PaHost_QueryDeviceInfo( hostDeviceInfo, coreDeviceIndex, isInput );
- DBUG(("PaHost_ScanDevices: paDevId = %d, coreDevId = %d\n", sNumPaDevices, hostDeviceInfo->audioDeviceID ));
- if( result > 0 )
- {
- sNumPaDevices += 1; // bump global counter if we got one
- numAdded += 1;
- }
- else if( result < 0 ) return result;
+ return sDevicePtrs[ id ];
}
- return numAdded;
-}
-
-/*************************************************************************
-** Try to fill in the device info for this device.
-** Return 1 if a good device that PA can use.
-** Return 0 if not appropriate
-** or return negative error.
-**
-*/
-static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput )
-{
- OSErr err;
- int index;
- UInt32 outSize;
- AudioStreamBasicDescription formatDesc;
- Boolean result;
- AudioDeviceID devID;
- double *sampleRates = NULL; /* non-const ptr */
- PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo;
- double possibleSampleRates[] = {8000.0, 11025.0, 22050.0, 44100.0, 48000.0, 88200.0, 96000.0};
- int maxNumSampleRates = sizeof( possibleSampleRates ) / sizeof( double );
+ deviceInfo = PaHost_AllocateFastMemory( sizeof(PaDeviceInfo) );
+ if( deviceInfo == NULL ) return NULL;
deviceInfo->structVersion = 1;
deviceInfo->maxInputChannels = 0;
deviceInfo->maxOutputChannels = 0;
deviceInfo->numSampleRates = -1;
- devID = sCoreDeviceIDs[ coreDeviceIndex ];
- hostDeviceInfo->audioDeviceID = devID;
- // Figure out supported sample rates
- // Make room in case device supports all rates.
- sampleRates = (double*)PaHost_AllocateFastMemory( maxNumSampleRates * sizeof(double) );
- if( sampleRates == NULL ) return paInsufficientMemory;
+ // fill in format descriptor
+ if( id < sNumDevices )
+ {
+ devID = sDeviceIDList[ id ];
- deviceInfo->sampleRates = sampleRates;
- deviceInfo->numSampleRates = 0;
+ // Get the device name
+ deviceInfo->name = deviceNameFromID( devID );
- // Loop through the possible sampling rates and check each to see if the device supports it.
- for (index = 0; index < maxNumSampleRates; index ++)
- {
- memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
- formatDesc.mSampleRate = possibleSampleRates[index];
- result = deviceDoesSupportFormat( devID, &formatDesc, isInput );
+ // Figure out supported sample rates
+ // Make room in case device supports all rates.
+ sampleRates = (double*)PaHost_AllocateFastMemory( MAX_NUMSAMPLINGRATES * sizeof(double) );
+ deviceInfo->sampleRates = sampleRates;
+ deviceInfo->numSampleRates = 0;
- if (result == true)
+ // Loop through the possible sampling rates and check each to see if the device supports it.
+ for (index = 0; index < MAX_NUMSAMPLINGRATES; index ++)
{
- deviceInfo->numSampleRates += 1;
- *sampleRates = possibleSampleRates[index];
- sampleRates++;
- }
- }
- // If no sample rates supported, then not a very good device.
- if( deviceInfo->numSampleRates == 0 ) goto error;
+ memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
+ formatDesc.mSampleRate = possibleSampleRates[index];
+ result = deviceDoesSupportFormat( devID, &formatDesc );
- // Get data format info from the device.
- outSize = sizeof(formatDesc);
- err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc);
+ if (result == true)
+ {
+ deviceInfo->numSampleRates += 1;
+ *sampleRates = possibleSampleRates[index];
+ sampleRates++;
+ }
+ }
- // If no channels supported, then not a very good device.
- if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error;
+ // Get data format info from the device.
+ deviceDataFormatFromID(devID, &formatDesc);
- if( isInput )
- {
- deviceInfo->maxInputChannels = formatDesc.mChannelsPerFrame;
- }
- else
- {
+ deviceInfo->maxInputChannels = 0; // FIXME - Input and Output are separate devices!
deviceInfo->maxOutputChannels = formatDesc.mChannelsPerFrame;
- }
- // FIXME - where to put current sample rate?: formatDesc.mSampleRate
+ // FIXME - where to put current sample rate?: formatDesc.mSampleRate
- // Right now the Core Audio headers only define one formatID: LinearPCM
- // Apparently LinearPCM must be Float32 for now.
- switch (formatDesc.mFormatID)
- {
- case kAudioFormatLinearPCM:
- deviceInfo->nativeSampleFormats = paFloat32;
-
- // FIXME - details about the format are in these flags.
- // formatDesc.mFormatFlags
-
- // here are the possibilities
- // kLinearPCMFormatFlagIsFloat // set for floating point, clear for integer
- // kLinearPCMFormatFlagIsBigEndian // set for big endian, clear for little
- // kLinearPCMFormatFlagIsSignedInteger // set for signed integer, clear for unsigned integer,
- // only valid if kLinearPCMFormatFlagIsFloat is clear
- // kLinearPCMFormatFlagIsPacked // set if the sample bits are packed as closely together as possible,
- // clear if they are high or low aligned within the channel
- // kLinearPCMFormatFlagIsAlignedHigh // set if the sample bits are placed
- break;
+ // Right now the Core Audio headers only define one formatID: LinearPCM
+ // Apparently LinearPCM must be Float32 for now.
+ // FIXME -
+ switch (formatDesc.mFormatID)
+ {
+ case kAudioFormatLinearPCM:
+ deviceInfo->nativeSampleFormats = paFloat32;
+
+ // FIXME - details about the format are in these flags.
+ // formatDesc.mFormatFlags
+
+ // here are the possibilities
+ // kLinearPCMFormatFlagIsFloat // set for floating point, clear for integer
+ // kLinearPCMFormatFlagIsBigEndian // set for big endian, clear for little
+ // kLinearPCMFormatFlagIsSignedInteger // set for signed integer, clear for unsigned integer,
+ // only valid if kLinearPCMFormatFlagIsFloat is clear
+ // kLinearPCMFormatFlagIsPacked // set if the sample bits are packed as closely together as possible,
+ // clear if they are high or low aligned within the channel
+ // kLinearPCMFormatFlagIsAlignedHigh // set if the sample bits are placed
+
+ break;
+ default:
+ deviceInfo->nativeSampleFormats = paFloat32; // FIXME
+ break;
+ }
- default:
- deviceInfo->nativeSampleFormats = paFloat32; // FIXME
- break;
}
- // Get the device name
- deviceInfo->name = PaHost_DeviceNameFromID( devID, isInput );
- return 1;
+ sDevicePtrs[ id ] = deviceInfo;
+ return deviceInfo;
-error:
- if( sampleRates != NULL ) free( sampleRates );
- return 0;
+ /* FIXME
+ error:
+ free( sampleRates );
+ free( deviceInfo );
+ */
+
+ return NULL;
}
/*************************************************************************
static PaError Pa_MaybeQueryDevices( void )
{
- if( sNumPaDevices == 0 )
+ if( sNumDevices == 0 )
{
return Pa_QueryDevices();
}
PaError PaHost_Init( void )
{
+#if PA_SIMULATE_UNDERFLOW
+ PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n"));
+#endif
return Pa_MaybeQueryDevices();
}
AudioBufferList* outOutputData )
{
PaError result = 0;
- char *inputNativeBufferfPtr = NULL;
- char *outputNativeBufferfPtr = NULL;
+ char *inBufPtr;
+ char *outBufPtr;
+ int gotInput = 0;
+ int gotOutput = 0;
int i;
int buffersProcessed = 0;
int done = 0;
past->past_NumCallbacks += 1;
+#if PA_SIMULATE_UNDERFLOW
+ if(gUnderCallbackCounter++ == UNDER_SLEEP_AT)
+ {
+ Sleep(UNDER_SLEEP_FOR);
+ }
+#endif
+
#if PA_TRACE_RUN
AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks );
#endif
Pa_StartUsageCalculation( past );
/* If we are using output, then we need an empty output buffer. */
+ gotOutput = 0;
if( past->past_NumOutputChannels > 0 )
{
- outputNativeBufferfPtr = (char*)outOutputData->mBuffers[0].mData;
+ outBufPtr = outOutputData->mBuffers[0].mData,
+ gotOutput = 1;
}
/* If we are using input, then we need a full input buffer. */
+ gotInput = 0;
+ inBufPtr = NULL;
if( past->past_NumInputChannels > 0 )
{
- inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData;
+ inBufPtr = inInputData->mBuffers[0].mData,
+ gotInput = 1;
}
buffersProcessed += 1;
{
if( done )
{
- if( outputNativeBufferfPtr )
+ if( gotOutput )
{
/* Clear remainder of wave buffer if we are waiting for stop. */
AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i );
- memset( outputNativeBufferfPtr, 0, pahsc->pahsc_BytesPerUserNativeOutputBuffer );
+ memset( outBufPtr, 0, pahsc->pahsc_BytesPerUserOutputBuffer );
}
}
else
{
- /* Convert 32 bit native data to user data and call user routine. */
- result = PaConvert_Process( past, inputNativeBufferfPtr, outputNativeBufferfPtr );
+ /* Convert 16 bit native data to user data and call user routine. */
+ result = Pa_CallConvertFloat32( past, (float *) inBufPtr, (float *) outBufPtr );
if( result != 0) done = 1;
}
- if( inputNativeBufferfPtr ) inputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeInputBuffer;
- if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeOutputBuffer;
+ if( gotInput ) inBufPtr += pahsc->pahsc_BytesPerUserInputBuffer;
+ if( gotOutput) outBufPtr += pahsc->pahsc_BytesPerUserOutputBuffer;
}
Pa_EndUsageCalculation( past );
return (result != 0) ? result : done;
}
-OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime,
- void* contextPtr)
+OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow, const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime, AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime, void* contextPtr)
{
PaError result = 0;
past = (internalPortAudioStream *) contextPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
-// printf("Num input Buffers: %d; Num output Buffers: %d.\n", inInputData->mNumberBuffers, outOutputData->mNumberBuffers);
+ // Just Curious: printf("Num input Buffers: %d; Num output Buffers: %d.\n", inInputData->mNumberBuffers, outOutputData->mNumberBuffers);
/* Has someone asked us to abort by calling Pa_AbortStream()? */
if( past->past_StopNow )
}
else
{
- /* use time stamp from CoreAudio if valid */
- if( inOutputTime->mFlags & kAudioTimeStampSampleTimeValid)
- {
- past->past_FrameCount = inOutputTime->mSampleTime;
- }
-
/* Process full input buffer and fill up empty output buffers. */
if( (result = Pa_TimeSlice( past, inInputData, outOutputData )) != 0)
{
return result;
}
-#if 0
static int PaHost_CalcTimeOut( internalPortAudioStream *past )
{
/* Calculate timeOut longer than longest time it could take to play all buffers. */
if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC;
return timeOut;
}
-#endif
-
-
-/*******************************************************************/
-/* Attempt to set device sample rate. */
-static PaError PaHost_SetSampleRate( AudioDeviceID devID, Boolean isInput, double sampleRate )
-{
- AudioStreamBasicDescription formatDesc;
- OSStatus err;
- memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
- formatDesc.mSampleRate = sampleRate;
- err = AudioDeviceSetProperty( devID, 0, 0,
- isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
-
- if (err != kAudioHardwareNoError) return paInvalidSampleRate;
- else return paNoError;
-}
/*******************************************************************/
PaError PaHost_OpenInputStream( internalPortAudioStream *past )
{
- PaHostSoundControl *pahsc;
- const PaHostDeviceInfo *hostDeviceInfo;
PaError result = paNoError;
- UInt32 bytesPerHostBuffer;
- UInt32 dataSize;
- OSStatus err = noErr;
+ PaHostSoundControl *pahsc;
int bytesPerInputFrame;
+ const PaDeviceInfo *pad;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
-
- DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID));
- if( (past->past_InputDeviceID < LOWEST_INPUT_DEVID) ||
- (past->past_InputDeviceID > HIGHEST_INPUT_DEVID) )
- {
- return paInvalidDeviceId;
- }
- hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID];
-
- /* Try to set sample rate. */
- result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_INPUT, past->past_SampleRate );
- if( result != paNoError ) return result;
-
- if( past->past_NumInputChannels != hostDeviceInfo->paInfo.maxInputChannels )
- {
-#if 1
- return paInvalidChannelCount; // FIXME - how support mono?
-#else
-FIXME - should this be set on a stream basis? Is it possible to change?
- /* Attempt to set number of channels. */
- AudioStreamBasicDescription formatDesc;
- OSStatus err;
- memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
- formatDesc.mChannelsPerFrame = past->past_NumInputChannels;
-
- err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0,
- IS_INPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
- if (err != kAudioHardwareNoError)
- {
- result = paInvalidChannelCount;
- goto error;
- }
-#endif
- }
-
- // calculate native buffer sizes in bytes
- bytesPerInputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels;
- pahsc->pahsc_BytesPerUserNativeInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame;
- bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerInputFrame;
-
- // Change the bufferSize of the device! Is this per device or just for our stream?
- dataSize = sizeof(UInt32);
- err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_INPUT,
- kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer);
- if( err != noErr )
- {
- ERR_RPT(("Could not force buffer size!"));
- result = paHostError;
- goto error;
- }
- // setup conversion procedure
- result = PaConvert_SetupInput( past, paFloat32 );
-
- return result;
+ DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID));
+ pad = Pa_GetDeviceInfo( past->past_InputDeviceID );
+ if( pad == NULL ) return paInternalError;
-error:
+ bytesPerInputFrame = Pa_GetSampleSize(pad->nativeSampleFormats) * past->past_NumInputChannels;
+ pahsc->pahsc_BytesPerUserInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame;
+ pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserInputBuffer;
+ // FIXME
return result;
}
/*******************************************************************/
PaError PaHost_OpenOutputStream( internalPortAudioStream *past )
{
- PaHostSoundControl *pahsc;
- const PaHostDeviceInfo *hostDeviceInfo;
PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+ const PaDeviceInfo *pad;
UInt32 bytesPerHostBuffer;
- UInt32 dataSize;
+ UInt32 dataSize;
+ UInt32 hardwareLatency = -1;
+ Boolean writeable = false;
OSStatus err = noErr;
int bytesPerOutputFrame;
-
+
pahsc = (PaHostSoundControl *) past->past_DeviceData;
-
+
DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID));
- if( (past->past_OutputDeviceID < LOWEST_OUTPUT_DEVID) ||
- (past->past_OutputDeviceID > HIGHEST_OUTPUT_DEVID) )
- {
- return paInvalidDeviceId;
- }
- hostDeviceInfo = &sDeviceInfos[past->past_OutputDeviceID];
+ pad = Pa_GetDeviceInfo( past->past_OutputDeviceID );
+ if( pad == NULL ) return paInternalError;
- /* Try to set sample rate. */
- result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_OUTPUT, past->past_SampleRate );
- if( result != paNoError ) return result;
+ pahsc->pahsc_OutputAudioDeviceID = sDeviceIDList[past->past_OutputDeviceID];
- if( past->past_NumOutputChannels != hostDeviceInfo->paInfo.maxOutputChannels )
- {
-#if 1
- return paInvalidChannelCount; // FIXME - how support mono?
-#else
- /* Attempt to set number of channels. */
- AudioStreamBasicDescription formatDesc;
- OSStatus err;
- memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
- formatDesc.mChannelsPerFrame = past->past_NumOutputChannels;
- err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0,
- IS_OUTPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
-
- if (err != kAudioHardwareNoError)
- {
- result = paInvalidChannelCount;
- goto error;
- }
-#endif
- }
+ bytesPerOutputFrame = Pa_GetSampleSize(pad->nativeSampleFormats) * past->past_NumOutputChannels;
+ pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame;
+ pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserOutputBuffer;
- // calculate buffer sizes in bytes
- bytesPerOutputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels;
- pahsc->pahsc_BytesPerUserNativeOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame;
- bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerOutputFrame;
+ // FIXME - force host buffer to user size
- // Change the bufferSize of the device! Is this per device or just for our stream?
- dataSize = sizeof(bytesPerHostBuffer);
- err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_OUTPUT,
+ // change the bufferSize of the device
+ bytesPerHostBuffer = past->past_OutputBufferSize; // FIXME
+ dataSize = sizeof(UInt32);
+ err = AudioDeviceSetProperty( pahsc->pahsc_OutputAudioDeviceID, 0, 0, false,
kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer);
if( err != noErr )
{
result = paHostError;
goto error;
}
-
- // setup conversion procedure
- result = PaConvert_SetupOutput( past, paFloat32 );
-
+
+ // FIXME -- this isn't working for some reason. I can't figure out what the error code is.
+ dataSize = sizeof(UInt32);
+ err = AudioDeviceGetProperty(pahsc->pahsc_OutputAudioDeviceID, 0, false, kAudioDevicePropertyLatency, &dataSize, &writeable);
+ if( err != noErr )
+ {
+ PRINT(("A CoreAudio error occurred: %s.\n", coreAudioErrorString( err ) ));
+ }
+
+ err = AudioDeviceGetProperty(pahsc->pahsc_OutputAudioDeviceID, 0, false, kAudioDevicePropertyLatency, &dataSize, (void *)&hardwareLatency);
+ if ( err != noErr )
+ {
+ PRINT(("A CoreAudio error occurred: %s.\n", coreAudioErrorString( err ) ));
+ }
+ else
+ {
+ PRINT(("Output Stream Hardware Latency = %d frames.\n", hardwareLatency ));
+ }
+
return result;
error:
PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- return pahsc->pahsc_FramesPerHostBuffer;
+ return pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer;
}
/*******************************************************************
-* Determine how many User Buffers we can put into our CoreAudio stream buffer.
-* Uses:
-* past->past_FramesPerUserBuffer, etc.
-* Sets:
-* past->past_NumUserBuffers
-* pahsc->pahsc_UserBuffersPerHostBuffer
-* pahsc->pahsc_FramesPerHostBuffer
+* Determine number of WAVE Buffers
+* and how many User Buffers we can put into each WAVE buffer.
*/
-static void PaHost_CalcHostBufferSize( internalPortAudioStream *past )
+void PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
{
- PaHostSoundControl *pahsc = ( PaHostSoundControl *)past->past_DeviceData;
- unsigned int minNumUserBuffers;
-
- // Determine number of user buffers based on minimum latency.
- minNumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
- // Compare to user requested number in user wants more than the minimum.
- past->past_NumUserBuffers = ( minNumUserBuffers > past->past_NumUserBuffers ) ?
- minNumUserBuffers : past->past_NumUserBuffers;
+ PaHostSoundControl *pahsc = past->past_DeviceData;
+ unsigned int minNumBuffers;
+ int minFramesPerHostBuffer;
+ int maxFramesPerHostBuffer;
+ int minTotalFrames;
+ int userBuffersPerHostBuffer;
+ int framesPerHostBuffer;
+ int numHostBuffers;
+
+ /* Calculate minimum and maximum sizes based on timing and sample rate. */
+ minFramesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0);
+ minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
+ DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
+
+ maxFramesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0);
+ maxFramesPerHostBuffer = (maxFramesPerHostBuffer + 7) & ~7;
+ DBUG(("PaHost_CalcNumHostBuffers: maxFramesPerHostBuffer = %d\n", maxFramesPerHostBuffer ));
+
+ /* Determine number of user buffers based on minimum latency. */
+ 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 ));
- // For CoreAudio, we only have one Host buffer, so...
- pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers;
- // Calculate size of CoreAudio buffer.
- pahsc->pahsc_FramesPerHostBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers;
+ minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer;
+
+ /* We cannot make the WAVE buffers too small because they may not get serviced quickly enough. */
+ if( (int) past->past_FramesPerUserBuffer < minFramesPerHostBuffer )
+ {
+ userBuffersPerHostBuffer =
+ (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) /
+ past->past_FramesPerUserBuffer;
+ }
+ else
+ {
+ userBuffersPerHostBuffer = 1;
+ }
+
+
+ framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
+ /* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */
+ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
+
+ /* Make sure we have anough WAVE buffers. */
+ if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS)
+ {
+ numHostBuffers = PA_MIN_NUM_HOST_BUFFERS;
+ }
+ else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) &&
+ ((int) past->past_FramesPerUserBuffer < (maxFramesPerHostBuffer/2) ) )
+ {
+ /* 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;
+ framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
+ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
+ /* If we have gone too far, back up one. */
+ if( (framesPerHostBuffer > maxFramesPerHostBuffer) ||
+ (numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) )
+ {
+ userBuffersPerHostBuffer -= 1;
+ framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
+ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
+ break;
+ }
+ }
+ }
+
+ pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer;
+ pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer;
+ pahsc->pahsc_NumHostBuffers = numHostBuffers;
DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers ));
DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
}
/*******************************************************************/
memset( pahsc, 0, sizeof(PaHostSoundControl) );
past->past_DeviceData = (void *) pahsc;
- // If we are using both input and out, then they must be on the same CoreAudio device,
- // until we implement a FIFO between two devices.
- if( (past->past_OutputDeviceID != paNoDevice) && (past->past_InputDeviceID != paNoDevice) )
- {
- AudioDeviceID inputID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
- AudioDeviceID outputID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID;
- if( inputID != outputID )
- {
- ERR_RPT(("PortAudio: input and output must use same CoreAudio device!\n"));
- return paInvalidDeviceId;
- }
- }
+ /* Figure out how user buffers fit into WAVE buffers. */
+ // FIXME - just force for now
- PaHost_CalcHostBufferSize( past );
+ pahsc->pahsc_UserBuffersPerHostBuffer = 1;
+ pahsc->pahsc_FramesPerHostBuffer = past->past_FramesPerUserBuffer;
+ pahsc->pahsc_NumHostBuffers = 2; // FIXME - dunno?!
{
int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate);
- PRINT(("PortAudio on OS X - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency ));
+ PRINT(("PortAudio on OSX - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency ));
}
-
- /* Setup constants for CPU load measurement. */
- pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer);
/* ------------------ OUTPUT */
if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) )
{
- pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID;
result = PaHost_OpenOutputStream( past );
if( result < 0 ) goto error;
}
/* ------------------ INPUT */
if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) )
{
- pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
result = PaHost_OpenInputStream( past );
if( result < 0 ) goto error;
}
/*************************************************************************/
PaError PaHost_StartOutput( internalPortAudioStream *past )
{
- return 0;
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+ OSStatus err = noErr;
+
+
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ if( past->past_OutputDeviceID != paNoDevice )
+ {
+ // Associate an IO proc with the device and pass a pointer to the audio data context
+ err = AudioDeviceAddIOProc(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc, past);
+ if (err != noErr) goto error;
+
+ // start playing sound through the device
+ err = AudioDeviceStart(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc);
+ if (err != noErr) goto error;
+ }
+
+error:
+ return result;
}
/*************************************************************************/
PaError PaHost_StartInput( internalPortAudioStream *past )
{
- return 0;
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ if( past->past_InputDeviceID != paNoDevice )
+ {
+ // FIXME
+ }
+ return result;
}
/*************************************************************************/
PaError PaHost_StartEngine( internalPortAudioStream *past )
{
- OSStatus err = noErr;
PaError result = paNoError;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+#if PA_USE_TIMER_CALLBACK
+ int resolution;
+ int bufsPerTimerCallback;
+ int msecPerBuffer;
+#endif /* PA_USE_TIMER_CALLBACK */
+
past->past_StopSoon = 0;
past->past_StopNow = 0;
past->past_IsActive = 1;
-
- // Associate an IO proc with the device and pass a pointer to the audio data context
- err = AudioDeviceAddIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc, past);
- if (err != noErr) goto error;
-
- // start playing sound through the device
- err = AudioDeviceStart(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc);
- if (err != noErr) goto error;
- return result;
+ pahsc->pahsc_FramesPlayed = 0.0;
+ pahsc->pahsc_LastPosition = 0;
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result );
#endif
-
-error:
- return paHostError; // FIXME - save host error
+ return result;
}
/*************************************************************************/
PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
{
- OSStatus err = noErr;
+ int timeOut;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
- (void) abort;
/* Tell background thread to stop generating more data and to let current data play out. */
past->past_StopSoon = 1;
/* If aborting, tell background thread to stop NOW! */
if( abort ) past->past_StopNow = 1;
- past->past_IsActive = 0;
-
-#if PA_TRACE_START_STOP
- AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
-#endif
- // FIXME - we should ask proc to stop instead of stopping abruptly
- err = AudioDeviceStop(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc);
- if (err != noErr) goto Bail;
-
- err = AudioDeviceRemoveIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc);
- if (err != noErr) goto Bail;
+ timeOut = PaHost_CalcTimeOut( past );
+ past->past_IsActive = 0;
return paNoError;
-
-Bail:
- return paHostError; // FIXME - save err
}
/*************************************************************************/
PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ (void) abort;
+
+ // FIXME
return paNoError;
}
/*************************************************************************/
PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
{
+ PaHostSoundControl *pahsc;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ (void) abort;
+
+#if PA_TRACE_START_STOP
+ AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
+#endif
+
+ // FIXME if( pahsc->pahsc_OutputAudioDeviceID != ??? )
+ {
+ OSStatus err = noErr;
+
+ err = AudioDeviceStop(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc);
+ if (err != noErr) goto Bail;
+
+ err = AudioDeviceRemoveIOProc(pahsc->pahsc_OutputAudioDeviceID, (AudioDeviceIOProc)appIOProc);
+ if (err != noErr) goto Bail;
+ }
+Bail:
return paNoError;
}
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
#endif
+ /* Free data and device for output. */
+
+ /* Free data and device for input. */
free( pahsc );
past->past_DeviceData = NULL;
**
** set PA_MIN_LATENCY_MSEC=200
**
-** in the cshrc file.
+** 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")
-#if 1
-int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond )
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
{
- int minBuffers;
- int denominator;
- int minLatencyMsec = PA_MIN_LATENCY_MSEC;
- char *minLatencyText = getenv(PA_LATENCY_ENV_NAME);
- if( minLatencyText != NULL )
+ int minLatencyMsec = 0;
+ double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate;
+ int minBuffers;
+
+ /* Let user determine minimal latency by setting environment variable. */
{
- PRINT(("PA_MIN_LATENCY_MSEC = %s\n", minLatencyText ));
- minLatencyMsec = atoi( minLatencyText );
- if( minLatencyMsec < 1 ) minLatencyMsec = 1;
- else if( minLatencyMsec > 5000 ) minLatencyMsec = 5000;
+ minLatencyMsec = PA_MIN_LATENCY_MSEC;
}
- denominator = 1000.0 * framesPerBuffer;
- minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator );
- if( minBuffers < 1 ) minBuffers = 1;
- return minBuffers;
-}
-#else
-/*************************************************************************
-** Determine minimum number of buffers required for this host based
-** on minimum latency.
-*/
-int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate )
-{
- int minUserBuffers;
- int minFramesPerHostBuffer;
-
- // Calculate minimum and maximum sizes based on timing and sample rate.
- minFramesPerHostBuffer = (int) (PA_MIN_LATENCY_MSEC * sampleRate / 1000.0);
- // round up to nearest multiple of 8
- minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
- DBUG(("Pa_GetMinNumBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
+ DBUG(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));
+ minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer));
+ if( minBuffers < 2 ) minBuffers = 2;
- minUserBuffers = (minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer;
- if( minUserBuffers < 1 ) minUserBuffers = 1;
-
- return minUserBuffers;
+ return minBuffers;
}
-#endif
/*************************************************************************
** Cleanup device info.
{
int i;
- if( sDeviceInfos != NULL )
+ if( sNumDevices > 0 )
{
- for( i=0; i<sNumPaDevices; i++ )
+
+ if( sDevicePtrs != NULL )
{
- if( sDeviceInfos[i].paInfo.name != NULL ) free( (char*)sDeviceInfos[i].paInfo.name );
- if( sDeviceInfos[i].paInfo.sampleRates != NULL ) free( (void*)sDeviceInfos[i].paInfo.sampleRates );
+
+ for( i=0; i<sNumDevices; i++ )
+ {
+ if( sDevicePtrs[i] != NULL )
+ {
+
+ free( (char*)sDevicePtrs[i]->name );
+ free( (void*)sDevicePtrs[i]->sampleRates );
+ free( sDevicePtrs[i] );
+ }
+ }
+
+ free( sDevicePtrs );
+ sDevicePtrs = NULL;
}
- free( sDeviceInfos );
- sDeviceInfos = NULL;
- }
- sNumPaDevices = 0;
+ sNumDevices = 0;
+ }
return paNoError;
}
/*************************************************************************/
void Pa_Sleep( long msec )
{
-#if 0
- struct timeval timeout;
- timeout.tv_sec = msec / 1000;
- timeout.tv_usec = (msec % 1000) * 1000;
- select( 0, NULL, NULL, NULL, &timeout );
-#else
+ /* struct timeval timeout;
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+ select( 0, NULL, NULL, NULL, &timeout );
+ */
usleep( msec * 1000 );
-#endif
}
/*************************************************************************
/*************************************************************************/
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{
- AudioTimeStamp timeStamp;
- PaTimestamp streamTime;
PaHostSoundControl *pahsc;
internalPortAudioStream *past = (internalPortAudioStream *) stream;
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
-
- AudioDeviceGetCurrentTime(pahsc->pahsc_AudioDeviceID, &timeStamp);
-
- streamTime = ( timeStamp.mFlags & kAudioTimeStampSampleTimeValid) ?
- timeStamp.mSampleTime : past->past_FrameCount;
- return streamTime;
+ // FIXME PaHost_UpdateStreamTime( pahsc );
+ return pahsc->pahsc_FramesPlayed;
}
-# 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:
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
/*
* $Id$
- * PortAudio Portable Real-Time Audio Library. Copyright (c) 1999-2001 Phil Burk.
+ * PortAudio Portable Real-Time Audio Library
* Latest Version at: http://www.portaudio.com
+ * SGI IRIX implementation by Pieter Suurmond, aug 17, 2001.
*
- * Silicon Graphics (SGI) IRIX implementation by Pieter Suurmond.
- * This implementation uses sproc()-spawning, not the POSIX-threads.
+ * Copyright (c) 1999-2000 Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
-MODIFICATIONS:
+ */
+/*
+Modfication History:
8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2.
- 8/17/2001 - v15, first unstable alpha release for IRIX, sent to Phil & Ross.
- 9/23/2001 - Many fixes and changes: POLLIN for input, not POLLOUT!
- 7/04/2002 - Implemented multiple user buffers per host buffer to allow clients that
- request smaller buffersizes.
-
- [v18-0.05] Try to use CVS via the Mac now to upload instead of e-mailing to Phil & Ross.
-
+ 8/17/2001 - (v15 pa_sgi sub-version #0.04), wow, much is working now! Send this to Phil & Ross.
+ ID-stuff is nicer here now than in the linux_oss-alpha-version, v15. Was able to get
+ rid of a number of globals (like "sNumDevices" for instance).
TODO:
+ - Test under IRIX 6.5.
+ - Maybe use pthread instead of (platform-specific) poll/select/pollfd-calls.
+ (As Gary Scavone more or less suggested(?)... But can I get enough process-control then?)
- 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)
- - Implement fancy callback block adapter as described in the PDF by Stephane Letz in the ASIO dir.
- - Do some more tests... (see Makefile).
-
+ - 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?)
+ - Make sure that the fuzz-test doesn't let all IRIX crash (especially with higher buff-sizes).
+ - 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 Media Programming Guide (online books and man-pages come
- with IRIX 6.2 and may not be publically available on the internet).
+ - 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 <malloc.h>
+#include <memory.h>
+#include <math.h>
-#include "../pa_common/portaudio.h" /* (Makefile fails to find in subdirs, -I doesn't work?). */
-#include "../pa_common/pa_host.h"
-#include "../pa_common/pa_trace.h"
+#include "portaudio.h" /* Portaudio headers. */
+#include "pa_host.h"
+#include "pa_trace.h"
-#include <sys/time.h>
+#include <sys/time.h> /* System specific (IRIX 6.2). */
#include <sys/types.h>
#include <sys/prctl.h>
-#include <sys/schedctl.h> /* For schedctl(NDPRI, NDPHIMIN). */
-#include <fcntl.h> /* fcntl.h needed. */
-#include <unistd.h> /* For streams, ioctl(), etc. */
+#include <sys/schedctl.h>
+#include <fcntl.h> /* fcntl.h needed. */
+#include <unistd.h> /* For streams, ioctl(), etc. */
+#include <signal.h>
#include <ulocks.h>
#include <poll.h>
-#include <dmedia/audio.h> /* System specific (IRIX 6.2-6.5). */
-
-/*----------------- MACROS --------------------*/
-#define PRINT(x) { printf x; fflush(stdout); }
-#define ERR_RPT(x) PRINT(x)
-#define DBUG(x) /* PRINT(x) */
-#define DBUGX(x) /* PRINT(x) */
+#include <limits.h>
+#include <dmedia/audio.h>
-#define MAX_CHARS_DEVNAME (16)
-#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7. */
- /* Constants used in 'Pa_GetMinNumBuffers()' below: */
-#define MIN_LATENCY_MSEC (200) /* Used if 'getenv("PA_MIN_LATENCY_MSEC")' fails. */
-#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC") /* Same names as in file pa_unix.h. */
+/*--------------------------------------------*/
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) PRINT(x)
+#define DBUGX(x) /* PRINT(x) */
-/*------------------------------- IRIX AL specific device info: --------------------------------------*/
-typedef struct internalPortAudioDevice
-{
- PaDeviceID pad_DeviceID; /* THIS "ID" IS NEW HERE. */
- 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: */
- struct internalPortAudioDevice* pad_Next; /* Singly linked list (NULL=end). */
-} internalPortAudioDevice;
+#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). */
-/*----------------- Structure containing all SGI IRIX specific data: ---------------------------------------*/
-typedef struct PaHostSoundControl
+typedef struct internalPortAudioDevice /* IRIX specific device info: */
{
- ALconfig pahsc_ALconfigIN, /* IRIX-audio-library-datatype. Configuration */
- pahsc_ALconfigOUT; /* stucts separate for input and output ports. */
- ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */
- pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */
- int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */
-
- unsigned int pahsc_UserBuffersPerHostBuffer,
- pahsc_SamplesPerInputHostBuffer, /* Channels per frame are accounted for. */
- pahsc_SamplesPerOutputHostBuffer,
- pahsc_BytesPerInputHostBuffer, /* Size per sample are accounted for. */
- pahsc_BytesPerOutputHostBuffer;
- short *pahsc_InputHostBuffer, /* Allocated here, in this file, if necessary. */
- *pahsc_OutputHostBuffer;
-
- struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */
- pahsc_LastExitTime;
- long pahsc_InsideCountSum,
- pahsc_TotalCountSum;
-} PaHostSoundControl;
+ 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;
-/*-------------------------------------------------------- Shared Data -------------------------------*/
-static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */
-static int sPaHostError = 0; /* Maybe more than one process writing errs!? */
-usema_t *SendSema, /* These variables are shared between the */
- *RcvSema; /* audio handling process and main process. */
-/*--------------------------*/
-long Pa_GetHostError(void)
+typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */
{
- return (long)sPaHostError;
+ ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */
+ pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */
+ int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */
+ short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */
+ *pahsc_NativeOutputBuffer;
+ unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */
+ pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */
+ unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */
+ pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */
+ struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */
+ pahsc_LastExitTime;
+ long pahsc_InsideCountSum,
+ pahsc_TotalCountSum;
}
+PaHostSoundControl;
+
+/*----------------------------- Shared Data ------------------------------------------------------*/
+static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */
+static int sPaHostError = 0; /* Maybe more than one process writing errs!? */
/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/
/* (copied from source pa_linux_oss/pa_linux_oss.c) */
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. */
+ /* Query system timer for usage analysis and to prevent overuse of CPU. */
getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime );
}
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 )); */
+ /* 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) +
past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
pahsc->pahsc_InsideCountSum = 0;
pahsc->pahsc_TotalCountSum = 0;
- }
}
- past->past_IfLastExitValid = 1;
}
+ 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 );
{ /* 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. */
- }
+ {
+ 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. */
+ }
}
/*------------------------------------------------------------------------------------------*/
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()! */
+ /* Then also choose other CallConvertXX()! */
/*--------------------------------- number of available i/o channels: ------------------*/
if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max))
return translateSGIerror();
return translateSGIerror();
pad->pad_Info.maxOutputChannels = max;
DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels))
- /*--------------------------------- supported samplerates: ----------------------*/
- pad->pad_Info.numSampleRates = 7;
+ /*--------------------------------- 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;
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 ! */
+{ /* 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 */
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)
{
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.) */
+ { /* (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 */
+ } /* 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;
}
/*------------------------------------------------*/
PaDeviceID Pa_GetDefaultInputDeviceID(void)
{
- return 0; /* 0 is the default device ID. */
+ 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. */
+/*--------------------------------------------------------------------------------------*/
+/* Build linked list with all available audio devices on this SGI machine. */
+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. */
+ int audioLibFileID;
- if (sDeviceList) /* Allow re-init, only warn, no error. */
- {
+ if (sDeviceList) /* Allow re-init, only warn, no err. */
+ {
ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n"));
return r;
- }
- /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/
+ }
+ /*------------- ADD THE SGI DEFAULT DEVICES 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. */
+ { /* 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)
"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: -------------------*/
- /*---------------------------------------------------------------------------------------------*/
+ sDeviceList = pad; /* First element in linked list (pad->pad_Next is already NULL). */
+ /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LIST: --------------*/
+ /*---------------------------------------------------------------------------------*/
return r;
}
+/*------------------------------------------------------------------*/
+usema_t *SendSema, /* These variables are shared between the audio */
+*RcvSema; /* handling process and the main process. */
+
/*--------------------------------------------------------------------------------------------*/
#define MIN(a,b) ((a)<(b)?(a):(b)) /* MIN()-function is used below. */
#define kPollSEMA 0 /* To index the pollfd-array, reads nicer than just */
#define kPollIN 2
void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_StartEngine() */
{ /* as a separate thread. (Argument must be void*). */
- short evtLoop; /* Reset by parent indirectly, or at local errors. */
+ short evtLoop=1; /* Reset by parent indirectly, or at local errors. */
PaError result;
struct pollfd PollFD[3]; /* To catch kPollSEMA-, kPollOUT- and kPollIN-events. */
- internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument. */
- PaHostSoundControl *pahsc;
- short n, inputEvent, outputEvent, semaEvent; /* .revents are shorts. */
- short *inBuffer, *outBuffer; /* FIX: Only 16 bit for now, may change... */
- unsigned int samplesPerInputUserBuffer, samplesPerOutputUserBuffer;
-
- DBUG(("Entering sproc-thread.\n"));
- if (!past)
- {
- sPaHostError = paInternalError; /* Or paBadStreamPtr ? */
- ERR_RPT(("argument NULL!\n"));
- goto skip;
- }
- pahsc = (PaHostSoundControl*)past->past_DeviceData;
- if (!pahsc)
- {
+ internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument.*/
+ PaHostSoundControl *pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (pahsc == NULL)
+ {
sPaHostError = paInternalError; /* The only way is to signal error to shared area?! */
- ERR_RPT(("past_DeviceData NULL!\n"));
- goto skip; /* Sproc-ed threads MAY NOT RETURN paInternalError. */
- }
- /*----------------------------- open AL-ports here, after sproc(): -----------------------*/
- if (past->past_NumInputChannels > 0) /* Open input port. */
- {
- pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", pahsc->pahsc_ALconfigIN);
- if (!pahsc->pahsc_ALportIN)
- {
- ERR_RPT(("Failed to open AL input port.\n"));
- sPaHostError = paInternalError;
- goto skip;
- }
- DBUG(("Opened %d input channel(s).\n", past->past_NumInputChannels));
- samplesPerInputUserBuffer = pahsc->pahsc_SamplesPerInputHostBuffer /
- pahsc->pahsc_UserBuffersPerHostBuffer;
- }
- if (past->past_NumOutputChannels > 0) /* Open output port. */
- {
- pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", pahsc->pahsc_ALconfigOUT);
- if (!pahsc->pahsc_ALportOUT)
- {
- ERR_RPT(("Failed to open AL output port.\n"));
- sPaHostError = paInternalError; /* Assume pahsc_ALconfigs are the */
- goto skip; /* same for IN and OUT in case */
- } /* both ports are opened (bidir). */
- DBUG(("Opened %d output channel(s).\n", past->past_NumOutputChannels));
- samplesPerOutputUserBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer /
- pahsc->pahsc_UserBuffersPerHostBuffer;
- DBUG(("samplesPerOutputUserBuffer = %d\n", samplesPerOutputUserBuffer));
- }
- /*-----------------------------------------------------------------------*/
+ goto skipALL; /* Sproc-ed threads MAY NOT RETURN paInternalError. */
+ }
past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */
+ DBUG(("entering thread.\n"));
PollFD[kPollIN].fd = ALgetfd(pahsc->pahsc_ALportIN); /* ALgetfd returns -1 on failures */
- PollFD[kPollIN].events = POLLIN; /* such as ALport not there. */
+ PollFD[kPollIN].events = POLLOUT; /* such as ALport not there. */
+ /* .events = POLLOUT ??? ok? */
PollFD[kPollOUT].fd = ALgetfd(pahsc->pahsc_ALportOUT);
PollFD[kPollOUT].events = POLLOUT; /* .events = POLLOUT is OK. */
schedctl(NDPRI, NDPHIMIN); /* Sets non-degrading priority for this process. */
PollFD[kPollSEMA].fd = usopenpollsema(SendSema, 0777); /* To communicate with parent. */
PollFD[kPollSEMA].events = POLLIN; /* .events = POLLIN is OK. */
- uspsema(SendSema); /* Blocks until ... MUST be here, this uspsema(). */
- evtLoop = ((past->past_StopNow | past->past_StopSoon) == 0);
- while (evtLoop)
- {
+ uspsema(SendSema); /* Blocks until the next (first)signal is received???? */
+ do
+ {
/*---------------------------- SET FILLPOINTS AND WAIT UNTIL SOMETHING HAPPENS: ----------*/
- if (pahsc->pahsc_InputHostBuffer) /* Then pahsc_ALportIN should also be there! */
+ if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */
/* For input port, fill point is number of locations in the sample queue that must be */
/* filled in order to trigger a return from select(). (or poll()) */
/* Notice IRIX docs mention number of samples as argument, not number of sampleframes.*/
- if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputHostBuffer))
- { /* Multiple amount as transferred per time. */
+ if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputBuffer))
+ { /* Same amount as transferred per time. */
ERR_RPT(("ALsetfillpoint() for ALportIN failed.\n"));
sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */
- goto skip;
- }
- if (pahsc->pahsc_OutputHostBuffer) /* Then pahsc_ALportOUT should also be there! */
+ goto skipIO;
+ }
+ if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */
/* For output port, fill point is number of locations that must be free in order to */
/* wake up from select(). (or poll()) */
- if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputHostBuffer))
- {
+ if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputBuffer))
+ {
ERR_RPT(("ALsetfillpoint() for ALportOUT failed.\n"));
sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */
- goto skip;
- } /* poll() with timeout=-1 makes it block until a requested */
+ goto skipIO;
+ } /* poll() with timeout=-1 makes it block until a requested */
poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */
- /* array <0, events is ignored and revents is set to 0. */
+ /* array <0, events is ignored and revents is set to 0. */
/*---------------------------- MESSAGE-EVENT FROM PARENT THREAD: -------------------------*/
- semaEvent = PollFD[kPollSEMA].revents & POLLIN;
- if (semaEvent)
- {
- if (past->past_StopSoon)
+ if (PollFD[kPollSEMA].revents & POLLIN)
+ {
+ if (past->past_StopNow || past->past_StopSoon)
evtLoop = 0;
+ uspsema(SendSema); /* Decrements count of previously allocated semaphore SendSema. If count */
+ /* is then negative, semaphore will logically block calling process until */
+ /* count is incremented due to an usvsema call made by another process. */
+ usvsema(RcvSema); /* Increments the count associated with RcvSema. If there are any */
+ /* processes queued waiting for the semaphore the first one is awakened. */
+ /* Here usvsema sends an acknowledgement to the "SendAudioCommand()". */
if (past->past_StopNow)
- goto skip;
- }
- /*------------------------------------- FILLED-EVENT FROM INPUT BUFFER: --------------------------*/
- inputEvent = PollFD[kPollIN].revents & POLLIN;
- if (inputEvent) /* Don't need to check (pahsc->pahsc_InputHostBuffer): */
- { /* if buffer was not there, ALport not there, no events! */
- if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_InputHostBuffer,
- pahsc->pahsc_SamplesPerInputHostBuffer))
- { /* Here again: number of samples instead of number of frames. */
+ goto skipIO; /* Else go on for a little while... */
+ }
+ /*------------------------------------- FREE-EVENT FROM INPUT BUFFER: ----------------------------*/
+ if (PollFD[kPollIN].revents & POLLOUT) /* Don't need to check (pahsc->pahsc_NativeInputBuffer): */
+ { /* if buffer was not there, ALport not there, no events! */
+ if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer,
+ pahsc->pahsc_SamplesPerInputBuffer))
+ { /* Here again: number of samples instead of number of frames. */
ERR_RPT(("ALreadsamps() failed.\n"));
sPaHostError = paInternalError;
- goto skip;
- }
+ goto skipIO; /* (Using exit(-1) would be a bit rude.) */
}
- outputEvent = PollFD[kPollOUT].revents & POLLOUT;
+ }
/*------------------------------------- USER-CALLBACK-ROUTINE: -----------------------------------*/
- if (inputEvent | outputEvent) /* (Bitwise is ok.) */
- { /* To be sure we that really DID input-transfer or gonna DO output-transfer, and that it is */
- /* not just "sema"- (i.e. user)-event, or some other system-event that awakened the poll(). */
+ if ((PollFD[kPollIN].revents & POLLOUT) || (PollFD[kPollOUT].revents & POLLOUT))
+ { /* To be sure we that really DID input-transfer or gonna DO output-transfer, and that it is */
+ /* not just "sema"- (i.e. user)-event, or some other system-event that awakened the poll(). */
Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */
- /* user data and call user routine. */
- inBuffer = pahsc->pahsc_InputHostBuffer; /* Short pointers for now, care! */
- outBuffer = pahsc->pahsc_OutputHostBuffer;
- n = pahsc->pahsc_UserBuffersPerHostBuffer; /* 'n' may never start at NULL ! */
- do {
- result = Pa_CallConvertInt16(past, inBuffer, outBuffer);
- if (result) /* This is apparently NOT an error! Just letting the userCallBack stop us. */
- { DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result)); goto skip; }
- inBuffer += samplesPerInputUserBuffer; /* Num channels is accounted for. */
- outBuffer += samplesPerOutputUserBuffer;
- } while (--n);
+ result = Pa_CallConvertInt16(past, /* user data and call user routine. */
+ pahsc->pahsc_NativeInputBuffer,
+ pahsc->pahsc_NativeOutputBuffer);
Pa_EndUsageCalculation(past);
- }
- /*------------------------------------- FREE-EVENT FROM OUTPUT BUFFER: ---------------------------*/
- if (outputEvent) /* Don't need to check (pahsc->pahsc_OutputHostBuffer) */
- { /* because if filedescriptor not there, no event for it. */
- if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_OutputHostBuffer,
- pahsc->pahsc_SamplesPerOutputHostBuffer))
- {
- ERR_RPT(("ALwritesamps() failed.\n")); /* Better use SEMAS for messaging back to parent! */
- sPaHostError = paInternalError;
- goto skip;
- }
+ if (result)
+ {
+ DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result));
+ goto skipIO; /* But it is apparently NOT an error! */
+ } /* Just letting the userCallBack stop us. */
+ }
+ /*------------------------------------- FILLED-EVENT FROM OUTPUT BUFFER: -------------------------*/
+ if (PollFD[kPollOUT].revents & POLLOUT) /* Don't need to check (pahsc->pahsc_NativeOutputBuffer) */
+ { /* because if filedescriptor not there, no event for it. */
+ if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer,
+ pahsc->pahsc_SamplesPerOutputBuffer))
+ {
+ ERR_RPT(("ALwritesamps() failed.\n"));
+ sPaHostError = paInternalError; /* Better use SEMAS also for messaging back to parent! */
+ goto skipIO;
}
}
-skip:
- /*------------------------------- close AL-ports ----------------------------*/
- if (pahsc->pahsc_ALportIN)
- {
- if (ALcloseport(pahsc->pahsc_ALportIN))
- translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
- else /* But go on anyway... to release other stuff... */
- pahsc->pahsc_ALportIN = (ALport)0;
- }
- if (pahsc->pahsc_ALportOUT)
- {
- if (ALcloseport(pahsc->pahsc_ALportOUT))
- translateSGIerror();
- else
- pahsc->pahsc_ALportOUT = (ALport)0;
- }
+ /*------------------------------------------------------------------------------------------------*/
+ }
+ while (evtLoop); /* Set at init-time, only reset indirectly via semaphore, */
+skipIO: /* or in case of error, only within this loop. */
+ DBUG(("leaving thread.\n")); /* Don't we need to cleanup semaphore-stuff / thread itself? */
+skipALL: /* (make threadPID in the struct -1 again, for instance?) */
past->past_IsActive = 0;
- if (semaEvent)
- {
- uspsema(SendSema); /* StopEngine() was still waiting for this acknowledgement. */
- usvsema(RcvSema); /* (semaEvent initialized with 0.) */
- }
- DBUG(("Leaving sproc-thread.\n"));
-}
-
+ pahsc->pahsc_threadPID == -1; /* Signal back, so StopEngine() for example won't call KILL().... hmmm doesn't work yet! */
+ /* SHIT: when this process ends, it also KILLS of the parent!!! because sigint = kill?? */
+ exit(0); /* Unix process. SIGCLD is sent to parent (if prctl wa called with 0 by parent). */
+} /* if prctl was called with 9 by parent, then when this process ends, it also */
+/* KILLS off the parent!!! */
/*--------------------------------------------------------------------------------------*/
PaError PaHost_OpenStream(internalPortAudioStream *past)
PaHostSoundControl *pahsc;
unsigned int minNumBuffers;
internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */
- long pvbuf[8], sr, alq; /* To get/set hardware configs. */
-
+ 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;
- }
+ 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)); /* Hmmm, not too elegant, besides, the */
+ pahsc->pahsc_threadPID = -1; /* pahsc_threadPID must 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 *) malloc(pahsc->pahsc_BytesPerInputBuffer);
+ if( pahsc->pahsc_NativeInputBuffer == NULL )
{
- ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */
- result = paInsufficientMemory; goto done; /* code (nothing will be freed). */
+ ERR_RPT(("(normal yet) Memory allocation 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 *) malloc(pahsc->pahsc_BytesPerOutputBuffer);
+ if (pahsc->pahsc_NativeOutputBuffer == NULL)
+ {
+ ERR_RPT(("(normal yet) Memory allocation failed.\n"));
+ result = paInsufficientMemory; goto done;
}
- memset(pahsc, 0, sizeof(PaHostSoundControl));
- pahsc->pahsc_threadPID = -1; /* Should pahsc_threadPID be inited to */
- past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */
+ }
/*------------------------------------------ Manipulate hardware if necessary and allowed: --*/
ALseterrorhandler(0); /* 0 = turn off the default error handler. */
pvbuf[0] = AL_INPUT_RATE;
pvbuf[2] = AL_INPUT_COUNT;
pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */
pvbuf[6] = AL_OUTPUT_COUNT;
- sr = (long)(past->past_SampleRate + 0.5); /* Common for both input and output :-) */
- /*-----------------------------------------------------------------------------*/
- /* OVERWRITE 'past_NumUserBuffers'-field in the struct supplied by the caller. */
- /* This field may be set to zero by a client application to ask for minimum */
- /* latency. It is used below, to set both input- and output-AL-queuesizes. */
- minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer,
- past->past_SampleRate); /* Take biggest. */
- past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ?
- minNumBuffers : past->past_NumUserBuffers;
- DBUG(("past->past_NumUserBuffers=%d\n", past->past_NumUserBuffers));
- /*----------------------------------------------------------------------------------*/
- pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers >> 1;
- DBUG(("pahsc_UserBuffersPerHostBuffer=%d\n",pahsc->pahsc_UserBuffersPerHostBuffer));
- /* 1 is minimum because Pa_GetMinNumBuffers() returns >= 2.
- Callback will be called 'pahsc_UserBuffersPerHostBuffer' times (with 'past_FramesPerUserBuffer')
- per host transfer. */
- /*---------------------------------------------------- SET INPUT CONFIGURATION: ---------------------*/
- if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */
- { /* sponding native AL-number(s). */
- /*--------------------------------------------------- Allocate native buffers: --------------*/
- pahsc->pahsc_SamplesPerInputHostBuffer = pahsc->pahsc_UserBuffersPerHostBuffer *
- past->past_FramesPerUserBuffer * /* Needed by the */
- past->past_NumInputChannels; /* audio-thread. */
- DBUG(("pahsc_SamplesPerInputHostBuffer=%d\n", pahsc->pahsc_SamplesPerInputHostBuffer));
- pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_SamplesPerInputHostBuffer * sizeof(short);
- pahsc->pahsc_InputHostBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer);
- if (!pahsc->pahsc_InputHostBuffer)
- {
- ERR_RPT(("Fast memory allocation failed (in).\n"));
- result = paInsufficientMemory;
- goto done;
- }
+ 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;
- }
+ 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. */
+ { /* 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 Hz.\n", sr, pvbuf[1]));
- result = paHostError;
- goto done;
- }
+ another process is currently using input at %ld kHz.\n", sr, pvbuf[1]));
+ result = paHostError; goto done;
+ }
pvbuf[1] = sr; /* Then set input-rate. */
if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2))
- goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */
- } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */
- pahsc->pahsc_ALconfigIN = ALnewconfig(); /* Released at PaHost_CloseStream(). */
- if (pahsc->pahsc_ALconfigIN == (ALconfig)0)
- goto sgiError;
- if (ALsetsampfmt(pahsc->pahsc_ALconfigIN, AL_SAMPFMT_TWOSCOMP))/* Choose paInt16 as native i/o-format. */
- goto sgiError;
- if (ALsetwidth (pahsc->pahsc_ALconfigIN, AL_SAMPLE_16)) /* Only meaningful when sample format for */
- goto sgiError; /* config is set to two's complement format. */
- /************************ Future versions might (dynamically) switch to 32-bit floats? *******
- if (ALsetsampfmt(pahsc_ALconfigIN, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.)
- goto sgiError;
- if (ALsetfloatmax (pahsc_ALconfigIN, 1.0)) Only meaningful when sample format for config
- goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */
- /*--------- Set internal AL queuesize (in samples, not in frames!) -------------------------------*/
- alq = (long)past->past_NumUserBuffers * past->past_FramesPerUserBuffer * past->past_NumInputChannels;
- DBUG(("AL input queuesize = %ld samples.\n", alq));
- if (ALsetqueuesize(pahsc->pahsc_ALconfigIN, alq))
- goto sgiError;
- if (ALsetchannels (pahsc->pahsc_ALconfigIN, (long)(past->past_NumInputChannels)))
- goto sgiError; /* Returns 0 on success, -1 on failure. */
+ goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */
}
- /*---------------------------------------------------- SET OUTPUT CONFIGURATION: ------------------------*/
- if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */
- { /* We use padOUT/IN later on, or at least 1 of both. */
- pahsc->pahsc_SamplesPerOutputHostBuffer = pahsc->pahsc_UserBuffersPerHostBuffer *
- past->past_FramesPerUserBuffer * /* Needed by the */
- past->past_NumOutputChannels; /* audio-thread. */
- DBUG(("pahsc_SamplesPerOutputHostBuffer=%d\n", pahsc->pahsc_SamplesPerOutputHostBuffer));
- pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_SamplesPerOutputHostBuffer * sizeof(short);
- pahsc->pahsc_OutputHostBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer);
- if (!pahsc->pahsc_OutputHostBuffer)
- {
- ERR_RPT(("Fast memory allocation failed (out).\n"));
- result = paInsufficientMemory;
- goto done;
- }
+ }
+ 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;
- }
+ result = paHostError; goto done;
+ }
if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4))
goto sgiError;
- if (pvbuf[5] != sr)
- { /* Output needed and rate different from current harware-rate. */
+ if ((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 Hz.\n", sr, pvbuf[5]));
- result = paHostError;
- goto done; /* Will free again the inputbuffer */
- } /* that was just created above. */
+ another process is currently using output at %ld kHz.\n", sr, pvbuf[5]));
+ result = paHostError; goto done; /* Will free again the inputbuffer */
+ } /* that was just created above. */
pvbuf[5] = sr; /* Then set output-rate. */
if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2))
goto sgiError;
- }
- pahsc->pahsc_ALconfigOUT = ALnewconfig(); /* Released at PaHost_CloseStream(). */
- if (pahsc->pahsc_ALconfigOUT == (ALconfig)0)
- goto sgiError;
- if (ALsetsampfmt(pahsc->pahsc_ALconfigOUT, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */
- goto sgiError;
- if (ALsetwidth (pahsc->pahsc_ALconfigOUT, AL_SAMPLE_16)) /* Only meaningful when sample format for */
- goto sgiError; /* config is set to two's complement format. */
- /** Future versions might (dynamically) switch to 32-bit floats. **/
- alq = (long)past->past_NumUserBuffers * past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
- DBUG(("AL output queuesize = %ld samples.\n", alq));
- if (ALsetqueuesize(pahsc->pahsc_ALconfigOUT, alq))
- goto sgiError;
- if (ALsetchannels (pahsc->pahsc_ALconfigOUT, (long)(past->past_NumOutputChannels)))
- goto sgiError;
}
- /*----------------------------------------------- TEST DEVICE ID's: --------------------*/
- if ((past->past_OutputDeviceID != past->past_InputDeviceID) && /* Who SETS these devive-numbers? */
- (past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0))
- {
- ERR_RPT(("Cannot setup bidirectional stream between different devices.\n"));
- result = paHostError;
- goto done;
+ }
+ /*------------------------------------------ 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, fillpoints in the thread are ok now. */
+
+ /* 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:
+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;
PaHostSoundControl *pahsc;
usptr_t *arena;
if (!past) /* Test argument. */
- {
+ {
ERR_RPT(("PaHost_StartEngine(NULL)!\n"));
return paBadStreamPtr;
- }
+ }
pahsc = (PaHostSoundControl*)past->past_DeviceData;
if (!pahsc)
- {
+ {
ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData = NULL!\n"));
return paHostError;
- }
+ }
past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */
past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */
past->past_IsActive = 1;
-
+
/* Although the pthread_create() function, as well as <pthread.h>, may be */
/* available in IRIX, use sproc() on SGI to create audio-background-thread. */
/* (Linux/oss uses pthread_create() instead of __clone() because: */
/* - pthread_create also works for other UNIX systems like Solaris, */
/* - Java HotSpot VM crashes in pthread_setcanceltype() using __clone().) */
-
+
usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* (From SGI-AL-examples, file */
arena = usinit(tmpnam(0)); /* motifexample.c, function */
SendSema = usnewpollsema(arena, 0); /* InitializeAudioProcess().) */
- RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process
- will be permitted through a semaphore at a time. Values > 1
- imply that up to val resources may be simultaneously used, but requests
- for more than val resources cause the calling process to block until a
- resource comes free (by a process holding a resource performing a
- usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */
- prctl(PR_SETEXITSIG, 0); /* No not (void*)9, but 0, which doesn't kill the parent! */
- /* PR_SETEXITSIG controls whether all members of a share group will be
- signaled if any one of them leaves the share group (either via exit()
- or exec()). If 2nd arg, interpreted as an int is 0, then normal IRIX
- process termination rules apply, namely that the parent is sent a
- SIGCLD upon death of child, but no indication of death of parent is
- given. If the second argument is a valid signal number then if any
- member of a share group leaves the share group, a signal is
- sent to ALL surviving members of the share group. */
+ RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process
+ will be permitted through a semaphore at a time. Values > 1
+ imply that up to val resources may be simultaneously used, but requests
+ for more than val resources cause the calling process to block until a
+ resource comes free (by a process holding a resource performing a
+ usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */
+ prctl(PR_SETEXITSIG, 0);/* No not (void*)9, but 0, which doesn't kill the parent! */
+ /* PR_SETEXITSIG controls whether all members of a share group will be
+ signaled if any one of them leaves the share group
+ (either via exit() or exec()). If second
+ argument, interpreted as an int is 0, then normal IRIX
+ process termination rules apply, namely that the parent
+ is sent a SIGCLD upon death of child, but no indication
+ of death of parent is given. If the second argument is
+ a valid signal number then if any member
+ of a share group leaves the share group, a signal is
+ sent to ALL surviving members of the share group. */
/* SPAWN AUDIO-CHILD: */
pahsc->pahsc_threadPID = sproc(Pa_SgiAudioProcess, /* Returns process ID of */
PR_SALL, /* new process, or -1. */
- (void*)past); /* Pass past as optional */ /* IS THIS SAFE, will past never */
- if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ /* be moved around in memory???? */
- {
+ (void*)past); /* Pass past as optional */
+ if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */
+ {
ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n"));
sPaHostError = oserror(); /* Pass native error-number to shared area. */
return paHostError; /* But return the generic error-number. */
- }
+ }
return paNoError; /* Hmmm, errno may come from other threads in same group! */
} /* ("man sproc" in IRIX6.2 to read about _SGI_MP_SOURCE.) */
int hres;
long timeOut;
PaError result = paNoError;
- PaHostSoundControl *pahsc;
-
- DBUG(("PaHost_StopEngine() called.\n"));
- if (!past)
- return paBadStreamPtr;
- pahsc = (PaHostSoundControl*)past->past_DeviceData;
- /* Prevent from doing this twice!! */
- if ((!pahsc) || /* Some tests call this CLOSE twice!! */
- (!past->past_IsActive) ||
- past->past_StopSoon || past->past_StopNow)
- return result; /* paNoError (already stopped, no err?). */
+ PaHostSoundControl *pahsc = (PaHostSoundControl*)past->past_DeviceData;
+
+ if (pahsc == NULL)
+ return result; /* paNoError */
past->past_StopSoon = 1; /* Tell background thread to stop generating */
if (abort) /* more and to let current data play out. If */
past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */
- /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/
+
+ /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/
usvsema(SendSema); /* Increments count associated with SendSema. */
- /* Wait for the response. */
+ /* Wait for the response. */
uspsema(RcvSema); /* Decrements count of previously allocated */
- /* semaphore specified by RcvSema. */
- while (past->past_IsActive) /* REALLY WAIT. */
- {
- /* DBUG(("wait 1 ms for audio-thread to stop.\n")); */
- Pa_Sleep(1);
- }
-
-#if 0 /* We don't need to KILL(), just COMMUNICATE and be patient... */
+ /* semaphore specified by RcvSema. */
+ /* Must be sure sub-process is really there,... otherwise above semas block?! */
if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */
- {
- DBUG(("PaHost_StopEngine() is about to kill(SIGKILL) audio-thread.\n"));
+ {
+ /* How to JOIN a "sproc"-thread to recover memory resources????? */
+ /* hres = pthread_join( pahsc->pahsc_ThreadPID, NULL ); */
+ DBUG(("PaHost_StopEngine() is about to KILL(SIGKILL) audio-thread.\n"));
if (kill(pahsc->pahsc_threadPID, SIGKILL)) /* Or SIGTERM or SIGQUIT(core) */
- { /* Returns -1 in case of error. */
+ { /* Returns -1 in case of error. */
result = paHostError;
sPaHostError = oserror(); /* Hmmm, other threads may also write here! */
ERR_RPT(("PaHost_StopEngine() failed to kill audio-thread.\n"));
- }
+ }
else
pahsc->pahsc_threadPID = -1; /* Notify that we've killed this thread. */
- }
-#endif
+ }
past->past_IsActive = 0; /* Even when kill() failed and pahsc_threadPID still there??? */
return result;
}
{
PaHostSoundControl *pahsc;
PaError result = paNoError;
-
- DBUG(("PaHost_CloseStream() called.\n"));
- if (!past)
+
+ if (past == NULL)
return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if (!pahsc) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */
- return result; /* This test prevents from freeing NULL-pointers. */
+ if (pahsc == 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_ALconfigIN)
- { /* Release configuration structs, only if allocated. */
- ALfreeconfig(pahsc->pahsc_ALconfigIN);
- pahsc->pahsc_ALconfigIN = NULL;
- }
- if (pahsc->pahsc_ALconfigOUT)
- {
- ALfreeconfig(pahsc->pahsc_ALconfigOUT); /* (Al-ports were already closed by audioProcess). */
- pahsc->pahsc_ALconfigOUT = NULL;
- }
- if (pahsc->pahsc_InputHostBuffer)
- {
- PaHost_FreeFastMemory(pahsc->pahsc_InputHostBuffer, pahsc->pahsc_BytesPerInputHostBuffer);
- pahsc->pahsc_InputHostBuffer = NULL;
- }
- if (pahsc->pahsc_OutputHostBuffer)
- {
- PaHost_FreeFastMemory(pahsc->pahsc_OutputHostBuffer, pahsc->pahsc_BytesPerOutputHostBuffer);
- pahsc->pahsc_OutputHostBuffer = NULL;
- }
- PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl));
- past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST MEM. */
+ 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)
+ {
+ free(pahsc->pahsc_NativeInputBuffer);
+ pahsc->pahsc_NativeInputBuffer = NULL;
+ }
+ if (pahsc->pahsc_NativeOutputBuffer)
+ {
+ free(pahsc->pahsc_NativeOutputBuffer);
+ pahsc->pahsc_NativeOutputBuffer = NULL;
+ }
+ PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl)); /* Not just free(pahsc) because */
+ past->past_DeviceData = NULL; /* PaHost_OpenStream(); allocated FAST (thus mpinned?) MEM. */
return result;
}
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+** set PA_MIN_LATENCY_MSEC=200
+** in the AUTOEXEC.BAT file and reboot.
+** If the environment variable is not set, then the latency will be
+** determined based on the OS. Windows NT has higher latency than Win95.
+*/
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
-/*------------------------------------------------------------------------*/
-/* Determine minimum number of buffers required for (SGI) host based on */
-/* minimum latency. Latency can be optionally set by user by setting an */
-/* environment variable. For example, to set my latency to 200 msec, I've */
-/* put this line in my '.cshrc' file: setenv PA_MIN_LATENCY_MSEC 200 */
-/* It always calls the 'PRINT' macro. */
-/* The minimum number that is returned is 2. */
-/* This number is directly proportional to the AL-queue sizes to set up. */
-/* It is one more than the number of user buffers per host buffer - in */
-/* case minimum is returned, or, twice the user buffers per host buffer. */
-/*------------------------------------------------------------------------*/
-int Pa_GetMinNumBuffers(int framesPerUserBuffer, double framesPerSecond)
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
{
- int minBuffers, minLatencyMsec;
- char *minLatencyText;
- double actualLatency;
-
- minLatencyText = getenv(PA_LATENCY_ENV_NAME); /* Defined at top of file. */
- if (minLatencyText)
- {
- minLatencyMsec = atoi(minLatencyText);
- if (minLatencyMsec < 10)
- { /* 10 is the minimum. */
- minLatencyMsec = 10;
- PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' below minimum of %d milliseconds.\n",
- minLatencyMsec));
- }
- else if (minLatencyMsec > 4000)
- { /* 4000 is the maximum. */
- minLatencyMsec = 4000;
- PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' above maximum of %d milliseconds.\n",
- minLatencyMsec));
- }
- else
- PRINT (("Using environment variable 'PA_MIN_LATENCY_MSEC' (set to %d milliseconds).\n",
- minLatencyMsec));
- }
- else
- {
- minLatencyMsec = MIN_LATENCY_MSEC; /* Defined at top of this file. */
- PRINT (("Environment variable 'PA_MIN_LATENCY_MSEC' not found.\nUsing default of %d milliseconds\n",
- minLatencyMsec));
- }
- minBuffers = (int)((minLatencyMsec * framesPerSecond) /
- (1000.0 * framesPerUserBuffer));
- if (minBuffers < 2)
- minBuffers = 2;
- actualLatency = 1000.0 * minBuffers * framesPerUserBuffer / framesPerSecond;
- PRINT (("Actual AL latency set to %.2f milliseconds\n", actualLatency));
- return minBuffers;
+ 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. */
+PaError PaHost_Term(void) /* Frees all of the linked devices. */
{ /* Called by Pa_Terminate() from pa_lib.c. */
internalPortAudioDevice *pad = sDeviceList,
- *nxt;
+ *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; */
+ return 0; /* Got rid of sNumDevices=0; */
}
/***********************************************************************/
{
void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */
if (addr) /* range and locks the pages into memory. A counter */
- { /* is incremented each time the page is locked. The */
+ { /* is incremented each time the page is locked. The */
if (mpin(addr, numBytes)) /* superuser can lock as many pages as it wishes, */
- { /* others are limited to the configurable PLOCK_MA. */
+ { /* others are limited to the configurable PLOCK_MA. */
ERR_RPT(("PaHost_AllocateFastMemory() failed to mpin() memory.\n"));
#if 1
free(addr); /* You MAY cut out these 2 lines to be less strict, */
addr = NULL; /* you then only get the warning but PA goes on... */
#endif /* Only problem then may be corresponding munpin() */
- } /* call at PaHost_FreeFastMemory(), below. */
+ } /* call at PaHost_FreeFastMemory(), below. */
memset(addr, 0, numBytes); /* Locks established with mlock are not inherited by */
- } /* a child process after a fork. Furthermore, IRIX- */
+ } /* a child process after a fork. Furthermore, IRIX- */
return addr; /* man-pages warn against mixing both mpin and mlock */
} /* in 1 piece of code, so stick to mpin()/munpin() ! */
void PaHost_FreeFastMemory(void *addr, long numBytes)
{
if (addr)
- {
+ {
if (munpin(addr, numBytes)) /* Will munpin() fail when it was never mpinned? */
ERR_RPT(("WARNING: PaHost_FreeFastMemory() failed to munpin() memory.\n"));
free(addr); /* But go on, try to release it, just warn... */
- }
+ }
}
/*----------------------------------------------------------*/
/*-------------------------------------------------------------------*/
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{
- internalPortAudioStream *past = (internalPortAudioStream *) stream;
-/* FIXME - return actual frames played, not frames generated.
-** Need to query the output device somehow.
-*/
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ /* FIXME - return actual frames played, not frames generated.
+ ** Need to query the output device somehow.
+ */
return past->past_FrameCount;
}
+++ /dev/null
-# 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
-
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * $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;
-}
+++ /dev/null
-/*
- * $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 );
-}
/*
* $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
*
#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().
{
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++ )
+ finished = 1;
+ }
+ else
+ {
+ for( i=0; i<(int)framesPerBuffer; i++ )
{
- /* 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);
+ 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 0;
+ return finished;
}
/*******************************************************************/
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 */
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");
#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;
}
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,
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++ )
{
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 );
}
-
- printf("Finished loop. Close stream.\n"); fflush(stdout);
-
err = Pa_CloseStream( stream );
if( err != paNoError ) goto error;
-
- printf("Done.\n"); fflush(stdout);
- {
- SAMPLE max = 0;
- SAMPLE posVal;
- int i;
- for( i=0; i<dataPtr->numSamples; i++ )
- {
- posVal = dataPtr->recordedSamples[i];
- if( posVal < 0 ) posVal = -posVal;
- if( posVal > max ) max = posVal;
- }
- printf("Largest recorded sample = %d\n", max );
- }
- /* Write recorded data to a file. */
-#if 0
- {
- FILE *fid;
- fid = fopen("recorded.raw", "wb");
- if( fid == NULL )
- {
- printf("Could not open file.");
- }
- else
- {
- fwrite( dataPtr->recordedSamples, dataPtr->samplesPerFrame * sizeof(SAMPLE), totalFrames, fid );
- fclose( fid );
- printf("Wrote data to 'recorded.raw'\n");
- }
- }
-#endif
-
-error:
- return err;
-}
-
-/****************************************************************/
-PaError TestPlayback( paTestData *dataPtr )
-{
- PortAudioStream *stream;
- PaError err;
- int i;
-
/* Playback recorded data. */
- dataPtr->frameIndex = 0;
+ data.frameIndex = 0;
printf("Begin playback.\n"); fflush(stdout);
err = Pa_OpenStream(
&stream,
PA_SAMPLE_TYPE,
NULL,
Pa_GetDefaultOutputDeviceID(),
- dataPtr->samplesPerFrame, /* stereo output */
+ data.samplesPerFrame, /* stereo output */
PA_SAMPLE_TYPE,
NULL,
SAMPLE_RATE,
- FRAMES_PER_BUFFER, /* frames per buffer */
+ 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,
- dataPtr );
+ &data );
if( err != paNoError ) goto error;
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
{
Pa_Sleep(100);
- printf("index = %d\n", dataPtr->frameIndex );
+ printf("index = %d\n", data.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("Done.\n"); fflush(stdout);
{
- printf("Could not allocate record array.\n");
- exit(1);
+ SAMPLE max = 0;
+ SAMPLE posVal;
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ posVal = data.recordedSamples[i];
+ if( posVal < 0 ) posVal = -posVal;
+ if( posVal > max ) max = posVal;
+ }
+ printf("Largest recorded sample = %d\n", max );
}
- 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++ )
+ /* Write recorded data to a file. */
+#if 0
{
- err = TestRecording( &data );
- if( err != paNoError ) goto error;
-
- err = TestPlayback( &data );
- if( err != paNoError ) goto error;
+ FILE *fid;
+ fid = fopen("recorded.raw", "wb");
+ if( fid == NULL )
+ {
+ printf("Could not open file.");
+ }
+ else
+ {
+ fwrite( data.recordedSamples, data.samplesPerFrame * sizeof(SAMPLE), totalFrames, fid );
+ fclose( fid );
+ printf("Wrote data to 'recorded.raw'\n");
+ }
}
-
+#endif
free( data.recordedSamples );
Pa_Terminate();
return 0;
-
error:
Pa_Terminate();
fprintf( stderr, "An error occured while using the portaudio stream\n" );
+++ /dev/null
-/*
- * $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;
-}
#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
+++ /dev/null
-/*
- * $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;
-}
+++ /dev/null
-/*
- * $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;
-}
/*
* $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>
#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;
float *out = (float*)outputBuffer;
unsigned long i;
int finished = 0;
- double phaseInc = 0.02;
- double phase = data->phase;
-
(void) outTime; /* Prevent unused variable warnings. */
(void) inputBuffer;
-
for( i=0; i<framesPerBuffer; i++ )
{
- phase += phaseInc;
- if( phase > TWOPI ) phase -= TWOPI;
- /* This is not a very efficient way to calc sines. */
- *out++ = (float) sin( phase ); /* mono */
- }
-
- if( data->sleepFor > 0 )
- {
- Pa_Sleep( data->sleepFor );
+ *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->phase = phase;
return finished;
}
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 */
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 );
+++ /dev/null
-/*
- * $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;
-}
#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,
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 );
PortAudioStream *stream;
PaError err;
paTestData data;
+ int i;
int go;
int numBuffers = 0;
int minBuffers = 0;
/* 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. */
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,
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;
}
* $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
*
/*
* $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
#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
#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;
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 );
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;
return finished;
}
-
/*******************************************************************/
int main(void);
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 */
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;
}
/*
* $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
*
#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
{
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().
}
return 0;
}
-
/*******************************************************************/
int main(void);
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 */
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" );
#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().
{
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;
+
+ phaseInc *= 1.02;
+ if( phaseInc > 0.5 ) phaseInc *= 0.5;
- output += LookupSine(data, phase);
+ /* 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;
}
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,
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
-/* Play an increasing number of sine waves until we hit MAX_USAGE */
do
{
data.numSines++;
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;
+++ /dev/null
-/*
- * $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;
-}
/* #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;
{
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;
{
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
for( i=0; i<framesToCalc; i++ )
{
*wptr++ = *rptr++; /* left */
- if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
+ *wptr++ = *rptr++; /* right */
}
}
data->frameIndex += framesToCalc;
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;
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;
for( i=0; i<framesPerBuffer; i++ )
{
*wptr++ = *rptr++; /* left */
- if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
+ *wptr++ = *rptr++; /* right */
}
data->frameIndex += framesPerBuffer;
finished = 0;
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 );
err = Pa_OpenStream(
&stream,
Pa_GetDefaultInputDeviceID(),
- NUM_CHANNELS, /* stereo input */
+ data.samplesPerFrame, /* stereo input */
PA_SAMPLE_TYPE,
NULL,
paNoDevice,
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;
}
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
{
}
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");
}
PA_SAMPLE_TYPE,
NULL,
Pa_GetDefaultOutputDeviceID(),
- NUM_CHANNELS, /* stereo output */
+ data.samplesPerFrame, /* stereo output */
PA_SAMPLE_TYPE,
NULL,
SAMPLE_RATE,
/*
+ * $Id$
* $Id$
* patest_sine.c
* Play a sine wave using the Portable Audio api for several seconds.
#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)
#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)
#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.
(void) outTime; /* Prevent unused variable warnings. */
(void) inputBuffer;
- data->outTime = outTime;
-
if( data->framesToGo < framesPerBuffer )
{
framesToCalc = data->framesToGo;
}
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(
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();
+++ /dev/null
-/*
- * $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;
-}
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. */
{
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 */
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:
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
#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)
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 ???
#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>
#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)
#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
{
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 */
/* 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. */
}
/****************************************** 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
static PaError Pa_QueryDevice( const char *deviceName, internalPortAudioDevice *pad )
{
int result = paHostError;
+ int numBytes;
int tempDevHandle;
int numChannels, maxNumChannels;
int format;
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;
static PaError Pa_QueryDevices( void )
{
internalPortAudioDevice *pad, *lastPad;
+ int numBytes;
int go = 1;
int numDevices = 0;
PaError testResult;
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 )
+/*******************************************************************************************/
+static PaError Pa_AudioThreadProc( internalPortAudioStream *past )
{
- int result = 0;
+ PaError result = 0;
+ PaHostSoundControl *pahsc;
+ short bytes_read = 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) )
+#if 1
{
- 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;
- }
- }
+#define SCHEDULER_POLICY SCHED_RR
- 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)
+ 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)
{
- ERR_RPT(("PaHost_WatchDogProc: failed to lower audio priority. errno = %d\n", errno ));
- /* Fall through into killing audio thread. */
+ perror("sched_setscheduler");
+ printf("PortAudio: only superuser can use real-time priority.\n");
}
else
{
- ERR_RPT(("PaHost_WatchDogProc: lowered audio priority to prevent hogging of CPU.\n"));
- goto cleanup;
+ printf("PortAudio: callback priority set to level %d!\n", schp.sched_priority);
}
}
-
-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;
- PaHostSoundControl *pahsc;
- ssize_t bytes_read, bytes_written;
- count_info info;
- int delta;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paInternalError;
-
-#ifdef GNUSTEP
- GSRegisterCurrentThread(); /* SB20010904 */
-#endif
-
- result = PaHost_BoostPriority( past );
- if( result < 0 ) goto error;
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. */
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;
}
/*******************************************************************************************/
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;
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 )
}
/* 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 );
{
PaError result = paNoError;
PaHostSoundControl *pahsc;
+ int tmp;
+ int flags;
+ int numBytes, maxChannels;
unsigned int minNumBuffers;
internalPortAudioDevice *pad;
DBUG(("PaHost_OpenStream() called.\n" ));
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 *
{
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)
{
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)
{
{
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)
{
* - 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;
}
PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
{
int hres;
+ long timeOut;
PaError result = paNoError;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
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
{
result = paHostError;
sPaHostError = hres;
}
- pahsc->pahsc_AudioThread = INVALID_THREAD;
+ pahsc->pahsc_ThreadPID = -1;
}
past->past_IsActive = 0;
*/
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;
}
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;
}
/***********************************************************************/
/* Modifications
* 7/19/01 Mike Berry - casts for compiling with __MWERKS__ CodeWarrior
* 9/27/01 Phil Burk - use number of frames instead of real-time for CPULoad calculation.
- * 4/19/02 Phil Burk - Check for Win XP for system latency calculation.
*/
/* Compiler flags:
SUPPORT_AUDIO_CAPTURE - define this flag if you want to SUPPORT_AUDIO_CAPTURE
#include "pa_host.h"
#include "pa_trace.h"
#include "dsound_wrapper.h"
-
#define PRINT(x) { printf x; fflush(stdout); }
#define ERR_RPT(x) PRINT(x)
#define DBUG(x) /* PRINT(x) */
#define DBUGX(x) /* PRINT(x) */
-
#define PA_USE_HIGH_LATENCY (0)
#if PA_USE_HIGH_LATENCY
#define PA_WIN_9X_LATENCY (500)
#define PA_WIN_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
#define UNDER_START_GAP (10)
#define UNDER_STOP_GAP (UNDER_START_GAP + 4)
#endif
-
/************************************************* Definitions ********/
typedef struct internalPortAudioStream internalPortAudioStream;
typedef struct internalPortAudioDevice
PaDeviceInfo pad_Info;
}
internalPortAudioDevice;
-
/* Define structure to contain all DirectSound and Windows specific data. */
typedef struct PaHostSoundControl
{
double pahsc_InverseTicksPerUserBuffer;
}
PaHostSoundControl;
-
/************************************************* Shared Data ********/
/* FIXME - put Mutex around this shared data. */
static int sNumDevices = 0;
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 )
{
/* 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 };
(LOWPASS_COEFFICIENT_1 * newUsage);
}
}
-
/****************************************** END CPU UTILIZATION *******/
static PaError Pa_QueryDevices( void )
{
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
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;
}
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
/* Modification History:
PLB = Phil Burk
JM = Julien Maillard
- RDB = Ross Bencina
PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer)
PLB20010413 - check for excessive numbers of channels
PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
including condition including of memory.h,
- and explicit typecasting on memory allocation
+ and explicit typecasting on memory allocation
PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory
PLB20010816 - pass process instead of thread to SetPriorityClass()
PLB20010927 - use number of frames instead of real-time for CPULoad calculation.
JM20020118 - prevent hung thread when buffers underflow.
- PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount
- RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init
- RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices
- refactoring, renaming and fixed a few edge case bugs
*/
#include <stdio.h>
#include "pa_trace.h"
/************************************************* Constants ********/
-#define PA_TRACK_MEMORY (0)
-
#define PA_USE_TIMER_CALLBACK (0) /* Select between two options for background task. 0=thread, 1=timer */
+#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */
/* Switches for debugging. */
#define PA_SIMULATE_UNDERFLOW (0) /* Set to one to force an underflow of the output buffer. */
-
/* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */
#define PA_TRACE_RUN (0)
#define PA_TRACE_START_STOP (1)
-
-#define PA_USE_HIGH_LATENCY (0) /* For debugging glitches. */
-
#if PA_USE_HIGH_LATENCY
#define PA_MIN_MSEC_PER_HOST_BUFFER (100)
#define PA_MAX_MSEC_PER_HOST_BUFFER (300) /* Do not exceed unless user buffer exceeds */
#define PA_WIN_9X_LATENCY (200)
#endif
#define MIN_TIMEOUT_MSEC (1000)
-
/*
** Use higher latency for NT because it is even worse at real-time
** operation than Win9x.
*/
#define PA_WIN_NT_LATENCY (PA_WIN_9X_LATENCY * 2)
-#define PA_WIN_WDM_LATENCY (PA_WIN_9X_LATENCY)
#if PA_SIMULATE_UNDERFLOW
static gUnderCallbackCounter = 0;
#define PRINT(x) { printf x; fflush(stdout); }
#define ERR_RPT(x) PRINT(x)
-#define DBUG(x) /* PRINT(x) /**/
+#define DBUG(x) /* PRINT(x) */
#define DBUGX(x) /* PRINT(x) */
/************************************************* Definitions ********/
/**************************************************************
* Structure for internal host specific stream data.
* This is allocated on a per stream basis.
*/
-typedef struct PaWMMEStreamData
+typedef struct PaHostSoundControl
{
/* Input -------------- */
- HWAVEIN hWaveIn;
- WAVEHDR *inputBuffers;
- int currentInputBuffer;
- int bytesPerHostInputBuffer;
- int bytesPerUserInputBuffer; /* native buffer size in bytes */
+ HWAVEIN pahsc_HWaveIn;
+ WAVEHDR *pahsc_InputBuffers;
+ int pahsc_CurrentInputBuffer;
+ int pahsc_BytesPerHostInputBuffer;
+ int pahsc_BytesPerUserInputBuffer; /* native buffer size in bytes */
/* Output -------------- */
- HWAVEOUT hWaveOut;
- WAVEHDR *outputBuffers;
- int currentOutputBuffer;
- int bytesPerHostOutputBuffer;
- int bytesPerUserOutputBuffer; /* native buffer size in bytes */
+ HWAVEOUT pahsc_HWaveOut;
+ WAVEHDR *pahsc_OutputBuffers;
+ int pahsc_CurrentOutputBuffer;
+ int pahsc_BytesPerHostOutputBuffer;
+ int pahsc_BytesPerUserOutputBuffer; /* native buffer size in bytes */
/* Run Time -------------- */
- PaTimestamp framesPlayed;
- long lastPosition; /* used to track frames played. */
+ PaTimestamp pahsc_FramesPlayed;
+ long pahsc_LastPosition; /* used to track frames played. */
/* For measuring CPU utilization. */
- LARGE_INTEGER entryCount;
- double inverseTicksPerHostBuffer;
+ LARGE_INTEGER pahsc_EntryCount;
+ double pahsc_InverseTicksPerHostBuffer;
/* Init Time -------------- */
- int numHostBuffers;
- int framesPerHostBuffer;
- int userBuffersPerHostBuffer;
- CRITICAL_SECTION streamLock; /* Mutext to prevent threads from colliding. */
- INT streamLockInited;
+ int pahsc_NumHostBuffers;
+ int pahsc_FramesPerHostBuffer;
+ int pahsc_UserBuffersPerHostBuffer;
+ CRITICAL_SECTION pahsc_StreamLock; /* Mutext to prevent threads from colliding. */
+ INT pahsc_StreamLockInited;
#if PA_USE_TIMER_CALLBACK
- BOOL ifInsideCallback; /* Test for reentrancy. */
- MMRESULT timerID;
+ BOOL pahsc_IfInsideCallback; /* Test for reentrancy. */
+ MMRESULT pahsc_TimerID;
#else
- HANDLE abortEvent;
- int abortEventInited;
- HANDLE bufferEvent;
- int bufferEventInited;
- HANDLE engineThread;
- DWORD engineThreadID;
+ HANDLE pahsc_AbortEvent;
+ int pahsc_AbortEventInited;
+ HANDLE pahsc_BufferEvent;
+ int pahsc_BufferEventInited;
+ HANDLE pahsc_EngineThread;
+ DWORD pahsc_EngineThreadID;
#endif
}
-PaWMMEStreamData;
+PaHostSoundControl;
/************************************************* Shared Data ********/
/* FIXME - put Mutex around this shared data. */
static int sNumInputDevices = 0;
static int sPaHostError = 0;
static const char sMapperSuffixInput[] = " - Input";
static const char sMapperSuffixOutput[] = " - Output";
-
-#if PA_TRACK_MEMORY
-static int sNumAllocations = 0;
-#endif
-
/************************************************* Macros ********/
/* Convert external PA ID to an internal ID that includes WAVE_MAPPER */
#define PaDeviceIdToWinId(id) (((id) < sNumInputDevices) ? (id - 1) : (id - sNumInputDevices - 1))
/************************************************* Prototypes **********/
-
-void Pa_InitializeNumDevices( void );
-PaError Pa_AllocateDevicePtrs( void );
-
+static Pa_QueryDevices( void );
static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg,
DWORD dwUser, DWORD dw1, DWORD dw2);
PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past );
-static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData );
+static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc );
static PaError PaHost_BackgroundManager( internalPortAudioStream *past );
-static void *PaHost_AllocateTrackedMemory( long numBytes );
-static void PaHost_FreeTrackedMemory( void *addr );
-
-/*******************************************************************/
-static PaError PaHost_AllocateWMMEStreamData( internalPortAudioStream *stream )
-{
- PaError result = paNoError;
- PaWMMEStreamData *wmmeStreamData;
-
- wmmeStreamData = (PaWMMEStreamData *) PaHost_AllocateFastMemory(sizeof(PaWMMEStreamData)); /* MEM */
- if( wmmeStreamData == NULL )
- {
- result = paInsufficientMemory;
- goto error;
- }
- memset( wmmeStreamData, 0, sizeof(PaWMMEStreamData) );
- stream->past_DeviceData = (void *) wmmeStreamData;
-
- return result;
-
-error:
- return result;
-}
-
-/*******************************************************************/
-static void PaHost_FreeWMMEStreamData( internalPortAudioStream *internalStream )
-{
- PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) internalStream->past_DeviceData;
-
- PaHost_FreeFastMemory( wmmeStreamData, sizeof(PaWMMEStreamData) ); /* MEM */
- internalStream->past_DeviceData = NULL;
-}
-/*************************************************************************/
-static PaWMMEStreamData* PaHost_GetWMMEStreamData( internalPortAudioStream* internalStream )
-{
- PaWMMEStreamData *result = NULL;
-
- if( internalStream != NULL )
- {
- result = (PaWMMEStreamData *) internalStream->past_DeviceData;
- }
- return result;
-}
/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
-/* FIXME: the cpu usage code should be factored out into a common module */
-static void Pa_InitializeCpuUsageScalar( internalPortAudioStream *stream )
+static void Pa_StartUsageCalculation( internalPortAudioStream *past )
{
- PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
-
- LARGE_INTEGER frequency;
- if( QueryPerformanceFrequency( &frequency ) == 0 )
- {
- wmmeStreamData->inverseTicksPerHostBuffer = 0.0;
- }
- else
- {
- wmmeStreamData->inverseTicksPerHostBuffer = stream->past_SampleRate /
- ( (double)frequency.QuadPart * stream->past_FramesPerUserBuffer * wmmeStreamData->userBuffersPerHostBuffer );
- DBUG(("inverseTicksPerHostBuffer = %g\n", wmmeStreamData->inverseTicksPerHostBuffer ));
- }
-}
-static void Pa_StartUsageCalculation( internalPortAudioStream *stream )
-{
- PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
-
- if( wmmeStreamData == NULL ) return;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
/* Query system timer for usage analysis and to prevent overuse of CPU. */
- QueryPerformanceCounter( &wmmeStreamData->entryCount );
+ QueryPerformanceCounter( &pahsc->pahsc_EntryCount );
}
-static void Pa_EndUsageCalculation( internalPortAudioStream *stream )
+static void Pa_EndUsageCalculation( internalPortAudioStream *past )
{
- LARGE_INTEGER CurrentCount;
- PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
-
- if( wmmeStreamData == NULL ) return;
+ LARGE_INTEGER CurrentCount = { 0, 0 };
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
/*
- * Measure CPU utilization during this callback. Note that this calculation
- * assumes that we had the processor the whole time.
- */
+ ** Measure CPU utilization during this callback. Note that this calculation
+ ** assumes that we had the processor the whole time.
+ */
#define LOWPASS_COEFFICIENT_0 (0.9)
#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
if( QueryPerformanceCounter( &CurrentCount ) )
{
- LONGLONG InsideCount = CurrentCount.QuadPart - wmmeStreamData->entryCount.QuadPart;
- double newUsage = InsideCount * wmmeStreamData->inverseTicksPerHostBuffer;
- stream->past_Usage = (LOWPASS_COEFFICIENT_0 * stream->past_Usage) +
- (LOWPASS_COEFFICIENT_1 * newUsage);
+ LONGLONG InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart;
+ double newUsage = InsideCount * pahsc->pahsc_InverseTicksPerHostBuffer;
+ past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
+ (LOWPASS_COEFFICIENT_1 * newUsage);
}
}
/****************************************** END CPU UTILIZATION *******/
-static void Pa_InitializeNumDevices( void )
-{
- sNumInputDevices = waveInGetNumDevs();
- if( sNumInputDevices > 0 )
- {
- sNumInputDevices += 1; /* add one extra for the WAVE_MAPPER */
- sDefaultInputDeviceID = 0;
- }
- else
- {
- sDefaultInputDeviceID = paNoDevice;
- }
-
- sNumOutputDevices = waveOutGetNumDevs();
- if( sNumOutputDevices > 0 )
- {
- sNumOutputDevices += 1; /* add one extra for the WAVE_MAPPER */
- sDefaultOutputDeviceID = sNumInputDevices;
- }
- else
- {
- sDefaultOutputDeviceID = paNoDevice;
- }
-
- sNumDevices = sNumInputDevices + sNumOutputDevices;
-}
-
-static PaError Pa_AllocateDevicePtrs( void )
+static PaError Pa_QueryDevices( void )
{
int numBytes;
- int i;
-
+ /* Count the devices and add one extra for the WAVE_MAPPER */
+ sNumInputDevices = waveInGetNumDevs() + 1;
+ sDefaultInputDeviceID = 0;
+ sNumOutputDevices = waveOutGetNumDevs() + 1;
+ sDefaultOutputDeviceID = sNumInputDevices;
+ sNumDevices = sNumInputDevices + sNumOutputDevices;
/* Allocate structures to hold device info. */
/* PLB20010402 - was allocating too much memory. */
/* numBytes = sNumDevices * sizeof(PaDeviceInfo); // PLB20010402 */
-
- if( sNumDevices > 0 )
- {
- numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */
- sDevicePtrs = (PaDeviceInfo **) PaHost_AllocateTrackedMemory( numBytes ); /* MEM */
- if( sDevicePtrs == NULL ) return paInsufficientMemory;
-
- for( i = 0; i < sNumDevices; i++ )
- sDevicePtrs[i] = NULL; /* RDB20020417 explicitly set each ptr to NULL */
- }
- else
- {
- sDevicePtrs = NULL;
- }
-
+ numBytes = sNumDevices * sizeof(PaDeviceInfo *); /* PLB20010402 */
+ sDevicePtrs = (PaDeviceInfo **) GlobalAlloc( GPTR, numBytes ); /* MEM */
+ if( sDevicePtrs == NULL ) return paInsufficientMemory;
return paNoError;
}
-/*************************************************************************/
+/************************************************************************************/
long Pa_GetHostError()
{
return sPaHostError;
/*************************************************************************/
int Pa_CountDevices()
{
- if( PaHost_IsInitialized() )
- return sNumDevices;
- else
- return 0;
+ if( sNumDevices <= 0 ) Pa_Initialize();
+ return sNumDevices;
}
/*************************************************************************
- * If a PaDeviceInfo structure has not already been created,
- * then allocate one and fill it in for the selected device.
- *
- * We create one extra input and one extra output device for the WAVE_MAPPER.
- * [Does anyone know how to query the default device and get its name?]
- */
+** If a PaDeviceInfo structure has not already been created,
+** then allocate one and fill it in for the selected device.
+**
+** We create one extra input and one extra output device for the WAVE_MAPPER.
+** [Does anyone know how to query the default device and get its name?]
+*/
const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
{
#define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */
{
return sDevicePtrs[ id ];
}
- deviceInfo = (PaDeviceInfo *)PaHost_AllocateTrackedMemory( sizeof(PaDeviceInfo) ); /* MEM */
+ deviceInfo = (PaDeviceInfo *)GlobalAlloc( GPTR, sizeof(PaDeviceInfo) ); /* MEM */
if( deviceInfo == NULL ) return NULL;
deviceInfo->structVersion = 1;
deviceInfo->maxInputChannels = 0;
deviceInfo->maxOutputChannels = 0;
deviceInfo->numSampleRates = 0;
- sampleRates = (double*)PaHost_AllocateTrackedMemory( MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */
+ sampleRates = (double*)GlobalAlloc( GPTR, MAX_NUMSAMPLINGRATES * sizeof(double) ); /* MEM */
deviceInfo->sampleRates = sampleRates;
deviceInfo->nativeSampleFormats = paInt16; /* should query for higher bit depths below */
if( id < sNumInputDevices )
{
/* input device */
- int inputMmID = PaDeviceIdToWinId(id);
+ int inputMmID = id - 1; /* WAVE_MAPPER is -1 so we start with WAVE_MAPPER */
WAVEINCAPS wic;
if( waveInGetDevCaps( inputMmID, &wic, sizeof( WAVEINCAPS ) ) != MMSYSERR_NOERROR )
goto error;
/* Append I/O suffix to WAVE_MAPPER device. */
if( inputMmID == WAVE_MAPPER )
{
- s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */
+ s = (char *) GlobalAlloc( GMEM_FIXED, strlen( wic.szPname ) + 1 + sizeof(sMapperSuffixInput) ); /* MEM */
strcpy( s, wic.szPname );
strcat( s, sMapperSuffixInput );
}
else
{
- s = (char *) PaHost_AllocateTrackedMemory( strlen( wic.szPname ) + 1 ); /* MEM */
+ s = (char *) GlobalAlloc( GMEM_FIXED, strlen( wic.szPname ) + 1 ); /* MEM */
strcpy( s, wic.szPname );
}
deviceInfo->name = s;
deviceInfo->maxInputChannels = wic.wChannels;
/* Sometimes a device can return a rediculously large number of channels.
- * This happened with an SBLive card on a Windows ME box.
- * If that happens, then force it to 2 channels. PLB20010413
- */
+ ** This happened with an SBLive card on a Windows ME box.
+ ** If that happens, then force it to 2 channels. PLB20010413
+ */
if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) )
{
ERR_RPT(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels ));
else if( id - sNumInputDevices < sNumOutputDevices )
{
/* output device */
- int outputMmID = PaDeviceIdToWinId(id);
+ int outputMmID = id - sNumInputDevices - 1;
WAVEOUTCAPS woc;
if( waveOutGetDevCaps( outputMmID, &woc, sizeof( WAVEOUTCAPS ) ) != MMSYSERR_NOERROR )
goto error;
/* Append I/O suffix to WAVE_MAPPER device. */
if( outputMmID == WAVE_MAPPER )
{
- s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) ); /* MEM */
+ s = (char *) GlobalAlloc( GMEM_FIXED, strlen( woc.szPname ) + 1 + sizeof(sMapperSuffixOutput) ); /* MEM */
strcpy( s, woc.szPname );
strcat( s, sMapperSuffixOutput );
}
else
{
- s = (char *) PaHost_AllocateTrackedMemory( strlen( woc.szPname ) + 1 ); /* MEM */
+ s = (char *) GlobalAlloc( GMEM_FIXED, strlen( woc.szPname ) + 1 ); /* MEM */
strcpy( s, woc.szPname );
}
deviceInfo->name = s;
deviceInfo->maxOutputChannels = woc.wChannels;
/* Sometimes a device can return a rediculously large number of channels.
- * This happened with an SBLive card on a Windows ME box.
- * It also happens on Win XP!
- */
+ ** This happened with an SBLive card on a Windows ME box.
+ ** If that happens, then force it to 2 channels. PLB20010413
+ */
if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) )
{
-#if 1
+ ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels ));
deviceInfo->maxOutputChannels = 2;
-#else
- /* If channel max is goofy, then query for max channels. PLB20020228
- * This doesn't seem to help. Disable code for now. Remove it later.
- */
- ERR_RPT(("Pa_GetDeviceInfo: Num output channels reported as %d!", deviceInfo->maxOutputChannels ));
- deviceInfo->maxOutputChannels = 0;
- /* Attempt to find the correct maximum by querying the device. */
- for( i=2; i<16; i += 2 )
- {
- WAVEFORMATEX wfx;
- wfx.wFormatTag = WAVE_FORMAT_PCM;
- wfx.nSamplesPerSec = 44100;
- wfx.wBitsPerSample = 16;
- wfx.cbSize = 0; /* ignored */
- wfx.nChannels = (WORD) i;
- wfx.nAvgBytesPerSec = wfx.nChannels * wfx.nSamplesPerSec * sizeof(short);
- wfx.nBlockAlign = (WORD)(wfx.nChannels * sizeof(short));
- if( waveOutOpen( NULL, outputMmID, &wfx, 0, 0, WAVE_FORMAT_QUERY ) == MMSYSERR_NOERROR )
- {
- deviceInfo->maxOutputChannels = i;
- }
- else
- {
- break;
- }
- }
-#endif
- ERR_RPT((" Changed to %d.\n", deviceInfo->maxOutputChannels ));
}
-
/* Add a sample rate to the list if we can do stereo 16 bit at that rate
* based on the format flags. */
if( woc.dwFormats & WAVE_FORMAT_1M16 ||woc.dwFormats & WAVE_FORMAT_1S16 )
sampleRates[ deviceInfo->numSampleRates++ ] = 22050.;
if( woc.dwFormats & WAVE_FORMAT_4M16 ||woc.dwFormats & WAVE_FORMAT_4S16 )
sampleRates[ deviceInfo->numSampleRates++ ] = 44100.;
-
/* Add a sample rate to the list if we can do stereo 16 bit at that rate
* based on opening the device successfully. */
for( i=0; i < NUM_CUSTOMSAMPLINGRATES; i++ )
}
sDevicePtrs[ id ] = deviceInfo;
return deviceInfo;
-
error:
- PaHost_FreeTrackedMemory( sampleRates ); /* MEM */
- PaHost_FreeTrackedMemory( deviceInfo ); /* MEM */
+ GlobalFree( sampleRates ); /* MEM */
+ GlobalFree( deviceInfo ); /* MEM */
return NULL;
}
/*************************************************************************
- * Returns recommended device ID.
- * On the PC, the recommended device can be specified by the user by
- * setting an environment variable. For example, to use device #1.
- *
- * set PA_RECOMMENDED_OUTPUT_DEVICE=1
- *
- * The user should first determine the available device ID by using
- * the supplied application "pa_devs".
- */
+** Returns recommended device ID.
+** On the PC, the recommended device can be specified by the user by
+** setting an environment variable. For example, to use device #1.
+**
+** set PA_RECOMMENDED_OUTPUT_DEVICE=1
+**
+** The user should first determine the available device ID by using
+** the supplied application "pa_devs".
+*/
#define PA_ENV_BUF_SIZE (32)
#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE")
#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE")
DWORD hresult;
char envbuf[PA_ENV_BUF_SIZE];
PaDeviceID recommendedID = paNoDevice;
-
/* Let user determine default device by setting environment variable. */
hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE );
if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
}
return recommendedID;
}
+static PaError Pa_MaybeQueryDevices( void )
+{
+ if( sNumDevices == 0 )
+ {
+ return Pa_QueryDevices();
+ }
+ return 0;
+}
/**********************************************************************
- * Check for environment variable, else query devices and use result.
- */
+** Check for environment variable, else query devices and use result.
+*/
PaDeviceID Pa_GetDefaultInputDeviceID( void )
{
- PaDeviceID result;
-
+ PaError result;
result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME );
- if( result == paNoDevice || result < 0 || result >= sNumInputDevices )
+ if( result < 0 )
{
+ result = Pa_MaybeQueryDevices();
+ if( result < 0 ) return result;
result = sDefaultInputDeviceID;
}
return result;
}
PaDeviceID Pa_GetDefaultOutputDeviceID( void )
{
- PaDeviceID result;
-
+ PaError result;
result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME );
- if( result == paNoDevice || result < sNumInputDevices || result >= sNumDevices )
+ if( result < 0 )
{
+ result = Pa_MaybeQueryDevices();
+ if( result < 0 ) return result;
result = sDefaultOutputDeviceID;
}
return result;
}
/**********************************************************************
- * Initialize Host dependant part of API.
- */
+** Initialize Host dependant part of API.
+*/
PaError PaHost_Init( void )
{
-
-#if PA_TRACK_MEMORY
- PRINT(("PaHost_Init: sNumAllocations = %d\n", sNumAllocations ));
-#endif
-
#if PA_SIMULATE_UNDERFLOW
PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n"));
#endif
-
-
- Pa_InitializeNumDevices();
-
- return Pa_AllocateDevicePtrs();
+ return Pa_MaybeQueryDevices();
}
/**********************************************************************
- * Check WAVE buffers to see if they are done.
- * Fill any available output buffers and use any available
- * input buffers by calling user callback.
- *
- * This routine will loop until:
- * user callback returns !=0 OR
- * all output buffers are filled OR
- * past->past_StopSoon is set OR
- * an error occurs when calling WMME.
- *
- * Returns >0 when user requests a stop, <0 on error.
- *
- */
-static PaError Pa_TimeSlice( internalPortAudioStream *stream )
+** Check WAVE buffers to see if they are done.
+** Fill any available output buffers and use any available
+** input buffers by calling user callback.
+**
+** This routine will loop until:
+** user callback returns !=0 OR
+** all output buffers are filled OR
+** past->past_StopSoon is set OR
+** an error occurs when calling WMME.
+**
+** Returns >0 when user requests a stop, <0 on error.
+**
+*/
+static PaError Pa_TimeSlice( internalPortAudioStream *past )
{
- PaError result = paNoError;
- MMRESULT mmresult;
+ PaError result = 0;
+ long bytesEmpty = 0;
+ long bytesFilled = 0;
+ long buffersEmpty = 0;
+ MMRESULT mresult;
char *inBufPtr;
char *outBufPtr;
int gotInput = 0;
int i;
int buffersProcessed = 0;
int done = 0;
- PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
-
- if( wmmeStreamData == NULL ) return paInternalError;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
- stream->past_NumCallbacks += 1;
+ past->past_NumCallbacks += 1;
#if PA_TRACE_RUN
- AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", stream->past_NumCallbacks );
+ AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks );
#endif
/* JM20020118 - prevent hung thread when buffers underflow. */
/* while( !done ) /* BAD */
- while( !done && !stream->past_StopSoon ) /* GOOD */
+ while( !done && !past->past_StopSoon ) /* GOOD */
{
#if PA_SIMULATE_UNDERFLOW
if(gUnderCallbackCounter++ == UNDER_SLEEP_AT)
/* If we are using output, then we need an empty output buffer. */
gotOutput = 0;
outBufPtr = NULL;
- if( stream->past_NumOutputChannels > 0 )
+ if( past->past_NumOutputChannels > 0 )
{
- if((wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].dwFlags & WHDR_DONE) == 0)
+ if((pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ].dwFlags & WHDR_DONE) == 0)
{
break; /* If none empty then bail and try again later. */
}
else
{
- outBufPtr = wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ].lpData;
+ outBufPtr = pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ].lpData;
gotOutput = 1;
}
}
/* Use an input buffer if one is available. */
gotInput = 0;
inBufPtr = NULL;
- if( ( stream->past_NumInputChannels > 0 ) &&
- (wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].dwFlags & WHDR_DONE) )
+ if( ( past->past_NumInputChannels > 0 ) &&
+ (pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ].dwFlags & WHDR_DONE) )
{
- inBufPtr = wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ].lpData;
+ inBufPtr = pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ].lpData;
gotInput = 1;
#if PA_TRACE_RUN
AddTraceMessage("Pa_TimeSlice: got input buffer at ", (int)inBufPtr );
- AddTraceMessage("Pa_TimeSlice: got input buffer # ", wmmeStreamData->currentInputBuffer );
+ AddTraceMessage("Pa_TimeSlice: got input buffer # ", pahsc->pahsc_CurrentInputBuffer );
#endif
}
buffersProcessed += 1;
/* Each Wave buffer contains multiple user buffers so do them all now. */
/* Base Usage on time it took to process one host buffer. */
- Pa_StartUsageCalculation( stream );
- for( i=0; i<wmmeStreamData->userBuffersPerHostBuffer; i++ )
+ Pa_StartUsageCalculation( past );
+ for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
{
if( done )
{
{
/* Clear remainder of wave buffer if we are waiting for stop. */
AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i );
- memset( outBufPtr, 0, wmmeStreamData->bytesPerUserOutputBuffer );
+ memset( outBufPtr, 0, pahsc->pahsc_BytesPerUserOutputBuffer );
}
}
else
{
/* Convert 16 bit native data to user data and call user routine. */
- result = Pa_CallConvertInt16( stream, (short *) inBufPtr, (short *) outBufPtr );
+ result = Pa_CallConvertInt16( past, (short *) inBufPtr, (short *) outBufPtr );
if( result != 0) done = 1;
}
- if( gotInput ) inBufPtr += wmmeStreamData->bytesPerUserInputBuffer;
- if( gotOutput) outBufPtr += wmmeStreamData->bytesPerUserOutputBuffer;
+ if( gotInput ) inBufPtr += pahsc->pahsc_BytesPerUserInputBuffer;
+ if( gotOutput) outBufPtr += pahsc->pahsc_BytesPerUserOutputBuffer;
}
- Pa_EndUsageCalculation( stream );
+ Pa_EndUsageCalculation( past );
/* Send WAVE buffer to Wave Device to be refilled. */
if( gotInput )
{
- mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn,
- &wmmeStreamData->inputBuffers[ wmmeStreamData->currentInputBuffer ],
+ mresult = waveInAddBuffer( pahsc->pahsc_HWaveIn,
+ &pahsc->pahsc_InputBuffers[ pahsc->pahsc_CurrentInputBuffer ],
sizeof(WAVEHDR) );
- if( mmresult != MMSYSERR_NOERROR )
+ if( mresult != MMSYSERR_NOERROR )
{
- sPaHostError = mmresult;
+ sPaHostError = mresult;
result = paHostError;
break;
}
- wmmeStreamData->currentInputBuffer = (wmmeStreamData->currentInputBuffer+1 >= wmmeStreamData->numHostBuffers) ?
- 0 : wmmeStreamData->currentInputBuffer+1;
+ pahsc->pahsc_CurrentInputBuffer = (pahsc->pahsc_CurrentInputBuffer+1 >= pahsc->pahsc_NumHostBuffers) ?
+ 0 : pahsc->pahsc_CurrentInputBuffer+1;
}
/* Write WAVE buffer to Wave Device. */
if( gotOutput )
{
#if PA_TRACE_START_STOP
- AddTraceMessage( "Pa_TimeSlice: writing buffer ", wmmeStreamData->currentOutputBuffer );
+ AddTraceMessage( "Pa_TimeSlice: writing buffer ", pahsc->pahsc_CurrentOutputBuffer );
#endif
- mmresult = waveOutWrite( wmmeStreamData->hWaveOut,
- &wmmeStreamData->outputBuffers[ wmmeStreamData->currentOutputBuffer ],
+ mresult = waveOutWrite( pahsc->pahsc_HWaveOut,
+ &pahsc->pahsc_OutputBuffers[ pahsc->pahsc_CurrentOutputBuffer ],
sizeof(WAVEHDR) );
- if( mmresult != MMSYSERR_NOERROR )
+ if( mresult != MMSYSERR_NOERROR )
{
- sPaHostError = mmresult;
+ sPaHostError = mresult;
result = paHostError;
break;
}
- wmmeStreamData->currentOutputBuffer = (wmmeStreamData->currentOutputBuffer+1 >= wmmeStreamData->numHostBuffers) ?
- 0 : wmmeStreamData->currentOutputBuffer+1;
+ pahsc->pahsc_CurrentOutputBuffer = (pahsc->pahsc_CurrentOutputBuffer+1 >= pahsc->pahsc_NumHostBuffers) ?
+ 0 : pahsc->pahsc_CurrentOutputBuffer+1;
}
}
}
/*******************************************************************/
-static PaError PaHost_BackgroundManager( internalPortAudioStream *stream )
+static PaError PaHost_BackgroundManager( internalPortAudioStream *past )
{
- PaError result = paNoError;
+ PaError result = 0;
int i;
- int numQueuedoutputBuffers = 0;
- PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
+ int numQueuedOutputBuffers = 0;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
/* Has someone asked us to abort by calling Pa_AbortStream()? */
- if( stream->past_StopNow )
+ if( past->past_StopNow )
{
- stream->past_IsActive = 0; /* Will cause thread to return. */
+ past->past_IsActive = 0; /* Will cause thread to return. */
}
/* Has someone asked us to stop by calling Pa_StopStream()
* OR has a user callback returned '1' to indicate finished.
*/
- else if( stream->past_StopSoon )
+ else if( past->past_StopSoon )
{
/* Poll buffer and when all have played then exit thread. */
/* Count how many output buffers are queued. */
- numQueuedoutputBuffers = 0;
- if( stream->past_NumOutputChannels > 0 )
+ numQueuedOutputBuffers = 0;
+ if( past->past_NumOutputChannels > 0 )
{
- for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
+ for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
- if( !( wmmeStreamData->outputBuffers[ i ].dwFlags & WHDR_DONE) )
+ if( !( pahsc->pahsc_OutputBuffers[ i ].dwFlags & WHDR_DONE) )
{
#if PA_TRACE_START_STOP
- AddTraceMessage( "PaHost_BackgroundManager: waiting for buffer ", i );
+ AddTraceMessage( "WinMMPa_OutputThreadProc: waiting for buffer ", i );
#endif
- numQueuedoutputBuffers++;
+ numQueuedOutputBuffers++;
}
}
}
#if PA_TRACE_START_STOP
- AddTraceMessage( "PaHost_BackgroundManager: numQueuedoutputBuffers ", numQueuedoutputBuffers );
+ AddTraceMessage( "WinMMPa_OutputThreadProc: numQueuedOutputBuffers ", numQueuedOutputBuffers );
#endif
- if( numQueuedoutputBuffers == 0 )
+ if( numQueuedOutputBuffers == 0 )
{
- stream->past_IsActive = 0; /* Will cause thread to return. */
+ past->past_IsActive = 0; /* Will cause thread to return. */
}
}
else
{
/* Process full input buffer and fill up empty output buffers. */
- if( (result = Pa_TimeSlice( stream )) != 0)
+ if( (result = Pa_TimeSlice( past )) != 0)
{
/* User callback has asked us to stop. */
#if PA_TRACE_START_STOP
- AddTraceMessage( "PaHost_BackgroundManager: TimeSlice() returned ", result );
+ AddTraceMessage( "WinMMPa_OutputThreadProc: TimeSlice() returned ", result );
#endif
- stream->past_StopSoon = 1; /* Request that audio play out then stop. */
+ past->past_StopSoon = 1; /* Request that audio play out then stop. */
result = paNoError;
}
}
- PaHost_UpdateStreamTime( wmmeStreamData );
+ PaHost_UpdateStreamTime( pahsc );
return result;
}
/*******************************************************************/
static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
- internalPortAudioStream *stream;
- PaWMMEStreamData *wmmeStreamData;
+ internalPortAudioStream *past;
+ PaHostSoundControl *pahsc;
PaError result;
-
- stream = (internalPortAudioStream *) dwUser;
- if( stream == NULL ) return;
- wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
- if( wmmeStreamData == NULL ) return;
- if( wmmeStreamData->ifInsideCallback )
+ past = (internalPortAudioStream *) dwUser;
+ if( past == NULL ) return;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+ if( pahsc->pahsc_IfInsideCallback )
{
- if( wmmeStreamData->timerID != 0 )
+ if( pahsc->pahsc_TimerID != 0 )
{
- timeKillEvent(wmmeStreamData->timerID); /* Stop callback timer. */
- wmmeStreamData->timerID = 0;
+ timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */
+ pahsc->pahsc_TimerID = 0;
}
return;
}
- wmmeStreamData->ifInsideCallback = 1;
+ pahsc->pahsc_IfInsideCallback = 1;
/* Manage flags and audio processing. */
- result = PaHost_BackgroundManager( stream );
+ result = PaHost_BackgroundManager( past );
if( result != paNoError )
{
- stream->past_IsActive = 0;
+ past->past_IsActive = 0;
}
- wmmeStreamData->ifInsideCallback = 0;
+ pahsc->pahsc_IfInsideCallback = 0;
}
#else /* PA_USE_TIMER_CALLBACK */
/*******************************************************************/
static DWORD WINAPI WinMMPa_OutputThreadProc( void *pArg )
{
- internalPortAudioStream *stream;
- PaWMMEStreamData *wmmeStreamData;
+ internalPortAudioStream *past;
+ PaHostSoundControl *pahsc;
+ void *inputBuffer=NULL;
HANDLE events[2];
int numEvents = 0;
DWORD result = 0;
DWORD waitResult;
DWORD numTimeouts = 0;
DWORD timeOut;
- stream = (internalPortAudioStream *) pArg;
- wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
+ past = (internalPortAudioStream *) pArg;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
#if PA_TRACE_START_STOP
AddTraceMessage( "WinMMPa_OutputThreadProc: timeoutPeriod", timeoutPeriod );
- AddTraceMessage( "WinMMPa_OutputThreadProc: past_NumUserBuffers", stream->past_NumUserBuffers );
+ AddTraceMessage( "WinMMPa_OutputThreadProc: past_NumUserBuffers", past->past_NumUserBuffers );
#endif
/* Calculate timeOut as half the time it would take to play all buffers. */
- timeOut = (DWORD) (500.0 * PaHost_GetTotalBufferFrames( stream ) / stream->past_SampleRate);
+ timeOut = (DWORD) (500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate);
/* Get event(s) ready for wait. */
- events[numEvents++] = wmmeStreamData->bufferEvent;
- if( wmmeStreamData->abortEventInited ) events[numEvents++] = wmmeStreamData->abortEvent;
+ events[numEvents++] = pahsc->pahsc_BufferEvent;
+ if( pahsc->pahsc_AbortEventInited ) events[numEvents++] = pahsc->pahsc_AbortEvent;
/* Stay in this thread as long as we are "active". */
- while( stream->past_IsActive )
+ while( past->past_IsActive )
{
/*******************************************************************/
/******** WAIT here for an event from WMME or PA *******************/
{
sPaHostError = GetLastError();
result = paHostError;
- stream->past_IsActive = 0;
+ past->past_IsActive = 0;
}
/* Timeout? Don't stop. Just keep polling for DONE.*/
else if( waitResult == WAIT_TIMEOUT )
{
#if PA_TRACE_START_STOP
- AddTraceMessage( "WinMMPa_OutputThreadProc: timed out ", numQueuedoutputBuffers );
+ AddTraceMessage( "WinMMPa_OutputThreadProc: timed out ", numQueuedOutputBuffers );
#endif
numTimeouts += 1;
}
/* Manage flags and audio processing. */
- result = PaHost_BackgroundManager( stream );
+ result = PaHost_BackgroundManager( past );
if( result != paNoError )
{
- stream->past_IsActive = 0;
+ past->past_IsActive = 0;
}
}
return result;
#endif
/*******************************************************************/
-PaError PaHost_OpenInputStream( internalPortAudioStream *stream )
+PaError PaHost_OpenInputStream( internalPortAudioStream *past )
{
+ MMRESULT mr;
PaError result = paNoError;
- MMRESULT mmresult;
- PaWMMEStreamData *wmmeStreamData;
+ PaHostSoundControl *pahsc;
int i;
int inputMmId;
int bytesPerInputFrame;
WAVEFORMATEX wfx;
- const PaDeviceInfo *deviceInfo;
-
- wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
- DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_InputDeviceID));
- deviceInfo = Pa_GetDeviceInfo( stream->past_InputDeviceID );
- if( deviceInfo == NULL ) return paInternalError;
-
- switch( deviceInfo->nativeSampleFormats )
+ const PaDeviceInfo *pad;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID));
+ pad = Pa_GetDeviceInfo( past->past_InputDeviceID );
+ if( pad == NULL ) return paInternalError;
+ switch( pad->nativeSampleFormats )
{
case paInt32:
case paFloat32:
- bytesPerInputFrame = sizeof(float) * stream->past_NumInputChannels;
+ bytesPerInputFrame = sizeof(float) * past->past_NumInputChannels;
break;
default:
- bytesPerInputFrame = sizeof(short) * stream->past_NumInputChannels;
+ bytesPerInputFrame = sizeof(short) * past->past_NumInputChannels;
break;
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
- wfx.nChannels = (WORD) stream->past_NumInputChannels;
- wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate;
- wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * stream->past_SampleRate);
+ wfx.nChannels = (WORD) past->past_NumInputChannels;
+ wfx.nSamplesPerSec = (DWORD) past->past_SampleRate;
+ wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * past->past_SampleRate);
wfx.nBlockAlign = (WORD)bytesPerInputFrame;
- wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/stream->past_NumInputChannels) * 8);
+ wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/past->past_NumInputChannels) * 8);
wfx.cbSize = 0;
- inputMmId = PaDeviceIdToWinId( stream->past_InputDeviceID );
+ inputMmId = PaDeviceIdToWinId( past->past_InputDeviceID );
#if PA_USE_TIMER_CALLBACK
- mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx,
+ mr = waveInOpen( &pahsc->pahsc_HWaveIn, inputMmId, &wfx,
0, 0, CALLBACK_NULL );
#else
- mmresult = waveInOpen( &wmmeStreamData->hWaveIn, inputMmId, &wfx,
- (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT );
+ mr = waveInOpen( &pahsc->pahsc_HWaveIn, inputMmId, &wfx,
+ (DWORD)pahsc->pahsc_BufferEvent, (DWORD) past, CALLBACK_EVENT );
#endif
- if( mmresult != MMSYSERR_NOERROR )
+ if( mr != MMSYSERR_NOERROR )
{
ERR_RPT(("PortAudio: PaHost_OpenInputStream() failed!\n"));
result = paHostError;
- sPaHostError = mmresult;
+ sPaHostError = mr;
goto error;
}
/* Allocate an array to hold the buffer pointers. */
- wmmeStreamData->inputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */
- if( wmmeStreamData->inputBuffers == NULL )
+ pahsc->pahsc_InputBuffers = (WAVEHDR *) GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */
+ if( pahsc->pahsc_InputBuffers == NULL )
{
result = paInsufficientMemory;
goto error;
}
/* Allocate each buffer. */
- for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
+ for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
- wmmeStreamData->inputBuffers[i].lpData = (char *)PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostInputBuffer ); /* MEM */
- if( wmmeStreamData->inputBuffers[i].lpData == NULL )
+ pahsc->pahsc_InputBuffers[i].lpData = (char *)GlobalAlloc( GMEM_FIXED, pahsc->pahsc_BytesPerHostInputBuffer ); /* MEM */
+ if( pahsc->pahsc_InputBuffers[i].lpData == NULL )
{
result = paInsufficientMemory;
goto error;
}
- wmmeStreamData->inputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostInputBuffer;
- wmmeStreamData->inputBuffers[i].dwUser = i;
- if( ( mmresult = waveInPrepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR )
+ pahsc->pahsc_InputBuffers[i].dwBufferLength = pahsc->pahsc_BytesPerHostInputBuffer;
+ pahsc->pahsc_InputBuffers[i].dwUser = i;
+ if( ( mr = waveInPrepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR )
{
result = paHostError;
- sPaHostError = mmresult;
+ sPaHostError = mr;
goto error;
}
}
return result;
-
error:
return result;
}
/*******************************************************************/
-PaError PaHost_OpenOutputStream( internalPortAudioStream *stream )
+PaError PaHost_OpenOutputStream( internalPortAudioStream *past )
{
+ MMRESULT mr;
PaError result = paNoError;
- MMRESULT mmresult;
- PaWMMEStreamData *wmmeStreamData;
+ PaHostSoundControl *pahsc;
int i;
int outputMmID;
int bytesPerOutputFrame;
WAVEFORMATEX wfx;
- const PaDeviceInfo *deviceInfo;
-
- wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
- DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", stream->past_OutputDeviceID));
-
- deviceInfo = Pa_GetDeviceInfo( stream->past_OutputDeviceID );
- if( deviceInfo == NULL ) return paInternalError;
-
- switch( deviceInfo->nativeSampleFormats )
+ const PaDeviceInfo *pad;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID));
+ pad = Pa_GetDeviceInfo( past->past_OutputDeviceID );
+ if( pad == NULL ) return paInternalError;
+ switch( pad->nativeSampleFormats )
{
case paInt32:
case paFloat32:
- bytesPerOutputFrame = sizeof(float) * stream->past_NumOutputChannels;
+ bytesPerOutputFrame = sizeof(float) * past->past_NumOutputChannels;
break;
default:
- bytesPerOutputFrame = sizeof(short) * stream->past_NumOutputChannels;
+ bytesPerOutputFrame = sizeof(short) * past->past_NumOutputChannels;
break;
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
- wfx.nChannels = (WORD) stream->past_NumOutputChannels;
- wfx.nSamplesPerSec = (DWORD) stream->past_SampleRate;
- wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * stream->past_SampleRate);
+ wfx.nChannels = (WORD) past->past_NumOutputChannels;
+ wfx.nSamplesPerSec = (DWORD) past->past_SampleRate;
+ wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * past->past_SampleRate);
wfx.nBlockAlign = (WORD)bytesPerOutputFrame;
- wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/stream->past_NumOutputChannels) * 8);
+ wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/past->past_NumOutputChannels) * 8);
wfx.cbSize = 0;
- outputMmID = PaDeviceIdToWinId( stream->past_OutputDeviceID );
+ outputMmID = PaDeviceIdToWinId( past->past_OutputDeviceID );
#if PA_USE_TIMER_CALLBACK
- mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx,
+ mr = waveOutOpen( &pahsc->pahsc_HWaveOut, outputMmID, &wfx,
0, 0, CALLBACK_NULL );
#else
- wmmeStreamData->abortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
- if( wmmeStreamData->abortEvent == NULL )
+ pahsc->pahsc_AbortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ if( pahsc->pahsc_AbortEvent == NULL )
{
result = paHostError;
sPaHostError = GetLastError();
goto error;
}
- wmmeStreamData->abortEventInited = 1;
- mmresult = waveOutOpen( &wmmeStreamData->hWaveOut, outputMmID, &wfx,
- (DWORD)wmmeStreamData->bufferEvent, (DWORD) stream, CALLBACK_EVENT );
+ pahsc->pahsc_AbortEventInited = 1;
+ mr = waveOutOpen( &pahsc->pahsc_HWaveOut, outputMmID, &wfx,
+ (DWORD)pahsc->pahsc_BufferEvent, (DWORD) past, CALLBACK_EVENT );
#endif
- if( mmresult != MMSYSERR_NOERROR )
+ if( mr != MMSYSERR_NOERROR )
{
ERR_RPT(("PortAudio: PaHost_OpenOutputStream() failed!\n"));
result = paHostError;
- sPaHostError = mmresult;
+ sPaHostError = mr;
goto error;
}
/* Allocate an array to hold the buffer pointers. */
- wmmeStreamData->outputBuffers = (WAVEHDR *) PaHost_AllocateTrackedMemory( sizeof(WAVEHDR)*wmmeStreamData->numHostBuffers ); /* MEM */
- if( wmmeStreamData->outputBuffers == NULL )
+ pahsc->pahsc_OutputBuffers = (WAVEHDR *) GlobalAlloc( GMEM_FIXED | GMEM_ZEROINIT, sizeof(WAVEHDR)*pahsc->pahsc_NumHostBuffers ); /* MEM */
+ if( pahsc->pahsc_OutputBuffers == NULL )
{
result = paInsufficientMemory;
goto error;
}
/* Allocate each buffer. */
- for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
+ for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
- wmmeStreamData->outputBuffers[i].lpData = (char *) PaHost_AllocateTrackedMemory( wmmeStreamData->bytesPerHostOutputBuffer ); /* MEM */
- if( wmmeStreamData->outputBuffers[i].lpData == NULL )
+ pahsc->pahsc_OutputBuffers[i].lpData = (char *) GlobalAlloc( GMEM_FIXED, pahsc->pahsc_BytesPerHostOutputBuffer ); /* MEM */
+ if( pahsc->pahsc_OutputBuffers[i].lpData == NULL )
{
result = paInsufficientMemory;
goto error;
}
- wmmeStreamData->outputBuffers[i].dwBufferLength = wmmeStreamData->bytesPerHostOutputBuffer;
- wmmeStreamData->outputBuffers[i].dwUser = i;
- if( (mmresult = waveOutPrepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR )
+ pahsc->pahsc_OutputBuffers[i].dwBufferLength = pahsc->pahsc_BytesPerHostOutputBuffer;
+ pahsc->pahsc_OutputBuffers[i].dwUser = i;
+ if( (mr = waveOutPrepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) )) != MMSYSERR_NOERROR )
{
result = paHostError;
- sPaHostError = mmresult;
+ sPaHostError = mr;
goto error;
}
}
return result;
-
error:
return result;
}
/*******************************************************************/
-PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *stream )
+PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
{
- PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
- return wmmeStreamData->numHostBuffers * wmmeStreamData->framesPerHostBuffer;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ return pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer;
}
/*******************************************************************
- * Determine number of WAVE Buffers
- * and how many User Buffers we can put into each WAVE buffer.
- */
-static void PaHost_CalcNumHostBuffers( internalPortAudioStream *stream )
+* Determine number of WAVE Buffers
+* and how many User Buffers we can put into each WAVE buffer.
+*/
+static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
{
- PaWMMEStreamData *wmmeStreamData = (PaWMMEStreamData *) stream->past_DeviceData;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
unsigned int minNumBuffers;
- int minframesPerHostBuffer;
- int maxframesPerHostBuffer;
+ int minFramesPerHostBuffer;
+ int maxFramesPerHostBuffer;
int minTotalFrames;
int userBuffersPerHostBuffer;
int framesPerHostBuffer;
int numHostBuffers;
-
/* Calculate minimum and maximum sizes based on timing and sample rate. */
- minframesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001);
- minframesPerHostBuffer = (minframesPerHostBuffer + 7) & ~7;
- DBUG(("PaHost_CalcNumHostBuffers: minframesPerHostBuffer = %d\n", minframesPerHostBuffer ));
- maxframesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * stream->past_SampleRate * 0.001);
- maxframesPerHostBuffer = (maxframesPerHostBuffer + 7) & ~7;
- DBUG(("PaHost_CalcNumHostBuffers: maxframesPerHostBuffer = %d\n", maxframesPerHostBuffer ));
+ minFramesPerHostBuffer = (int) (PA_MIN_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0);
+ minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
+ DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
+ maxFramesPerHostBuffer = (int) (PA_MAX_MSEC_PER_HOST_BUFFER * past->past_SampleRate / 1000.0);
+ maxFramesPerHostBuffer = (maxFramesPerHostBuffer + 7) & ~7;
+ DBUG(("PaHost_CalcNumHostBuffers: maxFramesPerHostBuffer = %d\n", maxFramesPerHostBuffer ));
/* Determine number of user buffers based on minimum latency. */
- minNumBuffers = Pa_GetMinNumBuffers( stream->past_FramesPerUserBuffer, stream->past_SampleRate );
- stream->past_NumUserBuffers = ( minNumBuffers > stream->past_NumUserBuffers ) ? minNumBuffers : stream->past_NumUserBuffers;
- DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", stream->past_NumUserBuffers ));
- minTotalFrames = stream->past_NumUserBuffers * stream->past_FramesPerUserBuffer;
+ 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 WAVE buffers too small because they may not get serviced quickly enough. */
- if( (int) stream->past_FramesPerUserBuffer < minframesPerHostBuffer )
+ if( (int) past->past_FramesPerUserBuffer < minFramesPerHostBuffer )
{
userBuffersPerHostBuffer =
- (minframesPerHostBuffer + stream->past_FramesPerUserBuffer - 1) /
- stream->past_FramesPerUserBuffer;
+ (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) /
+ past->past_FramesPerUserBuffer;
}
else
{
userBuffersPerHostBuffer = 1;
}
- framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
+ framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
/* Calculate number of WAVE buffers needed. Round up to cover minTotalFrames. */
numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
/* Make sure we have anough WAVE buffers. */
numHostBuffers = PA_MIN_NUM_HOST_BUFFERS;
}
else if( (numHostBuffers > PA_MAX_NUM_HOST_BUFFERS) &&
- ((int) stream->past_FramesPerUserBuffer < (maxframesPerHostBuffer/2) ) )
+ ((int) past->past_FramesPerUserBuffer < (maxFramesPerHostBuffer/2) ) )
{
/* 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;
- framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
+ framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
/* If we have gone too far, back up one. */
- if( (framesPerHostBuffer > maxframesPerHostBuffer) ||
+ if( (framesPerHostBuffer > maxFramesPerHostBuffer) ||
(numHostBuffers < PA_MAX_NUM_HOST_BUFFERS) )
{
userBuffersPerHostBuffer -= 1;
- framesPerHostBuffer = stream->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
+ framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
break;
}
}
}
- wmmeStreamData->userBuffersPerHostBuffer = userBuffersPerHostBuffer;
- wmmeStreamData->framesPerHostBuffer = framesPerHostBuffer;
- wmmeStreamData->numHostBuffers = numHostBuffers;
- DBUG(("PaHost_CalcNumHostBuffers: userBuffersPerHostBuffer = %d\n", wmmeStreamData->userBuffersPerHostBuffer ));
- DBUG(("PaHost_CalcNumHostBuffers: numHostBuffers = %d\n", wmmeStreamData->numHostBuffers ));
- DBUG(("PaHost_CalcNumHostBuffers: framesPerHostBuffer = %d\n", wmmeStreamData->framesPerHostBuffer ));
- DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", stream->past_NumUserBuffers ));
+ pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer;
+ pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer;
+ pahsc->pahsc_NumHostBuffers = numHostBuffers;
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
}
/*******************************************************************/
-PaError PaHost_OpenStream( internalPortAudioStream *stream )
+PaError PaHost_OpenStream( internalPortAudioStream *past )
{
PaError result = paNoError;
- PaWMMEStreamData *wmmeStreamData;
-
- result = PaHost_AllocateWMMEStreamData( stream );
- if( result != paNoError ) return result;
-
- wmmeStreamData = PaHost_GetWMMEStreamData( stream );
-
+ PaHostSoundControl *pahsc;
+ /* Allocate and initialize host data. */
+ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */
+ if( pahsc == NULL )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ memset( pahsc, 0, sizeof(PaHostSoundControl) );
+ past->past_DeviceData = (void *) pahsc;
/* Figure out how user buffers fit into WAVE buffers. */
- PaHost_CalcNumHostBuffers( stream );
+ PaHost_CalcNumHostBuffers( past );
{
- int msecLatency = (int) ((PaHost_GetTotalBufferFrames(stream) * 1000) / stream->past_SampleRate);
- DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(stream), msecLatency ));
+ int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate);
+ DBUG(("PortAudio on WMME - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency ));
}
- InitializeCriticalSection( &wmmeStreamData->streamLock );
- wmmeStreamData->streamLockInited = 1;
+ InitializeCriticalSection( &pahsc->pahsc_StreamLock );
+ pahsc->pahsc_StreamLockInited = 1;
#if (PA_USE_TIMER_CALLBACK == 0)
- wmmeStreamData->bufferEventInited = 0;
- wmmeStreamData->bufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- if( wmmeStreamData->bufferEvent == NULL )
+ pahsc->pahsc_BufferEventInited = 0;
+ pahsc->pahsc_BufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if( pahsc->pahsc_BufferEvent == NULL )
{
result = paHostError;
sPaHostError = GetLastError();
goto error;
}
- wmmeStreamData->bufferEventInited = 1;
+ pahsc->pahsc_BufferEventInited = 1;
#endif /* (PA_USE_TIMER_CALLBACK == 0) */
/* ------------------ OUTPUT */
- wmmeStreamData->bytesPerUserOutputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumOutputChannels * sizeof(short);
- wmmeStreamData->bytesPerHostOutputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserOutputBuffer;
- if( (stream->past_OutputDeviceID != paNoDevice) && (stream->past_NumOutputChannels > 0) )
+ pahsc->pahsc_BytesPerUserOutputBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels * sizeof(short);
+ pahsc->pahsc_BytesPerHostOutputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserOutputBuffer;
+ if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) )
{
- result = PaHost_OpenOutputStream( stream );
+ result = PaHost_OpenOutputStream( past );
if( result < 0 ) goto error;
}
/* ------------------ INPUT */
- wmmeStreamData->bytesPerUserInputBuffer = stream->past_FramesPerUserBuffer * stream->past_NumInputChannels * sizeof(short);
- wmmeStreamData->bytesPerHostInputBuffer = wmmeStreamData->userBuffersPerHostBuffer * wmmeStreamData->bytesPerUserInputBuffer;
- if( (stream->past_InputDeviceID != paNoDevice) && (stream->past_NumInputChannels > 0) )
+ pahsc->pahsc_BytesPerUserInputBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels * sizeof(short);
+ pahsc->pahsc_BytesPerHostInputBuffer = pahsc->pahsc_UserBuffersPerHostBuffer * pahsc->pahsc_BytesPerUserInputBuffer;
+ if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) )
{
- result = PaHost_OpenInputStream( stream );
+ result = PaHost_OpenInputStream( past );
if( result < 0 ) goto error;
}
-
- Pa_InitializeCpuUsageScalar( stream );
-
+ /* Calculate scalar used in CPULoad calculation. */
+ {
+ LARGE_INTEGER frequency;
+ if( QueryPerformanceFrequency( &frequency ) == 0 )
+ {
+ pahsc->pahsc_InverseTicksPerHostBuffer = 0.0;
+ }
+ else
+ {
+ pahsc->pahsc_InverseTicksPerHostBuffer = past->past_SampleRate /
+ ( (double)frequency.QuadPart * past->past_FramesPerUserBuffer * pahsc->pahsc_UserBuffersPerHostBuffer );
+ DBUG(("pahsc_InverseTicksPerHostBuffer = %g\n", pahsc->pahsc_InverseTicksPerHostBuffer ));
+ }
+ }
return result;
-
error:
- PaHost_CloseStream( stream );
+ PaHost_CloseStream( past );
return result;
}
/*************************************************************************/
-PaError PaHost_StartOutput( internalPortAudioStream *stream )
+PaError PaHost_StartOutput( internalPortAudioStream *past )
{
+ MMRESULT mr;
+ PaHostSoundControl *pahsc;
PaError result = paNoError;
- MMRESULT mmresult;
int i;
- PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream );
-
- if( wmmeStreamData == NULL ) return paInternalError;
-
- if( stream->past_OutputDeviceID != paNoDevice )
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( past->past_OutputDeviceID != paNoDevice )
{
- if( (mmresult = waveOutPause( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR )
+ if( (mr = waveOutPause( pahsc->pahsc_HWaveOut )) != MMSYSERR_NOERROR )
{
result = paHostError;
- sPaHostError = mmresult;
+ sPaHostError = mr;
goto error;
}
- for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
+ for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
- ZeroMemory( wmmeStreamData->outputBuffers[i].lpData, wmmeStreamData->outputBuffers[i].dwBufferLength );
- mmresult = waveOutWrite( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) );
- if( mmresult != MMSYSERR_NOERROR )
+ ZeroMemory( pahsc->pahsc_OutputBuffers[i].lpData, pahsc->pahsc_OutputBuffers[i].dwBufferLength );
+ mr = waveOutWrite( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) );
+ if( mr != MMSYSERR_NOERROR )
{
result = paHostError;
- sPaHostError = mmresult;
+ sPaHostError = mr;
goto error;
}
- stream->past_FrameCount += wmmeStreamData->framesPerHostBuffer;
+ past->past_FrameCount += pahsc->pahsc_FramesPerHostBuffer;
}
- wmmeStreamData->currentOutputBuffer = 0;
- if( (mmresult = waveOutRestart( wmmeStreamData->hWaveOut )) != MMSYSERR_NOERROR )
+ pahsc->pahsc_CurrentOutputBuffer = 0;
+ if( (mr = waveOutRestart( pahsc->pahsc_HWaveOut )) != MMSYSERR_NOERROR )
{
result = paHostError;
- sPaHostError = mmresult;
+ sPaHostError = mr;
goto error;
}
}
-
+ DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));
error:
- DBUG(("PaHost_StartOutput: wave returned mmresult = 0x%X.\n", mmresult));
return result;
}
/*************************************************************************/
-PaError PaHost_StartInput( internalPortAudioStream *internalStream )
+PaError PaHost_StartInput( internalPortAudioStream *past )
{
PaError result = paNoError;
- MMRESULT mmresult;
+ MMRESULT mr;
int i;
- PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream );
-
- if( wmmeStreamData == NULL ) return paInternalError;
-
- if( internalStream->past_InputDeviceID != paNoDevice )
+ PaHostSoundControl *pahsc;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( past->past_InputDeviceID != paNoDevice )
{
- for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
+ for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
- mmresult = waveInAddBuffer( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) );
- if( mmresult != MMSYSERR_NOERROR )
+ mr = waveInAddBuffer( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) );
+ if( mr != MMSYSERR_NOERROR )
{
result = paHostError;
- sPaHostError = mmresult;
+ sPaHostError = mr;
goto error;
}
}
- wmmeStreamData->currentInputBuffer = 0;
- mmresult = waveInStart( wmmeStreamData->hWaveIn );
- DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult));
- if( mmresult != MMSYSERR_NOERROR )
+ pahsc->pahsc_CurrentInputBuffer = 0;
+ mr = waveInStart( pahsc->pahsc_HWaveIn );
+ DBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", hr));
+ if( mr != MMSYSERR_NOERROR )
{
result = paHostError;
- sPaHostError = mmresult;
+ sPaHostError = mr;
goto error;
}
}
-
error:
return result;
}
/*************************************************************************/
-PaError PaHost_StartEngine( internalPortAudioStream *stream )
+PaError PaHost_StartEngine( internalPortAudioStream *past )
{
PaError result = paNoError;
- PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream );
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
#if PA_USE_TIMER_CALLBACK
int resolution;
int bufsPerTimerCallback;
int msecPerBuffer;
#endif /* PA_USE_TIMER_CALLBACK */
- if( wmmeStreamData == NULL ) return paInternalError;
-
- stream->past_StopSoon = 0;
- stream->past_StopNow = 0;
- stream->past_IsActive = 1;
- wmmeStreamData->framesPlayed = 0.0;
- wmmeStreamData->lastPosition = 0;
+ past->past_StopSoon = 0;
+ past->past_StopNow = 0;
+ past->past_IsActive = 1;
+ pahsc->pahsc_FramesPlayed = 0.0;
+ pahsc->pahsc_LastPosition = 0;
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result );
#endif
#if PA_USE_TIMER_CALLBACK
/* Create timer that will wake us up so we can fill the DSound buffer. */
- bufsPerTimerCallback = wmmeStreamData->numHostBuffers/4;
+ bufsPerTimerCallback = pahsc->pahsc_NumHostBuffers/4;
if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1;
if( bufsPerTimerCallback < 1 ) bufsPerTimerCallback = 1;
msecPerBuffer = (1000 * bufsPerTimerCallback *
- wmmeStreamData->userBuffersPerHostBuffer *
- internalStream->past_FramesPerUserBuffer ) / (int) internalStream->past_SampleRate;
+ pahsc->pahsc_UserBuffersPerHostBuffer *
+ past->past_FramesPerUserBuffer ) / (int) past->past_SampleRate;
if( msecPerBuffer < 10 ) msecPerBuffer = 10;
else if( msecPerBuffer > 100 ) msecPerBuffer = 100;
resolution = msecPerBuffer/4;
- wmmeStreamData->timerID = timeSetEvent( msecPerBuffer, resolution,
+ pahsc->pahsc_TimerID = timeSetEvent( msecPerBuffer, resolution,
(LPTIMECALLBACK) Pa_TimerCallback,
- (DWORD) stream, TIME_PERIODIC );
- if( wmmeStreamData->timerID == 0 )
+ (DWORD) past, TIME_PERIODIC );
+ if( pahsc->pahsc_TimerID == 0 )
{
result = paHostError;
sPaHostError = GetLastError();;
goto error;
}
#else /* PA_USE_TIMER_CALLBACK */
- ResetEvent( wmmeStreamData->abortEvent );
+ ResetEvent( pahsc->pahsc_AbortEvent );
/* Create thread that waits for audio buffers to be ready for processing. */
- wmmeStreamData->engineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, stream, 0, &wmmeStreamData->engineThreadID );
- if( wmmeStreamData->engineThread == NULL )
+ pahsc->pahsc_EngineThread = CreateThread( 0, 0, WinMMPa_OutputThreadProc, past, 0, &pahsc->pahsc_EngineThreadID );
+ if( pahsc->pahsc_EngineThread == NULL )
{
result = paHostError;
sPaHostError = GetLastError();;
goto error;
}
#if PA_TRACE_START_STOP
- AddTraceMessage( "PaHost_StartEngine: thread ", (int) wmmeStreamData->engineThread );
+ AddTraceMessage( "PaHost_StartEngine: thread ", (int) pahsc->pahsc_EngineThread );
#endif
/* I used to pass the thread which was failing. I now pass GetCurrentProcess().
- * This fix could improve latency for some applications. It could also result in CPU
- * starvation if the callback did too much processing.
- * I also added result checks, so we might see more failures at initialization.
- * Thanks to Alberto di Bene for spotting this.
- */
+ ** This fix could improve latency for some applications. It could also result in CPU
+ ** starvation if the callback did too much processing.
+ ** I also added result checks, so we might see more failures at initialization.
+ ** Thanks to Alberto di Bene for spotting this.
+ */
if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) /* PLB20010816 */
{
result = paHostError;
sPaHostError = GetLastError();;
goto error;
}
- if( !SetThreadPriority( wmmeStreamData->engineThread, THREAD_PRIORITY_HIGHEST ) )
+ if( !SetThreadPriority( pahsc->pahsc_EngineThread, THREAD_PRIORITY_HIGHEST ) )
{
result = paHostError;
sPaHostError = GetLastError();;
goto error;
}
#endif
-
error:
return result;
}
+
/*************************************************************************/
-PaError PaHost_StopEngine( internalPortAudioStream *internalStream, int abort )
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
{
int timeOut;
- PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream );
-
- if( wmmeStreamData == NULL ) return paNoError;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
/* Tell background thread to stop generating more data and to let current data play out. */
- internalStream->past_StopSoon = 1;
+ past->past_StopSoon = 1;
/* If aborting, tell background thread to stop NOW! */
- if( abort ) internalStream->past_StopNow = 1;
+ if( abort ) past->past_StopNow = 1;
/* Calculate timeOut longer than longest time it could take to play all buffers. */
- timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( internalStream ) / internalStream->past_SampleRate);
+ timeOut = (DWORD) (1500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate);
if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC;
#if PA_USE_TIMER_CALLBACK
- if( (internalStream->past_OutputDeviceID != paNoDevice) &&
- internalStream->past_IsActive &&
- (wmmeStreamData->timerID != 0) )
+ if( (past->past_OutputDeviceID != paNoDevice) &&
+ past->past_IsActive &&
+ (pahsc->pahsc_TimerID != 0) )
{
/* Wait for IsActive to drop. */
- while( (internalStream->past_IsActive) && (timeOut > 0) )
+ while( (past->past_IsActive) && (timeOut > 0) )
{
Sleep(10);
timeOut -= 10;
}
- timeKillEvent( wmmeStreamData->timerID ); /* Stop callback timer. */
- wmmeStreamData->timerID = 0;
+ timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */
+ pahsc->pahsc_TimerID = 0;
}
#else /* PA_USE_TIMER_CALLBACK */
#if PA_TRACE_START_STOP
- AddTraceMessage( "PaHost_StopEngine: thread ", (int) wmmeStreamData->engineThread );
+ AddTraceMessage( "PaHost_StopEngine: thread ", (int) pahsc->pahsc_EngineThread );
#endif
- if( (internalStream->past_OutputDeviceID != paNoDevice) &&
- (internalStream->past_IsActive) &&
- (wmmeStreamData->engineThread != NULL) )
+ if( (past->past_OutputDeviceID != paNoDevice) &&
+ (past->past_IsActive) &&
+ (pahsc->pahsc_EngineThread != NULL) )
{
DWORD got;
/* Tell background thread to stop generating more data and to let current data play out. */
DBUG(("PaHost_StopEngine: waiting for background thread.\n"));
- got = WaitForSingleObject( wmmeStreamData->engineThread, timeOut );
+ got = WaitForSingleObject( pahsc->pahsc_EngineThread, timeOut );
if( got == WAIT_TIMEOUT )
{
ERR_RPT(("PaHost_StopEngine: timed out while waiting for background thread to finish.\n"));
return paTimedOut;
}
- CloseHandle( wmmeStreamData->engineThread );
- wmmeStreamData->engineThread = NULL;
+ CloseHandle( pahsc->pahsc_EngineThread );
+ pahsc->pahsc_EngineThread = NULL;
}
#endif /* PA_USE_TIMER_CALLBACK */
- internalStream->past_IsActive = 0;
+ past->past_IsActive = 0;
return paNoError;
}
/*************************************************************************/
-PaError PaHost_StopInput( internalPortAudioStream *stream, int abort )
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
{
- MMRESULT mmresult;
- PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream );
-
- if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */
- (void) abort; /* unused parameter */
-
- if( wmmeStreamData->hWaveIn != NULL )
+ MMRESULT mr;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ (void) abort;
+ if( pahsc->pahsc_HWaveIn != NULL )
{
- mmresult = waveInReset( wmmeStreamData->hWaveIn );
- if( mmresult != MMSYSERR_NOERROR )
+ mr = waveInReset( pahsc->pahsc_HWaveIn );
+ if( mr != MMSYSERR_NOERROR )
{
- sPaHostError = mmresult;
+ sPaHostError = mr;
return paHostError;
}
}
return paNoError;
}
/*************************************************************************/
-PaError PaHost_StopOutput( internalPortAudioStream *internalStream, int abort )
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
{
- MMRESULT mmresult;
- PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream );
-
- if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return paNoError? */
- (void) abort; /* unused parameter */
-
+ MMRESULT mr;
+ PaHostSoundControl *pahsc;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ (void) abort;
#if PA_TRACE_START_STOP
- AddTraceMessage( "PaHost_StopOutput: hWaveOut ", (int) wmmeStreamData->hWaveOut );
+ AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
#endif
- if( wmmeStreamData->hWaveOut != NULL )
+ if( pahsc->pahsc_HWaveOut != NULL )
{
- mmresult = waveOutReset( wmmeStreamData->hWaveOut );
- if( mmresult != MMSYSERR_NOERROR )
+ mr = waveOutReset( pahsc->pahsc_HWaveOut );
+ if( mr != MMSYSERR_NOERROR )
{
- sPaHostError = mmresult;
+ sPaHostError = mr;
return paHostError;
}
}
return paNoError;
}
/*******************************************************************/
-PaError PaHost_CloseStream( internalPortAudioStream *stream )
+PaError PaHost_CloseStream( internalPortAudioStream *past )
{
- int i;
- PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( stream );
-
- if( stream == NULL ) return paBadStreamPtr;
- if( wmmeStreamData == NULL ) return paNoError; /* FIXME: why return no error? */
-
+ int i;
+ PaHostSoundControl *pahsc;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
#if PA_TRACE_START_STOP
- AddTraceMessage( "PaHost_CloseStream: hWaveOut ", (int) wmmeStreamData->hWaveOut );
+ AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
#endif
/* Free data and device for output. */
- if( wmmeStreamData->hWaveOut )
+ if( pahsc->pahsc_HWaveOut )
{
- if( wmmeStreamData->outputBuffers )
+ if( pahsc->pahsc_OutputBuffers )
{
- for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
+ for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
- waveOutUnprepareHeader( wmmeStreamData->hWaveOut, &wmmeStreamData->outputBuffers[i], sizeof(WAVEHDR) );
- PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers[i].lpData ); /* MEM */
+ waveOutUnprepareHeader( pahsc->pahsc_HWaveOut, &pahsc->pahsc_OutputBuffers[i], sizeof(WAVEHDR) );
+ GlobalFree( pahsc->pahsc_OutputBuffers[i].lpData ); /* MEM */
}
- PaHost_FreeTrackedMemory( wmmeStreamData->outputBuffers ); /* MEM */
+ GlobalFree( pahsc->pahsc_OutputBuffers ); /* MEM */
}
- waveOutClose( wmmeStreamData->hWaveOut );
+ waveOutClose( pahsc->pahsc_HWaveOut );
}
/* Free data and device for input. */
- if( wmmeStreamData->hWaveIn )
+ if( pahsc->pahsc_HWaveIn )
{
- if( wmmeStreamData->inputBuffers )
+ if( pahsc->pahsc_InputBuffers )
{
- for( i=0; i<wmmeStreamData->numHostBuffers; i++ )
+ for( i=0; i<pahsc->pahsc_NumHostBuffers; i++ )
{
- waveInUnprepareHeader( wmmeStreamData->hWaveIn, &wmmeStreamData->inputBuffers[i], sizeof(WAVEHDR) );
- PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers[i].lpData ); /* MEM */
+ waveInUnprepareHeader( pahsc->pahsc_HWaveIn, &pahsc->pahsc_InputBuffers[i], sizeof(WAVEHDR) );
+ GlobalFree( pahsc->pahsc_InputBuffers[i].lpData ); /* MEM */
}
- PaHost_FreeTrackedMemory( wmmeStreamData->inputBuffers ); /* MEM */
+ GlobalFree( pahsc->pahsc_InputBuffers ); /* MEM */
}
- waveInClose( wmmeStreamData->hWaveIn );
+ waveInClose( pahsc->pahsc_HWaveIn );
}
#if (PA_USE_TIMER_CALLBACK == 0)
- if( wmmeStreamData->abortEventInited ) CloseHandle( wmmeStreamData->abortEvent );
- if( wmmeStreamData->bufferEventInited ) CloseHandle( wmmeStreamData->bufferEvent );
+ if( pahsc->pahsc_AbortEventInited ) CloseHandle( pahsc->pahsc_AbortEvent );
+ if( pahsc->pahsc_BufferEventInited ) CloseHandle( pahsc->pahsc_BufferEvent );
#endif
- if( wmmeStreamData->streamLockInited )
- DeleteCriticalSection( &wmmeStreamData->streamLock );
-
- PaHost_FreeWMMEStreamData( stream );
-
+ if( pahsc->pahsc_StreamLockInited )
+ DeleteCriticalSection( &pahsc->pahsc_StreamLock );
+ PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); /* MEM */
+ past->past_DeviceData = NULL;
return paNoError;
}
/*************************************************************************
- * 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.
- */
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+**
+** set PA_MIN_LATENCY_MSEC=200
+**
+** in the AUTOEXEC.BAT file and reboot.
+** If the environment variable is not set, then the latency will be determined
+** based on the OS. Windows NT has higher latency than Win95.
+*/
#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
{
char envbuf[PA_ENV_BUF_SIZE];
+ DWORD hostVersion;
DWORD hresult;
int minLatencyMsec = 0;
double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate;
int minBuffers;
-
/* Let user determine minimal latency by setting environment variable. */
hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE );
if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
{
- minLatencyMsec = atoi( envbuf ); /* REVIEW: will we crash if the environment variable contains some nasty value? */
+ minLatencyMsec = atoi( envbuf );
}
else
{
- /* Set minimal latency based on whether NT or other OS.
+ /* Set minimal latency based on whether NT or Win95.
* 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;
- }
+ 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
return minBuffers;
}
/*************************************************************************
- * Cleanup device info.
- */
+** Cleanup device info.
+*/
PaError PaHost_Term( void )
{
int i;
-
if( sNumDevices > 0 )
{
if( sDevicePtrs != NULL )
{
if( sDevicePtrs[i] != NULL )
{
- PaHost_FreeTrackedMemory( (char*)sDevicePtrs[i]->name ); /* MEM */
- PaHost_FreeTrackedMemory( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */
- PaHost_FreeTrackedMemory( sDevicePtrs[i] ); /* MEM */
+ GlobalFree( (char*)sDevicePtrs[i]->name ); /* MEM */
+ GlobalFree( (void*)sDevicePtrs[i]->sampleRates ); /* MEM */
+ GlobalFree( sDevicePtrs[i] ); /* MEM */
}
}
- PaHost_FreeTrackedMemory( sDevicePtrs ); /* MEM */
+ GlobalFree( sDevicePtrs ); /* MEM */
sDevicePtrs = NULL;
}
sNumDevices = 0;
}
-
-#if PA_TRACK_MEMORY
- PRINT(("PaHost_Term: sNumAllocations = %d\n", sNumAllocations ));
-#endif
-
return paNoError;
}
/*************************************************************************/
Sleep( msec );
}
/*************************************************************************
-FIXME: the following memory allocation routines should not be declared here
* Allocate memory that can be accessed in real-time.
* This may need to be held in physical memory so that it is not
* paged to virtual memory.
*/
void *PaHost_AllocateFastMemory( long numBytes )
{
- return PaHost_AllocateTrackedMemory( numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */
+ void *addr = GlobalAlloc( GPTR, numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */
+ return addr;
}
/*************************************************************************
* Free memory that could be accessed in real-time.
*/
void PaHost_FreeFastMemory( void *addr, long numBytes )
{
- (void) numBytes; /* unused parameter */
-
- PaHost_FreeTrackedMemory( addr ); /* MEM */
-}
-
-/*************************************************************************
- * Track memory allocations to avoid leaks.
- */
-static void *PaHost_AllocateTrackedMemory( long numBytes )
-{
- void *result = GlobalAlloc( GPTR, numBytes ); /* MEM */
-
-#if PA_TRACK_MEMORY
- if( result != NULL ) sNumAllocations += 1;
-#endif
- return result;
-}
-
-static void PaHost_FreeTrackedMemory( void *addr )
-{
- if( addr != NULL )
- {
- GlobalFree( addr ); /* MEM */
-#if PA_TRACK_MEMORY
- sNumAllocations -= 1;
-#endif
- }
+ if( addr != NULL ) GlobalFree( addr ); /* MEM */
}
-
/***********************************************************************/
-PaError PaHost_StreamActive( internalPortAudioStream *internalStream )
+PaError PaHost_StreamActive( internalPortAudioStream *past )
{
- if( internalStream == NULL ) return paBadStreamPtr;
-
- return (PaError) internalStream->past_IsActive;
+ PaHostSoundControl *pahsc;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+ return (PaError) past->past_IsActive;
}
/*************************************************************************
* This must be called periodically because mmtime.u.sample
* is a DWORD and can wrap and lose sync after a few hours.
*/
-static PaError PaHost_UpdateStreamTime( PaWMMEStreamData *wmmeStreamData )
+static PaError PaHost_UpdateStreamTime( PaHostSoundControl *pahsc )
{
- MMRESULT mmresult;
+ MMRESULT mr;
MMTIME mmtime;
mmtime.wType = TIME_SAMPLES;
-
- if( wmmeStreamData->hWaveOut != NULL )
+ if( pahsc->pahsc_HWaveOut != NULL )
{
- mmresult = waveOutGetPosition( wmmeStreamData->hWaveOut, &mmtime, sizeof(mmtime) );
+ mr = waveOutGetPosition( pahsc->pahsc_HWaveOut, &mmtime, sizeof(mmtime) );
}
else
{
- mmresult = waveInGetPosition( wmmeStreamData->hWaveIn, &mmtime, sizeof(mmtime) );
+ mr = waveInGetPosition( pahsc->pahsc_HWaveIn, &mmtime, sizeof(mmtime) );
}
-
- if( mmresult != MMSYSERR_NOERROR )
+ if( mr != MMSYSERR_NOERROR )
{
- sPaHostError = mmresult;
+ sPaHostError = mr;
return paHostError;
}
-
- /* This data has two variables and is shared by foreground and background.
- * So we need to make it thread safe. */
- EnterCriticalSection( &wmmeStreamData->streamLock );
- wmmeStreamData->framesPlayed += ((long)mmtime.u.sample) - wmmeStreamData->lastPosition;
- wmmeStreamData->lastPosition = (long)mmtime.u.sample;
- LeaveCriticalSection( &wmmeStreamData->streamLock );
-
+ /* This data has two variables and is shared by foreground and background. */
+ /* So we need to make it thread safe. */
+ EnterCriticalSection( &pahsc->pahsc_StreamLock );
+ pahsc->pahsc_FramesPlayed += ((long)mmtime.u.sample) - pahsc->pahsc_LastPosition;
+ pahsc->pahsc_LastPosition = (long)mmtime.u.sample;
+ LeaveCriticalSection( &pahsc->pahsc_StreamLock );
return paNoError;
}
/*************************************************************************/
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{
- internalPortAudioStream *internalStream = PaHost_GetStreamRepresentation( stream );
- PaWMMEStreamData *wmmeStreamData = PaHost_GetWMMEStreamData( internalStream );
-
- if( internalStream == NULL ) return paBadStreamPtr;
- if( wmmeStreamData == NULL ) return paInternalError;
-
- PaHost_UpdateStreamTime( wmmeStreamData );
- return wmmeStreamData->framesPlayed;
+ PaHostSoundControl *pahsc;
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ PaHost_UpdateStreamTime( pahsc );
+ return pahsc->pahsc_FramesPlayed;
}
-/*************************************************************************/
-
-
-
** 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
int main(void)
{
int i;
- SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK];
+ SAMPLE samples[SAMPLES_PER_FRAME];
PaError err;
PABLIO_Stream *aStream;
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 );
+++ /dev/null
-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
+++ /dev/null
-interesting info