aboutsummaryrefslogtreecommitdiff
path: root/pd/portaudio
diff options
context:
space:
mode:
Diffstat (limited to 'pd/portaudio')
-rw-r--r--pd/portaudio/Makefile.in177
-rwxr-xr-xpd/portaudio/fixdir.bat19
-rwxr-xr-xpd/portaudio/fixfile.bat7
-rwxr-xr-xpd/portaudio/install-sh251
-rw-r--r--pd/portaudio/pa_mac_sm/pa_mac_sm.c1656
-rw-r--r--pd/portaudio/pa_sgi/pa_sgi.c1417
-rw-r--r--pd/portaudio/pa_unix/pa_unix_hostapis.c64
-rw-r--r--pd/portaudio/pa_unix/pa_unix_util.c175
-rw-r--r--pd/portaudio/pa_unix_oss/low_latency_tip.txtbin3111 -> 0 bytes
-rw-r--r--pd/portaudio/pa_unix_oss/pa_unix_oss.c1918
-rw-r--r--pd/portaudio/pa_unix_oss/recplay.c114
11 files changed, 0 insertions, 5798 deletions
diff --git a/pd/portaudio/Makefile.in b/pd/portaudio/Makefile.in
deleted file mode 100644
index 841aedb9..00000000
--- a/pd/portaudio/Makefile.in
+++ /dev/null
@@ -1,177 +0,0 @@
-#
-# PortAudio V19 Makefile.in
-#
-# Dominic Mazzoni
-#
-
-PREFIX = @prefix@
-CC = @CC@
-CFLAGS = @CFLAGS@ -Ipa_common @DEFS@
-LIBS = @LIBS@
-AR = @AR@
-RANLIB = @RANLIB@
-INSTALL = @INSTALL@
-SHARED_FLAGS = @SHARED_FLAGS@
-DLL_LIBS = @DLL_LIBS@
-CXXFLAGS = @CXXFLAGS@
-NASM = @NASM@
-NASMOPT = @NASMOPT@
-
-OTHER_OBJS = @OTHER_OBJS@
-
-PALIB = libportaudio.a
-PADLL = @PADLL@
-PADLLV = $(PADLL).0.0.19
-PAINC = pa_common/portaudio.h
-
-COMMON_OBJS = \
- pa_common/pa_allocation.o \
- pa_common/pa_converters.o \
- pa_common/pa_cpuload.o \
- pa_common/pa_dither.o \
- pa_common/pa_front.o \
- pa_common/pa_process.o \
- pa_common/pa_skeleton.o \
- pa_common/pa_stream.o \
- pa_common/pa_trace.o
-
-TESTS = \
- bin/paqa_devs \
- bin/paqa_errs \
- bin/patest1 \
- bin/patest_buffer \
- bin/patest_callbackstop \
- bin/patest_clip \
- bin/patest_dither \
- bin/patest_hang \
- bin/patest_in_overflow \
- bin/patest_latency \
- bin/patest_leftright \
- bin/patest_longsine \
- bin/patest_many \
- bin/patest_maxsines \
- bin/patest_multi_sine \
- bin/patest_out_underflow \
- bin/patest_pink \
- bin/patest_prime \
- bin/patest_read_record \
- bin/patest_record \
- bin/patest_ringmix \
- bin/patest_saw \
- bin/patest_sine8 \
- bin/patest_sine \
- bin/patest_sine_formats \
- bin/patest_sine_time \
- bin/patest_start_stop \
- bin/patest_stop \
- bin/patest_sync \
- bin/patest_toomanysines \
- bin/patest_underflow \
- bin/patest_wire \
- bin/patest_write_sine \
- bin/pa_devs \
- bin/pa_fuzz \
- bin/pa_minlat
-
-# Most of these don't compile yet. Put them in TESTS, above, if
-# you want to try to compile them...
-ALL_TESTS = \
- bin/debug_convert \
- bin/debug_dither_calc \
- bin/debug_dual \
- bin/debug_multi_in \
- bin/debug_multi_out \
- bin/debug_record \
- bin/debug_record_reuse \
- bin/debug_sine_amp \
- bin/debug_sine \
- bin/debug_sine_formats \
- bin/debug_srate \
- bin/debug_test1 \
- bin/pa_devs \
- bin/pa_fuzz \
- bin/pa_minlat \
- bin/paqa_devs \
- bin/paqa_errs \
- bin/patest1 \
- bin/patest_buffer \
- bin/patest_clip \
- bin/patest_dither \
- bin/patest_hang \
- bin/patest_in_overflow \
- bin/patest_latency \
- bin/patest_leftright \
- bin/patest_longsine \
- bin/patest_many \
- bin/patest_maxsines \
- bin/patest_multi_sine \
- bin/patest_out_underflow \
- bin/patest_pink \
- bin/patest_read_record \
- bin/patest_record \
- bin/patest_ringmix \
- bin/patest_saw \
- bin/patest_sine8 \
- bin/patest_sine \
- bin/patest_sine_formats \
- bin/patest_sine_time \
- bin/patest_start_stop \
- bin/patest_stop \
- bin/patest_sync \
- bin/patest_toomanysines \
- bin/patest_underflow \
- bin/patest_wire \
- bin/patest_write_sine
-
-OBJS = $(COMMON_OBJS) $(OTHER_OBJS)
-
-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) lib/$(PADLLV)
-
-%.o: %.c Makefile $(PAINC)
- $(CC) -c $(CFLAGS) $< -o $@
-
-%.o: %.cpp Makefile $(PAINC)
- $(CXX) -c $(CXXFLAGS) $< -o $@
-
-%.o: %.asm
- $(NASM) $(NASMOPT) -o $@ $<
-
-bin:
- mkdir bin
-
-lib:
- mkdir lib
-
-
-
diff --git a/pd/portaudio/fixdir.bat b/pd/portaudio/fixdir.bat
deleted file mode 100755
index 92d6c747..00000000
--- a/pd/portaudio/fixdir.bat
+++ /dev/null
@@ -1,19 +0,0 @@
-rem Use Astyle to fix style in 'C' files
-cd %1%
-
-fixlines -p *.c
-fixlines -p *.cpp
-fixlines -p *.cc
-
-astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.c
-astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cpp
-astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cc
-del *.orig
-@rem convert line terminators to Unix style LFs
-fixlines -u *.c
-fixlines -u *.cpp
-fixlines -u *.cc
-fixlines -u *.h
-del *.bak
-
-cd ..\
diff --git a/pd/portaudio/fixfile.bat b/pd/portaudio/fixfile.bat
deleted file mode 100755
index 48f6fbc2..00000000
--- a/pd/portaudio/fixfile.bat
+++ /dev/null
@@ -1,7 +0,0 @@
-rem Use Astyle to fix style in a file
-fixlines -p %1%
-astyle --style=ansi -c -o --convert-tabs --indent-preprocessor %1%
-del %1%.orig
-@rem convert line terminators to Unix style LFs
-fixlines -u %1%
-del %1%.bak
diff --git a/pd/portaudio/install-sh b/pd/portaudio/install-sh
deleted file mode 100755
index e9de2384..00000000
--- a/pd/portaudio/install-sh
+++ /dev/null
@@ -1,251 +0,0 @@
-#!/bin/sh
-#
-# install - install a program, script, or datafile
-# This comes from X11R5 (mit/util/scripts/install.sh).
-#
-# Copyright 1991 by the Massachusetts Institute of Technology
-#
-# Permission to use, copy, modify, distribute, and sell this software and its
-# documentation for any purpose is hereby granted without fee, provided that
-# the above copyright notice appear in all copies and that both that
-# copyright notice and this permission notice appear in supporting
-# documentation, and that the name of M.I.T. not be used in advertising or
-# publicity pertaining to distribution of the software without specific,
-# written prior permission. M.I.T. makes no representations about the
-# suitability of this software for any purpose. It is provided "as is"
-# without express or implied warranty.
-#
-# Calling this script install-sh is preferred over install.sh, to prevent
-# `make' implicit rules from creating a file called install from it
-# when there is no Makefile.
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch. It can only install one file at a time, a restriction
-# shared with many OS's install programs.
-
-
-# set DOITPROG to echo to test this script
-
-# Don't use :- since 4.3BSD and earlier shells don't like it.
-doit="${DOITPROG-}"
-
-
-# put in absolute paths if you don't have them in your path; or use env. vars.
-
-mvprog="${MVPROG-mv}"
-cpprog="${CPPROG-cp}"
-chmodprog="${CHMODPROG-chmod}"
-chownprog="${CHOWNPROG-chown}"
-chgrpprog="${CHGRPPROG-chgrp}"
-stripprog="${STRIPPROG-strip}"
-rmprog="${RMPROG-rm}"
-mkdirprog="${MKDIRPROG-mkdir}"
-
-transformbasename=""
-transform_arg=""
-instcmd="$mvprog"
-chmodcmd="$chmodprog 0755"
-chowncmd=""
-chgrpcmd=""
-stripcmd=""
-rmcmd="$rmprog -f"
-mvcmd="$mvprog"
-src=""
-dst=""
-dir_arg=""
-
-while [ x"$1" != x ]; do
- case $1 in
- -c) instcmd="$cpprog"
- shift
- continue;;
-
- -d) dir_arg=true
- shift
- continue;;
-
- -m) chmodcmd="$chmodprog $2"
- shift
- shift
- continue;;
-
- -o) chowncmd="$chownprog $2"
- shift
- shift
- continue;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift
- shift
- continue;;
-
- -s) stripcmd="$stripprog"
- shift
- continue;;
-
- -t=*) transformarg=`echo $1 | sed 's/-t=//'`
- shift
- continue;;
-
- -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
- shift
- continue;;
-
- *) if [ x"$src" = x ]
- then
- src=$1
- else
- # this colon is to work around a 386BSD /bin/sh bug
- :
- dst=$1
- fi
- shift
- continue;;
- esac
-done
-
-if [ x"$src" = x ]
-then
- echo "install: no input file specified"
- exit 1
-else
- true
-fi
-
-if [ x"$dir_arg" != x ]; then
- dst=$src
- src=""
-
- if [ -d $dst ]; then
- instcmd=:
- chmodcmd=""
- else
- instcmd=mkdir
- fi
-else
-
-# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
-# might cause directories to be created, which would be especially bad
-# if $src (and thus $dsttmp) contains '*'.
-
- if [ -f $src -o -d $src ]
- then
- true
- else
- echo "install: $src does not exist"
- exit 1
- fi
-
- if [ x"$dst" = x ]
- then
- echo "install: no destination specified"
- exit 1
- else
- true
- fi
-
-# If destination is a directory, append the input filename; if your system
-# does not like double slashes in filenames, you may need to add some logic
-
- if [ -d $dst ]
- then
- dst="$dst"/`basename $src`
- else
- true
- fi
-fi
-
-## this sed command emulates the dirname command
-dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
-
-# Make sure that the destination directory exists.
-# this part is taken from Noah Friedman's mkinstalldirs script
-
-# Skip lots of stat calls in the usual case.
-if [ ! -d "$dstdir" ]; then
-defaultIFS='
-'
-IFS="${IFS-${defaultIFS}}"
-
-oIFS="${IFS}"
-# Some sh's can't handle IFS=/ for some reason.
-IFS='%'
-set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
-IFS="${oIFS}"
-
-pathcomp=''
-
-while [ $# -ne 0 ] ; do
- pathcomp="${pathcomp}${1}"
- shift
-
- if [ ! -d "${pathcomp}" ] ;
- then
- $mkdirprog "${pathcomp}"
- else
- true
- fi
-
- pathcomp="${pathcomp}/"
-done
-fi
-
-if [ x"$dir_arg" != x ]
-then
- $doit $instcmd $dst &&
-
- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
-else
-
-# If we're going to rename the final executable, determine the name now.
-
- if [ x"$transformarg" = x ]
- then
- dstfile=`basename $dst`
- else
- dstfile=`basename $dst $transformbasename |
- sed $transformarg`$transformbasename
- fi
-
-# don't allow the sed command to completely eliminate the filename
-
- if [ x"$dstfile" = x ]
- then
- dstfile=`basename $dst`
- else
- true
- fi
-
-# Make a temp file name in the proper directory.
-
- dsttmp=$dstdir/#inst.$$#
-
-# Move or copy the file name to the temp name
-
- $doit $instcmd $src $dsttmp &&
-
- trap "rm -f ${dsttmp}" 0 &&
-
-# and set any options; do chmod last to preserve setuid bits
-
-# If any of these fail, we abort the whole thing. If we want to
-# ignore errors from any of these, just make sure not to ignore
-# errors from the above "$doit $instcmd $src $dsttmp" command.
-
- if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
- if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
- if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
- if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
-
-# Now rename the file to the real destination.
-
- $doit $rmcmd -f $dstdir/$dstfile &&
- $doit $mvcmd $dsttmp $dstdir/$dstfile
-
-fi &&
-
-
-exit 0
diff --git a/pd/portaudio/pa_mac_sm/pa_mac_sm.c b/pd/portaudio/pa_mac_sm/pa_mac_sm.c
deleted file mode 100644
index 59457ded..00000000
--- a/pd/portaudio/pa_mac_sm/pa_mac_sm.c
+++ /dev/null
@@ -1,1656 +0,0 @@
-/*
- * $Id: pa_mac_sm.c,v 1.1.2.1 2002/06/07 21:20:48 rossb Exp $
- * Portable Audio I/O Library for Macintosh
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 Phil Burk
- *
- * Special thanks to Chris Rolfe for his many helpful suggestions, bug fixes,
- * and code contributions.
- * Thanks also to Tue Haste Andersen, Alberto Ricci, Nico Wald,
- * Roelf Toxopeus and Tom Erbe for testing the code and making
- * numerous suggestions.
- *
- * 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.
- */
-/* Modification History
- PLB20010415 - ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID
- PLB20010415 - Device Scan was crashing for anything other than siBadSoundInDevice, but some Macs may return other errors!
- PLB20010420 - Fix TIMEOUT in record mode.
- PLB20010420 - Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON
- 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
-9 on PowerMacs, and OS X if compiled with CARBON
-
-OUTPUT
-A circular array of CmpSoundHeaders is used as a queue. For low latency situations
-there will only be two small buffers used. For higher latency, more and larger buffers
-may be used.
-To play the sound we use SndDoCommand() with bufferCmd. Each buffer is followed
-by a callbackCmd which informs us when the buffer has been processsed.
-
-INPUT
-The SndInput Manager SPBRecord call is used for sound input. If only
-input is used, then the PA user callback is called from the Input completion proc.
-For full-duplex, or output only operation, the PA callback is called from the
-HostBuffer output completion proc. In that case, input sound is passed to the
-callback by a simple FIFO.
-
-TODO:
-O- Add support for native sample data formats other than int16.
-O- Review buffer sizing. Should it be based on result of siDeviceBufferInfo query?
-O- Determine default devices somehow.
-*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <memory.h>
-#include <math.h>
-
-/* Mac specific includes */
-#include "OSUtils.h"
-#include <MacTypes.h>
-#include <Math64.h>
-#include <Errors.h>
-#include <Sound.h>
-#include <SoundInput.h>
-#include <SoundComponents.h>
-#include <Devices.h>
-#include <DateTimeUtils.h>
-#include <Timer.h>
-#include <Gestalt.h>
-
-#include "portaudio.h"
-#include "pa_host.h"
-#include "pa_trace.h"
-
-#ifndef FALSE
- #define FALSE (0)
- #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 DBUG(x) /* PRINT(x) /**/
-#define DBUGX(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_MAX_NUM_HOST_BUFFERS (16) /* Do not exceed!! */
-#define PA_MAX_DEVICE_INFO (32)
-
-/* Conversions for 16.16 fixed point code. */
-#define DoubleToUnsignedFixed(x) ((UnsignedFixed) ((x) * 65536.0))
-#define UnsignedFixedToDouble(fx) (((double)(fx)) * (1.0/(1<<16)))
-
-/************************************************************************************/
-/****************** Structures ******************************************************/
-/************************************************************************************/
-/* Use for passing buffers from input callback to output callback for processing. */
-typedef struct MultiBuffer
-{
- char *buffers[PA_MAX_NUM_HOST_BUFFERS];
- int numBuffers;
- int nextWrite;
- int nextRead;
-}
-MultiBuffer;
-
-/* Define structure to contain all Macintosh specific data. */
-typedef struct PaHostSoundControl
-{
- UInt64 pahsc_EntryCount;
- double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
-
- /* 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. */
- volatile char pahsc_IfInsideCallback;
- /* Input */
- SPB pahsc_InputParams;
- SICompletionUPP pahsc_InputCompletionProc;
- MultiBuffer pahsc_InputMultiBuffer;
- int32 pahsc_BytesPerInputHostBuffer;
- int32 pahsc_InputRefNum;
- /* Output */
- CmpSoundHeader pahsc_SoundHeaders[PA_MAX_NUM_HOST_BUFFERS];
- int32 pahsc_BytesPerOutputHostBuffer;
- 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. */
-}
-PaHostSoundControl;
-
-/* Mac specific device information. */
-typedef struct internalPortAudioDevice
-{
- long pad_DeviceRefNum;
- long pad_DeviceBufferSize;
- Component pad_Identifier;
- PaDeviceInfo pad_Info;
-}
-internalPortAudioDevice;
-
-/************************************************************************************/
-/****************** Data ************************************************************/
-/************************************************************************************/
-static int sNumDevices = 0;
-static internalPortAudioDevice sDevices[PA_MAX_DEVICE_INFO] = { 0 };
-static int32 sPaHostError = 0;
-static int sDefaultOutputDeviceID;
-static int sDefaultInputDeviceID;
-
-/************************************************************************************/
-/****************** Prototypes ******************************************************/
-/************************************************************************************/
-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 int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerBuffer, double sampleRate );
-static double *PaMac_GetSampleRatesFromHandle ( int numRates, Handle h );
-static PaError PaMac_ScanInputDevices( void );
-static PaError PaMac_ScanOutputDevices( void );
-static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad );
-static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad );
-static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader );
-static void PaMac_EndLoadCalculation( internalPortAudioStream *past );
-static void PaMac_PlayNext ( internalPortAudioStream *past, int index );
-static long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index );
-static pascal void PaMac_InputCompletionProc(SPBPtr recParams);
-static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCmd);
-static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index );
-long PaHost_GetTotalBufferFrames( internalPortAudioStream *past );
-static int Mac_IsVirtualMemoryOn( void );
-static void PToCString(unsigned char* inString, char* outString);
-char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf );
-char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf );
-int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf );
-int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf );
-int MultiBuffer_IsWriteable( MultiBuffer *mbuf );
-int MultiBuffer_IsReadable( MultiBuffer *mbuf );
-void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf );
-void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf );
-
-/*************************************************************************
-** Simple FIFO index control for multiple buffers.
-** Read and Write indices range from 0 to 2N-1.
-** This allows us to distinguish between full and empty.
-*/
-char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf )
-{
- return mbuf->buffers[mbuf->nextWrite % mbuf->numBuffers];
-}
-char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf )
-{
- return mbuf->buffers[mbuf->nextRead % mbuf->numBuffers];
-}
-int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf )
-{
- return mbuf->nextRead % mbuf->numBuffers;
-}
-int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf )
-{
- return mbuf->nextWrite % mbuf->numBuffers;
-}
-
-int MultiBuffer_IsWriteable( MultiBuffer *mbuf )
-{
- int bufsFull = mbuf->nextWrite - mbuf->nextRead;
- if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers);
- return (bufsFull < mbuf->numBuffers);
-}
-int MultiBuffer_IsReadable( MultiBuffer *mbuf )
-{
- int bufsFull = mbuf->nextWrite - mbuf->nextRead;
- if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers);
- return (bufsFull > 0);
-}
-void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf )
-{
- int temp = mbuf->nextRead + 1;
- mbuf->nextRead = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp;
-}
-void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf )
-{
- int temp = mbuf->nextWrite + 1;
- mbuf->nextWrite = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp;
-}
-
-/*************************************************************************
-** String Utility by Chris Rolfe
-*/
-static void PToCString(unsigned char* inString, char* outString)
-{
- long i;
- for(i=0; i<inString[0]; i++) /* convert Pascal to C string */
- outString[i] = inString[i+1];
- outString[i]=0;
-}
-
-/*************************************************************************/
-PaError PaHost_Term( void )
-{
- int i;
- PaDeviceInfo *dev;
- double *rates;
- /* Free any allocated sample rate arrays. */
- for( i=0; i<sNumDevices; i++ )
- {
- dev = &sDevices[i].pad_Info;
- rates = (double *) dev->sampleRates;
- if( (rates != NULL) ) free( rates ); /* MEM_011 */
- dev->sampleRates = NULL;
- if( dev->name != NULL ) free( (void *) dev->name ); /* MEM_010 */
- dev->name = NULL;
- }
- sNumDevices = 0;
- return paNoError;
-}
-
-/*************************************************************************
- PaHost_Init() is the library initialization function - call this before
- using the library.
-*/
-PaError PaHost_Init( void )
-{
- PaError err;
- NumVersionVariant version;
-
- version.parts = SndSoundManagerVersion();
- DBUG(("SndSoundManagerVersion = 0x%x\n", version.whole));
-
- /* Have we already initialized the device info? */
- err = (PaError) Pa_CountDevices();
- if( err < 0 ) return err;
- else return paNoError;
-}
-
-/*************************************************************************
- PaMac_ScanOutputDevices() queries the properties of all output devices.
-*/
-static PaError PaMac_ScanOutputDevices( void )
-{
- PaError err;
- Component identifier=0;
- ComponentDescription criteria = { kSoundOutputDeviceType, 0, 0, 0, 0 };
- long numComponents, i;
-
- /* Search the system linked list for output components */
- numComponents = CountComponents (&criteria);
- identifier = 0;
- sDefaultOutputDeviceID = sNumDevices; /* FIXME - query somehow */
- for (i = 0; i < numComponents; i++)
- {
- /* passing nil returns first matching component. */
- identifier = FindNextComponent( identifier, &criteria);
- sDevices[sNumDevices].pad_Identifier = identifier;
-
- /* Set up for default OUTPUT devices. */
- err = PaMac_QueryOutputDeviceInfo( identifier, &sDevices[sNumDevices] );
- if( err < 0 ) return err;
- else sNumDevices++;
-
- }
-
- return paNoError;
-}
-
-/*************************************************************************
- PaMac_ScanInputDevices() queries the properties of all input devices.
-*/
-static PaError PaMac_ScanInputDevices( void )
-{
- Str255 deviceName;
- int count;
- Handle iconHandle;
- PaError err;
- OSErr oserr;
- count = 1;
- sDefaultInputDeviceID = sNumDevices; /* FIXME - query somehow */ /* PLB20010415 - was setting sDefaultOutputDeviceID */
- while(true)
- {
- /* Thanks Chris Rolfe and Alberto Ricci for this trick. */
- oserr = SPBGetIndexedDevice(count++, deviceName, &iconHandle);
- DBUG(("PaMac_ScanInputDevices: SPBGetIndexedDevice returned %d\n", oserr ));
-#if 1
- /* PLB20010415 - was giving error for anything other than siBadSoundInDevice, but some Macs may return other errors! */
- if(oserr != noErr) break; /* Some type of error is expected when count > devices */
-#else
- if(oserr == siBadSoundInDevice)
- { /* it's expected when count > devices */
- oserr = noErr;
- break;
- }
- if(oserr != noErr)
- {
- ERR_RPT(("ERROR: SPBGetIndexedDevice(%d,,) returned %d\n", count-1, oserr ));
- sPaHostError = oserr;
- return paHostError;
- }
-#endif
- DisposeHandle(iconHandle); /* Don't need the icon */
-
- err = PaMac_QueryInputDeviceInfo( deviceName, &sDevices[sNumDevices] );
- DBUG(("PaMac_ScanInputDevices: PaMac_QueryInputDeviceInfo returned %d\n", err ));
- if( err < 0 ) return err;
- else if( err == 1 ) sNumDevices++;
- }
-
- return paNoError;
-}
-
-/* Sample rate info returned by using siSampleRateAvailable selector in SPBGetDeviceInfo() */
-/* Thanks to Chris Rolfe for help with this query. */
-#pragma options align=mac68k
-typedef struct
-{
- int16 numRates;
- UnsignedFixed (**rates)[]; /* Handle created by SPBGetDeviceInfo */
-}
-SRateInfo;
-#pragma options align=reset
-
-/*************************************************************************
-** PaMac_QueryOutputDeviceInfo()
-** Query information about a named output device.
-** Clears contents of ipad and writes info based on queries.
-** Return one if OK,
-** zero if device cannot be used,
-** or negative error.
-*/
-static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad )
-{
- int len;
- OSErr err;
- PaDeviceInfo *dev = &ipad->pad_Info;
- SRateInfo srinfo = {0};
- int numRates;
- ComponentDescription tempD;
- Handle nameH=nil, infoH=nil, iconH=nil;
-
- memset( ipad, 0, sizeof(internalPortAudioDevice) );
-
- dev->structVersion = 1;
- dev->maxInputChannels = 0;
- dev->maxOutputChannels = 2;
- dev->nativeSampleFormats = paInt16; /* FIXME - query to see if 24 or 32 bit data can be handled. */
-
- /* Get sample rates supported. */
- err = GetSoundOutputInfo(identifier, siSampleRateAvailable, (Ptr) &srinfo);
- if(err != noErr)
- {
- ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetSoundOutputInfo siSampleRateAvailable returned %d\n", err ));
- goto error;
- }
- numRates = srinfo.numRates;
- DBUG(("PaMac_QueryOutputDeviceInfo: srinfo.numRates = 0x%x\n", srinfo.numRates ));
- if( numRates == 0 )
- {
- dev->numSampleRates = -1;
- numRates = 2;
- }
- else
- {
- dev->numSampleRates = numRates;
- }
- dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates );
- /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */
- DisposeHandle((Handle) srinfo.rates);
-
- /* Device name */
- /* we pass an existing handle for the component name;
- we don't care about the info (type, subtype, etc.) or icon, so set them to nil */
- infoH = nil;
- iconH = nil;
- nameH = NewHandle(0);
- if(nameH == nil) return paInsufficientMemory;
- err = GetComponentInfo(identifier, &tempD, nameH, infoH, iconH);
- if (err)
- {
- ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetComponentInfo returned %d\n", err ));
- goto error;
- }
- len = (*nameH)[0] + 1;
- dev->name = (char *) malloc(len); /* MEM_010 */
- if( dev->name == NULL )
- {
- DisposeHandle(nameH);
- return paInsufficientMemory;
- }
- else
- {
- PToCString((unsigned char *)(*nameH), (char *) dev->name);
- DisposeHandle(nameH);
- }
-
- DBUG(("PaMac_QueryOutputDeviceInfo: dev->name = %s\n", dev->name ));
- return paNoError;
-
-error:
- sPaHostError = err;
- return paHostError;
-
-}
-
-/*************************************************************************
-** PaMac_QueryInputDeviceInfo()
-** Query information about a named input device.
-** Clears contents of ipad and writes info based on queries.
-** Return one if OK,
-** zero if device cannot be used,
-** or negative error.
-*/
-static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad )
-{
- PaError result = paNoError;
- int len;
- OSErr err;
- long mRefNum = 0;
- long tempL;
- int16 tempS;
- Fixed tempF;
- PaDeviceInfo *dev = &ipad->pad_Info;
- SRateInfo srinfo = {0};
- int numRates;
-
- memset( ipad, 0, sizeof(internalPortAudioDevice) );
- dev->maxOutputChannels = 0;
-
- /* Open device based on name. If device is in use, it may not be able to open in write mode. */
- err = SPBOpenDevice( deviceName, siWritePermission, &mRefNum);
- if (err)
- {
- /* If device is in use, it may not be able to open in write mode so try read mode. */
- err = SPBOpenDevice( deviceName, siReadPermission, &mRefNum);
- if (err)
- {
- ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBOpenDevice returned %d\n", err ));
- sPaHostError = err;
- return paHostError;
- }
- }
-
- /* Define macros for printing out device info. */
-#define PrintDeviceInfo(selector,var) \
- err = SPBGetDeviceInfo(mRefNum, selector, (Ptr) &var); \
- if (err) { \
- DBUG(("query %s failed\n", #selector )); \
- }\
- else { \
- DBUG(("query %s = 0x%x\n", #selector, var )); \
- }
-
- PrintDeviceInfo( siContinuous, tempS );
- PrintDeviceInfo( siAsync, tempS );
- PrintDeviceInfo( siNumberChannels, tempS );
- PrintDeviceInfo( siSampleSize, tempS );
- PrintDeviceInfo( siSampleRate, tempF );
- PrintDeviceInfo( siChannelAvailable, tempS );
- PrintDeviceInfo( siActiveChannels, tempL );
- PrintDeviceInfo( siDeviceBufferInfo, tempL );
-
- err = SPBGetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL);
- if (err == 0) DBUG(("%s = 0x%x\n", "siActiveChannels", tempL ));
- /* Can we use this device? */
- err = SPBGetDeviceInfo(mRefNum, siAsync, (Ptr) &tempS);
- if (err)
- {
- ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siAsync returned %d\n", err ));
- goto error;
- }
- if( tempS == 0 ) goto useless; /* Does not support async recording so forget about it. */
-
- err = SPBGetDeviceInfo(mRefNum, siChannelAvailable, (Ptr) &tempS);
- if (err)
- {
- ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siChannelAvailable returned %d\n", err ));
- goto error;
- }
- dev->maxInputChannels = tempS;
-
- /* Get sample rates supported. */
- err = SPBGetDeviceInfo(mRefNum, siSampleRateAvailable, (Ptr) &srinfo);
- if (err)
- {
- ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleRateAvailable returned %d\n", err ));
- goto error;
- }
-
- numRates = srinfo.numRates;
- DBUG(("numRates = 0x%x\n", numRates ));
- if( numRates == 0 )
- {
- dev->numSampleRates = -1;
- numRates = 2;
- }
- else
- {
- dev->numSampleRates = numRates;
- }
- dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates );
- /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */
- DisposeHandle((Handle) srinfo.rates);
-
- /* Get size of device buffer. */
- err = SPBGetDeviceInfo(mRefNum, siDeviceBufferInfo, (Ptr) &tempL);
- if (err)
- {
- ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siDeviceBufferInfo returned %d\n", err ));
- goto error;
- }
- ipad->pad_DeviceBufferSize = tempL;
- DBUG(("siDeviceBufferInfo = %d\n", tempL ));
-
- /* Set format based on sample size. */
- err = SPBGetDeviceInfo(mRefNum, siSampleSize, (Ptr) &tempS);
- if (err)
- {
- ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleSize returned %d\n", err ));
- goto error;
- }
- switch( tempS )
- {
- case 0x0020:
- dev->nativeSampleFormats = paInt32; /* FIXME - warning, code probably won't support this! */
- break;
- case 0x0010:
- default: /* FIXME - What about other formats? */
- dev->nativeSampleFormats = paInt16;
- break;
- }
- DBUG(("nativeSampleFormats = %d\n", dev->nativeSampleFormats ));
-
- /* Device name */
- len = deviceName[0] + 1; /* Get length of Pascal string */
- dev->name = (char *) malloc(len); /* MEM_010 */
- if( dev->name == NULL )
- {
- result = paInsufficientMemory;
- goto cleanup;
- }
- PToCString(deviceName, (char *) dev->name);
- DBUG(("deviceName = %s\n", dev->name ));
- result = (PaError) 1;
- /* All done so close up device. */
-cleanup:
- if( mRefNum ) SPBCloseDevice(mRefNum);
- return result;
-
-error:
- if( mRefNum ) SPBCloseDevice(mRefNum);
- sPaHostError = err;
- return paHostError;
-
-useless:
- if( mRefNum ) SPBCloseDevice(mRefNum);
- return (PaError) 0;
-}
-
-/*************************************************************************
-** Allocate a double array and fill it with listed sample rates.
-*/
-static double * PaMac_GetSampleRatesFromHandle ( int numRates, Handle h )
-{
- OSErr err = noErr;
- SInt8 hState;
- int i;
- UnsignedFixed *fixedRates;
- double *rates = (double *) malloc( numRates * sizeof(double) ); /* MEM_011 */
- if( rates == NULL ) return NULL;
- /* Save and restore handle state as suggested by TechNote at:
- http://developer.apple.com/technotes/tn/tn1122.html
- */
- hState = HGetState (h);
- if (!(err = MemError ()))
- {
- HLock (h);
- if (!(err = MemError ( )))
- {
- fixedRates = (UInt32 *) *h;
- for( i=0; i<numRates; i++ )
- {
- rates[i] = UnsignedFixedToDouble(fixedRates[i]);
- }
-
- HSetState (h,hState);
- err = MemError ( );
- }
- }
- if( err )
- {
- free( rates );
- ERR_RPT(("Error in PaMac_GetSampleRatesFromHandle = %d\n", err ));
- }
- return rates;
-}
-
-/*************************************************************************/
-int Pa_CountDevices()
-{
- PaError err;
- DBUG(("Pa_CountDevices()\n"));
- /* If no devices, go find some. */
- if( sNumDevices <= 0 )
- {
- err = PaMac_ScanOutputDevices();
- if( err != paNoError ) goto error;
- err = PaMac_ScanInputDevices();
- if( err != paNoError ) goto error;
- }
- return sNumDevices;
-
-error:
- PaHost_Term();
- DBUG(("Pa_CountDevices: returns %d\n", err ));
- return err;
-
-}
-
-/*************************************************************************/
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
-{
- if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
- return &sDevices[id].pad_Info;
-}
-/*************************************************************************/
-PaDeviceID Pa_GetDefaultInputDeviceID( void )
-{
- return sDefaultInputDeviceID;
-}
-
-/*************************************************************************/
-PaDeviceID Pa_GetDefaultOutputDeviceID( void )
-{
- return sDefaultOutputDeviceID;
-}
-
-/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
-static void PaMac_StartLoadCalculation( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- UnsignedWide widePad;
- if( pahsc == NULL ) return;
- /* Query system timer for usage analysis and to prevent overuse of CPU. */
- Microseconds( &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;
- 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_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);
-
-}
-
-/***********************************************************************
-** Called by Pa_StartStream()
-*/
-PaError PaHost_StartInput( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- pahsc->pahsc_IsRecording = 0;
- pahsc->pahsc_StopRecording = 0;
- pahsc->pahsc_InputMultiBuffer.nextWrite = 0;
- pahsc->pahsc_InputMultiBuffer.nextRead = 0;
- return PaMac_RecordNext( past );
-}
-
-/***********************************************************************
-** Called by Pa_StopStream().
-** May be called during error recovery or cleanup code
-** so protect against NULL pointers.
-*/
-PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
-{
- int32 timeOutMsec;
- PaError result = paNoError;
- OSErr err = 0;
- long mRefNum;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return paNoError;
-
- (void) abort;
-
- mRefNum = pahsc->pahsc_InputRefNum;
-
- DBUG(("PaHost_StopInput: mRefNum = %d\n", mRefNum ));
- if( mRefNum )
- {
- DBUG(("PaHost_StopInput: pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording ));
- if( pahsc->pahsc_IsRecording )
- {
- /* PLB20010420 - Fix TIMEOUT in record mode. */
- pahsc->pahsc_StopRecording = 1; /* Request that we stop recording. */
- err = SPBStopRecording(mRefNum);
- DBUG(("PaHost_StopInput: then pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording ));
-
- /* Calculate timeOut longer than longest time it could take to play one buffer. */
- timeOutMsec = (int32) ((1500.0 * pahsc->pahsc_FramesPerHostBuffer) / past->past_SampleRate);
- /* Keep querying sound channel until it is no longer busy playing. */
- while( !err && pahsc->pahsc_IsRecording && (timeOutMsec > 0))
- {
- Pa_Sleep(20);
- timeOutMsec -= 20;
- }
- if( timeOutMsec <= 0 )
- {
- ERR_RPT(("PaHost_StopInput: timed out!\n"));
- return paTimedOut;
- }
- }
- }
- if( err )
- {
- sPaHostError = err;
- result = paHostError;
- }
-
- DBUG(("PaHost_StopInput: finished.\n", mRefNum ));
- return result;
-}
-
-/***********************************************************************/
-static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader )
-{
- sndHeader->numChannels = past->past_NumOutputChannels;
- sndHeader->sampleRate = DoubleToUnsignedFixed(past->past_SampleRate);
- sndHeader->loopStart = 0;
- sndHeader->loopEnd = 0;
- sndHeader->encode = cmpSH;
- sndHeader->baseFrequency = kMiddleC;
- sndHeader->markerChunk = nil;
- sndHeader->futureUse2 = nil;
- sndHeader->stateVars = nil;
- sndHeader->leftOverSamples = nil;
- sndHeader->compressionID = 0;
- sndHeader->packetSize = 0;
- sndHeader->snthID = 0;
- sndHeader->sampleSize = 8 * sizeof(int16); // FIXME - might be 24 or 32 bits some day;
- sndHeader->sampleArea[0] = 0;
- 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 )
-{
- SndCommand pauseCommand;
- SndCommand resumeCommand;
- int i;
- OSErr error;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return paInternalError;
- if( pahsc->pahsc_Channel == NULL ) return paInternalError;
-
- past->past_StopSoon = 0;
- past->past_IsActive = 1;
- pahsc->pahsc_NumOutsQueued = 0;
- pahsc->pahsc_NumOutsPlayed = 0;
-
- SetFramesDone( pahsc, 0.0 );
-
- /* Pause channel so it does not do back ground processing while we are still filling the queue. */
- pauseCommand.cmd = pauseCmd;
- pauseCommand.param1 = pauseCommand.param2 = 0;
- error = SndDoCommand (pahsc->pahsc_Channel, &pauseCommand, true);
- if (noErr != error) goto exit;
-
- /* Queue all of the buffers so we start off full. */
- for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
- {
- PaMac_PlayNext( past, i );
- }
-
- /* Resume channel now that the queue is full. */
- resumeCommand.cmd = resumeCmd;
- resumeCommand.param1 = resumeCommand.param2 = 0;
- error = SndDoImmediate( pahsc->pahsc_Channel, &resumeCommand );
- if (noErr != error) goto exit;
-
- return paNoError;
-exit:
- past->past_IsActive = 0;
- sPaHostError = error;
- ERR_RPT(("Error in PaHost_StartOutput: SndDoCommand returned %d\n", error ));
- return paHostError;
-}
-
-/*******************************************************************/
-long PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- return (long) (pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer);
-}
-
-/***********************************************************************
-** Called by Pa_StopStream().
-** May be called during error recovery or cleanup code
-** so protect against NULL pointers.
-*/
-PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
-{
- int32 timeOutMsec;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return paNoError;
- if( pahsc->pahsc_Channel == NULL ) return paNoError;
-
- DBUG(("PaHost_StopOutput()\n"));
- if( past->past_IsActive == 0 ) return paNoError;
-
- /* Set flags for callback function to see. */
- if( abort ) past->past_StopNow = 1;
- past->past_StopSoon = 1;
- /* Calculate timeOut longer than longest time it could take to play all buffers. */
- timeOutMsec = (int32) ((1500.0 * PaHost_GetTotalBufferFrames( past )) / past->past_SampleRate);
- /* Keep querying sound channel until it is no longer busy playing. */
- while( past->past_IsActive && (timeOutMsec > 0))
- {
- Pa_Sleep(20);
- timeOutMsec -= 20;
- }
- if( timeOutMsec <= 0 )
- {
- ERR_RPT(("PaHost_StopOutput: timed out!\n"));
- return paTimedOut;
- }
- else return paNoError;
-}
-
-/***********************************************************************/
-PaError PaHost_StartEngine( internalPortAudioStream *past )
-{
- (void) past; /* Prevent unused variable warnings. */
- return paNoError;
-}
-
-/***********************************************************************/
-PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
-{
- (void) past; /* Prevent unused variable warnings. */
- (void) abort; /* Prevent unused variable warnings. */
- return paNoError;
-}
-/***********************************************************************/
-PaError PaHost_StreamActive( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- return (PaError) ( past->past_IsActive + pahsc->pahsc_IsRecording );
-}
-int Mac_IsVirtualMemoryOn( void )
-{
- long attr;
- OSErr result = Gestalt( gestaltVMAttr, &attr );
- DBUG(("gestaltVMAttr : 0x%x\n", attr ));
- return ((attr >> gestaltVMHasPagingControl ) & 1);
-}
-
-/*******************************************************************
-* Determine number of host Buffers
-* and how many User Buffers we can put into each host buffer.
-*/
-static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- int32 minNumBuffers;
- int32 minFramesPerHostBuffer;
- int32 minTotalFrames;
- int32 userBuffersPerHostBuffer;
- int32 framesPerHostBuffer;
- int32 numHostBuffers;
-
- 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 );
-
- 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. */
- if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer )
- {
- userBuffersPerHostBuffer =
- (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) /
- past->past_FramesPerUserBuffer;
- }
- else
- {
- userBuffersPerHostBuffer = 1;
- }
- framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
-
- /* Calculate number of host buffers needed. Round up to cover minTotalFrames. */
- numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
- /* Make sure we have enough host 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. */
- while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS)
- {
- userBuffersPerHostBuffer += 1;
- framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
- numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
- }
- }
-
- 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 *past )
-{
- OSErr err;
- PaError result = paHostError;
- PaHostSoundControl *pahsc;
- int i;
- /* Allocate and initialize host data. */
- pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
- if( pahsc == NULL )
- {
- return paInsufficientMemory;
- }
- past->past_DeviceData = (void *) pahsc;
-
- /* If recording, and virtual memory is turned on, then use bigger buffers to prevent glitches. */
- if( (past->past_NumInputChannels > 0) && Mac_IsVirtualMemoryOn() )
- {
- pahsc->pahsc_MinFramesPerHostBuffer = MAC_VIRTUAL_FRAMES_PER_BUFFER;
- }
- else
- {
- pahsc->pahsc_MinFramesPerHostBuffer = MAC_PHYSICAL_FRAMES_PER_BUFFER;
- }
-
- 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 )
- {
- /* Create sound channel to which we can send commands. */
- pahsc->pahsc_Channel = 0L;
- err = SndNewChannel(&pahsc->pahsc_Channel, sampledSynth, 0, nil); /* FIXME - use kUseOptionalOutputDevice if not default. */
- if(err != 0)
- {
- ERR_RPT(("Error in PaHost_OpenStream: SndNewChannel returned 0x%x\n", err ));
- goto error;
- }
-
- /* Install our callback function pointer straight into the sound channel structure */
- /* Use new CARBON name for callback procedure. */
-#if TARGET_API_MAC_CARBON
- pahsc->pahsc_OutputCompletionProc = NewSndCallBackUPP(PaMac_OutputCompletionProc);
-#else
- pahsc->pahsc_OutputCompletionProc = NewSndCallBackProc(PaMac_OutputCompletionProc);
-#endif
-
- pahsc->pahsc_Channel->callBack = pahsc->pahsc_OutputCompletionProc;
-
- pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumOutputChannels * sizeof(int16);
- for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
- {
- char *buf = (char *)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer);
- if (buf == NULL)
- {
- ERR_RPT(("Error in PaHost_OpenStream: could not allocate output buffer. Size = \n", pahsc->pahsc_BytesPerOutputHostBuffer ));
- goto memerror;
- }
-
- PaMac_InitSoundHeader( past, &pahsc->pahsc_SoundHeaders[i] );
- pahsc->pahsc_SoundHeaders[i].samplePtr = buf;
- pahsc->pahsc_SoundHeaders[i].numFrames = (unsigned long) pahsc->pahsc_FramesPerHostBuffer;
-
- }
- }
-#ifdef SUPPORT_AUDIO_CAPTURE
- /* ------------------ INPUT */
- /* Use double buffer scheme that matches output. */
- if( past->past_NumInputChannels > 0 )
- {
- int16 tempS;
- long tempL;
- Fixed tempF;
- long mRefNum;
- unsigned char noname = 0; /* FIXME - use real device names. */
-#if TARGET_API_MAC_CARBON
- pahsc->pahsc_InputCompletionProc = NewSICompletionUPP((SICompletionProcPtr)PaMac_InputCompletionProc);
-#else
- pahsc->pahsc_InputCompletionProc = NewSICompletionProc((ProcPtr)PaMac_InputCompletionProc);
-#endif
- pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumInputChannels * sizeof(int16);
- for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
- {
- char *buf = (char *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer);
- if ( buf == NULL )
- {
- ERR_RPT(("PaHost_OpenStream: could not allocate input buffer. Size = \n", pahsc->pahsc_BytesPerInputHostBuffer ));
- goto memerror;
- }
- pahsc->pahsc_InputMultiBuffer.buffers[i] = buf;
- }
- pahsc->pahsc_InputMultiBuffer.numBuffers = pahsc->pahsc_NumHostBuffers;
-
- err = SPBOpenDevice( (const unsigned char *) &noname, siWritePermission, &mRefNum); /* FIXME - use name so we get selected device */
- // FIXME err = SPBOpenDevice( (const unsigned char *) sDevices[past->past_InputDeviceID].pad_Info.name, siWritePermission, &mRefNum);
- if (err) goto error;
- pahsc->pahsc_InputRefNum = mRefNum;
- DBUG(("PaHost_OpenStream: mRefNum = %d\n", mRefNum ));
-
- /* Set input device characteristics. */
- tempS = 1;
- err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS);
- if (err)
- {
- ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siContinuous returned %d\n", err ));
- goto error;
- }
-
- tempL = 0x03;
- err = SPBSetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL);
- if (err)
- {
- DBUG(("PaHost_OpenStream: setting siActiveChannels returned 0x%x. Error ignored.\n", err ));
- }
-
- /* PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. */
- tempS = past->past_NumInputChannels;
- err = SPBSetDeviceInfo(mRefNum, siNumberChannels, (Ptr) &tempS);
- if (err)
- {
- ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siNumberChannels returned %d\n", err ));
- goto error;
- }
-
- tempF = ((unsigned long)past->past_SampleRate) << 16;
- err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF);
- if (err)
- {
- ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siSampleRate returned %d\n", err ));
- goto error;
- }
-
- /* Setup record-parameter block */
- pahsc->pahsc_InputParams.inRefNum = mRefNum;
- pahsc->pahsc_InputParams.milliseconds = 0; // not used
- pahsc->pahsc_InputParams.completionRoutine = pahsc->pahsc_InputCompletionProc;
- pahsc->pahsc_InputParams.interruptRoutine = 0;
- pahsc->pahsc_InputParams.userLong = (long) past;
- pahsc->pahsc_InputParams.unused1 = 0;
- }
-#endif /* SUPPORT_AUDIO_CAPTURE */
- DBUG(("PaHost_OpenStream: complete.\n"));
- return paNoError;
-
-error:
- PaHost_CloseStream( past );
- ERR_RPT(("PaHost_OpenStream: sPaHostError = 0x%x.\n", err ));
- sPaHostError = err;
- return paHostError;
-
-memerror:
- PaHost_CloseStream( past );
- return paInsufficientMemory;
-}
-
-/***********************************************************************
-** Called by Pa_CloseStream().
-** May be called during error recovery or cleanup code
-** so protect against NULL pointers.
-*/
-PaError PaHost_CloseStream( internalPortAudioStream *past )
-{
- PaError result = paNoError;
- OSErr err = 0;
- int i;
- PaHostSoundControl *pahsc;
-
- DBUG(("PaHost_CloseStream( 0x%x )\n", past ));
-
- if( past == NULL ) return paBadStreamPtr;
-
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return paNoError;
-
- if( past->past_NumOutputChannels > 0 )
- {
- /* TRUE means flush now instead of waiting for quietCmd to be processed. */
- if( pahsc->pahsc_Channel != NULL ) SndDisposeChannel(pahsc->pahsc_Channel, TRUE);
- {
- for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
- {
- Ptr p = (Ptr) pahsc->pahsc_SoundHeaders[i].samplePtr;
- if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerOutputHostBuffer );
- }
- }
- }
-
- if( past->past_NumInputChannels > 0 )
- {
- if( pahsc->pahsc_InputRefNum )
- {
- err = SPBCloseDevice(pahsc->pahsc_InputRefNum);
- pahsc->pahsc_InputRefNum = 0;
- if( err )
- {
- sPaHostError = err;
- result = paHostError;
- }
- }
- {
- for (i = 0; i<pahsc->pahsc_InputMultiBuffer.numBuffers; i++)
- {
- Ptr p = (Ptr) pahsc->pahsc_InputMultiBuffer.buffers[i];
- if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerInputHostBuffer );
- }
- }
- }
-
- past->past_DeviceData = NULL;
- PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) );
-
- DBUG(("PaHost_CloseStream: complete.\n", past ));
- return result;
-}
-/*************************************************************************/
-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 );
-}
-/*************************************************************************/
-static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerUserBuffer, double sampleRate )
-{
- int minUserPerHost = ( minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer;
- int numBufs = PA_MIN_NUM_HOST_BUFFERS * minUserPerHost;
- if( numBufs < PA_MIN_NUM_HOST_BUFFERS ) numBufs = PA_MIN_NUM_HOST_BUFFERS;
- (void) sampleRate;
- return numBufs;
-}
-
-/*************************************************************************/
-void Pa_Sleep( int32 msec )
-{
- EventRecord event;
- int32 sleepTime, endTime;
- /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */
- sleepTime = ((msec * 60) + 999) / 1000;
- if( sleepTime < 1 ) sleepTime = 1;
- endTime = TickCount() + sleepTime;
- do
- {
- DBUGX(("Sleep for %d ticks.\n", sleepTime ));
- /* Use WaitNextEvent() to sleep without getting events. */
- /* PLB20010907 - Pass unused event to WaitNextEvent instead of NULL to prevent
- * Mac OSX crash. Thanks Dominic Mazzoni. */
- WaitNextEvent( 0, &event, sleepTime, NULL );
- sleepTime = endTime - TickCount();
- }
- while( sleepTime > 0 );
-}
-/*************************************************************************/
-int32 Pa_GetHostError( void )
-{
- int32 err = sPaHostError;
- sPaHostError = 0;
- return err;
-}
-
-/*************************************************************************
- * 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.
- * This call MUST be balanced with a call to PaHost_FreeFastMemory().
- */
-void *PaHost_AllocateFastMemory( long numBytes )
-{
- void *addr = NewPtrClear( numBytes );
- if( (addr == NULL) || (MemError () != 0) ) return NULL;
-
-#if (TARGET_API_MAC_CARBON == 0)
- if( HoldMemory( addr, numBytes ) != noErr )
- {
- DisposePtr( (Ptr) addr );
- return NULL;
- }
-#endif
- 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 == NULL ) return;
-#if TARGET_API_MAC_CARBON
- (void) numBytes;
-#else
- UnholdMemory( addr, numBytes );
-#endif
- DisposePtr( (Ptr) addr );
-}
-
-/*************************************************************************/
-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;
-}
-
-/**************************************************************************
-** Callback for Input, SPBRecord()
-*/
-int gRecordCounter = 0;
-int gPlayCounter = 0;
-pascal void PaMac_InputCompletionProc(SPBPtr recParams)
-{
- PaError result = paNoError;
- int finished = 1;
- internalPortAudioStream *past;
- PaHostSoundControl *pahsc;
-
- gRecordCounter += 1; /* debug hack to see if engine running */
-
- /* Get our PA data from Mac structure. */
- past = (internalPortAudioStream *) recParams->userLong;
- if( past == NULL ) return;
-
- if( past->past_Magic != PA_MAGIC )
- {
- AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, past", (long) past );
- AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, magic", (long) past->past_Magic );
- goto error;
- }
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
- past->past_NumCallbacks += 1;
-
- /* Have we been asked to stop recording? */
- if( (recParams->error == abortErr) || pahsc->pahsc_StopRecording ) goto error;
-
- /* If there are no output channels, then we need to call the user callback function from here.
- * Otherwise we will call the user code during the output completion routine.
- */
- if(past->past_NumOutputChannels == 0)
- {
- SetFramesDone( pahsc,
- pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
- result = PaMac_CallUserLoop( past, NULL );
- }
-
- /* Did user code ask us to stop? If not, issue another recording request. */
- if( (result == paNoError) && (pahsc->pahsc_StopRecording == 0) )
- {
- result = PaMac_RecordNext( past );
- if( result != paNoError ) pahsc->pahsc_IsRecording = 0;
- }
- else goto error;
-
- return;
-
-error:
- pahsc->pahsc_IsRecording = 0;
- pahsc->pahsc_StopRecording = 0;
- return;
-}
-
-/***********************************************************************
-** Called by either input or output completion proc.
-** Grabs input data if any present, and calls PA conversion code,
-** that in turn calls user code.
-*/
-static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr )
-{
- PaError result = paNoError;
- 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)
- {
- if( MultiBuffer_IsReadable( &pahsc->pahsc_InputMultiBuffer ) )
- {
- inPtr = (int16 *) MultiBuffer_GetNextReadBuffer( &pahsc->pahsc_InputMultiBuffer );
- MultiBuffer_AdvanceReadIndex( &pahsc->pahsc_InputMultiBuffer );
- }
- }
-
- /* 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;
- }
- }
-
- PaMac_EndLoadCalculation( past );
- }
- return result;
-}
-
-/***********************************************************************
-** Setup next recording buffer in FIFO and issue recording request to Snd Input Manager.
-*/
-static PaError PaMac_RecordNext( internalPortAudioStream *past )
-{
- PaError result = paNoError;
- OSErr err;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- /* Get pointer to next buffer to record into. */
- pahsc->pahsc_InputParams.bufferPtr = MultiBuffer_GetNextWriteBuffer( &pahsc->pahsc_InputMultiBuffer );
-
- /* Advance write index if there is room. Otherwise keep writing same buffer. */
- if( MultiBuffer_IsWriteable( &pahsc->pahsc_InputMultiBuffer ) )
- {
- MultiBuffer_AdvanceWriteIndex( &pahsc->pahsc_InputMultiBuffer );
- }
-
- AddTraceMessage("PaMac_RecordNext: bufferPtr", (long) pahsc->pahsc_InputParams.bufferPtr );
- AddTraceMessage("PaMac_RecordNext: nextWrite", pahsc->pahsc_InputMultiBuffer.nextWrite );
-
- /* Setup parameters and issue an asynchronous recording request. */
- pahsc->pahsc_InputParams.bufferLength = pahsc->pahsc_BytesPerInputHostBuffer;
- pahsc->pahsc_InputParams.count = pahsc->pahsc_BytesPerInputHostBuffer;
- err = SPBRecord(&pahsc->pahsc_InputParams, true);
- if( err )
- {
- AddTraceMessage("PaMac_RecordNext: SPBRecord error ", err );
- sPaHostError = err;
- result = paHostError;
- }
- else
- {
- pahsc->pahsc_IsRecording = 1;
- }
- return result;
-}
-
-/**************************************************************************
-** Callback for Output Playback()
-** Return negative error, 0 to continue, 1 to stop.
-*/
-long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index )
-{
- PaHostSoundControl *pahsc;
- long result = 0;
- int finished = 1;
- char *outPtr;
-
- gPlayCounter += 1; /* debug hack */
-
- past->past_NumCallbacks += 1;
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return -1;
- /* Are we nested?! */
- if( pahsc->pahsc_IfInsideCallback ) return 0;
- pahsc->pahsc_IfInsideCallback = 1;
- /* Get pointer to buffer to fill. */
- outPtr = pahsc->pahsc_SoundHeaders[index].samplePtr;
- /* Combine with any sound input, and call user callback. */
- result = PaMac_CallUserLoop( past, (int16 *) outPtr );
-
- pahsc->pahsc_IfInsideCallback = 0;
- return result;
-}
-
-/*************************************************************************************
-** Called by SoundManager when ready for another buffer.
-*/
-static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd)
-{
- internalPortAudioStream *past;
- PaHostSoundControl *pahsc;
- (void) theChannel;
- (void) theCallBackCmd;
-
- /* Get our data from Mac structure. */
- past = (internalPortAudioStream *) theCallBackCmd->param2;
- if( past == NULL ) return;
-
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
- pahsc->pahsc_NumOutsPlayed += 1;
-
- SetFramesDone( pahsc,
- pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
-
- PaMac_BackgroundManager( past, theCallBackCmd->param1 );
-}
-
-/*******************************************************************/
-static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index )
-{
- PaError result = paNoError;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- /* Has someone asked us to abort by calling Pa_AbortStream()? */
- if( past->past_StopNow )
- {
- SndCommand command;
- /* Clear the queue of any pending commands. */
- command.cmd = flushCmd;
- command.param1 = command.param2 = 0;
- SndDoImmediate( pahsc->pahsc_Channel, &command );
- /* Then stop currently playing buffer, if any. */
- command.cmd = quietCmd;
- SndDoImmediate( pahsc->pahsc_Channel, &command );
- past->past_IsActive = 0;
- }
- /* Has someone asked us to stop by calling Pa_StopStream()
- * OR has a user callback returned '1' to indicate finished.
- */
- else if( past->past_StopSoon )
- {
- if( (pahsc->pahsc_NumOutsQueued - pahsc->pahsc_NumOutsPlayed) <= 0 )
- {
- past->past_IsActive = 0; /* We're finally done. */
- }
- }
- else
- {
- PaMac_PlayNext( past, index );
- }
- return result;
-}
-
-/*************************************************************************************
-** Fill next buffer with sound and queue it for playback.
-*/
-static void PaMac_PlayNext ( internalPortAudioStream *past, int index )
-{
- OSErr error;
- long result;
- SndCommand playCmd;
- SndCommand callbackCmd;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
-
- /* 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;
- callbackCmd.param2 = (long)past;
- error = SndDoCommand (pahsc->pahsc_Channel, &callbackCmd, true );
- if( error != noErr ) goto gotError;
- pahsc->pahsc_NumOutsQueued += 1;
-
- return;
-
-gotError:
- sPaHostError = error;
-done:
- return;
-}
diff --git a/pd/portaudio/pa_sgi/pa_sgi.c b/pd/portaudio/pa_sgi/pa_sgi.c
deleted file mode 100644
index 8b45d09d..00000000
--- a/pd/portaudio/pa_sgi/pa_sgi.c
+++ /dev/null
@@ -1,1417 +0,0 @@
-/*
- * $Id: pa_sgi.c,v 1.2.2.20 2004/01/03 19:20:09 pieter Exp $
- * PortAudio Portable Real-Time Audio Library.
- * Latest Version at: http://www.portaudio.com.
- * Silicon Graphics (SGI) IRIX implementation by Pieter Suurmond.
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-/** @file
- @brief SGI IRIX AL implementation (according to V19 API version 2.0).
-
- @note This file started as a copy of pa_skeleton.c (v 1.1.2.35 2003/09/20), it
- has nothing to do with the old V18 pa_sgi version: this implementation uses the
- newer IRIX AL calls and uses pthreads instead of sproc.
-
- On IRIX, one may type './configure' followed by 'gmake' from the portaudio root
- directory to build the static and shared libraries, as well as all the tests.
-
- On IRIX 6.5, using 'make' instead of 'gmake' may cause Makefile to fail. (This
- happens on my machine: make does not understand syntax with 2 colons on a line,
- like this:
- $(TESTS): bin/%: [snip]
-
- Maybe this is due to an old make version(?), my only solution is: use gmake.
- Anyway, all the tests compile well now, with GCC 3.3, as well as with MIPSpro 7.2.1.
- Tested:
- - paqa_devs ok, but at a certain point digital i/o fails:
- TestAdvance: INPUT, device = 2, rate = 32000, numChannels = 1, format = 1
- Possibly, this is an illegal sr or number of channels for digital i/o.
- - paqa_errs 13 of the tests run ok, but 5 of them give weird results.
- + patest1 ok.
- + patest_buffer ok.
- + patest_callbackstop ok.
- - patest_clip ok, but hear no difference between dithering turned OFF and ON.
- + patest_hang ok.
- + patest_latency ok.
- + patest_leftright ok.
- + patest_maxsines ok.
- + patest_many ok.
- + patest_multi_sine ok.
- + patest_pink ok.
- + patest_prime ok.
- - patest_read_record ok, but playback stops a little earlier than 5 seconds it seems(?).
- + patest_record ok.
- + patest_ringmix ok.
- + patest_saw ok.
- + patest_sine ok.
- + patest_sine8 ok.
- - patest_sine_formats ok, FLOAT32 + INT16 + INT18 are OK, but UINT8 IS NOT OK!
- + patest_sine_time ok.
- + patest_start_stop ok, but under/overflow errors of course in the AL queue monitor.
- + patest_stop ok.
- - patest_sync ok?
- + patest_toomanysines ok.
- - patest_underflow ok? (stopping after SleepTime = 91: err=Stream is stopped)
- - patest_wire ok.
- + patest_write_sine ok.
- + pa_devs ok.
- Ok on an Indy, in both stereo and quadrophonic mode.
- + pa_fuzz ok.
- + pa_minlat ok.
-
- Worked on (or checked) proposals:
-
- 003: Improve Latency Specification OK, but not 100% sure: plus or minus 1 host buffer?
- 004 OK: Allow Callbacks to Accept Variable Number of Frames per Buffer.
- Simply using a fixed host buffer size. Very roughly implemented now, the adaption
- to limited-requested latencies and samplerate may be improved. At least this
- implementation chooses its own internal host buffer size (no coredumps any longer).
- 005 OK: Blocking Read/Write Interface.
- 006: Non-interleaved buffers seems OK? Covered by the buffer-processor and such?....
- 009 OK: Host error reporting should now be.
- 010 OK: State Machine and State Querying Functions.
- 011 OK: Renaming done.
- 014 Implementation Style Guidelines (sorry, my braces are not ANSI style).
- 015 OK: Callback Timestamps (During priming, though, these are still null!).
- 016 OK: Use Structs for Pa_OpenStream() Parameters.
- 019: Notify Client When All Buffers Have Played (Ok, covered by the buffer processor?)
- 020 OK: Allow Callback to prime output stream (StartStream() should do the priming)
- Should be tested more thoroughly for full duplex streams. (patest_prime seems ok).
-
-
- @todo Underrun or overflow flags at some more places.
-
- @todo Callback Timestamps during priming.
-
- @todo Improve adaption to number of channels, samplerate and such when inventing
- some frames per host buffer (when client requests 0).
-
- @todo Make a complete new version to support 'sproc'-applications.
- Or could we manage that with some clever if-defs?
- It must be clear which version we use (especially when using pa as lib!):
- an irix-sproc() version or pthread version.
-
- @todo In Makefile.in: 'make clean' does not remove lib/libportaudio.so.0.0.19.
-
- Note: Even when mono-output is requested, with ALv7, the audio library opens
- a outputs stereo. One can observe this in SGI's 'Audio Queue Monitor'.
-*/
-
-#include <string.h> /* For strlen() but also for strerror()! */
-#include <stdio.h> /* printf() */
-#include <math.h> /* fabs() */
-
-#include <dmedia/audio.h> /* IRIX AL (audio library). Link with -laudio. */
-#include <dmedia/dmedia.h> /* IRIX DL (digital media library), solely for */
- /* function dmGetUST(). Link with -ldmedia. */
-#include <errno.h> /* To catch 'oserror' after AL-calls. */
-#include <pthread.h> /* POSIX threads. */
-#include <unistd.h>
-
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-
- /* Uncomment for diagnostics: */
-#define DBUG(x) /*{ printf x; fflush(stdout); }*/
-
-
-/* prototypes for functions declared in this file */
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif /* __cplusplus */
-
-PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *ipp,
- const PaStreamParameters *opp,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-
-
-/*
- Apparently, we must use macros for reporting unanticipated host errors.
- Only in case we return paUnanticipatedHostError from an Portaudio call,
- we have to call one of the following three macro's.
- (Constant paAL is defined in pa_common/portaudio.h. See also proposal 009.)
-
- After an AL error, use this to translate the AL error code to human text:
-*/
-#define PA_SGI_SET_LAST_AL_ERROR() \
- {\
- int ee = oserror();\
- PaUtil_SetLastHostErrorInfo(paAL, ee, alGetErrorString(ee));\
- }
-/*
- But after a generic IRIX error, let strerror() translate the error code from
- the operating system and use this (strerror() gives the same as perror()):
-*/
-#define PA_SGI_SET_LAST_IRIX_ERROR() \
- {\
- int ee = oserror();\
- PaUtil_SetLastHostErrorInfo(paAL, ee, strerror(ee));\
- }
-
-/* GOT RID OF calling PaUtil_SetLastHostErrorInfo() with 0 as error number.
-- Weird samplerate difference became: paInvalidSampleRate.
-- Failing to set AL queue size became: paInternalError
- (Because I cannot decide between paBufferTooBig and paBufferTooSmall
- because it may even the 'default AL queue size that failed... Or
- should we introduce another error-code like 'paInvalidQueueSize'?... NO)
-*/
-
-/* PaSGIHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct
-{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
- PaUtilAllocationGroup* allocations;
- /* implementation specific data goes here. */
- ALvalue* sgiDeviceIDs; /* Array of AL resource device numbers. */
- /* PaHostApiIndex hostApiIndex; Hu? As in the linux and oss files? */
-}
-PaSGIHostApiRepresentation;
-
-/*
- Initialises sgiDeviceIDs array.
-*/
-PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- int e, i, deviceCount, def_in, def_out;
- PaSGIHostApiRepresentation* SGIHostApi;
- PaDeviceInfo* deviceInfoArray;
- static const short numParams = 4; /* Array with name, samplerate, channels */
- ALpv y[numParams]; /* and type. */
- static const short maxDevNameChars = 32; /* Including the terminating null char. */
- char devName[maxDevNameChars]; /* Too lazy for dynamic alloc. */
-
- /* DBUG(("PaSGI_Initialize() started.\n")); */
- SGIHostApi = (PaSGIHostApiRepresentation*)PaUtil_AllocateMemory(sizeof(PaSGIHostApiRepresentation));
- if( !SGIHostApi )
- { result = paInsufficientMemory; goto cleanup; }
- SGIHostApi->allocations = PaUtil_CreateAllocationGroup();
- if( !SGIHostApi->allocations )
- { result = paInsufficientMemory; goto cleanup; }
- *hostApi = &SGIHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paAL; /* IRIX AL type id, was paInDevelopment. */
- (*hostApi)->info.name = "SGI IRIX AL";
- (*hostApi)->info.defaultInputDevice = paNoDevice; /* Set later. */
- (*hostApi)->info.defaultOutputDevice = paNoDevice; /* Set later. */
- (*hostApi)->info.deviceCount = 0; /* We 'll increment in the loop below. */
-
- /* Determine the total number of input and output devices (thanks to Gary Scavone). */
- deviceCount = alQueryValues(AL_SYSTEM, AL_DEVICES, 0, 0, 0, 0);
- if (deviceCount < 0) /* Returns -1 in case of failure. */
- {
- DBUG(("Failed to count devices: alQueryValues()=%d; %s.\n",
- deviceCount, alGetErrorString(oserror())));
- result = paDeviceUnavailable; /* Is this an appropriate error return code? */
- goto cleanup;
- }
- if (deviceCount > 0)
- {
- (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- SGIHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount);
- if (!(*hostApi)->deviceInfos)
- { result = paInsufficientMemory; goto cleanup; }
-
- /* Allocate all device info structs in a contiguous block. */
- deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
- SGIHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount);
- if (!deviceInfoArray)
- { result = paInsufficientMemory; goto cleanup; }
- /* Store all AL device IDs in an array. */
- SGIHostApi->sgiDeviceIDs = (ALvalue*)PaUtil_GroupAllocateMemory(SGIHostApi->allocations,
- deviceCount * sizeof(ALvalue));
- if (!SGIHostApi->sgiDeviceIDs)
- { result = paInsufficientMemory; goto cleanup; }
- /* Same query again, but now store all IDs in array sgiDeviceIDs (still using no qualifiers).*/
- e = alQueryValues(AL_SYSTEM, AL_DEVICES, SGIHostApi->sgiDeviceIDs, deviceCount, 0, 0);
- if (e != deviceCount)
- {
- if (e < 0) /* Sure an AL error really occurred. */
- { PA_SGI_SET_LAST_AL_ERROR() result = paUnanticipatedHostError; }
- else /* Seems we lost some devices. */
- { DBUG(("Number of devices suddenly changed!\n")); result = paDeviceUnavailable; }
- goto cleanup;
- }
- y[0].param = AL_DEFAULT_INPUT;
- y[1].param = AL_DEFAULT_OUTPUT;
- e = alGetParams(AL_SYSTEM, y, 2); /* Get params global to the AL system. */
- if (e != 2)
- {
- if (e < 0)
- {
- PA_SGI_SET_LAST_AL_ERROR() /* Calls oserror() and alGetErrorString(). */
- result = paUnanticipatedHostError; /* Sure an AL error really occurred. */
- }
- else
- {
- DBUG(("Default input and/or output could not be found!\n"));
- result = paDeviceUnavailable; /* FIX: What if only in or out are available? */
- }
- goto cleanup;
- }
- def_in = y[0].value.i; /* Remember both AL devices for a while. */
- def_out = y[1].value.i;
- y[0].param = AL_NAME;
- y[0].value.ptr = devName;
- y[0].sizeIn = maxDevNameChars; /* Including terminating null char. */
- y[1].param = AL_RATE;
- y[2].param = AL_CHANNELS;
- y[3].param = AL_TYPE; /* Subtype of AL_INPUT_DEVICE_TYPE or AL_OUTPUT_DEVICE_TYPE? */
- for (i=0; i < deviceCount; ++i) /* Fill allocated deviceInfo structs. */
- {
- PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex; /* Retrieve name, samplerate, channels and type. */
- e = alGetParams(SGIHostApi->sgiDeviceIDs[i].i, y, numParams);
- if (e != numParams)
- {
- if (e < 0) /* Calls oserror() and alGetErrorString(). */
- { PA_SGI_SET_LAST_AL_ERROR() result = paUnanticipatedHostError; }
- else
- { DBUG(("alGetParams() could not get all params!\n")); result = paInternalError; }
- goto cleanup;
- }
- deviceInfo->name = (char*)PaUtil_GroupAllocateMemory(SGIHostApi->allocations, strlen(devName) + 1);
- if (!deviceInfo->name)
- { result = paInsufficientMemory; goto cleanup; }
- strcpy((char*)deviceInfo->name, devName);
-
- /* Determine whether the received number of channels belongs to input or output device. */
- if (alIsSubtype(AL_INPUT_DEVICE_TYPE, y[3].value.i))
- {
- deviceInfo->maxInputChannels = y[2].value.i;
- deviceInfo->maxOutputChannels = 0;
- }
- else if (alIsSubtype(AL_OUTPUT_DEVICE_TYPE, y[3].value.i))
- {
- deviceInfo->maxInputChannels = 0;
- deviceInfo->maxOutputChannels = y[2].value.i;
- }
- else /* Should never occur. */
- {
- DBUG(("AL device is neither input nor output!\n"));
- result = paInternalError;
- goto cleanup;
- }
-
- /* Determine if this device is the default (in or out). If so, assign. */
- if (def_in == SGIHostApi->sgiDeviceIDs[i].i)
- {
- if ((*hostApi)->info.defaultInputDevice != paNoDevice)
- {
- DBUG(("Default input already assigned!\n"));
- result = paInternalError;
- goto cleanup;
- }
- (*hostApi)->info.defaultInputDevice = i;
- /* DBUG(("Default input assigned to pa device %d (%s).\n", i, deviceInfo->name)); */
- }
- else if (def_out == SGIHostApi->sgiDeviceIDs[i].i)
- {
- if ((*hostApi)->info.defaultOutputDevice != paNoDevice)
- {
- DBUG(("Default output already assigned!\n"));
- result = paInternalError;
- goto cleanup;
- }
- (*hostApi)->info.defaultOutputDevice = i;
- /* DBUG(("Default output assigned to pa device %d (%s).\n", i, deviceInfo->name)); */
- }
- /*---------------------------------------------- Default latencies set to 'reasonable' values. */
- deviceInfo->defaultLowInputLatency = 0.050; /* 50 milliseconds seems ok. */
- deviceInfo->defaultLowOutputLatency = 0.050; /* These are ALSO ABSOLUTE MINIMA in OpenStream(). */
- deviceInfo->defaultHighInputLatency = 0.500; /* 500 milliseconds a reasonable value? */
- deviceInfo->defaultHighOutputLatency = 0.500; /* Ten times these are ABSOLUTE MAX in OpenStream()). */
-
- deviceInfo->defaultSampleRate = alFixedToDouble(y[1].value.ll); /* Read current sr. */
- (*hostApi)->deviceInfos[i] = deviceInfo;
- ++(*hostApi)->info.deviceCount;
- }
- }
- /* What if (deviceCount==0)? */
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PaUtil_InitializeStreamInterface(&SGIHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface(&SGIHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-cleanup:
- if (result != paNoError)
- {
- if (SGIHostApi)
- {
- if (SGIHostApi->allocations)
- {
- PaUtil_FreeAllAllocations(SGIHostApi->allocations);
- PaUtil_DestroyAllocationGroup(SGIHostApi->allocations);
- }
- PaUtil_FreeMemory(SGIHostApi);
- }
- }
- return result;
-}
-
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaSGIHostApiRepresentation *SGIHostApi = (PaSGIHostApiRepresentation*)hostApi;
-
- /* Clean up any resources not handled by the allocation group. */
- if( SGIHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( SGIHostApi->allocations );
- PaUtil_DestroyAllocationGroup( SGIHostApi->allocations );
- }
- PaUtil_FreeMemory( SGIHostApi );
-}
-
-/*
- Check if samplerate is supported for this output device. Called once
- or twice by function IsFormatSupported() and one time by OpenStream().
- When paUnanticipatedHostError is returned, the caller does NOT have
- to call PA_SGI_SET_LAST_AL_ERROR() or such.
-*/
-static PaError sr_supported(int al_device, double sr)
-{
- int e;
- PaError result;
- ALparamInfo pinfo;
- long long lsr; /* 64 bit fixed point internal AL samplerate. */
-
- if (alGetParamInfo(al_device, AL_RATE, &pinfo))
- {
- e = oserror();
- DBUG(("alGetParamInfo(AL_RATE) failed: %s.\n", alGetErrorString(e)));
- if (e == AL_BAD_RESOURCE)
- result = paInvalidDevice;
- else
- {
- PA_SGI_SET_LAST_AL_ERROR() /* Sure an AL error occured. */
- result = paUnanticipatedHostError;
- }
- }
- else
- {
- lsr = alDoubleToFixed(sr); /* Within the range? */
- if ((pinfo.min.ll <= lsr) && (lsr <= pinfo.max.ll))
- result = paFormatIsSupported;
- else
- result = paInvalidSampleRate;
- }
- /* DBUG(("sr_supported()=%d.\n", result)); */
- return result;
-}
-
-
-/*
- See common/portaudio.h (suggestedLatency field is ignored).
-*/
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- PaSGIHostApiRepresentation* SGIHostApi = (PaSGIHostApiRepresentation*)hostApi;
- int inputChannelCount, outputChannelCount, result;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- /* Unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification. */
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
- /* Check that input device can support inputChannelCount. */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- return paInvalidChannelCount;
- /* Validate inputStreamInfo. */
- if( inputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- /* Check if samplerate is supported for this input device. */
- result = sr_supported(SGIHostApi->sgiDeviceIDs[inputParameters->device].i, sampleRate);
- if (result != paFormatIsSupported) /* PA_SGI_SET_LAST_AL_ERROR() may already be called. */
- return result;
- }
- else
- {
- inputChannelCount = 0;
- }
- if( outputParameters ) /* As with input above. */
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- return paInvalidChannelCount;
- if( outputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- /* Check if samplerate is supported for this output device. */
- result = sr_supported(SGIHostApi->sgiDeviceIDs[outputParameters->device].i, sampleRate);
- if (result != paFormatIsSupported)
- return result;
- }
- else
- {
- outputChannelCount = 0;
- }
- /* IMPLEMENT ME:
- Because the buffer adapter handles conversion between all standard
- sample formats, the following checks are only required if paCustomFormat
- is implemented, or under some other unusual conditions.
-
- - check that input device can support inputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
-
- - check that output device can support outputSampleFormat, or that
- we have the capability to convert from outputSampleFormat to
- a native format
- */
- /* suppress unused variable warnings */
- (void) inputSampleFormat;
- (void) outputSampleFormat;
- return paFormatIsSupported;
-}
-
-/** Auxilary struct, embedded twice in the struct below, for inputs and outputs. */
-typedef struct PaSGIhostPortBuffer
-{
- /** NULL means IRIX AL port closed. */
- ALport port;
- /** NULL means memory not allocated. */
- void* buffer;
-}
- PaSGIhostPortBuffer;
-
-/** Stream data structure specifically for this IRIX AL implementation. */
-typedef struct PaSGIStream
-{
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
- unsigned long framesPerHostCallback;
- /** Allocated host buffers and AL ports. */
- PaSGIhostPortBuffer hostPortBuffIn,
- hostPortBuffOut;
- /** Copy of stream flags given to OpenStream(). */
- PaStreamFlags streamFlags;
- /** Stream state may be 0 or 1 or 2, but never 3. */
- unsigned char state;
- /** Requests to stop or abort may come from the parent,
- or from the child itself (user callback result). */
- unsigned char stopAbort;
- pthread_t thread;
-}
- PaSGIStream;
-
-/** Stream can be in only one of the following three states: stopped (1), active (2), or
- callback finshed (0). To prevent 'state 3' from occurring, Setting and testing of the
- state bits is done atomically.
-*/
-#define PA_SGI_STREAM_FLAG_FINISHED_ (0) /* After callback finished or cancelled queued buffers. */
-#define PA_SGI_STREAM_FLAG_STOPPED_ (1) /* Set by OpenStream(), StopStream() and AbortStream(). */
-#define PA_SGI_STREAM_FLAG_ACTIVE_ (2) /* Set by StartStream. Reset by OpenStream(), */
- /* StopStream() and AbortStream(). */
-
-/** Stop requests, via the 'stopAbort' field can be either 1, meaning 'stop' or 2, meaning 'abort'.
- When both occur at the same time, 'abort' takes precedence, even after a first 'stop'.
-*/
-#define PA_SGI_REQ_CONT_ (0) /* Reset by OpenStream(), StopStream and AbortStream. */
-#define PA_SGI_REQ_STOP_ (1) /* Set by StopStream(). */
-#define PA_SGI_REQ_ABORT_ (2) /* Set by AbortStream(). */
-
-
-/** Called by OpenStream() once or twice. First, the number of channels, sampleformat, and
- queue size are configured. The configuration is then bound to the specified AL device.
- Then an AL port is opened. Finally, the samplerate of the device is altered (or at least
- set again).
-
- After successful return, actual latency is written in *latency, and actual samplerate
- in *samplerate.
-
- @param pa_params may be NULL and pa_params->channelCount may also be null, in both
- cases the function immediately returns.
- @return paNoError if configuration was skipped or if it succeeded.
-*/
-static PaError set_sgi_device(ALvalue* sgiDeviceIDs, /* Array built by PaSGI_Initialize(). */
- const PaStreamParameters* pa_params, /* read device and channels. */
- double* latency, /* Read and write in seconds. */
-
- PaSampleFormat pasfmt, /* Don't read from pa_params!. */
- char* direction, /* "r" or "w". */
- char* name,
- long framesPerHostBuffer,
- double* samplerate, /* Also writes back here. */
- PaSGIhostPortBuffer* hostPortBuff) /* Receive pointers here. */
-{
- int bytesPerFrame, sgiDevice, alErr, d, dd, iq_size, default_iq_size;
- ALpv pvs[2];
- ALconfig alc = NULL;
- PaError result = paNoError;
-
- if (!pa_params)
- goto cleanup; /* Not errors, just not full duplex, skip all. */
- if (!pa_params->channelCount)
- goto cleanup;
- alc = alNewConfig(); /* Create default config. This defaults to stereo, 16-bit integer data. */
- if (!alc) /* Call alFreeConfig() later, when done with it. */
- { result = paInsufficientMemory; goto cleanup; }
- /*----------------------- CONFIGURE NUMBER OF CHANNELS: ---------------------------*/
- if (alSetChannels(alc, pa_params->channelCount)) /* Returns 0 on success. */
- {
- if (oserror() == AL_BAD_CHANNELS)
- result = paInvalidChannelCount;
- else
- {
- PA_SGI_SET_LAST_AL_ERROR()
- result = paUnanticipatedHostError;
- }
- goto cleanup;
- }
- bytesPerFrame = pa_params->channelCount; /* Is multiplied by width below. */
- /*----------------------- CONFIGURE SAMPLE FORMAT: --------------------------------*/
- if (pasfmt == paFloat32)
- {
- if (alSetSampFmt(alc, AL_SAMPFMT_FLOAT))
- {
- if (oserror() == AL_BAD_SAMPFMT)
- result = paSampleFormatNotSupported;
- else
- {
- PA_SGI_SET_LAST_AL_ERROR()
- result = paUnanticipatedHostError;
- }
- goto cleanup;
- }
- bytesPerFrame *= 4; /* No need to set width for floats. */
- }
- else
- {
- if (alSetSampFmt(alc, AL_SAMPFMT_TWOSCOMP))
- {
- if (oserror() == AL_BAD_SAMPFMT)
- result = paSampleFormatNotSupported;
- else
- {
- PA_SGI_SET_LAST_AL_ERROR()
- result = paUnanticipatedHostError;
- }
- goto cleanup;
- }
- if (pasfmt == paInt8)
- {
- if (alSetWidth(alc, AL_SAMPLE_8))
- {
- if (oserror() == AL_BAD_WIDTH)
- result = paSampleFormatNotSupported;
- else
- {
- PA_SGI_SET_LAST_AL_ERROR()
- result = paUnanticipatedHostError;
- }
- goto cleanup;
- }
- /* bytesPerFrame *= 1; */
- }
- else if (pasfmt == paInt16)
- {
- if (alSetWidth(alc, AL_SAMPLE_16))
- {
- if (oserror() == AL_BAD_WIDTH)
- result = paSampleFormatNotSupported;
- else
- {
- PA_SGI_SET_LAST_AL_ERROR()
- result = paUnanticipatedHostError;
- }
- goto cleanup;
- }
- bytesPerFrame *= 2;
- }
- else if (pasfmt == paInt24)
- {
- if (alSetWidth(alc, AL_SAMPLE_24))
- {
- if (oserror() == AL_BAD_WIDTH)
- result = paSampleFormatNotSupported;
- else
- {
- PA_SGI_SET_LAST_AL_ERROR()
- result = paUnanticipatedHostError;
- }
- goto cleanup;
- }
- bytesPerFrame *= 3; /* OR 4 ???????! */
- }
- else return paSampleFormatNotSupported;
- }
- /*----------------------- SET INTERNAL AL QUEUE SIZE: -------------------------------*/
- /* The AL API doesn't provide a means for querying minimum and maximum buffer sizes.
- So, if the requested size fails, try again with a value that is closer to the AL's
- default queue size. In this implementation, 'Portaudio latency' corresponds to
- the AL queue size minus one buffersize:
- AL queue size - framesPerHostBuffer
- PA latency = -----------------------------------
- sample rate */
- default_iq_size = alGetQueueSize(alc);
- if (default_iq_size < 0) /* So let's first get that 'default size'. */
- { /* Default internal queue size could not be determined. */
- PA_SGI_SET_LAST_AL_ERROR()
- result = paUnanticipatedHostError;
- goto cleanup;
- }
- /* AL buffer becomes somewhat bigger than the suggested latency, notice this is */
- /* based on requsted samplerate, not in the actual rate, which is measured later. */
- /* Do NOT read pa_params->suggestedLatency, but use the limited *latency param! */
-
- iq_size = (int)(0.5 + ((*latency) * (*samplerate))) + (int)framesPerHostBuffer;
- /* The AL buffer becomes somewhat */
- /* bigger than the suggested latency. */
- if (iq_size < (framesPerHostBuffer << 1)) /* Make sure the minimum is twice */
- { /* framesPerHostBuffer. */
- DBUG(("Setting minimum queue size.\n"));
- iq_size = (framesPerHostBuffer << 1);
- }
- d = iq_size - default_iq_size; /* Determine whether we'll decrease */
- while (alSetQueueSize(alc, iq_size)) /* or increase after failing. */
- { /* Size in sample frames. */
- if (oserror() != AL_BAD_QSIZE) /* Stop at AL_BAD_CONFIG. */
- {
- PA_SGI_SET_LAST_AL_ERROR()
- result = paUnanticipatedHostError;
- goto cleanup;
- }
- dd = iq_size - default_iq_size; /* Stop when even the default size failed */
- if (((d >= 0) && (dd <= 0)) || /* (dd=0) or when difference flipped sign. */
- ((d <= 0) && (dd >= 0)) ||
- (iq_size <= framesPerHostBuffer)) /* Also guarentee that framesPerHostBuffer */
- { /* can be subtracted (res>0) after return. */
- DBUG(("Could not set AL queue size to %d sample frames!\n", iq_size));
- result = paInternalError; /* FIX: PROBABLY AN INAPROPRIATE ERROR CODE HERE. */
- goto cleanup; /* As inapropriate as paUnanticipatedHostError was? */
- }
- DBUG(("Failed to set internal queue size to %d frames, ", iq_size));
- if (d > 0)
- iq_size -= framesPerHostBuffer; /* Try lesser multiple. */
- else
- iq_size += framesPerHostBuffer; /* Try larger multiple. */
- DBUG(("trying %d frames now...\n", iq_size));
- }
- /* Note: Actual latency is written back to *latency after meausuring actual (not
- the requested) samplerate. See below.
- */
- /*----------------------- ALLOCATE HOST BUFFER: --------------------------------------*/
- hostPortBuff->buffer = PaUtil_AllocateMemory((long)bytesPerFrame * framesPerHostBuffer);
- if (!hostPortBuff->buffer) /* Caller is responsible for cleanup+close after failures! */
- { result = paInsufficientMemory; goto cleanup; }
- /*----------------------- BIND CONFIGURATION TO DEVICE: ------------------------------*/
- sgiDevice = sgiDeviceIDs[pa_params->device].i;
- if (alSetDevice(alc, sgiDevice)) /* Try to switch the hardware. */
- {
- if (oserror() == AL_BAD_DEVICE)
- result = paInvalidDevice;
- else
- {
- PA_SGI_SET_LAST_AL_ERROR()
- result = paUnanticipatedHostError;
- }
- goto cleanup;
- }
- /*----------------------- OPEN PORT: ----------------------------------------------*/
- hostPortBuff->port = alOpenPort(name, direction, alc); /* Caller is responsible */
- if (!hostPortBuff->port) /* for closing after fail. */
- {
- PA_SGI_SET_LAST_AL_ERROR()
- result = paUnanticipatedHostError;
- goto cleanup;
- } /* Maybe set SR earlier? */
- /*----------------------- SET SAMPLERATE: -----------------------------------------*/
- pvs[0].param = AL_MASTER_CLOCK; /* Attempt to set a crystal-based sample- */
- pvs[0].value.i = AL_CRYSTAL_MCLK_TYPE; /* rate on input or output device. */
- pvs[1].param = AL_RATE;
- pvs[1].value.ll = alDoubleToFixed(*samplerate);
- if (2 != alSetParams(sgiDevice, pvs, 2))
- {
- DBUG(("alSetParams() failed to set samplerate to %.4f Hz!\n", *samplerate));
- result = paInvalidSampleRate;
- goto cleanup;
- }
- /*----------------------- GET ACTUAL SAMPLERATE: ---------------------------*/
- alErr = alGetParams(sgiDevice, &pvs[1], 1); /* SEE WHAT WE REALY SET IT TO. */
- if (alErr != 1) /* And return that to caller. */
- {
- DBUG(("alGetParams() failed to read samplerate!\n"));
- result = paInvalidSampleRate;
- goto cleanup;
- }
- *samplerate = alFixedToDouble(pvs[1].value.ll); /* Between 1 Hz and 1 MHz. */
- if ((*samplerate < 1.0) || (*samplerate > 1000000.0))
- {
- DBUG(("alFixedToDouble() resulted a weird samplerate: %.6f Hz!\n", *samplerate));
- result = paInvalidSampleRate;
- goto cleanup;
- }
- /*----------------------- CALC ACTUAL LATENCY (based on actual SR): -----------------------*/
- *latency = (iq_size - framesPerHostBuffer) / (*samplerate); /* FIX: SURE > 0!???? */
-cleanup:
- if (alc)
- alFreeConfig(alc); /* We no longer need configuration. */
- return result;
-}
-
-/**
- Called by OpenStream() if it fails and by CloseStream. Only used here, in this file.
- Fields MUST be set to NULL or to a valid value, prior to call.
-*/
-static void streamCleanupAndClose(PaSGIStream* stream)
-{
- if (stream->hostPortBuffIn.port) alClosePort(stream->hostPortBuffIn.port); /* Close AL ports. */
- if (stream->hostPortBuffIn.buffer) PaUtil_FreeMemory(stream->hostPortBuffIn.buffer); /* Release buffers. */
- if (stream->hostPortBuffOut.port) alClosePort(stream->hostPortBuffOut.port);
- if (stream->hostPortBuffOut.buffer) PaUtil_FreeMemory(stream->hostPortBuffOut.buffer);
-}
-
-
-/* See pa_hostapi.h for a list of validity guarantees made about OpenStream parameters. */
-static PaError OpenStream(struct PaUtilHostApiRepresentation* hostApi,
- PaStream** s,
- const PaStreamParameters* ipp,
- const PaStreamParameters* opp,
- double sampleRate, /* Common to both i and o. */
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback* streamCallback,
- void* userData)
-{
- PaError result = paNoError;
- PaSGIHostApiRepresentation* SGIHostApi = (PaSGIHostApiRepresentation*)hostApi;
- PaSGIStream* stream = 0;
- unsigned long framesPerHostBuffer; /* Not necessarily the same as framesPerBuffer. */
- int inputChannelCount, outputChannelCount;
- PaSampleFormat inputSampleFormat, outputSampleFormat,
- hostInputSampleFormat, hostOutputSampleFormat;
- double sr_in, sr_out,
- latency_in, latency_out;
- static const PaSampleFormat irixFormats = (paInt8 | paInt16 | paInt24 | paFloat32);
- /* Constant used by PaUtil_SelectClosestAvailableFormat(). Because IRIX AL does not
- provide a way to query for possible formats for a given device, interface or port,
- just add together the formats we know that are supported in general by IRIX AL
- (at the end of the year 2003): AL_SAMPFMT_TWOSCOMP with AL_SAMPLE_8(=paInt8),
- AL_SAMPLE_16(=paInt16) or AL_SAMPLE_24(=paInt24); AL_SAMPFMT_FLOAT(=paFloat32);
- AL_SAMPFMT_DOUBLE(=paFloat64); IRIX misses unsigned 8 and 32 bit signed ints.
- */
- DBUG(("OpenStream() started.\n"));
- if (ipp)
- {
- inputChannelCount = ipp->channelCount;
- inputSampleFormat = ipp->sampleFormat;
- /* Unless alternate device specification is supported, reject the use of paUseHostApiSpecificDeviceSpecification. */
- if (ipp->device == paUseHostApiSpecificDeviceSpecification) /* DEVICE CHOOSEN BY CLIENT. */
- return paInvalidDevice;
- /* Check that input device can support inputChannelCount. */
- if (inputChannelCount > hostApi->deviceInfos[ipp->device]->maxInputChannels)
- return paInvalidChannelCount;
- /* Validate inputStreamInfo. */
- if (ipp->hostApiSpecificStreamInfo)
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- hostInputSampleFormat = PaUtil_SelectClosestAvailableFormat(irixFormats, inputSampleFormat);
- /* Check if samplerate is supported for this input device. */
- result = sr_supported(SGIHostApi->sgiDeviceIDs[ipp->device].i, sampleRate);
- if (result != paFormatIsSupported) /* PA_SGI_SET_LAST_AL_ERROR() may already be called. */
- return result;
- /* Validate input latency. Use defaults if necessary. */
- if (ipp->suggestedLatency < hostApi->deviceInfos[ipp->device]->defaultLowInputLatency)
- latency_in = hostApi->deviceInfos[ipp->device]->defaultLowInputLatency; /* Low = minimum. */
- else if (ipp->suggestedLatency > 10.0 * hostApi->deviceInfos[ipp->device]->defaultHighInputLatency)
- latency_in = 10.0 * hostApi->deviceInfos[ipp->device]->defaultHighInputLatency; /* 10*High = max. */
- else
- latency_in = ipp->suggestedLatency;
- }
- else
- {
- inputChannelCount = 0;
- inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
- latency_in = 0.0; /* Necessary? */
- }
- if (opp)
- {
- outputChannelCount = opp->channelCount;
- outputSampleFormat = opp->sampleFormat;
- if (opp->device == paUseHostApiSpecificDeviceSpecification) /* Like input (above). */
- return paInvalidDevice;
- if (outputChannelCount > hostApi->deviceInfos[opp->device]->maxOutputChannels)
- return paInvalidChannelCount;
- if (opp->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- hostOutputSampleFormat = PaUtil_SelectClosestAvailableFormat(irixFormats, outputSampleFormat);
- /* Check if samplerate is supported for this output device. */
- result = sr_supported(SGIHostApi->sgiDeviceIDs[opp->device].i, sampleRate);
- if (result != paFormatIsSupported)
- return result;
- /* Validate output latency. Use defaults if necessary. */
- if (opp->suggestedLatency < hostApi->deviceInfos[opp->device]->defaultLowOutputLatency)
- latency_out = hostApi->deviceInfos[opp->device]->defaultLowOutputLatency; /* Low = minimum. */
- else if (opp->suggestedLatency > 10.0 * hostApi->deviceInfos[opp->device]->defaultHighOutputLatency)
- latency_out = 10.0 * hostApi->deviceInfos[opp->device]->defaultHighOutputLatency; /* 10*High = max. */
- else
- latency_out = opp->suggestedLatency;
- }
- else
- {
- outputChannelCount = 0;
- outputSampleFormat = hostOutputSampleFormat = paInt16; /* Surpress 'uninitialised var' warning. */
- latency_out = 0.0;
- }
- /* Sure that ipp and opp will never be both NULL. */
-
- if( (streamFlags & paPlatformSpecificFlags) != 0 ) /* Validate platform specific flags. */
- return paInvalidFlag; /* Unexpected platform specific flag. */
-
- stream = (PaSGIStream*)PaUtil_AllocateMemory( sizeof(PaSGIStream) );
- if (!stream)
- { result = paInsufficientMemory; goto cleanup; }
-
- stream->hostPortBuffIn.port = (ALport)NULL; /* Ports closed. */
- stream->hostPortBuffIn.buffer = NULL; /* No buffers yet. */
- stream->hostPortBuffOut.port = (ALport)NULL;
- stream->hostPortBuffOut.buffer = NULL;
-
- if (streamCallback)
- PaUtil_InitializeStreamRepresentation(&stream->streamRepresentation,
- &SGIHostApi->callbackStreamInterface, streamCallback, userData);
- else
- PaUtil_InitializeStreamRepresentation(&stream->streamRepresentation,
- &SGIHostApi->blockingStreamInterface, streamCallback, userData);
- /* (NULL.) */
- if (framesPerBuffer == paFramesPerBufferUnspecified) /* Proposal 004. */
- { /* Keep framesPerBuffer zero but come up with some fixed host buffer size. */
- double lowest_lat = 0.0; /* 0.0 to surpress uninit warning, we're sure it will end up higher. */
- if (ipp)
- lowest_lat = latency_in; /* Sure > 0.0! */
- if (opp && (latency_out < lowest_lat))
- lowest_lat = latency_out;
- /* So that queue size becomes approximately 5 times framesPerHostBuffer: */
- framesPerHostBuffer = (unsigned long)((lowest_lat * sampleRate) / 4.0);
- /* But always limit: */
- if (framesPerHostBuffer < 64L)
- framesPerHostBuffer = 64L;
- else if (framesPerHostBuffer > 32768L)
- framesPerHostBuffer = 32768L;
- DBUG(("Decided to use a fixed host buffer size of %ld frames.\n", framesPerHostBuffer));
- }
- else
- framesPerHostBuffer = framesPerBuffer; /* Then just take the requested amount. No buffer-adaption yet? */
-
- sr_in = sr_out = sampleRate;
- /*-------------------------------------------------------------------------------------------*/
- result = set_sgi_device(SGIHostApi->sgiDeviceIDs, /* Needed by alSetDevice and other functs. */
- ipp, /* Reads channelCount, device but NOT latency. */
- &latency_in, /* Read limited requested latency but also WRITE actual. */
- hostInputSampleFormat, /* For alSetSampFmt and alSetWidth. */
- "r", /* "r" for reading from input port. */
- "portaudio in", /* Name string. */
- framesPerHostBuffer, /* As calculated or as requested by the client. */
- &sr_in, /* Receive actual s.rate after setting it. */
- &stream->hostPortBuffIn); /* Receives ALport and input host buffer. */
- if (result != paNoError) goto cleanup;
- /*-------------------------------------------------------------------------------------------*/
- result = set_sgi_device(SGIHostApi->sgiDeviceIDs,
- opp,
- &latency_out,
- hostOutputSampleFormat,
- "w", /* "w" for writing. */
- "portaudio out",
- framesPerHostBuffer,
- &sr_out,
- &stream->hostPortBuffOut);
- if (result != paNoError) goto cleanup;
- /*------------------------------------------------------------------------------------------*/
- if (fabs(sr_in - sr_out) > 0.001) /* Make sure both are the 'same'. */
- {
- DBUG(("Weird samplerate difference between input and output!\n"));
- result = paInvalidSampleRate; /* Could not come up with a better error code. */
- goto cleanup;
- } /* sr_in '==' sr_out. */
- sampleRate = sr_in; /* Following fields set to estimated or actual values: */
- stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
- stream->streamRepresentation.streamInfo.inputLatency = latency_in; /* 0.0 if output only. */
- stream->streamRepresentation.streamInfo.outputLatency = latency_out; /* 0.0 if input only. */
-
- PaUtil_InitializeCpuLoadMeasurer(&stream->cpuLoadMeasurer, sampleRate);
- result = PaUtil_InitializeBufferProcessor(&stream->bufferProcessor,
- inputChannelCount, inputSampleFormat, hostInputSampleFormat,
- outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags,
- framesPerBuffer, /* As requested by OpenStream(), may be zero! */
- framesPerHostBuffer, /* Use fixed number of frames per host buffer */
- paUtilFixedHostBufferSize, /* to keep things simple. See pa_common/pa_ */
- streamCallback, userData); /* process.h for more hostbuffersize options. */
- if (result != paNoError)
- goto cleanup;
-
- stream->framesPerHostCallback = framesPerHostBuffer;
- stream->streamFlags = streamFlags; /* Remember priming request. */
- stream->state = PA_SGI_STREAM_FLAG_STOPPED_; /* After opening, the stream */
- stream->stopAbort = PA_SGI_REQ_CONT_; /* is in the stopped state. */
- *s = (PaStream*)stream; /* Pass object to caller. */
-cleanup:
- if (result != paNoError) /* Always set result when jumping to cleanup after failure. */
- {
- if (stream)
- {
- streamCleanupAndClose(stream); /* Frees i/o buffers and closes AL ports. */
- PaUtil_FreeMemory(stream);
- }
- }
- return result;
-}
-
-/** POSIX thread that performs the actual i/o and calls the client's callback,
- spawned by StartStream().
-*/
-static void* PaSGIpthread(void *userData)
-{
- PaSGIStream* stream = (PaSGIStream*)userData;
- int callbackResult = paContinue;
- double nanosec_per_frame;
- PaStreamCallbackTimeInfo timeInfo = { 0, 0, 0 };
-
- stream->state = PA_SGI_STREAM_FLAG_ACTIVE_; /* Parent thread also sets active flag, but we
- make no assumption about who does this first. */
- nanosec_per_frame = 1000000000.0 / stream->streamRepresentation.streamInfo.sampleRate;
- /*----------------------------------------------- OUTPUT PRIMING: -----------------------------*/
- if (stream->hostPortBuffOut.port) /* Somewhat less than AL queue size so the next */
- { /* output buffer will (probably) not block. */
- unsigned long frames_to_prime = (long)(0.5 +
- (stream->streamRepresentation.streamInfo.outputLatency
- * stream->streamRepresentation.streamInfo.sampleRate));
- if (stream->streamFlags & paPrimeOutputBuffersUsingStreamCallback)
- {
- PaStreamCallbackFlags cbflags = paPrimingOutput;
- if (stream->hostPortBuffIn.port) /* Only set this flag in case of full duplex. */
- cbflags |= paInputUnderflow;
- DBUG(("Prime with client's callback: < %ld frames.\n", frames_to_prime));
- while (frames_to_prime >= stream->framesPerHostCallback) /* We will not do less (yet). */
- { /* TODO: Timestamps and CPU load */
- PaUtil_BeginBufferProcessing(&stream->bufferProcessor, /* measurement during priming. */
- &timeInfo,
- cbflags); /* Pass underflow + priming flags. */
- if (stream->hostPortBuffIn.port) /* Does that provide client's call- */
- PaUtil_SetNoInput(&stream->bufferProcessor); /* back with silent inputbuffers? */
-
- PaUtil_SetOutputFrameCount(&stream->bufferProcessor, 0); /* 0=take host buffer size. */
- PaUtil_SetInterleavedOutputChannels(&stream->bufferProcessor, 0,
- stream->hostPortBuffOut.buffer, 0);
- callbackResult = paContinue; /* Call the client's callback. */
- frames_to_prime -= PaUtil_EndBufferProcessing(&stream->bufferProcessor, &callbackResult);
- if (callbackResult == paAbort)
- { /* What should we do in other cases */
- stream->stopAbort = PA_SGI_REQ_ABORT_; /* where (callbackResult!=paContinue). */
- break; /* Don't even output the samples just returned (also skip following while). */
- }
- else /* Write interleaved samples to SGI device. */
- alWriteFrames(stream->hostPortBuffOut.port, stream->hostPortBuffOut.buffer,
- stream->framesPerHostCallback);
- }
- }
- else /* Prime with silence. */
- {
- DBUG(("Prime with silence: %ld frames.\n", frames_to_prime));
- alZeroFrames(stream->hostPortBuffOut.port, frames_to_prime);
- }
- }
- /*------------------------------------------------------ I/O: ---------------------------------*/
- while (!stream->stopAbort) /* Exit loop immediately when 'stop' or 'abort' are raised. */
- {
- unsigned long framesProcessed;
- stamp_t fn, t, fnd, td; /* Unsigned 64 bit. */
-
- PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
- /* IMPLEMENT ME: - handle buffer slips. */
- if (stream->hostPortBuffIn.port)
- {
- /* Get device sample frame number associated with next audio sample frame
- we're going to read from this port. */
- alGetFrameNumber(stream->hostPortBuffIn.port, &fn);
- /* Get some recent pair of (frame number, time) from the audio device to
- which our port is connected. time is 'UST' which is given in nanoseconds
- and shared with the other audio devices and with other media. */
- alGetFrameTime(stream->hostPortBuffIn.port, &fnd, &td);
- /* Calculate UST associated with fn, the next sample frame we're going to read or
- write. Because this is signed arithmetic, code works for both inputs and outputs. */
- t = td + (stamp_t) ((double)(fn - fnd) * nanosec_per_frame);
- /* If port is not in underflow or overflow state, we can alReadFrames() or
- alWriteFrames() here and know that t is the time associated with the first
- sample frame of the buffer we read or write. */
- timeInfo.inputBufferAdcTime = ((PaTime)t) / 1000000000.0;
- /* Read interleaved samples from AL port (I think it will block only the first time). */
- alReadFrames(stream->hostPortBuffIn.port, stream->hostPortBuffIn.buffer,
- stream->framesPerHostCallback);
- }
- if (stream->hostPortBuffOut.port)
- {
- alGetFrameNumber(stream->hostPortBuffOut.port, &fn);
- alGetFrameTime(stream->hostPortBuffOut.port, &fnd, &td);
- t = td + (stamp_t) ((double)(fn - fnd) * nanosec_per_frame);
- timeInfo.outputBufferDacTime = ((PaTime)t) / 1000000000.0;
- }
- dmGetUST((unsigned long long*)(&t)); /* Receive time in nanoseconds in t. */
- timeInfo.currentTime = ((PaTime)t) / 1000000000.0;
-
- /* If you need to byte swap or shift inputBuffer to convert it into a pa format, do it here. */
- PaUtil_BeginBufferProcessing(&stream->bufferProcessor,
- &timeInfo,
- 0 /* IMPLEMENT ME: pass underflow/overflow flags when necessary */);
-
- if (stream->hostPortBuffIn.port) /* Equivalent to (inputChannelCount > 0) */
- { /* We are sure about the amount to transfer (PaUtil_Set before alRead). */
- PaUtil_SetInputFrameCount(&stream->bufferProcessor, 0 /* 0 means take host buffer size */);
- PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor,
- 0, /* first channel of inputBuffer is channel 0 */
- stream->hostPortBuffIn.buffer,
- 0 ); /* 0 - use inputChannelCount passed to init buffer processor */
- }
- if (stream->hostPortBuffOut.port)
- {
- PaUtil_SetOutputFrameCount(&stream->bufferProcessor, 0 /* 0 means take host buffer size */);
- PaUtil_SetInterleavedOutputChannels(&stream->bufferProcessor,
- 0, /* first channel of outputBuffer is channel 0 */
- stream->hostPortBuffOut.buffer,
- 0 ); /* 0 - use outputChannelCount passed to init buffer processor */
- }
- /*
- You must pass a valid value of callback result to PaUtil_EndBufferProcessing()
- in general you would pass paContinue for normal operation, and
- paComplete to drain the buffer processor's internal output buffer.
- You can check whether the buffer processor's output buffer is empty
- using PaUtil_IsBufferProcessorOuputEmpty( bufferProcessor )
- */
- callbackResult = paContinue; /* Whoops, lost this somewhere, back again in v 1.2.2.16! */
- framesProcessed = PaUtil_EndBufferProcessing(&stream->bufferProcessor, &callbackResult);
- /* If you need to byte swap or shift outputBuffer to convert it to host format, do it here. */
- PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
-
- if (callbackResult != paContinue)
- { /* Once finished, call the finished callback. */
- DBUG(("SGI callbackResult = %d.\n", callbackResult));
- if (stream->streamRepresentation.streamFinishedCallback)
- stream->streamRepresentation.streamFinishedCallback(stream->streamRepresentation.userData);
- if (callbackResult == paAbort)
- {
- stream->stopAbort = PA_SGI_REQ_ABORT_;
- break; /* Don't play the last buffer returned. */
- }
- else /* paComplete or some other non-zero value. */
- stream->stopAbort = PA_SGI_REQ_STOP_;
- }
- if (stream->hostPortBuffOut.port) /* Write interleaved samples to SGI device */
- alWriteFrames(stream->hostPortBuffOut.port, /* (like unix_oss, AFTER checking callback result). */
- stream->hostPortBuffOut.buffer, stream->framesPerHostCallback);
- }
- if (stream->hostPortBuffOut.port) /* Drain output buffer(s), as long as we don't see an 'abort' request. */
- {
- while ((!(stream->stopAbort & PA_SGI_REQ_ABORT_)) && /* Assume _STOP_ is set (or meant). */
- (alGetFilled(stream->hostPortBuffOut.port) > 1)) /* In case of ABORT we quickly leave (again). */
- ; /* Don't provide any new (not even silent) samples, but let an underrun [almost] occur. */
- }
- if (callbackResult != paContinue)
- stream->state = PA_SGI_STREAM_FLAG_FINISHED_;
- return NULL;
-}
-
-
-/*
- When CloseStream() is called, the multi-api layer ensures
- that the stream has already been stopped or aborted.
-*/
-static PaError CloseStream(PaStream* s)
-{
- PaError result = paNoError;
- PaSGIStream* stream = (PaSGIStream*)s;
-
- DBUG(("SGI CloseStream() started.\n"));
- streamCleanupAndClose(stream); /* Releases i/o buffers and closes AL ports. */
- PaUtil_TerminateBufferProcessor(&stream->bufferProcessor);
- PaUtil_TerminateStreamRepresentation(&stream->streamRepresentation);
- PaUtil_FreeMemory(stream);
- return result;
-}
-
-
-static PaError StartStream(PaStream *s)
-{
- PaError result = paNoError;
- PaSGIStream* stream = (PaSGIStream*)s;
-
- DBUG(("StartStream() started.\n"));
- PaUtil_ResetBufferProcessor(&stream->bufferProcessor); /* See pa_common/pa_process.h. */
- if (stream->bufferProcessor.streamCallback)
- { /* only when callback is used */
- if (pthread_create(&stream->thread,
- NULL, /* pthread_attr_t * attr */
- PaSGIpthread, /* Function to spawn. */
- (void*)stream)) /* Pass stream as arg. */
- {
- PA_SGI_SET_LAST_IRIX_ERROR() /* Let's hope oserror() tells something useful. */
- result = paUnanticipatedHostError;
- }
- else
- stream->state = PA_SGI_STREAM_FLAG_ACTIVE_;
- } /* Set active before returning from this function. */
- else
- stream->state = PA_SGI_STREAM_FLAG_ACTIVE_; /* Apparently, setting active for blocking i/o is */
- return result; /* necessary (for patest_write_sine for example). */
-}
-
-
-static PaError StopStream( PaStream *s )
-{
- PaError result = paNoError;
- PaSGIStream* stream = (PaSGIStream*)s;
-
- if (stream->bufferProcessor.streamCallback) /* Only for callback streams. */
- {
- stream->stopAbort = PA_SGI_REQ_STOP_; /* Signal and wait for the thread to drain outputs. */
- if (pthread_join(stream->thread, NULL)) /* When succesful, stream->state */
- { /* is still ACTIVE, or FINISHED. */
- PA_SGI_SET_LAST_IRIX_ERROR()
- result = paUnanticipatedHostError;
- }
- else /* Transition from ACTIVE or FINISHED to STOPPED. */
- stream->state = PA_SGI_STREAM_FLAG_STOPPED_;
- stream->stopAbort = PA_SGI_REQ_CONT_; /* For possible next start. */
- }
-/* else
- stream->state = PA_SGI_STREAM_FLAG_STOPPED_; Is this necessary for blocking i/o? */
- return result;
-}
-
-
-static PaError AbortStream( PaStream *s )
-{
- PaError result = paNoError;
- PaSGIStream *stream = (PaSGIStream*)s;
-
- if (stream->bufferProcessor.streamCallback) /* Only for callback streams. */
- {
- stream->stopAbort = PA_SGI_REQ_ABORT_;
- if (pthread_join(stream->thread, NULL))
- {
- PA_SGI_SET_LAST_IRIX_ERROR()
- result = paUnanticipatedHostError;
- }
- else /* Transition from ACTIVE or FINISHED to STOPPED. */
- stream->state = PA_SGI_STREAM_FLAG_STOPPED_;
- stream->stopAbort = PA_SGI_REQ_CONT_; /* For possible next start. */
- }
-/* else
- stream->state = PA_SGI_STREAM_FLAG_STOPPED_; Is this necessary for blocking i/o? */
- return result;
-}
-
-
-static PaError IsStreamStopped( PaStream *s ) /* Not just the opposite of IsStreamActive(): */
-{ /* in the 'callback finished' state, it */
- /* returns zero instead of nonzero. */
- if (((PaSGIStream*)s)->state & PA_SGI_STREAM_FLAG_STOPPED_)
- return 1;
- return 0;
-}
-
-
-static PaError IsStreamActive( PaStream *s )
-{
- if (((PaSGIStream*)s)->state & PA_SGI_STREAM_FLAG_ACTIVE_)
- return 1;
- return 0;
-}
-
-
-static PaTime GetStreamTime( PaStream *s )
-{
- stamp_t t;
-
- (void) s; /* Suppress unused argument warning. */
- dmGetUST((unsigned long long*)(&t)); /* Receive time in nanoseconds in t. */
- return (PaTime)t / 1000000000.0;
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaSGIStream *stream = (PaSGIStream*)s;
-
- return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-/*
- As separate stream interfaces are used for blocking and callback
- streams, the following functions can be guaranteed to only be called
- for blocking streams.
-*/
-
-static PaError ReadStream( PaStream* s,
- void *buffer,
- unsigned long frames )
-{
- PaSGIStream* stream = (PaSGIStream*)s;
- int n;
-
-printf("stream->framesPerHostCallback=%ld.\n", stream->framesPerHostCallback);
-fflush(stdout);
-
- while (frames)
- {
- if (frames > stream->framesPerHostCallback) n = stream->framesPerHostCallback;
- else n = frames;
- /* Read interleaved samples from SGI device. */
- alReadFrames(stream->hostPortBuffIn.port, /* Port already opened by OpenStream(). */
- stream->hostPortBuffIn.buffer, n); /* Already allocated by OpenStream(). */
- /* alReadFrames() always returns 0. */
- PaUtil_SetInputFrameCount(&stream->bufferProcessor, 0); /* 0 means take host buffer size */
- PaUtil_SetInterleavedInputChannels(&stream->bufferProcessor,
- 0, /* first channel of inputBuffer is channel 0 */
- stream->hostPortBuffIn.buffer,
- 0 ); /* 0 means use inputChannelCount passed at init. */
- /* Copy samples from host input channels set up by the PaUtil_SetInterleavedInputChannels
- to a user supplied buffer. */
-printf("frames=%ld, buffer=%ld\n", frames, (long)buffer);
-fflush(stdout);
- PaUtil_CopyInput(&stream->bufferProcessor, &buffer, n);
- frames -= n;
- }
-printf("DONE: frames=%ld, buffer=%ld\n", frames, (long)buffer);
- return paNoError;
-}
-
-
-static PaError WriteStream( PaStream* s,
- const void *buffer,
- unsigned long frames )
-{
- PaSGIStream* stream = (PaSGIStream*)s;
- unsigned long n;
- while (frames)
- {
- PaUtil_SetOutputFrameCount(&stream->bufferProcessor, 0); /* 0 means take host buffer size */
- PaUtil_SetInterleavedOutputChannels(&stream->bufferProcessor,
- 0, /* first channel of inputBuffer is channel 0 */
- stream->hostPortBuffOut.buffer,
- 0 ); /* 0 means use inputChannelCount passed at init. */
- /* Copy samples from user supplied buffer to host input channels set up by
- PaUtil_SetInterleavedOutputChannels. Copies the minimum of the number of user frames
- (specified by the frameCount parameter) and the number of host frames (specified in
- a previous call to SetOutputFrameCount()). */
- n = PaUtil_CopyOutput(&stream->bufferProcessor, &buffer, frames);
- /* Write interleaved samples to SGI device. */
- alWriteFrames(stream->hostPortBuffOut.port, stream->hostPortBuffOut.buffer, n);
- frames -= n; /* alWriteFrames always returns 0. */
- }
- return paNoError;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
- return (signed long)alGetFilled(((PaSGIStream*)s)->hostPortBuffIn.port);
-}
-
-
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
- return (signed long)alGetFillable(((PaSGIStream*)s)->hostPortBuffOut.port);
-}
-
-
-/* CVS reminder:
- To download the 'v19-devel' branch from portaudio's CVS server for the first time, type:
- cvs -d:pserver:anonymous@www.portaudio.com:/home/cvs checkout -r v19-devel portaudio
- Then 'cd' to the 'portaudio' directory that should have been created.
- To commit changes:
- cvs -d:pserver:pieter@www.portaudio.com:/home/cvs login
- cvs -d:pserver:pieter@www.portaudio.com:/home/cvs commit -m 'blabla.' -r v19-devel pa_sgi/pa_sgi.c
- cvs -d:pserver:pieter@www.portaudio.com:/home/cvs logout
- To see if someone else worked on something:
- cvs -d:pserver:anonymous@www.portaudio.com:/home/cvs update -r v19-devel
- To get an older revision of a certain file (without sticky business):
- cvs -d:pserver:anonymous@www.portaudio.com:/home/cvs update -p -r 1.1.1.1.2.4 pa_tests/patest1.c >pa_tests/patest1.c-OLD
- To see logs:
- cvs -d:pserver:anonymous@www.portaudio.com:/home/cvs log pa_common/pa_skeleton.c
-*/
diff --git a/pd/portaudio/pa_unix/pa_unix_hostapis.c b/pd/portaudio/pa_unix/pa_unix_hostapis.c
deleted file mode 100644
index 9bddc2e0..00000000
--- a/pd/portaudio/pa_unix/pa_unix_hostapis.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * $Id: pa_unix_hostapis.c,v 1.1.2.5 2003/10/02 12:35:46 pieter Exp $
- * Portable Audio I/O Library UNIX initialization table
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-
-#include "pa_hostapi.h"
-
-PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-/* Added for IRIX, Pieter, oct 2, 2003: */
-PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-
-PaUtilHostApiInitializer *paHostApiInitializers[] =
- {
-#ifdef PA_USE_OSS
- PaOSS_Initialize,
-#endif
-
-#ifdef PA_USE_ALSA
- PaAlsa_Initialize,
-#endif
-
-#ifdef PA_USE_JACK
- PaJack_Initialize,
-#endif
- /* Added for IRIX, Pieter, oct 2, 2003: */
-#ifdef PA_USE_SGI
- PaSGI_Initialize,
-#endif
- 0 /* NULL terminated array */
- };
-
-int paDefaultHostApiIndex = 0;
-
-
diff --git a/pd/portaudio/pa_unix/pa_unix_util.c b/pd/portaudio/pa_unix/pa_unix_util.c
deleted file mode 100644
index f45848fb..00000000
--- a/pd/portaudio/pa_unix/pa_unix_util.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * $Id: pa_unix_util.c,v 1.1.2.7 2005/03/31 15:02:48 aknudsen Exp $
- * Portable Audio I/O Library
- * UNIX platform-specific support functions
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2000 Ross Bencina
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-
-#include <pthread.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include <assert.h>
-#include <string.h> /* For memset */
-
-#include "pa_util.h"
-#include "pa_unix_util.h"
-
-/*
- Track memory allocations to avoid leaks.
- */
-
-#if PA_TRACK_MEMORY
-static int numAllocations_ = 0;
-#endif
-
-
-void *PaUtil_AllocateMemory( long size )
-{
- void *result = malloc( size );
-
-#if PA_TRACK_MEMORY
- if( result != NULL ) numAllocations_ += 1;
-#endif
- return result;
-}
-
-
-void PaUtil_FreeMemory( void *block )
-{
- if( block != NULL )
- {
- free( block );
-#if PA_TRACK_MEMORY
- numAllocations_ -= 1;
-#endif
-
- }
-}
-
-
-int PaUtil_CountCurrentlyAllocatedBlocks( void )
-{
-#if PA_TRACK_MEMORY
- return numAllocations_;
-#else
- return 0;
-#endif
-}
-
-
-void Pa_Sleep( long msec )
-{
- while( msec > 999 ) /* For OpenBSD and IRIX, argument */
- { /* to usleep must be < 1000000. */
- usleep( 999000 );
- msec -= 999;
- }
- usleep( msec * 1000 );
-}
-
-/* *** NOT USED YET: ***
-static int usePerformanceCounter_;
-static double microsecondsPerTick_;
-*/
-
-void PaUtil_InitializeClock( void )
-{
- /* TODO */
-}
-
-
-PaTime PaUtil_GetTime( void )
-{
- struct timeval tv;
- gettimeofday( &tv, NULL );
- return (PaTime) tv.tv_usec / 1000000. + tv.tv_sec;
-}
-
-PaError PaUtil_InitializeThreading( PaUtilThreading *threading )
-{
- (void) paUtilErr_;
- return paNoError;
-}
-
-void PaUtil_TerminateThreading( PaUtilThreading *threading )
-{
-}
-
-PaError PaUtil_StartThreading( PaUtilThreading *threading, void *(*threadRoutine)(void *), void *data )
-{
- pthread_create( &threading->callbackThread, NULL, threadRoutine, data );
- return paNoError;
-}
-
-PaError PaUtil_CancelThreading( PaUtilThreading *threading, int wait, PaError *exitResult )
-{
- PaError result = paNoError;
- void *pret;
-
- if( exitResult )
- *exitResult = paNoError;
-
- /* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
- if( !wait )
- pthread_cancel( threading->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */
- pthread_join( threading->callbackThread, &pret );
-
-#ifdef PTHREAD_CANCELED
- if( pret && PTHREAD_CANCELED != pret )
-#else
- /* !wait means the thread may have been canceled */
- if( pret && wait )
-#endif
- {
- if( exitResult )
- *exitResult = *(PaError *) pret;
- free( pret );
- }
-
- return result;
-}
-
-/*
-static void *CanaryFunc( void *userData )
-{
- const unsigned intervalMsec = 1000;
- PaUtilThreading *th = (PaUtilThreading *) userData;
-
- while( 1 )
- {
- th->canaryTime = PaUtil_GetTime();
-
- pthread_testcancel();
- Pa_Sleep( intervalMsec );
- }
-
- pthread_exit( NULL );
-}
-*/
diff --git a/pd/portaudio/pa_unix_oss/low_latency_tip.txt b/pd/portaudio/pa_unix_oss/low_latency_tip.txt
deleted file mode 100644
index 2d982b79..00000000
--- a/pd/portaudio/pa_unix_oss/low_latency_tip.txt
+++ /dev/null
Binary files differ
diff --git a/pd/portaudio/pa_unix_oss/pa_unix_oss.c b/pd/portaudio/pa_unix_oss/pa_unix_oss.c
deleted file mode 100644
index 3eaccafb..00000000
--- a/pd/portaudio/pa_unix_oss/pa_unix_oss.c
+++ /dev/null
@@ -1,1918 +0,0 @@
-/*
- * $Id: pa_unix_oss.c,v 1.6.2.22 2005/03/08 21:26:53 aknudsen Exp $
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
- * OSS implementation by:
- * Douglas Repetto
- * Phil Burk
- * Dominic Mazzoni
- * Arve Knudsen
- *
- * Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files
- * (the "Software"), to deal in the Software without restriction,
- * including without limitation the rights to use, copy, modify, merge,
- * publish, distribute, sublicense, and/or sell copies of the Software,
- * and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * Any person wishing to distribute modifications to the Software is
- * requested to send the modifications to the original developer so that
- * they can be incorporated into the canonical version.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
- * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
- * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <pthread.h>
-#include <alloca.h>
-#include <malloc.h>
-#include <assert.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/poll.h>
-#include <limits.h>
-#include <semaphore.h>
-
-#ifdef __linux__
-# include <linux/soundcard.h>
-# define DEVICE_NAME_BASE "/dev/dsp"
-#else
-# include <machine/soundcard.h> /* JH20010905 */
-# define DEVICE_NAME_BASE "/dev/audio"
-#endif
-
-#include "portaudio.h"
-#include "pa_util.h"
-#include "pa_allocation.h"
-#include "pa_hostapi.h"
-#include "pa_stream.h"
-#include "pa_cpuload.h"
-#include "pa_process.h"
-#include "../pa_unix/pa_unix_util.h"
-
-static int sysErr_;
-static pthread_t mainThread_;
-
-/* Check return value of system call, and map it to PaError */
-#define ENSURE_(expr, code) \
- do { \
- if( UNLIKELY( (sysErr_ = (expr)) < 0 ) ) \
- { \
- /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
- if( (code) == paUnanticipatedHostError && pthread_self() == mainThread_ ) \
- { \
- PaUtil_SetLastHostErrorInfo( paALSA, sysErr_, strerror( errno ) ); \
- } \
- \
- PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
- result = (code); \
- goto error; \
- } \
- } while( 0 );
-
-#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
-
-/* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */
-
-typedef struct
-{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
-
- PaUtilAllocationGroup *allocations;
-
- PaHostApiIndex hostApiIndex;
-}
-PaOSSHostApiRepresentation;
-
-/** Per-direction structure for PaOssStream.
- *
- * Aspect StreamChannels: In case the user requests to open the same device for both capture and playback,
- * but with different number of channels we will have to adapt between the number of user and host
- * channels for at least one direction, since the configuration space is the same for both directions
- * of an OSS device.
- */
-typedef struct
-{
- int fd;
- const char *devName;
- int userChannelCount, hostChannelCount;
- int userInterleaved;
- void *buffer;
- PaSampleFormat userFormat, hostFormat;
- double latency;
- unsigned long hostFrames, numBufs;
- void **userBuffers; /* For non-interleaved blocking */
-} PaOssStreamComponent;
-
-/** Implementation specific representation of a PaStream.
- *
- */
-typedef struct PaOssStream
-{
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
-
- PaUtilThreading threading;
-
- int sharedDevice;
- unsigned long framesPerHostBuffer;
- int triggered; /* Have the devices been triggered yet (first start) */
-
- int isActive;
- int isStopped;
-
- int lastPosPtr;
- double lastStreamBytes;
-
- int framesProcessed;
-
- double sampleRate;
-
- int callbackMode;
- int callbackStop, callbackAbort;
-
- PaOssStreamComponent *capture, *playback;
- unsigned long pollTimeout;
- sem_t semaphore;
-}
-PaOssStream;
-
-typedef enum {
- StreamMode_In,
- StreamMode_Out
-} StreamMode;
-
-/* prototypes for functions declared in this file */
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate );
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData );
-static PaError CloseStream( PaStream* stream );
-static PaError StartStream( PaStream *stream );
-static PaError StopStream( PaStream *stream );
-static PaError AbortStream( PaStream *stream );
-static PaError IsStreamStopped( PaStream *s );
-static PaError IsStreamActive( PaStream *stream );
-static PaTime GetStreamTime( PaStream *stream );
-static double GetStreamCpuLoad( PaStream* stream );
-static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
-static PaError WriteStream( PaStream* stream, const void *buffer, unsigned long frames );
-static signed long GetStreamReadAvailable( PaStream* stream );
-static signed long GetStreamWriteAvailable( PaStream* stream );
-static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi );
-
-
-/** Initialize the OSS API implementation.
- *
- * This function will initialize host API datastructures and query host devices for information.
- *
- * Aspect DeviceCapabilities: Enumeration of host API devices is initiated from here
- *
- * Aspect FreeResources: If an error is encountered under way we have to free each resource allocated in this function,
- * this happens with the usual "error" label.
- */
-PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- PaOSSHostApiRepresentation *ossHostApi = NULL;
-
- PA_UNLESS( ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) ),
- paInsufficientMemory );
- PA_UNLESS( ossHostApi->allocations = PaUtil_CreateAllocationGroup(), paInsufficientMemory );
- ossHostApi->hostApiIndex = hostApiIndex;
-
- /* Initialize host API structure */
- *hostApi = &ossHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paOSS;
- (*hostApi)->info.name = "OSS";
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PA_ENSURE( BuildDeviceList( ossHostApi ) );
-
- PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable,
- PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
- mainThread_ = pthread_self();
-
- return result;
-
-error:
- if( ossHostApi )
- {
- if( ossHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( ossHostApi->allocations );
- PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
- }
-
- PaUtil_FreeMemory( ossHostApi );
- }
- return result;
-}
-
-PaError PaUtil_InitializeDeviceInfo( PaDeviceInfo *deviceInfo, const char *name, PaHostApiIndex hostApiIndex, int maxInputChannels,
- int maxOutputChannels, PaTime defaultLowInputLatency, PaTime defaultLowOutputLatency, PaTime defaultHighInputLatency,
- PaTime defaultHighOutputLatency, double defaultSampleRate, PaUtilAllocationGroup *allocations )
-{
- PaError result = paNoError;
-
- deviceInfo->structVersion = 2;
- if( allocations )
- {
- size_t len = strlen( name ) + 1;
- PA_UNLESS( deviceInfo->name = PaUtil_GroupAllocateMemory( allocations, len ), paInsufficientMemory );
- strncpy( (char *)deviceInfo->name, name, len );
- }
- else
- deviceInfo->name = name;
-
- deviceInfo->hostApi = hostApiIndex;
- deviceInfo->maxInputChannels = maxInputChannels;
- deviceInfo->maxOutputChannels = maxOutputChannels;
- deviceInfo->defaultLowInputLatency = defaultLowInputLatency;
- deviceInfo->defaultLowOutputLatency = defaultLowOutputLatency;
- deviceInfo->defaultHighInputLatency = defaultHighInputLatency;
- deviceInfo->defaultHighOutputLatency = defaultHighOutputLatency;
- deviceInfo->defaultSampleRate = defaultSampleRate;
-
-error:
- return result;
-}
-
-static PaError QueryDirection( const char *deviceName, StreamMode mode, double *defaultSampleRate, int *maxChannelCount,
- double *defaultLowLatency, double *defaultHighLatency )
-{
- PaError result = paNoError;
- int numChannels, maxNumChannels;
- int busy = 0;
- int devHandle = -1;
- int sr;
- *maxChannelCount = 0; /* Default value in case this fails */
-
- if ( (devHandle = open( deviceName, (mode == StreamMode_In ? O_RDONLY : O_WRONLY) | O_NONBLOCK )) < 0 )
- {
- if( errno == EBUSY || errno == EAGAIN )
- {
- PA_DEBUG(( "%s: Device %s busy\n", __FUNCTION__, deviceName ));
- }
- else
- {
- PA_DEBUG(( "%s: Can't access device: %s\n", __FUNCTION__, strerror( errno ) ));
- }
-
- return paDeviceUnavailable;
- }
-
- /* Negotiate for the maximum number of channels for this device. PLB20010927
- * Consider up to 16 as the upper number of channels.
- * Variable maxNumChannels should contain the actual upper limit after the call.
- * Thanks to John Lazzaro and Heiko Purnhagen for suggestions.
- */
- maxNumChannels = 0;
- for( numChannels = 1; numChannels <= 16; numChannels++ )
- {
- int temp = numChannels;
- if( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ) < 0 )
- {
- busy = EAGAIN == errno || EBUSY == errno;
- /* ioctl() failed so bail out if we already have stereo */
- if( maxNumChannels >= 2 )
- break;
- }
- else
- {
- /* ioctl() worked but bail out if it does not support numChannels.
- * We don't want to leave gaps in the numChannels supported.
- */
- if( (numChannels > 2) && (temp != numChannels) )
- break;
- if( temp > maxNumChannels )
- maxNumChannels = temp; /* Save maximum. */
- }
- }
- /* A: We're able to open a device for capture if it's busy playing back and vice versa,
- * but we can't configure anything */
- if( 0 == maxNumChannels && busy )
- {
- result = paDeviceUnavailable;
- goto error;
- }
-
- /* The above negotiation may fail for an old driver so try this older technique. */
- if( maxNumChannels < 1 )
- {
- int stereo = 1;
- if( ioctl( devHandle, SNDCTL_DSP_STEREO, &stereo ) < 0 )
- {
- maxNumChannels = 1;
- }
- else
- {
- maxNumChannels = (stereo) ? 2 : 1;
- }
- PA_DEBUG(( "%s: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", __FUNCTION__, maxNumChannels ))
- }
-
- /* During channel negotiation, the last ioctl() may have failed. This can
- * also cause sample rate negotiation to fail. Hence the following, to return
- * to a supported number of channels. SG20011005 */
- {
- /* use most reasonable default value */
- int temp = PA_MIN( maxNumChannels, 2 );
- ENSURE_( ioctl( devHandle, SNDCTL_DSP_CHANNELS, &temp ), paUnanticipatedHostError );
- }
-
- /* Get supported sample rate closest to 44100 Hz */
- if( *defaultSampleRate < 0 )
- {
- sr = 44100;
- if( ioctl( devHandle, SNDCTL_DSP_SPEED, &sr ) < 0 )
- {
- result = paUnanticipatedHostError;
- goto error;
- }
-
- *defaultSampleRate = sr;
- }
-
- *maxChannelCount = maxNumChannels;
- /* TODO */
- *defaultLowLatency = 512. / *defaultSampleRate;
- *defaultHighLatency = 2048. / *defaultSampleRate;
-
-error:
- if( devHandle >= 0 )
- close( devHandle );
-
- return result;
-}
-
-/** Query OSS device.
- *
- * This is where PaDeviceInfo objects are constructed and filled in with relevant information.
- *
- * Aspect DeviceCapabilities: The inferred device capabilities are recorded in a PaDeviceInfo object that is constructed
- * in place.
- */
-static PaError QueryDevice( char *deviceName, PaOSSHostApiRepresentation *ossApi, PaDeviceInfo **deviceInfo )
-{
- PaError result = paNoError;
- double sampleRate = -1.;
- int maxInputChannels, maxOutputChannels;
- PaTime defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency;
- PaError tmpRes = paNoError;
- int busy = 0;
- *deviceInfo = NULL;
-
- /* douglas:
- we have to do this querying in a slightly different order. apparently
- some sound cards will give you different info based on their settins.
- e.g. a card might give you stereo at 22kHz but only mono at 44kHz.
- the correct order for OSS is: format, channels, sample rate
- */
-
- /* Aspect StreamChannels: The number of channels supported for a device may depend on the mode it is
- * opened in, it may have more channels available for capture than playback and vice versa. Therefore
- * we will open the device in both read- and write-only mode to determine the supported number.
- */
- if( (tmpRes = QueryDirection( deviceName, StreamMode_In, &sampleRate, &maxInputChannels, &defaultLowInputLatency,
- &defaultHighInputLatency )) != paNoError )
- {
- if( tmpRes != paDeviceUnavailable )
- {
- PA_DEBUG(( "%s: Querying device %s for capture failed!\n", __FUNCTION__, deviceName ));
- /* PA_ENSURE( tmpRes ); */
- }
- ++busy;
- }
- if( (tmpRes = QueryDirection( deviceName, StreamMode_Out, &sampleRate, &maxOutputChannels, &defaultLowOutputLatency,
- &defaultHighOutputLatency )) != paNoError )
- {
- if( tmpRes != paDeviceUnavailable )
- {
- PA_DEBUG(( "%s: Querying device %s for playback failed!\n", __FUNCTION__, deviceName ));
- /* PA_ENSURE( tmpRes ); */
- }
- ++busy;
- }
- assert( 0 <= busy && busy <= 2 );
- if( 2 == busy ) /* Both directions are unavailable to us */
- {
- result = paDeviceUnavailable;
- goto error;
- }
-
- PA_UNLESS( *deviceInfo = PaUtil_GroupAllocateMemory( ossApi->allocations, sizeof (PaDeviceInfo) ), paInsufficientMemory );
- PA_ENSURE( PaUtil_InitializeDeviceInfo( *deviceInfo, deviceName, ossApi->hostApiIndex, maxInputChannels, maxOutputChannels,
- defaultLowInputLatency, defaultLowOutputLatency, defaultHighInputLatency, defaultHighOutputLatency, sampleRate,
- ossApi->allocations ) );
-
-error:
- return result;
-}
-
-/** Query host devices.
- *
- * Loop over host devices and query their capabilitiesu
- *
- * Aspect DeviceCapabilities: This function calls QueryDevice on each device entry and receives a filled in PaDeviceInfo object
- * per device, these are placed in the host api representation's deviceInfos array.
- */
-static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi )
-{
- PaError result = paNoError;
- PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep;
- int i;
- int numDevices = 0, maxDeviceInfos = 1;
- PaDeviceInfo **deviceInfos = NULL;
-
- /* These two will be set to the first working input and output device, respectively */
- commonApi->info.defaultInputDevice = paNoDevice;
- commonApi->info.defaultOutputDevice = paNoDevice;
-
- /* Find devices by calling QueryDevice on each
- * potential device names. When we find a valid one,
- * add it to a linked list.
- * A: Can there only be 10 devices? */
-
- for( i = 0; i < 10; i++ )
- {
- char deviceName[32];
- PaDeviceInfo *deviceInfo;
- int testResult;
- struct stat stbuf;
-
- if( i == 0 )
- snprintf(deviceName, sizeof (deviceName), "%s", DEVICE_NAME_BASE);
- else
- snprintf(deviceName, sizeof (deviceName), "%s%d", DEVICE_NAME_BASE, i);
-
- /* PA_DEBUG(("PaOSS BuildDeviceList: trying device %s\n", deviceName )); */
- if( stat( deviceName, &stbuf ) < 0 )
- {
- if( ENOENT != errno )
- PA_DEBUG(( "%s: Error stat'ing %s: %s\n", __FUNCTION__, deviceName, strerror( errno ) ));
- continue;
- }
- if( (testResult = QueryDevice( deviceName, ossApi, &deviceInfo )) != paNoError )
- {
- if( testResult != paDeviceUnavailable )
- PA_ENSURE( testResult );
-
- continue;
- }
-
- ++numDevices;
- if( !deviceInfos || numDevices > maxDeviceInfos )
- {
- maxDeviceInfos *= 2;
- PA_UNLESS( deviceInfos = (PaDeviceInfo **) realloc( deviceInfos, maxDeviceInfos * sizeof (PaDeviceInfo *) ),
- paInsufficientMemory );
- }
- deviceInfos[numDevices - 1] = deviceInfo;
-
- if( commonApi->info.defaultInputDevice == paNoDevice && deviceInfo->maxInputChannels > 0 )
- commonApi->info.defaultInputDevice = i;
- if( commonApi->info.defaultOutputDevice == paNoDevice && deviceInfo->maxOutputChannels > 0 )
- commonApi->info.defaultOutputDevice = i;
- }
-
- /* Make an array of PaDeviceInfo pointers out of the linked list */
-
- PA_DEBUG(("PaOSS %s: Total number of devices found: %d\n", __FUNCTION__, numDevices));
-
- commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- ossApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
- memcpy( commonApi->deviceInfos, deviceInfos, numDevices * sizeof (PaDeviceInfo *) );
-
- commonApi->info.deviceCount = numDevices;
-
-error:
- free( deviceInfos );
-
- return result;
-}
-
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
-
- if( ossHostApi->allocations )
- {
- PaUtil_FreeAllAllocations( ossHostApi->allocations );
- PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
- }
-
- PaUtil_FreeMemory( ossHostApi );
-}
-
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- PaError result = paNoError;
- PaDeviceIndex device;
- PaDeviceInfo *deviceInfo;
- char *deviceName;
- int inputChannelCount, outputChannelCount;
- int tempDevHandle = -1;
- int flags;
- PaSampleFormat inputSampleFormat, outputSampleFormat;
-
- if( inputParameters )
- {
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that input device can support inputChannelCount */
- if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
- return paInvalidChannelCount;
-
- /* validate inputStreamInfo */
- if( inputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- inputChannelCount = 0;
- }
-
- if( outputParameters )
- {
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
-
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
-
- if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
- return paInvalidDevice;
-
- /* check that output device can support inputChannelCount */
- if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
- return paInvalidChannelCount;
-
- /* validate outputStreamInfo */
- if( outputParameters->hostApiSpecificStreamInfo )
- return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
- }
- else
- {
- outputChannelCount = 0;
- }
-
- if (inputChannelCount == 0 && outputChannelCount == 0)
- return paInvalidChannelCount;
-
- /* if full duplex, make sure that they're the same device */
-
- if (inputChannelCount > 0 && outputChannelCount > 0 &&
- inputParameters->device != outputParameters->device)
- return paInvalidDevice;
-
- /* if full duplex, also make sure that they're the same number of channels */
-
- if (inputChannelCount > 0 && outputChannelCount > 0 &&
- inputChannelCount != outputChannelCount)
- return paInvalidChannelCount;
-
- /* open the device so we can do more tests */
-
- if( inputChannelCount > 0 )
- {
- result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi);
- if (result != paNoError)
- return result;
- }
- else
- {
- result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi);
- if (result != paNoError)
- return result;
- }
-
- deviceInfo = hostApi->deviceInfos[device];
- deviceName = (char *)deviceInfo->name;
-
- flags = O_NONBLOCK;
- if (inputChannelCount > 0 && outputChannelCount > 0)
- flags |= O_RDWR;
- else if (inputChannelCount > 0)
- flags |= O_RDONLY;
- else
- flags |= O_WRONLY;
-
- ENSURE_( tempDevHandle = open( deviceInfo->name, flags ), paDeviceUnavailable );
-
- /* PaOssStream_Configure will do the rest of the checking for us */
- /* PA_ENSURE( PaOssStream_Configure( tempDevHandle, deviceName, outputChannelCount, &sampleRate ) ); */
-
- /* everything succeeded! */
-
- error:
- if( tempDevHandle >= 0 )
- close( tempDevHandle );
-
- return result;
-}
-
-/** Validate stream parameters.
- *
- * Aspect StreamChannels: We verify that the number of channels is within the allowed range for the device
- */
-static PaError ValidateParameters( const PaStreamParameters *parameters, const PaDeviceInfo *deviceInfo, StreamMode mode )
-{
- int maxChans;
-
- assert( parameters );
-
- if( parameters->device == paUseHostApiSpecificDeviceSpecification )
- {
- return paInvalidDevice;
- }
-
- maxChans = (mode == StreamMode_In ? deviceInfo->maxInputChannels :
- deviceInfo->maxOutputChannels);
- if( parameters->channelCount > maxChans )
- {
- return paInvalidChannelCount;
- }
-
- return paNoError;
-}
-
-static PaError PaOssStreamComponent_Initialize( PaOssStreamComponent *component, const PaStreamParameters *parameters,
- int callbackMode, int fd, const char *deviceName )
-{
- PaError result = paNoError;
- assert( component );
-
- memset( component, 0, sizeof (PaOssStreamComponent) );
-
- component->fd = fd;
- component->devName = deviceName;
- component->userChannelCount = parameters->channelCount;
- component->userFormat = parameters->sampleFormat;
- component->latency = parameters->suggestedLatency;
- component->userInterleaved = !(parameters->sampleFormat & paNonInterleaved);
-
- if( !callbackMode && !component->userInterleaved )
- {
- /* Pre-allocate non-interleaved user provided buffers */
- PA_UNLESS( component->userBuffers = PaUtil_AllocateMemory( sizeof (void *) * component->userChannelCount ),
- paInsufficientMemory );
- }
-
-error:
- return result;
-}
-
-static void PaOssStreamComponent_Terminate( PaOssStreamComponent *component )
-{
- assert( component );
-
- if( component->fd >= 0 )
- close( component->fd );
- if( component->buffer )
- PaUtil_FreeMemory( component->buffer );
-
- if( component->userBuffers )
- PaUtil_FreeMemory( component->userBuffers );
-
- PaUtil_FreeMemory( component );
-}
-
-static PaError ModifyBlocking( int fd, int blocking )
-{
- PaError result = paNoError;
- int fflags;
-
- ENSURE_( fflags = fcntl( fd, F_GETFL ), paUnanticipatedHostError );
-
- if( blocking )
- fflags &= ~O_NONBLOCK;
- else
- fflags |= O_NONBLOCK;
-
- ENSURE_( fcntl( fd, F_SETFL, fflags ), paUnanticipatedHostError );
-
-error:
- return result;
-}
-
-static PaError OpenDevices( const char *idevName, const char *odevName, int *idev, int *odev )
-{
- PaError result = paNoError;
- int flags = O_NONBLOCK, duplex = 0;
- int enableBits = 0;
- *idev = *odev = -1;
-
- if( idevName && odevName )
- {
- duplex = 1;
- flags |= O_RDWR;
- }
- else if( idevName )
- flags |= O_RDONLY;
- else
- flags |= O_WRONLY;
-
- /* open first in nonblocking mode, in case it's busy...
- * A: then unset the non-blocking attribute */
- assert( flags & O_NONBLOCK );
- if( idevName )
- {
- ENSURE_( *idev = open( idevName, flags ), paDeviceUnavailable );
- PA_ENSURE( ModifyBlocking( *idev, 1 ) ); /* Blocking */
-
- /* Initially disable */
- enableBits = ~PCM_ENABLE_INPUT;
- ENSURE_( ioctl( *idev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
- }
- if( odevName )
- {
- if( !idevName )
- {
- ENSURE_( *odev = open( odevName, flags ), paDeviceUnavailable );
- PA_ENSURE( ModifyBlocking( *odev, 1 ) ); /* Blocking */
-
- /* Initially disable */
- enableBits = ~PCM_ENABLE_OUTPUT;
- ENSURE_( ioctl( *odev, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
- }
- else
- {
- ENSURE_( *odev = dup( *idev ), paUnanticipatedHostError );
- }
- }
-
-error:
- return result;
-}
-
-static PaError PaOssStream_Initialize( PaOssStream *stream, const PaStreamParameters *inputParameters, const PaStreamParameters *outputParameters,
- PaStreamCallback callback, void *userData, PaStreamFlags streamFlags,
- PaOSSHostApiRepresentation *ossApi )
-{
- PaError result = paNoError;
- int idev, odev;
- PaUtilHostApiRepresentation *hostApi = &ossApi->inheritedHostApiRep;
- const char *idevName = NULL, *odevName = NULL;
-
- assert( stream );
-
- memset( stream, 0, sizeof (PaOssStream) );
- stream->isStopped = 1;
-
- PA_ENSURE( PaUtil_InitializeThreading( &stream->threading ) );
-
- if( inputParameters && outputParameters )
- {
- if( inputParameters->device == outputParameters->device )
- stream->sharedDevice = 1;
- }
-
- if( inputParameters )
- idevName = hostApi->deviceInfos[inputParameters->device]->name;
- if( outputParameters )
- odevName = hostApi->deviceInfos[outputParameters->device]->name;
- PA_ENSURE( OpenDevices( idevName, odevName, &idev, &odev ) );
- if( inputParameters )
- {
- PA_UNLESS( stream->capture = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );
- PA_ENSURE( PaOssStreamComponent_Initialize( stream->capture, inputParameters, callback != NULL, idev, idevName ) );
- }
- if( outputParameters )
- {
- PA_UNLESS( stream->playback = PaUtil_AllocateMemory( sizeof (PaOssStreamComponent) ), paInsufficientMemory );
- PA_ENSURE( PaOssStreamComponent_Initialize( stream->playback, outputParameters, callback != NULL, odev, odevName ) );
- }
-
- if( callback != NULL )
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &ossApi->callbackStreamInterface, callback, userData );
- stream->callbackMode = 1;
- }
- else
- {
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- &ossApi->blockingStreamInterface, callback, userData );
- }
-
- ENSURE_( sem_init( &stream->semaphore, 0, 0 ), paInternalError );
-
-error:
- return result;
-}
-
-static void PaOssStream_Terminate( PaOssStream *stream )
-{
- assert( stream );
-
- PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
- PaUtil_TerminateThreading( &stream->threading );
-
- if( stream->capture )
- PaOssStreamComponent_Terminate( stream->capture );
- if( stream->playback )
- PaOssStreamComponent_Terminate( stream->playback );
-
- sem_destroy( &stream->semaphore );
-
- PaUtil_FreeMemory( stream );
-}
-
-/** Translate from PA format to OSS native.
- *
- */
-static PaError Pa2OssFormat( PaSampleFormat paFormat, int *ossFormat )
-{
- switch( paFormat )
- {
- case paUInt8:
- *ossFormat = AFMT_U8;
- break;
- case paInt8:
- *ossFormat = AFMT_S8;
- break;
- case paInt16:
- *ossFormat = AFMT_S16_NE;
- break;
- default:
- return paInternalError; /* This shouldn't happen */
- }
-
- return paNoError;
-}
-
-/** Return the PA-compatible formats that this device can support.
- *
- */
-static PaError GetAvailableFormats( PaOssStreamComponent *component, PaSampleFormat *availableFormats )
-{
- PaError result = paNoError;
- int mask = 0;
- PaSampleFormat frmts = 0;
-
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETFMTS, &mask ), paUnanticipatedHostError );
- if( mask & AFMT_U8 )
- frmts |= paUInt8;
- if( mask & AFMT_S8 )
- frmts |= paInt8;
- if( mask & AFMT_S16_NE )
- frmts |= paInt16;
- else
- result = paSampleFormatNotSupported;
-
- *availableFormats = frmts;
-
-error:
- return result;
-}
-
-static unsigned int PaOssStreamComponent_FrameSize( PaOssStreamComponent *component )
-{
- return Pa_GetSampleSize( component->hostFormat ) * component->hostChannelCount;
-}
-
-/** Buffer size in bytes.
- *
- */
-static unsigned long PaOssStreamComponent_BufferSize( PaOssStreamComponent *component )
-{
- return PaOssStreamComponent_FrameSize( component ) * component->hostFrames * component->numBufs;
-}
-
-static int CalcHigherLogTwo( int n )
-{
- int log2 = 0;
- while( (1<<log2) < n ) log2++;
- return log2;
-}
-
-static PaError PaOssStreamComponent_Configure( PaOssStreamComponent *component, double sampleRate, unsigned long framesPerBuffer,
- StreamMode streamMode, PaOssStreamComponent *master )
-{
- PaError result = paNoError;
- int temp, nativeFormat;
- int sr = (int)sampleRate;
- PaSampleFormat availableFormats, hostFormat;
- int chans = component->userChannelCount;
- int frgmt;
- int numBufs;
- int bytesPerBuf;
- double bufSz;
- unsigned long fragSz;
- audio_buf_info bufInfo;
-
- /* We may have a situation where only one component (the master) is configured, if both point to the same device.
- * In that case, the second component will copy settings from the other */
- if( !master )
- {
- /* Aspect BufferSettings: If framesPerBuffer is unspecified we have to infer a suitable fragment size.
- * The hardware need not respect the requested fragment size, so we may have to adapt.
- */
- if( framesPerBuffer == paFramesPerBufferUnspecified )
- {
- bufSz = component->latency * sampleRate;
- fragSz = bufSz / 4;
- }
- else
- {
- fragSz = framesPerBuffer;
- bufSz = component->latency * sampleRate + fragSz; /* Latency + 1 buffer */
- }
-
- PA_ENSURE( GetAvailableFormats( component, &availableFormats ) );
- hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, component->userFormat );
-
- /* OSS demands at least 2 buffers, and 16 bytes per buffer */
- numBufs = PA_MAX( bufSz / fragSz, 2 );
- bytesPerBuf = PA_MAX( fragSz * Pa_GetSampleSize( hostFormat ) * chans, 16 );
-
- /* The fragment parameters are encoded like this:
- * Most significant byte: number of fragments
- * Least significant byte: exponent of fragment size (i.e., for 256, 8)
- */
- frgmt = (numBufs << 16) + (CalcHigherLogTwo( bytesPerBuf ) & 0xffff);
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFRAGMENT, &frgmt ), paUnanticipatedHostError );
-
- /* A: according to the OSS programmer's guide parameters should be set in this order:
- * format, channels, rate */
-
- /* This format should be deemed good before we get this far */
- PA_ENSURE( Pa2OssFormat( hostFormat, &temp ) );
- nativeFormat = temp;
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_SETFMT, &temp ), paUnanticipatedHostError );
- PA_UNLESS( temp == nativeFormat, paInternalError );
-
- /* try to set the number of channels */
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_CHANNELS, &chans ), paSampleFormatNotSupported ); /* XXX: Should be paInvalidChannelCount? */
- /* It's possible that the minimum number of host channels is greater than what the user requested */
- PA_UNLESS( chans >= component->userChannelCount, paInvalidChannelCount );
-
- /* try to set the sample rate */
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_SPEED, &sr ), paInvalidSampleRate );
-
- /* reject if there's no sample rate within 1% of the one requested */
- if( (fabs( sampleRate - sr ) / sampleRate) > 0.01 )
- {
- PA_DEBUG(("%s: Wanted %f, closest sample rate was %d\n", __FUNCTION__, sampleRate, sr ));
- PA_ENSURE( paInvalidSampleRate );
- }
-
- ENSURE_( ioctl( component->fd, streamMode == StreamMode_In ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &bufInfo ),
- paUnanticipatedHostError );
- component->numBufs = bufInfo.fragstotal;
-
- /* This needs to be the last ioctl call before the first read/write, according to the OSS programmer's guide */
- ENSURE_( ioctl( component->fd, SNDCTL_DSP_GETBLKSIZE, &bytesPerBuf ), paUnanticipatedHostError );
-
- component->hostFrames = bytesPerBuf / Pa_GetSampleSize( hostFormat ) / chans;
- component->hostChannelCount = chans;
- component->hostFormat = hostFormat;
- }
- else
- {
- component->hostFormat = master->hostFormat;
- component->hostFrames = master->hostFrames;
- component->hostChannelCount = master->hostChannelCount;
- component->numBufs = master->numBufs;
- }
-
- PA_UNLESS( component->buffer = PaUtil_AllocateMemory( PaOssStreamComponent_BufferSize( component ) ),
- paInsufficientMemory );
-
-error:
- return result;
-}
-
-static PaError PaOssStreamComponent_Read( PaOssStreamComponent *component, unsigned long *frames )
-{
- PaError result = paNoError;
- size_t len = *frames * PaOssStreamComponent_FrameSize( component );
- ssize_t bytesRead;
-
- ENSURE_( bytesRead = read( component->fd, component->buffer, len ), paUnanticipatedHostError );
- *frames = bytesRead / PaOssStreamComponent_FrameSize( component );
-
-error:
- return result;
-}
-
-static PaError PaOssStreamComponent_Write( PaOssStreamComponent *component, unsigned long *frames )
-{
- PaError result = paNoError;
- size_t len = *frames * PaOssStreamComponent_FrameSize( component );
- ssize_t bytesWritten;
-
- ENSURE_( bytesWritten = write( component->fd, component->buffer, len ), paUnanticipatedHostError );
- *frames = bytesWritten / PaOssStreamComponent_FrameSize( component );
-
-error:
- return result;
-}
-
-/** Configure the stream according to input/output parameters.
- *
- * Aspect StreamChannels: The minimum number of channels supported by the device may exceed that requested by
- * the user, if so we'll record the actual number of host channels and adapt later.
- */
-static PaError PaOssStream_Configure( PaOssStream *stream, double sampleRate, unsigned long framesPerBuffer,
- double *inputLatency, double *outputLatency )
-{
- PaError result = paNoError;
- int duplex = stream->capture && stream->playback;
- unsigned long framesPerHostBuffer = 0;
-
- /* We should request full duplex first thing after opening the device */
- if( duplex && stream->sharedDevice )
- ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETDUPLEX, 0 ), paUnanticipatedHostError );
-
- if( stream->capture )
- {
- PaOssStreamComponent *component = stream->capture;
- PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_In, NULL );
-
- assert( component->hostChannelCount > 0 );
- assert( component->hostFrames > 0 );
-
- *inputLatency = component->hostFrames * (component->numBufs - 1) / sampleRate;
- }
- if( stream->playback )
- {
- PaOssStreamComponent *component = stream->playback, *master = stream->sharedDevice ? stream->capture : NULL;
- PA_ENSURE( PaOssStreamComponent_Configure( component, sampleRate, framesPerBuffer, StreamMode_Out,
- master ) );
-
- assert( component->hostChannelCount > 0 );
- assert( component->hostFrames > 0 );
-
- *outputLatency = component->hostFrames * (component->numBufs - 1) / sampleRate;
- }
-
- if( duplex )
- framesPerHostBuffer = PA_MIN( stream->capture->hostFrames, stream->playback->hostFrames );
- else if( stream->capture )
- framesPerHostBuffer = stream->capture->hostFrames;
- else if( stream->playback )
- framesPerHostBuffer = stream->playback->hostFrames;
-
- stream->framesPerHostBuffer = framesPerHostBuffer;
- stream->pollTimeout = (int) ceil( 1e6 * framesPerHostBuffer / sampleRate ); /* Period in usecs, rounded up */
-
- stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
-
-error:
- return result;
-}
-
-/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
-
-/** Open a PA OSS stream.
- *
- * Aspect StreamChannels: The number of channels is specified per direction (in/out), and can differ between the
- * two. However, OSS doesn't support separate configuration spaces for capture and playback so if both
- * directions are the same device we will demand the same number of channels. The number of channels can range
- * from 1 to the maximum supported by the device.
- *
- * Aspect BufferSettings: If framesPerBuffer != paFramesPerBufferUnspecified the number of frames per callback
- * must reflect this, in addition the host latency per device should approximate the corresponding
- * suggestedLatency. Based on these constraints we need to determine a number of frames per host buffer that
- * both capture and playback can agree on (they can be different devices), the buffer processor can adapt
- * between host and user buffer size, but the ratio should preferably be integral.
- */
-static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
- PaStream** s,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate,
- unsigned long framesPerBuffer,
- PaStreamFlags streamFlags,
- PaStreamCallback *streamCallback,
- void *userData )
-{
- PaError result = paNoError;
- PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
- PaOssStream *stream = NULL;
- int inputChannelCount = 0, outputChannelCount = 0;
- PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0, inputHostFormat = 0, outputHostFormat = 0;
- const PaDeviceInfo *inputDeviceInfo = 0, *outputDeviceInfo = 0;
- int bpInitialized = 0;
- double inLatency, outLatency;
-
- /* validate platform specific flags */
- if( (streamFlags & paPlatformSpecificFlags) != 0 )
- return paInvalidFlag; /* unexpected platform specific flag */
-
- if( inputParameters )
- {
- /* unless alternate device specification is supported, reject the use of
- paUseHostApiSpecificDeviceSpecification */
- inputDeviceInfo = hostApi->deviceInfos[inputParameters->device];
- PA_ENSURE( ValidateParameters( inputParameters, inputDeviceInfo, StreamMode_In ) );
-
- inputChannelCount = inputParameters->channelCount;
- inputSampleFormat = inputParameters->sampleFormat;
- }
- if( outputParameters )
- {
- outputDeviceInfo = hostApi->deviceInfos[outputParameters->device];
- PA_ENSURE( ValidateParameters( outputParameters, outputDeviceInfo, StreamMode_Out ) );
-
- outputChannelCount = outputParameters->channelCount;
- outputSampleFormat = outputParameters->sampleFormat;
- }
-
- /* Aspect StreamChannels: We currently demand that number of input and output channels are the same, if the same
- * device is opened for both directions
- */
- if( inputChannelCount > 0 && outputChannelCount > 0 )
- {
- if( inputParameters->device == outputParameters->device )
- {
- if( inputParameters->channelCount != outputParameters->channelCount )
- return paInvalidChannelCount;
- }
- }
-
- /* allocate and do basic initialization of the stream structure */
- PA_UNLESS( stream = (PaOssStream*)PaUtil_AllocateMemory( sizeof(PaOssStream) ), paInsufficientMemory );
- PaOssStream_Initialize( stream, inputParameters, outputParameters, streamCallback, userData, streamFlags, ossHostApi );
-
- PA_ENSURE( PaOssStream_Configure( stream, sampleRate, framesPerBuffer, &inLatency, &outLatency ) );
-
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
- if( inputParameters )
- {
- inputHostFormat = stream->capture->hostFormat;
- stream->streamRepresentation.streamInfo.inputLatency = inLatency +
- PaUtil_GetBufferProcessorInputLatency( &stream->bufferProcessor ) / sampleRate;
- }
- if( outputParameters )
- {
- outputHostFormat = stream->playback->hostFormat;
- stream->streamRepresentation.streamInfo.outputLatency = outLatency +
- PaUtil_GetBufferProcessorOutputLatency( &stream->bufferProcessor ) / sampleRate;
- }
-
- /* Initialize buffer processor with fixed host buffer size.
- * Aspect StreamSampleFormat: Here we commit the user and host sample formats, PA infrastructure will
- * convert between the two.
- */
- PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
- inputChannelCount, inputSampleFormat, inputHostFormat, outputChannelCount, outputSampleFormat,
- outputHostFormat, sampleRate, streamFlags, framesPerBuffer, stream->framesPerHostBuffer,
- paUtilFixedHostBufferSize, streamCallback, userData ) );
- bpInitialized = 1;
-
- *s = (PaStream*)stream;
-
- return result;
-
-error:
- if( bpInitialized )
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- if( stream )
- PaOssStream_Terminate( stream );
-
- return result;
-}
-
-/*! Poll on I/O filedescriptors.
-
- Poll till we've determined there's data for read or write. In the full-duplex case,
- we don't want to hang around forever waiting for either input or output frames, so
- whenever we have a timed out filedescriptor we check if we're nearing under/overrun
- for the other direction (critical limit set at one buffer). If so, we exit the waiting
- state, and go on with what we got. We align the number of frames on a host buffer
- boundary because it is possible that the buffer size differs for the two directions and
- the host buffer size is a compromise between the two.
- */
-static PaError PaOssStream_WaitForFrames( PaOssStream *stream, unsigned long *frames )
-{
- PaError result = paNoError;
- int pollPlayback = 0, pollCapture = 0;
- int captureAvail = INT_MAX, playbackAvail = INT_MAX, commonAvail;
- audio_buf_info bufInfo;
- /* int ofs = 0, nfds = stream->nfds; */
- fd_set readFds, writeFds;
- int nfds = 0;
- struct timeval selectTimeval = {0, 0};
- unsigned long timeout = stream->pollTimeout; /* In usecs */
- int captureFd = -1, playbackFd = -1;
-
- assert( stream );
- assert( frames );
-
- if( stream->capture )
- {
- pollCapture = 1;
- captureFd = stream->capture->fd;
- /* stream->capture->pfd->events = POLLIN; */
- }
- if( stream->playback )
- {
- pollPlayback = 1;
- playbackFd = stream->playback->fd;
- /* stream->playback->pfd->events = POLLOUT; */
- }
-
- FD_ZERO( &readFds );
- FD_ZERO( &writeFds );
-
- while( pollPlayback || pollCapture )
- {
- pthread_testcancel();
-
- /* select may modify the timeout parameter */
- selectTimeval.tv_usec = timeout;
- nfds = 0;
-
- if( pollCapture )
- {
- FD_SET( captureFd, &readFds );
- nfds = captureFd + 1;
- }
- if( pollPlayback )
- {
- FD_SET( playbackFd, &writeFds );
- nfds = PA_MAX( nfds, playbackFd + 1 );
- }
- ENSURE_( select( nfds, &readFds, &writeFds, NULL, &selectTimeval ), paUnanticipatedHostError );
- /*
- if( poll( stream->pfds + ofs, nfds, stream->pollTimeout ) < 0 )
- {
-
- ENSURE_( -1, paUnanticipatedHostError );
- }
- */
- pthread_testcancel();
-
- if( pollCapture )
- {
- if( FD_ISSET( captureFd, &readFds ) )
- {
- FD_CLR( captureFd, &readFds );
- pollCapture = 0;
- }
- /*
- if( stream->capture->pfd->revents & POLLIN )
- {
- --nfds;
- ++ofs;
- pollCapture = 0;
- }
- */
- else if( stream->playback ) /* Timed out, go on with playback? */
- {
- /*PA_DEBUG(( "%s: Trying to poll again for capture frames, pollTimeout: %d\n",
- __FUNCTION__, stream->pollTimeout ));*/
- }
- }
- if( pollPlayback )
- {
- if( FD_ISSET( playbackFd, &writeFds ) )
- {
- FD_CLR( playbackFd, &writeFds );
- pollPlayback = 0;
- }
- /*
- if( stream->playback->pfd->revents & POLLOUT )
- {
- --nfds;
- pollPlayback = 0;
- }
- */
- else if( stream->capture ) /* Timed out, go on with capture? */
- {
- /*PA_DEBUG(( "%s: Trying to poll again for playback frames, pollTimeout: %d\n\n",
- __FUNCTION__, stream->pollTimeout ));*/
- }
- }
- }
-
- if( stream->capture )
- {
- ENSURE_( ioctl( captureFd, SNDCTL_DSP_GETISPACE, &bufInfo ), paUnanticipatedHostError );
- captureAvail = bufInfo.fragments * stream->capture->hostFrames;
- if( !captureAvail )
- PA_DEBUG(( "%s: captureAvail: 0\n", __FUNCTION__ ));
-
- captureAvail = captureAvail == 0 ? INT_MAX : captureAvail; /* Disregard if zero */
- }
- if( stream->playback )
- {
- ENSURE_( ioctl( playbackFd, SNDCTL_DSP_GETOSPACE, &bufInfo ), paUnanticipatedHostError );
- playbackAvail = bufInfo.fragments * stream->playback->hostFrames;
- if( !playbackAvail )
- {
- PA_DEBUG(( "%s: playbackAvail: 0\n", __FUNCTION__ ));
- }
-
- playbackAvail = playbackAvail == 0 ? INT_MAX : playbackAvail; /* Disregard if zero */
- }
-
- commonAvail = PA_MIN( captureAvail, playbackAvail );
- if( commonAvail == INT_MAX )
- commonAvail = 0;
- commonAvail -= commonAvail % stream->framesPerHostBuffer;
-
- assert( commonAvail != INT_MAX );
- assert( commonAvail >= 0 );
- *frames = commonAvail;
-
-error:
- return result;
-}
-
-/** Prepare stream for capture/playback.
- *
- * In order to synchronize capture and playback properly we use the SETTRIGGER command.
- */
-static PaError PaOssStream_Prepare( PaOssStream *stream )
-{
- PaError result = paNoError;
- int enableBits = 0;
-
- if( stream->triggered )
- return result;
-
- if( stream->playback )
- {
- size_t bufSz = PaOssStreamComponent_BufferSize( stream->playback );
- memset( stream->playback->buffer, 0, bufSz );
-
- /* Looks like we have to turn off blocking before we try this, but if we don't fill the buffer
- * OSS will complain. */
- PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) );
- while (1)
- {
- if( write( stream->playback->fd, stream->playback->buffer, bufSz ) < 0 )
- break;
- }
- PA_ENSURE( ModifyBlocking( stream->playback->fd, 1 ) );
- }
-
- if( stream->sharedDevice )
- {
- enableBits = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT;
- ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
- }
- else
- {
- if( stream->capture )
- {
- enableBits = PCM_ENABLE_INPUT;
- ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
- }
- if( stream->playback )
- {
- enableBits = PCM_ENABLE_OUTPUT;
- ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_SETTRIGGER, &enableBits ), paUnanticipatedHostError );
- }
- }
-
- /* Ok, we have triggered the stream */
- stream->triggered = 1;
-
-error:
- return result;
-}
-
-/** Stop audio processing
- *
- */
-static PaError PaOssStream_Stop( PaOssStream *stream, int abort )
-{
- PaError result = paNoError;
-
- /* Looks like the only safe way to stop audio without reopening the device is SNDCTL_DSP_POST.
- * Also disable capture/playback till the stream is started again */
- if( stream->capture )
- {
- ENSURE_( ioctl( stream->capture->fd, SNDCTL_DSP_POST, 0 ), paUnanticipatedHostError );
- }
- if( stream->playback && !stream->sharedDevice )
- {
- ENSURE_( ioctl( stream->playback->fd, SNDCTL_DSP_POST, 0 ), paUnanticipatedHostError );
- }
-
-error:
- return result;
-}
-
-/** Clean up after thread exit.
- *
- * Aspect StreamState: If the user has registered a streamFinishedCallback it will be called here
- */
-static void OnExit( void *data )
-{
- PaOssStream *stream = (PaOssStream *) data;
- assert( data );
-
- PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
-
- PaOssStream_Stop( stream, stream->callbackAbort );
-
- PA_DEBUG(( "OnExit: Stoppage\n" ));
-
- /* Eventually notify user all buffers have played */
- if( stream->streamRepresentation.streamFinishedCallback )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
-
- stream->callbackAbort = 0; /* Clear state */
- stream->isActive = 0;
-}
-
-static PaError SetUpBuffers( PaOssStream *stream, unsigned long framesAvail )
-{
- PaError result = paNoError;
-
- if( stream->capture )
- {
- PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer,
- stream->capture->hostChannelCount );
- PaUtil_SetInputFrameCount( &stream->bufferProcessor, framesAvail );
- }
- if( stream->playback )
- {
- PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer,
- stream->playback->hostChannelCount );
- PaUtil_SetOutputFrameCount( &stream->bufferProcessor, framesAvail );
- }
-
- return result;
-}
-
-/** Thread procedure for callback processing.
- *
- * Aspect StreamState: StartStream will wait on this to initiate audio processing, useful in case the
- * callback should be used for buffer priming. When the stream is cancelled a separate function will
- * take care of the transition to the Callback Finished state (the stream isn't considered Stopped
- * before StopStream() or AbortStream() are called).
- */
-static void *PaOSS_AudioThreadProc( void *userData )
-{
- PaError result = paNoError;
- PaOssStream *stream = (PaOssStream*)userData;
- unsigned long framesAvail, framesProcessed;
- int callbackResult = paContinue;
- int triggered = stream->triggered; /* See if SNDCTL_DSP_TRIGGER has been issued already */
- int initiateProcessing = triggered; /* Already triggered? */
- PaStreamCallbackFlags cbFlags = 0; /* We might want to keep state across iterations */
-
- /*
-#if ( SOUND_VERSION > 0x030904 )
- audio_errinfo errinfo;
-#endif
-*/
-
- assert( stream );
-
- pthread_cleanup_push( &OnExit, stream ); /* Execute OnExit when exiting */
-
- /* The first time the stream is started we use SNDCTL_DSP_TRIGGER to accurately start capture and
- * playback in sync, when the stream is restarted after being stopped we simply start by reading/
- * writing.
- */
- PA_ENSURE( PaOssStream_Prepare( stream ) );
-
- /* If we are to initiate processing implicitly by reading/writing data, we start off in blocking mode */
- if( initiateProcessing )
- {
- /* Make sure devices are in blocking mode */
- if( stream->capture )
- ModifyBlocking( stream->capture->fd, 1 );
- if( stream->playback )
- ModifyBlocking( stream->playback->fd, 1 );
- }
-
- while( 1 )
- {
- PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* TODO: IMPLEMENT ME */
-
- pthread_testcancel();
-
- if( stream->callbackStop && callbackResult == paContinue )
- {
- PA_DEBUG(( "Setting callbackResult to paComplete\n" ));
- callbackResult = paComplete;
- }
-
- /* Aspect StreamState: Because of the messy OSS scheme we can't explicitly trigger device start unless
- * the stream has been recently started, we will have to go right ahead and read/write in blocking
- * fashion to trigger operation. Therefore we begin with processing one host buffer before we switch
- * to non-blocking mode.
- */
- if( !initiateProcessing )
- {
- PA_ENSURE( PaOssStream_WaitForFrames( stream, &framesAvail ) ); /* Wait on available frames */
- assert( framesAvail % stream->framesPerHostBuffer == 0 );
- }
- else
- {
- framesAvail = stream->framesPerHostBuffer;
- }
-
- while( framesAvail > 0 )
- {
- unsigned long frames = framesAvail;
-
- pthread_testcancel();
-
- PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
-
- /* Read data */
- if ( stream->capture )
- {
- PA_ENSURE( PaOssStreamComponent_Read( stream->capture, &frames ) );
- assert( frames == framesAvail );
- }
-
-#if ( SOUND_VERSION >= 0x030904 )
- /*
- Check with OSS to see if there have been any under/overruns
- since last time we checked.
- */
- /*
- if( ioctl( stream->deviceHandle, SNDCTL_DSP_GETERROR, &errinfo ) >= 0 )
- {
- if( errinfo.play_underruns )
- cbFlags |= paOutputUnderflow ;
- if( errinfo.record_underruns )
- cbFlags |= paInputUnderflow ;
- }
- else
- PA_DEBUG(( "SNDCTL_DSP_GETERROR command failed: %s\n", strerror( errno ) ));
- */
-#endif
-
- PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo,
- cbFlags );
- cbFlags = 0;
- PA_ENSURE( SetUpBuffers( stream, framesAvail ) );
-
- framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
- &callbackResult );
- assert( framesProcessed == framesAvail );
- PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
-
- if ( stream->playback )
- {
- frames = framesAvail;
-
- PA_ENSURE( PaOssStreamComponent_Write( stream->playback, &frames ) );
- assert( frames == framesAvail );
-
- /* TODO: handle bytesWritten != bytesRequested (slippage?) */
- }
-
- framesAvail -= framesProcessed;
- stream->framesProcessed += framesProcessed;
-
- if( callbackResult != paContinue )
- break;
- }
-
- if( initiateProcessing || !triggered )
- {
- /* Non-blocking */
- if( stream->capture )
- PA_ENSURE( ModifyBlocking( stream->capture->fd, 0 ) );
- if( stream->playback && !stream->sharedDevice )
- PA_ENSURE( ModifyBlocking( stream->playback->fd, 0 ) );
-
- initiateProcessing = 0;
- sem_post( &stream->semaphore );
- }
-
- if( callbackResult != paContinue )
- {
- stream->callbackAbort = callbackResult == paAbort;
- if( stream->callbackAbort || PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
- break;
- }
- }
-
- pthread_cleanup_pop( 1 );
-
-error:
- pthread_exit( NULL );
-}
-
-/** Close the stream.
- *
- */
-static PaError CloseStream( PaStream* s )
-{
- PaError result = paNoError;
- PaOssStream *stream = (PaOssStream*)s;
-
- assert( stream );
-
- PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
- PaOssStream_Terminate( stream );
-
- return result;
-}
-
-/** Start the stream.
- *
- * Aspect StreamState: After returning, the stream shall be in the Active state, implying that an eventual
- * callback will be repeatedly called in a separate thread. If a separate thread is started this function
- * will block untill it has started processing audio, otherwise audio processing is started directly.
- */
-static PaError StartStream( PaStream *s )
-{
- PaError result = paNoError;
- PaOssStream *stream = (PaOssStream*)s;
-
- stream->isActive = 1;
- stream->isStopped = 0;
- stream->lastPosPtr = 0;
- stream->lastStreamBytes = 0;
- stream->framesProcessed = 0;
-
- /* only use the thread for callback streams */
- if( stream->bufferProcessor.streamCallback )
- {
- PA_ENSURE( PaUtil_StartThreading( &stream->threading, &PaOSS_AudioThreadProc, stream ) );
- sem_wait( &stream->semaphore );
- }
- else
- PA_ENSURE( PaOssStream_Prepare( stream ) );
-
-error:
- return result;
-}
-
-static PaError RealStop( PaOssStream *stream, int abort )
-{
- PaError result = paNoError;
-
- if( stream->callbackMode )
- {
- if( abort )
- stream->callbackAbort = 1;
- else
- stream->callbackStop = 1;
-
- PA_ENSURE( PaUtil_CancelThreading( &stream->threading, !abort, NULL ) );
-
- stream->callbackStop = stream->callbackAbort = 0;
- }
- else
- PA_ENSURE( PaOssStream_Stop( stream, abort ) );
-
- stream->isStopped = 1;
-
-error:
- return result;
-}
-
-/** Stop the stream.
- *
- * Aspect StreamState: This will cause the stream to transition to the Stopped state, playing all enqueued
- * buffers.
- */
-static PaError StopStream( PaStream *s )
-{
- return RealStop( (PaOssStream *)s, 0 );
-}
-
-/** Abort the stream.
- *
- * Aspect StreamState: This will cause the stream to transition to the Stopped state, discarding all enqueued
- * buffers. Note that the buffers are not currently correctly discarded, this is difficult without closing
- * the OSS device.
- */
-static PaError AbortStream( PaStream *s )
-{
- return RealStop( (PaOssStream *)s, 1 );
-}
-
-/** Is the stream in the Stopped state.
- *
- */
-static PaError IsStreamStopped( PaStream *s )
-{
- PaOssStream *stream = (PaOssStream*)s;
-
- return (stream->isStopped);
-}
-
-/** Is the stream in the Active state.
- *
- */
-static PaError IsStreamActive( PaStream *s )
-{
- PaOssStream *stream = (PaOssStream*)s;
-
- return (stream->isActive);
-}
-
-static PaTime GetStreamTime( PaStream *s )
-{
- PaOssStream *stream = (PaOssStream*)s;
- count_info info;
- int delta;
-
- if( stream->playback ) {
- if( ioctl( stream->playback->fd, SNDCTL_DSP_GETOPTR, &info) == 0 ) {
- delta = ( info.bytes - stream->lastPosPtr ) & 0x000FFFFF;
- return ( stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->playback ) / stream->sampleRate;
- }
- }
- else {
- if (ioctl( stream->capture->fd, SNDCTL_DSP_GETIPTR, &info) == 0) {
- delta = (info.bytes - stream->lastPosPtr) & 0x000FFFFF;
- return ( stream->lastStreamBytes + delta) / PaOssStreamComponent_FrameSize( stream->capture ) / stream->sampleRate;
- }
- }
-
- /* the ioctl failed, but we can still give a coarse estimate */
-
- return stream->framesProcessed / stream->sampleRate;
-}
-
-
-static double GetStreamCpuLoad( PaStream* s )
-{
- PaOssStream *stream = (PaOssStream*)s;
-
- return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
-}
-
-
-/*
- As separate stream interfaces are used for blocking and callback
- streams, the following functions can be guaranteed to only be called
- for blocking streams.
-*/
-
-
-static PaError ReadStream( PaStream* s,
- void *buffer,
- unsigned long frames )
-{
- PaOssStream *stream = (PaOssStream*)s;
- int bytesRequested, bytesRead;
- unsigned long framesRequested;
- void *userBuffer;
-
- /* If user input is non-interleaved, PaUtil_CopyInput will manipulate the channel pointers,
- * so we copy the user provided pointers */
- if( stream->bufferProcessor.userInputIsInterleaved )
- userBuffer = buffer;
- else /* Copy channels into local array */
- {
- userBuffer = stream->capture->userBuffers;
- memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->capture->userChannelCount );
- }
-
- while( frames )
- {
- framesRequested = PA_MIN( frames, stream->capture->hostFrames );
-
- bytesRequested = framesRequested * PaOssStreamComponent_FrameSize( stream->capture );
- bytesRead = read( stream->capture->fd, stream->capture->buffer, bytesRequested );
- if ( bytesRequested != bytesRead )
- return paUnanticipatedHostError;
-
- PaUtil_SetInputFrameCount( &stream->bufferProcessor, stream->capture->hostFrames );
- PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, stream->capture->buffer, stream->capture->hostChannelCount );
- PaUtil_CopyInput( &stream->bufferProcessor, &userBuffer, framesRequested );
- frames -= framesRequested;
- }
- return paNoError;
-}
-
-
-static PaError WriteStream( PaStream* s,
- const void *buffer,
- unsigned long frames )
-{
- PaOssStream *stream = (PaOssStream*)s;
- int bytesRequested, bytesWritten;
- unsigned long framesConverted;
- const void *userBuffer;
-
- /* If user output is non-interleaved, PaUtil_CopyOutput will manipulate the channel pointers,
- * so we copy the user provided pointers */
- if( stream->bufferProcessor.userOutputIsInterleaved )
- userBuffer = buffer;
- else /* Copy channels into local array */
- {
- userBuffer = stream->playback->userBuffers;
- memcpy( (void *)userBuffer, buffer, sizeof (void *) * stream->playback->userChannelCount );
- }
-
- while( frames )
- {
- PaUtil_SetOutputFrameCount( &stream->bufferProcessor, stream->playback->hostFrames );
- PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, stream->playback->buffer, stream->playback->hostChannelCount );
-
- framesConverted = PaUtil_CopyOutput( &stream->bufferProcessor, &userBuffer, frames );
- frames -= framesConverted;
-
- bytesRequested = framesConverted * PaOssStreamComponent_FrameSize( stream->playback );
- bytesWritten = write( stream->playback->fd, stream->playback->buffer, bytesRequested );
-
- if ( bytesRequested != bytesWritten )
- return paUnanticipatedHostError;
- }
- return paNoError;
-}
-
-
-static signed long GetStreamReadAvailable( PaStream* s )
-{
- PaOssStream *stream = (PaOssStream*)s;
- audio_buf_info info;
-
- if( ioctl( stream->capture->fd, SNDCTL_DSP_GETISPACE, &info ) < 0 )
- return paUnanticipatedHostError;
- return info.fragments * stream->capture->hostFrames;
-}
-
-
-/* TODO: Compute number of allocated bytes somewhere else, can we use ODELAY with capture */
-static signed long GetStreamWriteAvailable( PaStream* s )
-{
- PaOssStream *stream = (PaOssStream*)s;
- int delay = 0;
-
- if( ioctl( stream->playback->fd, SNDCTL_DSP_GETODELAY, &delay ) < 0 )
- return paUnanticipatedHostError;
-
- return (PaOssStreamComponent_BufferSize( stream->playback ) - delay) / PaOssStreamComponent_FrameSize( stream->playback );
-}
-
diff --git a/pd/portaudio/pa_unix_oss/recplay.c b/pd/portaudio/pa_unix_oss/recplay.c
deleted file mode 100644
index 9d4c78cf..00000000
--- a/pd/portaudio/pa_unix_oss/recplay.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * recplay.c
- * Phil Burk
- * Minimal record and playback test.
- *
- */
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#ifndef __STDC__
-/* #include <getopt.h> */
-#endif /* __STDC__ */
-#include <fcntl.h>
-#ifdef __STDC__
-#include <string.h>
-#else /* __STDC__ */
-#include <strings.h>
-#endif /* __STDC__ */
-#include <sys/soundcard.h>
-
-#define NUM_BYTES (64*1024)
-#define BLOCK_SIZE (4*1024)
-
-#define AUDIO "/dev/dsp"
-
-char buffer[NUM_BYTES];
-
-int audioDev = 0;
-
-main (int argc, char *argv[])
-{
- int numLeft;
- char *ptr;
- int num;
- int samplesize;
-
- /********** RECORD ********************/
- /* Open audio device. */
- audioDev = open (AUDIO, O_RDONLY, 0);
- if (audioDev == -1)
- {
- perror (AUDIO);
- exit (-1);
- }
-
- /* Set to 16 bit samples. */
- samplesize = 16;
- ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize);
- if (samplesize != 16)
- {
- perror("Unable to set the sample size.");
- exit(-1);
- }
-
- /* Record in blocks */
- printf("Begin recording.\n");
- numLeft = NUM_BYTES;
- ptr = buffer;
- while( numLeft >= BLOCK_SIZE )
- {
- if ( (num = read (audioDev, ptr, BLOCK_SIZE)) < 0 )
- {
- perror (AUDIO);
- exit (-1);
- }
- else
- {
- printf("Read %d bytes\n", num);
- ptr += num;
- numLeft -= num;
- }
- }
-
- close( audioDev );
-
- /********** PLAYBACK ********************/
- /* Open audio device for writing. */
- audioDev = open (AUDIO, O_WRONLY, 0);
- if (audioDev == -1)
- {
- perror (AUDIO);
- exit (-1);
- }
-
- /* Set to 16 bit samples. */
- samplesize = 16;
- ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize);
- if (samplesize != 16)
- {
- perror("Unable to set the sample size.");
- exit(-1);
- }
-
- /* Play in blocks */
- printf("Begin playing.\n");
- numLeft = NUM_BYTES;
- ptr = buffer;
- while( numLeft >= BLOCK_SIZE )
- {
- if ( (num = write (audioDev, ptr, BLOCK_SIZE)) < 0 )
- {
- perror (AUDIO);
- exit (-1);
- }
- else
- {
- printf("Wrote %d bytes\n", num);
- ptr += num;
- numLeft -= num;
- }
- }
-
- close( audioDev );
-}