aboutsummaryrefslogtreecommitdiff
path: root/pd
diff options
context:
space:
mode:
authorMiller Puckette <millerpuckette@users.sourceforge.net>2006-06-03 19:13:08 +0000
committerMiller Puckette <millerpuckette@users.sourceforge.net>2006-06-03 19:13:08 +0000
commitbeb2211b63b4b80ee07a807e5ffdd441aeea6354 (patch)
tree876eb052d5cec7755053328a470c75e0638b6b94 /pd
parenteb976fa09171036cbaeaabf920708b2d39c49acc (diff)
FFT package selection
Zmoelnig's multi-'$' patch big-soundfile support Patch to set open directories (openpanel, savepanel) patch to allow funny characters in extern names fixed makefile.in to support intel mac svn path=/trunk/; revision=5164
Diffstat (limited to 'pd')
-rw-r--r--pd/doc/3.audio.examples/A06.frequency.pd1
-rw-r--r--pd/doc/5.reference/list-help.pd2
-rw-r--r--pd/doc/5.reference/openpanel-help.pd22
-rw-r--r--pd/doc/5.reference/print-help.pd6
-rw-r--r--pd/doc/7.stuff/tools/testtone.pd2
-rw-r--r--pd/extra/bonk~/bonk~-help.pd189
-rw-r--r--pd/extra/bonk~/makefile8
-rw-r--r--pd/extra/choice/makefile8
-rw-r--r--pd/extra/expr~/makefile22
-rw-r--r--pd/extra/fiddle~/makefile8
-rw-r--r--pd/extra/hilbert~.pd25
-rw-r--r--pd/extra/loop~/makefile8
-rw-r--r--pd/extra/lrshift~/makefile8
-rw-r--r--pd/extra/pique/makefile8
-rw-r--r--pd/portaudio/pa_asio/pa_asio.cpp69
-rw-r--r--pd/portaudio/pa_common/pa_converters.c134
-rw-r--r--pd/portaudio/pa_common/pa_dither.c7
-rw-r--r--pd/portaudio/pa_common/pa_endianness.h6
-rw-r--r--pd/portaudio/pa_common/pa_front.c19
-rw-r--r--pd/portaudio/pa_common/pa_process.c27
-rw-r--r--pd/portaudio/pa_common/pa_trace.c8
-rw-r--r--pd/portaudio/pa_common/pa_util.h4
-rw-r--r--pd/portaudio/pa_common/portaudio.h13
-rw-r--r--pd/portaudio/pa_jack/pa_jack.c6
-rw-r--r--pd/portaudio/pa_linux_alsa/pa_linux_alsa.c1150
-rw-r--r--pd/portaudio/pa_mac_core/notes.txt117
-rw-r--r--pd/portaudio/pa_mac_core/pa_mac_core.c2551
-rw-r--r--pd/portaudio/pa_win_ds/pa_win_ds.c58
-rw-r--r--pd/portaudio/pa_win_wdmks/pa_win_wdmks.c1668
-rw-r--r--pd/portaudio/pa_win_wdmks/readme.txt11
-rw-r--r--pd/portaudio/pa_win_wmme/pa_win_wmme.c17
-rw-r--r--pd/portaudio/pablio/ringbuffer.h2
-rw-r--r--pd/portmidi/pm_mac/pmmacosxcm.c2
-rw-r--r--pd/src/configure.in59
-rw-r--r--pd/src/d_fft.c9
-rw-r--r--pd/src/d_soundfile.c1
-rw-r--r--pd/src/g_array.c28
-rw-r--r--pd/src/g_canvas.c2
-rw-r--r--pd/src/g_editor.c7
-rw-r--r--pd/src/g_graph.c14
-rw-r--r--pd/src/g_template.c10
-rw-r--r--pd/src/g_traversal.c7
-rw-r--r--pd/src/m_atom.c8
-rw-r--r--pd/src/m_binbuf.c120
-rw-r--r--pd/src/makefile.in7
-rw-r--r--pd/src/makefile.nt14
-rw-r--r--pd/src/notes.txt25
-rw-r--r--pd/src/s_audio.c2
-rw-r--r--pd/src/s_audio_pa.c8
-rw-r--r--pd/src/s_audio_pablio.c30
-rw-r--r--pd/src/s_audio_pablio.h8
-rw-r--r--pd/src/s_audio_paring.c40
-rw-r--r--pd/src/s_audio_paring.h32
-rw-r--r--pd/src/s_inter.c2
-rw-r--r--pd/src/s_loader.c45
-rw-r--r--pd/src/s_main.c58
-rw-r--r--pd/src/u_main.tk118
-rw-r--r--pd/src/x_gui.c33
58 files changed, 4524 insertions, 2349 deletions
diff --git a/pd/doc/3.audio.examples/A06.frequency.pd b/pd/doc/3.audio.examples/A06.frequency.pd
index 50cff7c0..b0601b0e 100644
--- a/pd/doc/3.audio.examples/A06.frequency.pd
+++ b/pd/doc/3.audio.examples/A06.frequency.pd
@@ -58,3 +58,4 @@ loop. (get help on number boxes for details.);
#X connect 16 0 15 0;
#X connect 31 0 1 0;
#X connect 31 0 29 0;
+#X connect 31 0 29 1;
diff --git a/pd/doc/5.reference/list-help.pd b/pd/doc/5.reference/list-help.pd
index ea6355bb..1d5cf9d8 100644
--- a/pd/doc/5.reference/list-help.pd
+++ b/pd/doc/5.reference/list-help.pd
@@ -1,4 +1,4 @@
-#N canvas 105 298 629 492 12;
+#N canvas 596 406 629 492 12;
#X obj 29 11 list;
#X text 352 455 updated for Pd version 0.39;
#X text 76 12 - building and using variable-length messages;
diff --git a/pd/doc/5.reference/openpanel-help.pd b/pd/doc/5.reference/openpanel-help.pd
index 15e5d244..b8b7396a 100644
--- a/pd/doc/5.reference/openpanel-help.pd
+++ b/pd/doc/5.reference/openpanel-help.pd
@@ -1,11 +1,19 @@
-#N canvas 35 31 585 245 12;
-#X obj 128 136 openpanel;
+#N canvas 70 117 585 333 12;
+#X obj 128 196 openpanel;
#X msg 128 108 bang;
-#X obj 128 161 print;
+#X obj 128 221 print;
#X text 31 11 openpanel -- query you for a filename;
-#X text 48 218 see also:;
-#X obj 136 219 savepanel;
-#X text 272 223 updated for Pd version 0.33;
-#X text 33 59 When Openpanel gets a "bang" an "Open file" browser appears on the screen. If you select a file \, its name appears on the outlet.;
+#X text 48 278 see also:;
+#X obj 136 279 savepanel;
+#X text 28 44 When Openpanel gets a "bang" an "Open file" browser appears
+on the screen. If you select a file \, its name appears on the outlet.
+;
+#X text 285 289 updated for Pd version 0.40.;
+#X text 178 109 Starts open panel in current directory;
+#X msg 144 136 symbol /tmp;
+#X msg 146 161 symbol C:/;
+#X text 252 137 Starts in a specified directory;
#X connect 0 0 2 0;
#X connect 1 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 0 0;
diff --git a/pd/doc/5.reference/print-help.pd b/pd/doc/5.reference/print-help.pd
index 50af069a..4b8920fa 100644
--- a/pd/doc/5.reference/print-help.pd
+++ b/pd/doc/5.reference/print-help.pd
@@ -4,10 +4,12 @@
#X msg 70 51 234;
#X obj 29 96 print x1;
#X obj 21 10 print;
-#X text 37 134 Print prints out the messages it receives on the "terminal
+#X text 29 130 Print prints out the messages it receives on the "terminal
window" that Pd is run from.;
-#X text 249 200 updated for Pd version 0.31.;
#X text 73 10 -- print messages to terminal window;
+#X text 309 221 updated for Pd version 0.40.;
+#X text 27 167 Long symbol arguments are truncated to 78 characters
+and marked with "*" (but message selectors are printed in full.);
#X connect 0 0 3 0;
#X connect 1 0 3 0;
#X connect 2 0 3 0;
diff --git a/pd/doc/7.stuff/tools/testtone.pd b/pd/doc/7.stuff/tools/testtone.pd
index 5b4da125..6e88a268 100644
--- a/pd/doc/7.stuff/tools/testtone.pd
+++ b/pd/doc/7.stuff/tools/testtone.pd
@@ -117,7 +117,7 @@ but is free for you to use for any reasonable purpose. See the file
#X obj 52 174 vradio 15 1 0 2 tone-type tone-type-set empty 0 -6 0
8 -262144 -1 -1 1;
#X obj 51 104 vradio 15 1 0 3 tone-radio tone-radio-set empty 0 -6
-0 8 -262144 -1 -1 2;
+0 8 -262144 -1 -1 0;
#X obj 379 220 adc~;
#X obj 379 256 print~;
#X obj 438 227 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
diff --git a/pd/extra/bonk~/bonk~-help.pd b/pd/extra/bonk~/bonk~-help.pd
index 45b4e403..915d543b 100644
--- a/pd/extra/bonk~/bonk~-help.pd
+++ b/pd/extra/bonk~/bonk~-help.pd
@@ -1,24 +1,14 @@
-#N canvas 133 65 958 626 10;
-#X obj 320 579 print;
-#X floatatom 314 501 0 0 0 0 - - -;
-#X obj 320 549 spigot;
-#X msg 314 471 0;
-#X msg 351 471 1;
-#X msg 442 427 bang;
-#X obj 429 518 bonk~;
-#X msg 442 244 learn 1;
-#X msg 442 304 learn 0;
-#X msg 437 486 print;
-#X obj 390 467 adc~;
-#X text 320 597 cooked;
-#X msg 565 76 \; pd dsp 1;
-#X obj 257 579 print;
-#X floatatom 251 501 0 0 0 0 - - -;
-#X obj 257 549 spigot;
-#X msg 251 471 0;
-#X msg 282 471 1;
-#X text 257 597 raw;
-#N canvas 366 126 600 400 synth 0;
+#N canvas 193 43 967 599 10;
+#X obj 370 524 spigot;
+#X msg 442 397 bang;
+#X obj 429 488 bonk~;
+#X msg 442 214 learn 1;
+#X msg 442 274 learn 0;
+#X msg 437 456 print;
+#X obj 390 437 adc~;
+#X msg 614 538 \; pd dsp 1;
+#X obj 277 524 spigot;
+#N canvas 366 126 604 404 synth 0;
#X obj 112 24 r bonk-cooked;
#X obj 112 49 unpack;
#X obj 112 99 * 12;
@@ -69,104 +59,99 @@
#X connect 21 0 1 0;
#X connect 22 0 6 0;
#X connect 23 0 9 0;
-#X restore 804 86 pd synth;
-#X obj 454 549 s bonk-cooked;
-#X floatatom 804 63 0 0 0 0 - - -;
-#X msg 804 33 0;
-#X msg 442 274 learn 10;
-#X msg 442 334 forget;
-#X msg 442 364 write templates.txt;
-#X msg 442 394 read templates.txt;
-#X msg 835 33 90;
-#X msg 442 120 thresh 6 50;
-#X text 8 70 The Bonk object takes an audio signal input and looks
+#X restore 846 555 pd synth;
+#X floatatom 846 532 0 0 0 0 - - -;
+#X msg 846 502 0;
+#X msg 442 244 learn 10;
+#X msg 442 304 forget;
+#X msg 442 334 write templates.txt;
+#X msg 442 364 read templates.txt;
+#X msg 877 502 90;
+#X msg 442 81 thresh 6 50;
+#X text 8 56 The Bonk object takes an audio signal input and looks
for "attacks" defined as sharp changes in the spectral envelope of
the incoming sound. Optionally \, and less reliably \, you can have
Bonk check the attack against a collection of stored templates to try
to guess which of two or more instruments was hit. Bonk is described
theoretically in the 1998 ICMC proceedings \, reprinted on http://man104nfs.ucsd.edu/~mpuckett.
;
-#X text 470 70 click here;
-#X text 471 83 to start DSP;
-#X text 8 191 Bonk's two outputs are the raw spectrum of the attack
-(provided as a list of 11 numbers giving the signal "loudness" in the
-11 frequency bands used) \, and the "cooked" output which gives only
-an instrument number (counting up from zero) and a "velocity". The
-instrumnent number is significant only if Bonk has a "template set"
-in memory.;
-#X text 8 368 In this patch \, after starting DSP \, you can print
+#X text 602 504 click here;
+#X text 603 517 to start DSP;
+#X text 8 377 In this patch \, after starting DSP \, you can print
out the raw or cooked output using the two "spigots" or listen to a
synthesizer output by raising its volume.;
-#X text 259 448 enable printout;
-#X text 705 32 output volume;
-#X text 719 50 (0-100);
-#X text 533 118 Set low and high thresholds. Signal growth must exceed
-the high one and then fall to the low one to make an attack.;
-#X text 533 151 Minimum velocity to output (quieter notes are ignored.)
-;
-#X msg 442 180 mask 4 0.7;
-#X msg 442 214 debounce 0;
-#X text 8 299 Bonk's analysis is carried out on a 256-point window
+#X text 747 501 output volume;
+#X text 761 519 (0-100);
+#X msg 442 150 mask 4 0.7;
+#X msg 442 184 debounce 0;
+#X text 8 309 Bonk's analysis is carried out on a 256-point window
(6 msec at 44.1 kHz) and by default the analysis period is 128 samples.
The analysis period can be specified as Bonk's creation argument but
must be a multiple of 64;
-#X text 532 219 Minimum time (msec) between attacks;
-#X text 532 170 Describes how energy in each frequency band masks later
+#X text 532 185 Minimum time (msec) between attacks;
+#X text 532 140 Describes how energy in each frequency band masks later
energy in the band. Here the masking is total for 4 analysis periods
and then drops by 0.7 each period.;
-#X text 530 244 Forget all templates and start learning new ones. The
+#X text 530 214 Forget all templates and start learning new ones. The
argument gives the number of times you will hit each instrument (10
recommended.) Turn on the output volume above for audible feedback
as you train Bonk. "Learn 0" exits learn mode.;
-#X text 530 328 Forget the last template. In Learn mode \, use "forget"
+#X text 530 298 Forget the last template. In Learn mode \, use "forget"
to erase and record over a template.;
-#X text 595 368 Write templates to a file in text-editable format.
+#X text 595 334 Write templates to a file in text-editable format.
;
-#X text 596 398 Read templates from a file.;
-#X text 538 493 Print out all settings and templates.;
-#X msg 442 150 minvel 10;
-#X text 538 426 Poll the current spectrum via "raw" outlet \, You can
+#X text 596 364 Read templates from a file.;
+#X text 538 453 Print out all settings and templates.;
+#X msg 442 120 minvel 10;
+#X text 538 392 Poll the current spectrum via "raw" outlet \, You can
set a very high threshold if you don't want attacks mixed in.;
-#X text 218 12 BONK - an attack detector for small percussion instruments
+#X msg 437 426 debug 0;
+#X text 538 426 turn debugging on or off.;
+#X obj 326 525 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 419 525 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0
+1;
+#X obj 370 554 print cooked;
+#X obj 277 554 print raw;
+#X text 253 490 enable printout:;
+#X text 533 121 Minimum "velocity" to output (quieter notes are ignored.)
;
-#X msg 634 517 print;
-#X msg 437 456 debug 0;
-#X text 538 466 turn debugging on or off.;
-#X obj 118 422 phasor~ 110;
-#X obj 106 510 dac~;
-#X obj 105 483 *~;
-#X floatatom 160 466 5 0 0 0 - - -;
-#X obj 157 488 dbtorms;
-#X connect 1 0 2 1;
-#X connect 2 0 0 0;
-#X connect 3 0 1 0;
-#X connect 4 0 1 0;
-#X connect 5 0 6 0;
-#X connect 6 0 15 0;
-#X connect 6 1 2 0;
-#X connect 6 1 20 0;
-#X connect 7 0 6 0;
-#X connect 8 0 6 0;
-#X connect 9 0 6 0;
-#X connect 10 0 6 0;
-#X connect 14 0 15 1;
-#X connect 15 0 13 0;
-#X connect 16 0 14 0;
-#X connect 17 0 14 0;
-#X connect 21 0 19 0;
-#X connect 22 0 21 0;
-#X connect 23 0 6 0;
-#X connect 24 0 6 0;
-#X connect 25 0 6 0;
-#X connect 26 0 6 0;
-#X connect 27 0 21 0;
-#X connect 28 0 6 0;
-#X connect 39 0 6 0;
-#X connect 40 0 6 0;
-#X connect 49 0 6 0;
-#X connect 53 0 6 0;
-#X connect 55 0 57 0;
-#X connect 57 0 56 0;
-#X connect 57 0 56 1;
-#X connect 58 0 59 0;
-#X connect 59 0 57 1;
+#X obj 462 513 s bonk-cooked;
+#X text 218 12 BONK~ - an attack detector for small percussion instruments
+;
+#X text 8 174 Bonk's two outputs are the raw spectrum of the attack
+(provided as a list of 11 numbers giving the signal "loudness" in the
+11 frequency bands used) \, and the "cooked" output which gives only
+an instrument number (counting up from zero) and a "velocity". This
+"velocity" is the sum of the square roots of the amplitudes of the
+bands \, normalized so that 100 is an attack of amplitude of about
+1 The instrument number is significant only if Bonk has a "template
+set" in memory.;
+#X text 532 52 Set low and high thresholds. Signal growth must exceed
+the high one and then fall to the low one to make an attack. The unit
+is the sum of the proportional growth in the 11 filter bands. Proportional
+growth is essentially the logarithmic time derivative.;
+#X connect 0 0 40 0;
+#X connect 1 0 2 0;
+#X connect 2 0 8 0;
+#X connect 2 1 0 0;
+#X connect 2 1 44 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 5 0 2 0;
+#X connect 6 0 2 0;
+#X connect 8 0 41 0;
+#X connect 10 0 9 0;
+#X connect 11 0 10 0;
+#X connect 12 0 2 0;
+#X connect 13 0 2 0;
+#X connect 14 0 2 0;
+#X connect 15 0 2 0;
+#X connect 16 0 10 0;
+#X connect 17 0 2 0;
+#X connect 24 0 2 0;
+#X connect 25 0 2 0;
+#X connect 34 0 2 0;
+#X connect 36 0 2 0;
+#X connect 38 0 8 1;
+#X connect 39 0 0 1;
diff --git a/pd/extra/bonk~/makefile b/pd/extra/bonk~/makefile
index 578f7b8d..5c805bcd 100644
--- a/pd/extra/bonk~/makefile
+++ b/pd/extra/bonk~/makefile
@@ -75,8 +75,9 @@ LINUXINCLUDE = -I../../src
# ----------------------- Mac OSX -----------------------
pd_darwin: $(NAME).pd_darwin
+pd_imac: $(NAME).pd_imac
-.SUFFIXES: .pd_darwin
+.SUFFIXES: .pd_darwin .pd_imac
DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
-Wno-unused -Wno-parentheses -Wno-switch
@@ -86,6 +87,11 @@ DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
$(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
rm -f $*.o
+.c.pd_imac:
+ $(CC) $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ $(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_imac $*.o
+ rm -f $*.o
+
# ----------------------------------------------------------
clean:
diff --git a/pd/extra/choice/makefile b/pd/extra/choice/makefile
index 7345eed7..8ecb0dd4 100644
--- a/pd/extra/choice/makefile
+++ b/pd/extra/choice/makefile
@@ -75,8 +75,9 @@ LINUXINCLUDE = -I../../src
# ----------------------- Mac OSX -----------------------
pd_darwin: $(NAME).pd_darwin
+pd_imac: $(NAME).pd_imac
-.SUFFIXES: .pd_darwin
+.SUFFIXES: .pd_darwin .pd_imac
DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
-Wno-unused -Wno-parentheses -Wno-switch
@@ -86,6 +87,11 @@ DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
$(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
rm -f $*.o
+.c.pd_imac:
+ $(CC) $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ $(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_imac $*.o
+ rm -f $*.o
+
# ----------------------------------------------------------
clean:
diff --git a/pd/extra/expr~/makefile b/pd/extra/expr~/makefile
index ff1dae4b..e62ff9f3 100644
--- a/pd/extra/expr~/makefile
+++ b/pd/extra/expr~/makefile
@@ -124,7 +124,6 @@ linux_clobber: clean
# ----------------------- MAC OSX -----------------------
-pd_darwin: expr.pd_darwin expr~.pd_darwin fexpr~.pd_darwin
MACOSXOBJ = vexp.pd_darwin_o vexp_fun.pd_darwin_o vexp_if.pd_darwin_o
.SUFFIXES: .pd_darwin_o
@@ -133,6 +132,7 @@ MACOSXCFLAGS = -DMACOSX -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
MACOSXINCLUDE = -I../../src
+pd_darwin: expr.pd_darwin expr~.pd_darwin fexpr~.pd_darwin
.c.pd_darwin_o:
$(CC) -g $(MACOSXCFLAGS) $(MACOSXINCLUDE) -o $*.pd_darwin_o -c $*.c
@@ -152,6 +152,26 @@ fexpr~.pd_darwin: expr.pd_darwin
rm -f ../fexpr~.pd_darwin
-ln -s expr~/fexpr~.pd_darwin ..
+pd_imac: expr.pd_imac expr~.pd_imac fexpr~.pd_imac
+.c.pd_imac_o:
+ $(CC) -g $(MACOSXCFLAGS) $(MACOSXINCLUDE) -o $*.pd_imac_o -c $*.c
+
+expr.pd_imac: $(MACOSXOBJ)
+ $(CC) -bundle -undefined suppress -flat_namespace \
+ -o expr.pd_imac $(MACOSXOBJ) -lm
+ rm -f ../expr.pd_imac
+ -ln -s expr~/expr.pd_imac ..
+
+expr~.pd_imac: expr.pd_imac
+ -ln -s expr.pd_imac expr~.pd_imac
+ rm -f ../expr~.pd_imac
+ -ln -s expr~/expr~.pd_imac ..
+
+fexpr~.pd_imac: expr.pd_imac
+ -ln -s expr.pd_imac fexpr~.pd_imac
+ rm -f ../fexpr~.pd_imac
+ -ln -s expr~/fexpr~.pd_imac ..
+
install_darwin:
install expr.pd_darwin $(PDEXTERN)
rm -f $(PDEXTERN)/expr~.pd_darwin
diff --git a/pd/extra/fiddle~/makefile b/pd/extra/fiddle~/makefile
index bda5303e..dc99764b 100644
--- a/pd/extra/fiddle~/makefile
+++ b/pd/extra/fiddle~/makefile
@@ -75,8 +75,9 @@ LINUXINCLUDE = -I../../src
# ----------------------- Mac OSX -----------------------
pd_darwin: $(NAME).pd_darwin
+pd_imac: $(NAME).pd_imac
-.SUFFIXES: .pd_darwin
+.SUFFIXES: .pd_darwin .pd_imac
DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
-Wno-unused -Wno-parentheses -Wno-switch
@@ -86,6 +87,11 @@ DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
$(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
rm -f $*.o
+.c.pd_imac:
+ $(CC) $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ $(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_imac $*.o
+ rm -f $*.o
+
# ----------------------------------------------------------
clean:
diff --git a/pd/extra/hilbert~.pd b/pd/extra/hilbert~.pd
index dfafc942..152c2082 100644
--- a/pd/extra/hilbert~.pd
+++ b/pd/extra/hilbert~.pd
@@ -1,18 +1,27 @@
#N canvas 269 0 593 306 12;
-#X obj 113 68 biquad~ 0.83774 -0.06338 0.06338 -0.83774 1;
-#X obj 113 42 biquad~ 1.94632 -0.94657 0.94657 -1.94632 1;
-#X obj 94 125 biquad~ -0.02569 0.260502 -0.260502 0.02569 1;
-#X obj 94 151 biquad~ 1.8685 -0.870686 0.870686 -1.8685 1;
-#X obj 94 15 inlet~;
-#X obj 113 97 outlet~;
-#X obj 94 178 outlet~;
-#X text 32 210 This is a pair of 4th-order all-pass filters whose outputs
+#X obj 105 92 biquad~ 0.83774 -0.06338 0.06338 -0.83774 1;
+#X obj 105 66 biquad~ 1.94632 -0.94657 0.94657 -1.94632 1;
+#X obj 86 149 biquad~ -0.02569 0.260502 -0.260502 0.02569 1;
+#X obj 86 175 biquad~ 1.8685 -0.870686 0.870686 -1.8685 1;
+#X obj 86 39 inlet~;
+#X obj 105 121 outlet~;
+#X obj 86 202 outlet~;
+#X text 34 232 This is a pair of 4th-order all-pass filters whose outputs
somehow manage to be about 90 degrees out of phase from each other.
Both have different phases from the original. Adapted from a 4X patch
by Emmanuel Favreau \, circa 1982;
+#X obj 502 39 inlet;
+#X text 461 13 bang to clear;
+#X text 80 16 signal in;
+#X msg 502 112 clear;
#X connect 0 0 5 0;
#X connect 1 0 0 0;
#X connect 2 0 3 0;
#X connect 3 0 6 0;
#X connect 4 0 1 0;
#X connect 4 0 2 0;
+#X connect 8 0 11 0;
+#X connect 11 0 1 0;
+#X connect 11 0 0 0;
+#X connect 11 0 2 0;
+#X connect 11 0 3 0;
diff --git a/pd/extra/loop~/makefile b/pd/extra/loop~/makefile
index 9585cebe..b1eada70 100644
--- a/pd/extra/loop~/makefile
+++ b/pd/extra/loop~/makefile
@@ -76,8 +76,9 @@ LINUXINCLUDE = -I../../src
# ----------------------- Mac OSX -----------------------
pd_darwin: $(NAME).pd_darwin
+pd_imac: $(NAME).pd_imac
-.SUFFIXES: .pd_darwin
+.SUFFIXES: .pd_darwin .pd_imac
DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
-Wno-unused -Wno-parentheses -Wno-switch
@@ -87,6 +88,11 @@ DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
$(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
rm -f $*.o
+.c.pd_imac:
+ $(CC) $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ $(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_imac $*.o
+ rm -f $*.o
+
# ----------------------------------------------------------
clean:
diff --git a/pd/extra/lrshift~/makefile b/pd/extra/lrshift~/makefile
index d278e82a..2f9ccfa5 100644
--- a/pd/extra/lrshift~/makefile
+++ b/pd/extra/lrshift~/makefile
@@ -76,8 +76,9 @@ LINUXINCLUDE = -I../../src
# ----------------------- Mac OSX -----------------------
pd_darwin: $(NAME).pd_darwin
+pd_imac: $(NAME).pd_imac
-.SUFFIXES: .pd_darwin
+.SUFFIXES: .pd_darwin .pd_imac
DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
-Wno-unused -Wno-parentheses -Wno-switch
@@ -87,6 +88,11 @@ DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
$(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
rm -f $*.o
+.c.pd_imac:
+ $(CC) $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ $(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_imac $*.o
+ rm -f $*.o
+
# ----------------------------------------------------------
clean:
diff --git a/pd/extra/pique/makefile b/pd/extra/pique/makefile
index dd9a3350..41e830b2 100644
--- a/pd/extra/pique/makefile
+++ b/pd/extra/pique/makefile
@@ -75,8 +75,9 @@ LINUXINCLUDE = -I../../src
# ----------------------- Mac OSX -----------------------
pd_darwin: $(NAME).pd_darwin
+pd_imac: $(NAME).pd_imac
-.SUFFIXES: .pd_darwin
+.SUFFIXES: .pd_darwin .pd_imac
DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
-Wno-unused -Wno-parentheses -Wno-switch
@@ -86,6 +87,11 @@ DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
$(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
rm -f $*.o
+.c.pd_imac:
+ $(CC) $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ $(CC) -bundle -undefined suppress -flat_namespace -o $*.pd_imac $*.o
+ rm -f $*.o
+
# ----------------------------------------------------------
clean:
diff --git a/pd/portaudio/pa_asio/pa_asio.cpp b/pd/portaudio/pa_asio/pa_asio.cpp
index f95f39af..21987c71 100644
--- a/pd/portaudio/pa_asio/pa_asio.cpp
+++ b/pd/portaudio/pa_asio/pa_asio.cpp
@@ -1,5 +1,5 @@
/*
- * $Id: pa_asio.cpp,v 1.7.2.65 2005/02/21 08:07:10 rossbencina Exp $
+ * $Id: pa_asio.cpp,v 1.7.2.68 2005/12/05 04:55:28 rossbencina Exp $
* Portable Audio I/O Library for ASIO Drivers
*
* Author: Stephane Letz
@@ -1081,6 +1081,26 @@ PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
for( i=0; i < driverCount; ++i )
{
+
+ PA_DEBUG(("ASIO names[%d]:%s\n",i,names[i]));
+
+ // Since portaudio opens ALL ASIO drivers, and no one else does that,
+ // we face fact that some drivers were not meant for it, drivers which act
+ // like shells on top of REAL drivers, for instance.
+ // so we get duplicate handles, locks and other problems.
+ // so lets NOT try to load any such wrappers.
+ // The ones i [davidv] know of so far are:
+
+ if ( strcmp (names[i],"ASIO DirectX Full Duplex Driver") == 0
+ || strcmp (names[i],"ASIO Multimedia Driver") == 0
+ || strncmp(names[i],"Premiere",8) == 0 //"Premiere Elements Windows Sound 1.0"
+ || strncmp(names[i],"Adobe",5) == 0 ) //"Adobe Default Windows Sound 1.5"
+ {
+ PA_DEBUG(("BLACKLISTED!!!\n"));
+ continue;
+ }
+
+
/* Attempt to load the asio driver... */
if( LoadAsioDriver( names[i], &paAsioDriverInfo, asioHostApi->systemSpecific ) == paNoError )
{
@@ -1733,16 +1753,52 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
}
}
- PA_DEBUG(("before ASIOSetSampleRate(%f)\n",sampleRate));
- asioError = ASIOSetSampleRate( sampleRate );
- /* Set sample rate */
+
+ // check that the device supports the requested sample rate
+
+ asioError = ASIOCanSampleRate( sampleRate );
+ PA_DEBUG(("ASIOCanSampleRate(%f):%d\n",sampleRate, asioError ));
+
if( asioError != ASE_OK )
{
result = paInvalidSampleRate;
- PA_DEBUG(("ERROR: ASIOSetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
+ PA_DEBUG(("ERROR: ASIOCanSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
goto error;
}
- PA_DEBUG(("after ASIOSetSampleRate(%f)\n",sampleRate));
+
+
+ // retrieve the current sample rate, we only change to the requested
+ // sample rate if the device is not already in that rate.
+
+ ASIOSampleRate oldRate;
+ asioError = ASIOGetSampleRate(&oldRate);
+ if( asioError != ASE_OK )
+ {
+ result = paInvalidSampleRate;
+ PA_DEBUG(("ERROR: ASIOGetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
+ goto error;
+ }
+ PA_DEBUG(("ASIOGetSampleRate:%f\n",oldRate));
+
+ if (oldRate != sampleRate){
+
+ PA_DEBUG(("before ASIOSetSampleRate(%f)\n",sampleRate));
+ asioError = ASIOSetSampleRate( sampleRate );
+ /* Set sample rate */
+ if( asioError != ASE_OK )
+ {
+ result = paInvalidSampleRate;
+ PA_DEBUG(("ERROR: ASIOSetSampleRate: %s\n", PaAsio_GetAsioErrorText(asioError) ));
+ goto error;
+ }
+ PA_DEBUG(("after ASIOSetSampleRate(%f)\n",sampleRate));
+ }
+ else
+ {
+ PA_DEBUG(("No Need to change SR\n"));
+ }
+
+
/*
IMPLEMENT ME:
- if a full duplex stream is requested, check that the combination
@@ -2035,6 +2091,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
return result;
error:
+ PA_DEBUG(("goto errored\n"));
if( stream )
{
if( completedBuffersPlayedEventInited )
diff --git a/pd/portaudio/pa_common/pa_converters.c b/pd/portaudio/pa_common/pa_converters.c
index 4ee73c9a..a7e3a06c 100644
--- a/pd/portaudio/pa_common/pa_converters.c
+++ b/pd/portaudio/pa_common/pa_converters.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_converters.c,v 1.1.2.26 2004/12/11 16:32:38 aknudsen Exp $
+ * $Id: pa_converters.c,v 1.1.2.27 2005/11/02 12:14:07 rossbencina Exp $
* Portable Audio I/O Library sample conversion mechanism
*
* Based on the Open Source API proposed by Ross Bencina
@@ -325,7 +325,7 @@ static void Float32_To_Int32(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
+ PaInt32 *dest = (PaInt32*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
@@ -336,7 +336,7 @@ static void Float32_To_Int32(
*dest = lrintf(scaled-0.5f);
#else
double scaled = *src * 0x7FFFFFFF;
- *dest = (signed long) scaled;
+ *dest = (PaInt32) scaled;
#endif
src += sourceStride;
@@ -352,7 +352,7 @@ static void Float32_To_Int32_Dither(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
+ PaInt32 *dest = (PaInt32*)destinationBuffer;
while( count-- )
{
@@ -366,7 +366,7 @@ static void Float32_To_Int32_Dither(
double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
/* use smaller scaler to prevent overflow when we add the dither */
double dithered = ((double)*src * (2147483646.0)) + dither;
- *dest = (signed long) dithered;
+ *dest = (PaInt32) dithered;
#endif
src += sourceStride;
dest += destinationStride;
@@ -381,7 +381,7 @@ static void Float32_To_Int32_Clip(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
+ PaInt32 *dest = (PaInt32*)destinationBuffer;
(void) ditherGenerator; /* unused parameter */
while( count-- )
@@ -394,7 +394,7 @@ static void Float32_To_Int32_Clip(
#else
double scaled = *src * 0x7FFFFFFF;
PA_CLIP_( scaled, -2147483648., 2147483647. );
- *dest = (signed long) scaled;
+ *dest = (PaInt32) scaled;
#endif
src += sourceStride;
@@ -410,7 +410,7 @@ static void Float32_To_Int32_DitherClip(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
float *src = (float*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
+ PaInt32 *dest = (PaInt32*)destinationBuffer;
while( count-- )
{
@@ -426,7 +426,7 @@ static void Float32_To_Int32_DitherClip(
/* use smaller scaler to prevent overflow when we add the dither */
double dithered = ((double)*src * (2147483646.0)) + dither;
PA_CLIP_( dithered, -2147483648., 2147483647. );
- *dest = (signed long) dithered;
+ *dest = (PaInt32) dithered;
#endif
src += sourceStride;
@@ -443,7 +443,7 @@ static void Float32_To_Int24(
{
float *src = (float*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
+ PaInt32 temp;
(void) ditherGenerator; /* unused parameter */
@@ -451,7 +451,7 @@ static void Float32_To_Int24(
{
/* convert to 32 bit and drop the low 8 bits */
double scaled = *src * 0x7FFFFFFF;
- temp = (signed long) scaled;
+ temp = (PaInt32) scaled;
#if defined(PA_LITTLE_ENDIAN)
dest[0] = (unsigned char)(temp >> 8);
@@ -477,7 +477,7 @@ static void Float32_To_Int24_Dither(
{
float *src = (float*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
+ PaInt32 temp;
while( count-- )
{
@@ -487,7 +487,7 @@ static void Float32_To_Int24_Dither(
/* use smaller scaler to prevent overflow when we add the dither */
double dithered = ((double)*src * (2147483646.0)) + dither;
- temp = (signed long) dithered;
+ temp = (PaInt32) dithered;
#if defined(PA_LITTLE_ENDIAN)
dest[0] = (unsigned char)(temp >> 8);
@@ -513,7 +513,7 @@ static void Float32_To_Int24_Clip(
{
float *src = (float*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
+ PaInt32 temp;
(void) ditherGenerator; /* unused parameter */
@@ -522,7 +522,7 @@ static void Float32_To_Int24_Clip(
/* convert to 32 bit and drop the low 8 bits */
double scaled = *src * 0x7FFFFFFF;
PA_CLIP_( scaled, -2147483648., 2147483647. );
- temp = (signed long) scaled;
+ temp = (PaInt32) scaled;
#if defined(PA_LITTLE_ENDIAN)
dest[0] = (unsigned char)(temp >> 8);
@@ -548,7 +548,7 @@ static void Float32_To_Int24_DitherClip(
{
float *src = (float*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
- signed long temp;
+ PaInt32 temp;
while( count-- )
{
@@ -559,7 +559,7 @@ static void Float32_To_Int24_DitherClip(
double dithered = ((double)*src * (2147483646.0)) + dither;
PA_CLIP_( dithered, -2147483648., 2147483647. );
- temp = (signed long) dithered;
+ temp = (PaInt32) dithered;
#if defined(PA_LITTLE_ENDIAN)
dest[0] = (unsigned char)(temp >> 8);
@@ -584,7 +584,7 @@ static void Float32_To_Int16(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
+ PaInt16 *dest = (PaInt16*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
@@ -610,7 +610,7 @@ static void Float32_To_Int16_Dither(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
+ PaInt16 *dest = (PaInt16*)destinationBuffer;
while( count-- )
{
@@ -622,7 +622,7 @@ static void Float32_To_Int16_Dither(
#ifdef PA_USE_C99_LRINTF
*dest = lrintf(dithered-0.5f);
#else
- *dest = (signed short) dithered;
+ *dest = (PaInt16) dithered;
#endif
src += sourceStride;
@@ -638,7 +638,7 @@ static void Float32_To_Int16_Clip(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
+ PaInt16 *dest = (PaInt16*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
@@ -646,10 +646,10 @@ static void Float32_To_Int16_Clip(
#ifdef PA_USE_C99_LRINTF
long samp = lrintf((*src * (32767.0f)) -0.5f);
#else
- long samp = (signed long) (*src * (32767.0f));
+ long samp = (PaInt32) (*src * (32767.0f));
#endif
PA_CLIP_( samp, -0x8000, 0x7FFF );
- *dest = (signed short) samp;
+ *dest = (PaInt16) samp;
src += sourceStride;
dest += destinationStride;
@@ -664,7 +664,7 @@ static void Float32_To_Int16_DitherClip(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
float *src = (float*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
+ PaInt16 *dest = (PaInt16*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
@@ -673,12 +673,12 @@ static void Float32_To_Int16_DitherClip(
float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
/* use smaller scaler to prevent overflow when we add the dither */
float dithered = (*src * (32766.0f)) + dither;
- signed long samp = (signed long) dithered;
+ PaInt32 samp = (PaInt32) dithered;
PA_CLIP_( samp, -0x8000, 0x7FFF );
#ifdef PA_USE_C99_LRINTF
*dest = lrintf(samp-0.5f);
#else
- *dest = (signed short) samp;
+ *dest = (PaInt16) samp;
#endif
src += sourceStride;
@@ -723,7 +723,7 @@ static void Float32_To_Int8_Dither(
float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
/* use smaller scaler to prevent overflow when we add the dither */
float dithered = (*src * (126.0f)) + dither;
- signed long samp = (signed long) dithered;
+ PaInt32 samp = (PaInt32) dithered;
*dest = (signed char) samp;
src += sourceStride;
@@ -744,7 +744,7 @@ static void Float32_To_Int8_Clip(
while( count-- )
{
- signed long samp = (signed long)(*src * (127.0f));
+ PaInt32 samp = (PaInt32)(*src * (127.0f));
PA_CLIP_( samp, -0x80, 0x7F );
*dest = (signed char) samp;
@@ -769,7 +769,7 @@ static void Float32_To_Int8_DitherClip(
float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
/* use smaller scaler to prevent overflow when we add the dither */
float dithered = (*src * (126.0f)) + dither;
- signed long samp = (signed long) dithered;
+ PaInt32 samp = (PaInt32) dithered;
PA_CLIP_( samp, -0x80, 0x7F );
*dest = (signed char) samp;
@@ -866,7 +866,7 @@ static void Int32_To_Float32(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed long *src = (signed long*)sourceBuffer;
+ PaInt32 *src = (PaInt32*)sourceBuffer;
float *dest = (float*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
@@ -886,7 +886,7 @@ static void Int32_To_Int24(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed long *src = (signed long*)sourceBuffer;
+ PaInt32 *src = (PaInt32*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
(void) ditherGenerator; /* unused parameter */
@@ -930,13 +930,13 @@ static void Int32_To_Int16(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed long *src = (signed long*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
+ PaInt32 *src = (PaInt32*)sourceBuffer;
+ PaInt16 *dest = (PaInt16*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
{
- *dest = (signed short) ((*src) >> 16);
+ *dest = (PaInt16) ((*src) >> 16);
src += sourceStride;
dest += destinationStride;
@@ -950,15 +950,15 @@ static void Int32_To_Int16_Dither(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed long *src = (signed long*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
- signed long dither;
+ PaInt32 *src = (PaInt32*)sourceBuffer;
+ PaInt16 *dest = (PaInt16*)destinationBuffer;
+ PaInt32 dither;
while( count-- )
{
/* REVIEW */
dither = PaUtil_Generate16BitTriangularDither( ditherGenerator );
- *dest = (signed short) ((((*src)>>1) + dither) >> 15);
+ *dest = (PaInt16) ((((*src)>>1) + dither) >> 15);
src += sourceStride;
dest += destinationStride;
@@ -972,7 +972,7 @@ static void Int32_To_Int8(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed long *src = (signed long*)sourceBuffer;
+ PaInt32 *src = (PaInt32*)sourceBuffer;
signed char *dest = (signed char*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
@@ -992,9 +992,9 @@ static void Int32_To_Int8_Dither(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed long *src = (signed long*)sourceBuffer;
+ PaInt32 *src = (PaInt32*)sourceBuffer;
signed char *dest = (signed char*)destinationBuffer;
- signed long dither;
+ PaInt32 dither;
while( count-- )
{
@@ -1014,7 +1014,7 @@ static void Int32_To_UInt8(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed long *src = (signed long*)sourceBuffer;
+ PaInt32 *src = (PaInt32*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
@@ -1034,7 +1034,7 @@ static void Int32_To_UInt8_Dither(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed long *src = (signed long*)sourceBuffer;
+ PaInt32 *src = (PaInt32*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
@@ -1056,7 +1056,7 @@ static void Int24_To_Float32(
{
unsigned char *src = (unsigned char*)sourceBuffer;
float *dest = (float*)destinationBuffer;
- signed long temp;
+ PaInt32 temp;
(void) ditherGenerator; /* unused parameter */
@@ -1088,8 +1088,8 @@ static void Int24_To_Int32(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
unsigned char *src = (unsigned char*)sourceBuffer;
- signed long *dest = (signed long*) destinationBuffer;
- signed long temp;
+ PaInt32 *dest = (PaInt32*) destinationBuffer;
+ PaInt32 temp;
(void) ditherGenerator; /* unused parameter */
@@ -1121,9 +1121,9 @@ static void Int24_To_Int16(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
unsigned char *src = (unsigned char*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
+ PaInt16 *dest = (PaInt16*)destinationBuffer;
- signed short temp;
+ PaInt16 temp;
(void) ditherGenerator; /* unused parameter */
@@ -1132,12 +1132,12 @@ static void Int24_To_Int16(
#if defined(PA_LITTLE_ENDIAN)
/* src[0] is discarded */
- temp = (((signed short)src[1]));
- temp = temp | (signed short)(((signed short)src[2]) << 8);
+ temp = (((PaInt16)src[1]));
+ temp = temp | (PaInt16)(((PaInt16)src[2]) << 8);
#elif defined(PA_BIG_ENDIAN)
/* src[2] is discarded */
- temp = (signed short)(((signed short)src[0]) << 8);
- temp = temp | (((signed short)src[1]));
+ temp = (PaInt16)(((PaInt16)src[0]) << 8);
+ temp = temp | (((PaInt16)src[1]));
#endif
*dest = temp;
@@ -1262,7 +1262,7 @@ static void Int16_To_Float32(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed short *src = (signed short*)sourceBuffer;
+ PaInt16 *src = (PaInt16*)sourceBuffer;
float *dest = (float*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
@@ -1283,8 +1283,8 @@ static void Int16_To_Int32(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed short *src = (signed short*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
+ PaInt16 *src = (PaInt16*)sourceBuffer;
+ PaInt32 *dest = (PaInt32*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
@@ -1307,9 +1307,9 @@ static void Int16_To_Int24(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed short *src = (signed short*) sourceBuffer;
+ PaInt16 *src = (PaInt16*) sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
- signed short temp;
+ PaInt16 temp;
(void) ditherGenerator; /* unused parameter */
@@ -1339,7 +1339,7 @@ static void Int16_To_Int8(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed short *src = (signed short*)sourceBuffer;
+ PaInt16 *src = (PaInt16*)sourceBuffer;
signed char *dest = (signed char*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
@@ -1359,7 +1359,7 @@ static void Int16_To_Int8_Dither(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed short *src = (signed short*)sourceBuffer;
+ PaInt16 *src = (PaInt16*)sourceBuffer;
signed char *dest = (signed char*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
@@ -1379,7 +1379,7 @@ static void Int16_To_UInt8(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed short *src = (signed short*)sourceBuffer;
+ PaInt16 *src = (PaInt16*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
@@ -1399,7 +1399,7 @@ static void Int16_To_UInt8_Dither(
void *sourceBuffer, signed int sourceStride,
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
- signed short *src = (signed short*)sourceBuffer;
+ PaInt16 *src = (PaInt16*)sourceBuffer;
unsigned char *dest = (unsigned char*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
@@ -1441,7 +1441,7 @@ static void Int8_To_Int32(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
signed char *src = (signed char*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
+ PaInt32 *dest = (PaInt32*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
@@ -1490,12 +1490,12 @@ static void Int8_To_Int16(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
signed char *src = (signed char*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
+ PaInt16 *dest = (PaInt16*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
{
- (*dest) = (signed short)((*src) << 8);
+ (*dest) = (PaInt16)((*src) << 8);
src += sourceStride;
dest += destinationStride;
@@ -1551,7 +1551,7 @@ static void UInt8_To_Int32(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
unsigned char *src = (unsigned char*)sourceBuffer;
- signed long *dest = (signed long*)destinationBuffer;
+ PaInt32 *dest = (PaInt32*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
@@ -1600,12 +1600,12 @@ static void UInt8_To_Int16(
unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
{
unsigned char *src = (unsigned char*)sourceBuffer;
- signed short *dest = (signed short*)destinationBuffer;
+ PaInt16 *dest = (PaInt16*)destinationBuffer;
(void)ditherGenerator; /* unused parameter */
while( count-- )
{
- (*dest) = (signed short)((*src - 128) << 8);
+ (*dest) = (PaInt16)((*src - 128) << 8);
src += sourceStride;
dest += destinationStride;
diff --git a/pd/portaudio/pa_common/pa_dither.c b/pd/portaudio/pa_common/pa_dither.c
index eb6bec38..0600db62 100644
--- a/pd/portaudio/pa_common/pa_dither.c
+++ b/pd/portaudio/pa_common/pa_dither.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_dither.c,v 1.1.2.5 2003/09/20 21:06:19 rossbencina Exp $
+ * $Id: pa_dither.c,v 1.1.2.6 2005/05/28 22:49:02 rossbencina Exp $
* Portable Audio I/O Library triangular dither generator
*
* Based on the Open Source API proposed by Ross Bencina
@@ -35,6 +35,7 @@
#include "pa_dither.h"
+#include "pa_types.h"
#define PA_DITHER_BITS_ (15)
@@ -59,7 +60,7 @@ signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerato
* Shift before adding to prevent overflow which would skew the distribution.
* Also shift an extra bit for the high pass filter.
*/
-#define DITHER_SHIFT_ ((32 - PA_DITHER_BITS_) + 1)
+#define DITHER_SHIFT_ ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1)
current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
(((signed long)state->randSeed2)>>DITHER_SHIFT_);
@@ -86,7 +87,7 @@ float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *sta
* Shift before adding to prevent overflow which would skew the distribution.
* Also shift an extra bit for the high pass filter.
*/
-#define DITHER_SHIFT_ ((32 - PA_DITHER_BITS_) + 1)
+#define DITHER_SHIFT_ ((SIZEOF_LONG*8 - PA_DITHER_BITS_) + 1)
current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
(((signed long)state->randSeed2)>>DITHER_SHIFT_);
diff --git a/pd/portaudio/pa_common/pa_endianness.h b/pd/portaudio/pa_common/pa_endianness.h
index 052bced6..cb6f8ad5 100644
--- a/pd/portaudio/pa_common/pa_endianness.h
+++ b/pd/portaudio/pa_common/pa_endianness.h
@@ -1,7 +1,7 @@
#ifndef PA_ENDIANNESS_H
#define PA_ENDIANNESS_H
/*
- * $Id: pa_endianness.h,v 1.1.2.3 2003/09/20 21:06:19 rossbencina Exp $
+ * $Id: pa_endianness.h,v 1.1.2.5 2006/02/16 16:26:07 bjornroche Exp $
* Portable Audio I/O Library current platform endianness macros
*
* Based on the Open Source API proposed by Ross Bencina
@@ -67,11 +67,13 @@ extern "C"
/* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */
- #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
+ #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || defined(LITTLE_ENDIAN) || defined(__i386) || defined(_M_IX86)
#define PA_LITTLE_ENDIAN /* win32, assume intel byte order */
#else
+
+ #define PA_BIG_ENDIAN
#endif
diff --git a/pd/portaudio/pa_common/pa_front.c b/pd/portaudio/pa_common/pa_front.c
index d61c3008..696df8b2 100644
--- a/pd/portaudio/pa_common/pa_front.c
+++ b/pd/portaudio/pa_common/pa_front.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_front.c,v 1.1.2.51 2005/02/05 15:52:12 rossbencina Exp $
+ * $Id: pa_front.c,v 1.1.2.53 2006/03/20 18:11:09 aknudsen Exp $
* Portable Audio I/O Library Multi-Host API front end
* Validate function parameters and manage multiple host APIs.
*
@@ -256,6 +256,9 @@ static PaError InitializeHostApis( void )
if( hostApis_[hostApisCount_] )
{
+ PaUtilHostApiRepresentation* hostApi = hostApis_[hostApisCount_];
+ assert( hostApi->info.defaultInputDevice < hostApi->info.deviceCount );
+ assert( hostApi->info.defaultOutputDevice < hostApi->info.deviceCount );
hostApis_[hostApisCount_]->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;
@@ -905,8 +908,8 @@ static int SampleFormatIsValid( PaSampleFormat format )
- at least one of inputParameters & outputParmeters is valid (not NULL)
- - if inputParameters & outputParmeters are both valid, that
- inputParameters->device & outputParmeters->device both use the same host api
+ - if inputParameters & outputParameters are both valid, that
+ inputParameters->device & outputParameters->device both use the same host api
PaDeviceIndex inputParameters->device
- is within range (0 to Pa_GetDeviceCount-1) Or:
@@ -1786,11 +1789,12 @@ PaError Pa_ReadStream( PaStream* stream,
{
if( frames == 0 )
{
- result = paInternalError; /** @todo should return a different error code */
+ /* XXX: Should we not allow the implementation to signal any overflow condition? */
+ result = paNoError;
}
else if( buffer == 0 )
{
- result = paInternalError; /** @todo should return a different error code */
+ result = paBadBufferPtr;
}
else
{
@@ -1830,11 +1834,12 @@ PaError Pa_WriteStream( PaStream* stream,
{
if( frames == 0 )
{
- result = paInternalError; /** @todo should return a different error code */
+ /* XXX: Should we not allow the implementation to signal any underflow condition? */
+ result = paNoError;
}
else if( buffer == 0 )
{
- result = paInternalError; /** @todo should return a different error code */
+ result = paBadBufferPtr;
}
else
{
diff --git a/pd/portaudio/pa_common/pa_process.c b/pd/portaudio/pa_common/pa_process.c
index cf711d41..4a52165b 100644
--- a/pd/portaudio/pa_common/pa_process.c
+++ b/pd/portaudio/pa_common/pa_process.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_process.c,v 1.1.2.48 2004/12/13 09:48:43 rossbencina Exp $
+ * $Id: pa_process.c,v 1.1.2.51 2005/10/27 23:28:48 aknudsen Exp $
* Portable Audio I/O Library
* streamCallback <-> host buffer processing adapter
*
@@ -131,6 +131,14 @@ PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
PaError bytesPerSample;
unsigned long tempInputBufferSize, tempOutputBufferSize;
+ if( streamFlags & paNeverDropInput )
+ {
+ /* paNeverDropInput is only valid for full-duplex callback streams, with an unspecified number of frames per buffer. */
+ if( !streamCallback || !(inputChannelCount > 0 && outputChannelCount > 0) ||
+ framesPerUserBuffer != paFramesPerBufferUnspecified )
+ return paInvalidFlag;
+ }
+
/* initialize buffer ptrs to zero so they can be freed if necessary in error */
bp->tempInputBuffer = 0;
bp->tempInputBufferPtrs = 0;
@@ -571,7 +579,8 @@ void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,
unsigned int channel, void *data, unsigned int stride )
{
assert( channel < bp->outputChannelCount );
-
+ assert( data != NULL );
+
bp->hostOutputChannels[0][channel].data = data;
bp->hostOutputChannels[0][channel].stride = stride;
}
@@ -592,9 +601,8 @@ void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
for( i=0; i< channelCount; ++i )
{
- bp->hostOutputChannels[0][channel+i].data = p;
+ PaUtil_SetOutputChannel( bp, channel + i, p, channelCount );
p += bp->bytesPerHostOutputSample;
- bp->hostOutputChannels[0][channel+i].stride = channelCount;
}
}
@@ -604,8 +612,7 @@ void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
{
assert( channel < bp->outputChannelCount );
- bp->hostOutputChannels[0][channel].data = data;
- bp->hostOutputChannels[0][channel].stride = 1;
+ PaUtil_SetOutputChannel( bp, channel, data, 1 );
}
@@ -620,6 +627,7 @@ void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,
unsigned int channel, void *data, unsigned int stride )
{
assert( channel < bp->outputChannelCount );
+ assert( data != NULL );
bp->hostOutputChannels[1][channel].data = data;
bp->hostOutputChannels[1][channel].stride = stride;
@@ -641,9 +649,8 @@ void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
for( i=0; i< channelCount; ++i )
{
- bp->hostOutputChannels[1][channel+i].data = p;
+ PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount );
p += bp->bytesPerHostOutputSample;
- bp->hostOutputChannels[1][channel+i].stride = channelCount;
}
}
@@ -653,8 +660,7 @@ void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
{
assert( channel < bp->outputChannelCount );
- bp->hostOutputChannels[1][channel].data = data;
- bp->hostOutputChannels[1][channel].stride = 1;
+ PaUtil_Set2ndOutputChannel( bp, channel, data, 1 );
}
@@ -1180,6 +1186,7 @@ static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp)
for( i=0; i<bp->outputChannelCount; ++i )
{
+ assert( hostOutputChannels[i].data != NULL );
bp->outputConverter( hostOutputChannels[i].data,
hostOutputChannels[i].stride,
srcBytePtr, srcSampleStrideSamples,
diff --git a/pd/portaudio/pa_common/pa_trace.c b/pd/portaudio/pa_common/pa_trace.c
index 83514a05..e36329fd 100644
--- a/pd/portaudio/pa_common/pa_trace.c
+++ b/pd/portaudio/pa_common/pa_trace.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_trace.c,v 1.1.1.1.2.3 2003/09/20 21:09:15 rossbencina Exp $
+ * $Id: pa_trace.c,v 1.1.1.1.2.4 2005/11/02 12:06:44 rossbencina Exp $
* Portable Audio I/O Library Trace Facility
* Store trace information in real-time for later printing.
*
@@ -42,8 +42,8 @@
#if PA_TRACE_REALTIME_EVENTS
-static char *traceTextArray[MAX_TRACE_RECORDS];
-static int traceIntArray[MAX_TRACE_RECORDS];
+static char *traceTextArray[PA_MAX_TRACE_RECORDS];
+static int traceIntArray[PA_MAX_TRACE_RECORDS];
static int traceIndex = 0;
static int traceBlock = 0;
@@ -65,7 +65,7 @@ void PaUtil_DumpTraceMessages()
printf("%3d: %s = 0x%08X\n",
i, traceTextArray[i], traceIntArray[i] );
}
- ResetTraceMessages();
+ PaUtil_ResetTraceMessages();
fflush(stdout);
}
diff --git a/pd/portaudio/pa_common/pa_util.h b/pd/portaudio/pa_common/pa_util.h
index 149fbca3..d20badd2 100644
--- a/pd/portaudio/pa_common/pa_util.h
+++ b/pd/portaudio/pa_common/pa_util.h
@@ -1,7 +1,7 @@
#ifndef PA_UTIL_H
#define PA_UTIL_H
/*
- * $Id: pa_util.h,v 1.1.2.12 2003/09/20 21:09:55 rossbencina Exp $
+ * $Id: pa_util.h,v 1.1.2.13 2005/11/09 06:31:42 aknudsen Exp $
* Portable Audio I/O Library implementation utilities header
* common implementation utilities and interfaces
*
@@ -114,7 +114,7 @@ void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
void PaUtil_DebugPrint( const char *format, ... );
-#if (0) /* set to 1 to print debug messages */
+#ifdef PA_ENABLE_DEBUG_OUTPUT
#define PA_DEBUG(x) PaUtil_DebugPrint x ;
#else
#define PA_DEBUG(x)
diff --git a/pd/portaudio/pa_common/portaudio.h b/pd/portaudio/pa_common/portaudio.h
index 341d92c9..c5967b0b 100644
--- a/pd/portaudio/pa_common/portaudio.h
+++ b/pd/portaudio/pa_common/portaudio.h
@@ -2,7 +2,7 @@
#ifndef PORTAUDIO_H
#define PORTAUDIO_H
/*
- * $Id: portaudio.h,v 1.5.2.50 2004/12/13 11:50:40 rossbencina Exp $
+ * $Id: portaudio.h,v 1.5.2.53 2006/03/20 17:49:38 aknudsen Exp $
* PortAudio Portable Real-Time Audio Library
* PortAudio API Header File
* Latest version available at: http://www.portaudio.com/
@@ -92,7 +92,8 @@ typedef enum PaErrorCode
paCanNotWriteToACallbackStream, /**< @todo review error code name */
paCanNotReadFromAnOutputOnlyStream, /**< @todo review error code name */
paCanNotWriteToAnInputOnlyStream, /**< @todo review error code name */
- paIncompatibleStreamHostApi
+ paIncompatibleStreamHostApi,
+ paBadBufferPtr
} PaErrorCode;
@@ -247,13 +248,13 @@ typedef struct PaHostApiInfo
*/
int deviceCount;
- /** The the default input device for this host API. The value will be a
+ /** The default input device for this host API. The value will be a
device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice
if no default input device is available.
*/
PaDeviceIndex defaultInputDevice;
- /** The the default output device for this host API. The value will be a
+ /** The default output device for this host API. The value will be a
device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice
if no default output device is available.
*/
@@ -496,8 +497,8 @@ typedef struct PaStreamParameters
configure their latency based on these parameters, otherwise they may
choose the closest viable latency instead. Unless the suggested latency
is greater than the absolute upper limit for the device implementations
- shouldround the suggestedLatency up to the next practial value - ie to
- provide an equal or higher latency than suggestedLatency whereever possibe.
+ should round the suggestedLatency up to the next practial value - ie to
+ provide an equal or higher latency than suggestedLatency wherever possibe.
Actual latency values for an open stream may be retrieved using the
inputLatency and outputLatency fields of the PaStreamInfo structure
returned by Pa_GetStreamInfo().
diff --git a/pd/portaudio/pa_jack/pa_jack.c b/pd/portaudio/pa_jack/pa_jack.c
index d50ad210..2199365f 100644
--- a/pd/portaudio/pa_jack/pa_jack.c
+++ b/pd/portaudio/pa_jack/pa_jack.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_jack.c,v 1.1.2.19 2004/12/23 18:30:09 aknudsen Exp $
+ * $Id: pa_jack.c,v 1.1.2.20 2005/10/02 22:02:26 aknudsen Exp $
* PortAudio Portable Real-Time Audio Library
* Latest Version at: http://www.portaudio.com
* JACK Implementation by Joshua Haberman
@@ -573,7 +573,6 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] );
curDevInfo->defaultLowInputLatency = curDevInfo->defaultHighInputLatency =
jack_port_get_latency( p ) / globalSampleRate;
- free( p );
for( i = 0; clientPorts[i] != NULL; i++)
{
@@ -595,7 +594,6 @@ static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
jack_port_t *p = jack_port_by_name( jackApi->jack_client, clientPorts[0] );
curDevInfo->defaultLowOutputLatency = curDevInfo->defaultHighOutputLatency =
jack_port_get_latency( p ) / globalSampleRate;
- free( p );
for( i = 0; clientPorts[i] != NULL; i++)
{
@@ -961,13 +959,11 @@ static void CleanUpStream( PaJackStream *stream, int terminateStreamRepresentati
{
if( stream->local_input_ports[i] )
ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_input_ports[i] ), 0 );
- free( stream->remote_output_ports[i] );
}
for( i = 0; i < stream->num_outgoing_connections; ++i )
{
if( stream->local_output_ports[i] )
ASSERT_CALL( jack_port_unregister( stream->jack_client, stream->local_output_ports[i] ), 0 );
- free( stream->remote_input_ports[i] );
}
if( terminateStreamRepresentation )
diff --git a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c
index 0d0aa1ce..2f88fc2f 100644
--- a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c
+++ b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c
@@ -1,11 +1,11 @@
/*
- * $Id: pa_linux_alsa.c,v 1.1.2.71 2005/04/15 18:20:18 aknudsen Exp $
+ * $Id: pa_linux_alsa.c,v 1.1.2.92 2006/03/22 19:36:04 aknudsen Exp $
* PortAudio Portable Real-Time Audio Library
* Latest Version at: http://www.portaudio.com
* ALSA implementation by Joshua Haberman and Arve Knudsen
*
* Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
- * Copyright (c) 2005 Arve Knudsen <aknuds-1@broadpark.no>
+ * Copyright (c) 2005-2006 Arve Knudsen <aknuds-1@broadpark.no>
*
* Based on the Open Source API proposed by Ross Bencina
* Copyright (c) 1999-2002 Ross Bencina, Phil Burk
@@ -71,15 +71,32 @@
{ \
PaUtil_SetLastHostErrorInfo( paALSA, aErr_, snd_strerror( aErr_ ) ); \
} \
- PaUtil_DebugPrint(( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" )); \
+ PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \
+ if( (code) == paUnanticipatedHostError ) \
+ PA_DEBUG(( "Host error description: %s\n", snd_strerror( aErr_ ) )); \
result = (code); \
goto error; \
} \
} while( 0 );
+#define ENSURE_SYSTEM_(expr, success) \
+ do { \
+ if( UNLIKELY( (aErr_ = (expr)) != success ) ) \
+ { \
+ /* PaUtil_SetLastHostErrorInfo should only be used in the main thread */ \
+ if( pthread_self() != callbackThread_ ) \
+ { \
+ PaUtil_SetLastHostErrorInfo( paALSA, aErr_, strerror( aErr_ ) ); \
+ } \
+ PaUtil_DebugPrint( "Expression '" #expr "' failed in '" __FILE__ "', line: " STRINGIZE( __LINE__ ) "\n" ); \
+ result = paUnanticipatedHostError; \
+ goto error; \
+ } \
+ } while( 0 );
+
#define ASSERT_CALL_(expr, success) \
aErr_ = (expr); \
- assert( aErr_ == success );
+ assert( success == aErr_ );
static int aErr_; /* Used with ENSURE_ */
static pthread_t callbackThread_;
@@ -132,7 +149,7 @@ typedef struct PaAlsaStream
PaUtilBufferProcessor bufferProcessor;
PaAlsaThreading threading;
- unsigned long framesPerUserBuffer;
+ unsigned long framesPerUserBuffer, maxFramesPerHostBuffer;
int primeBuffers;
int callbackMode; /* bool: are we running in callback mode? */
@@ -140,7 +157,7 @@ typedef struct PaAlsaStream
/* the callback thread uses these to poll the sound device(s), waiting
* for data to be ready/available */
- struct pollfd *pfds;
+ struct pollfd* pfds;
int pollTimeout;
/* Used in communication between threads */
@@ -165,7 +182,7 @@ PaAlsaStream;
typedef struct PaAlsaHostApiRepresentation
{
- PaUtilHostApiRepresentation commonHostApiRep;
+ PaUtilHostApiRepresentation baseHostApiRep;
PaUtilStreamInterface callbackStreamInterface;
PaUtilStreamInterface blockingStreamInterface;
@@ -177,7 +194,7 @@ PaAlsaHostApiRepresentation;
typedef struct PaAlsaDeviceInfo
{
- PaDeviceInfo commonDeviceInfo;
+ PaDeviceInfo baseDeviceInfo;
char *alsaName;
int isPlug;
int minInputChannels;
@@ -214,7 +231,7 @@ static PaError KillCallbackThread( PaAlsaThreading *th, int wait, PaError *exitR
if( th->watchdogRunning )
{
pthread_cancel( th->watchdogThread );
- ASSERT_CALL_( pthread_join( th->watchdogThread, &pret ), 0 );
+ ENSURE_SYSTEM_( pthread_join( th->watchdogThread, &pret ), 0 );
if( pret && pret != PTHREAD_CANCELED )
{
@@ -227,8 +244,12 @@ static PaError KillCallbackThread( PaAlsaThreading *th, int wait, PaError *exitR
/* Only kill the thread if it isn't in the process of stopping (flushing adaptation buffers) */
/* TODO: Make join time out */
if( !wait )
+ {
+ PA_DEBUG(( "%s: Canceling thread %d\n", __FUNCTION__, th->callbackThread ));
pthread_cancel( th->callbackThread ); /* XXX: Safe to call this if the thread has exited on its own? */
- ASSERT_CALL_( pthread_join( th->callbackThread, &pret ), 0 );
+ }
+ PA_DEBUG(( "%s: Joining thread %d\n", __FUNCTION__, th->callbackThread ));
+ ENSURE_SYSTEM_( pthread_join( th->callbackThread, &pret ), 0 );
if( pret && pret != PTHREAD_CANCELED )
{
@@ -237,6 +258,40 @@ static PaError KillCallbackThread( PaAlsaThreading *th, int wait, PaError *exitR
free( pret );
}
+error:
+ return result;
+}
+
+/** Lock a pthread_mutex_t.
+ *
+ * @concern ThreadCancellation We're disabling thread cancellation while the thread is holding a lock, so mutexes are
+ * properly unlocked at termination time.
+ */
+static PaError LockMutex( pthread_mutex_t *mtx )
+{
+ PaError result = paNoError;
+ int oldState;
+
+ ENSURE_SYSTEM_( pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &oldState ), 0 );
+ ENSURE_SYSTEM_( pthread_mutex_lock( mtx ), 0 );
+
+error:
+ return result;
+}
+
+/** Unlock a pthread_mutex_t.
+ *
+ * @concern ThreadCancellation Thread cancellation is enabled again after the mutex is properly unlocked.
+ */
+static PaError UnlockMutex( pthread_mutex_t *mtx )
+{
+ PaError result = paNoError;
+ int oldState;
+
+ ENSURE_SYSTEM_( pthread_mutex_unlock( mtx ), 0 );
+ ENSURE_SYSTEM_( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, &oldState ), 0 );
+
+error:
return result;
}
@@ -283,13 +338,15 @@ static void *WatchdogFunc( void *userData )
assert( th );
- pthread_cleanup_push( &OnWatchdogExit, th ); /* Execute OnWatchdogExit when exiting */
+ /* Execute OnWatchdogExit when exiting */
+ pthread_cleanup_push( &OnWatchdogExit, th );
/* Boost priority of callback thread */
PA_ENSURE( result = BoostPriority( th ) );
if( !result )
{
- pthread_exit( NULL ); /* Boost failed, might as well exit */
+ /* Boost failed, might as well exit */
+ pthread_exit( NULL );
}
cpuTimeThen = th->callbackCpuTime;
@@ -445,7 +502,7 @@ static PaError CreateCallbackThread( PaAlsaThreading *th, void *(*callbackThread
{
int policy;
th->watchdogRunning = 1;
- ASSERT_CALL_( pthread_getschedparam( th->watchdogThread, &policy, &wdSpm ), 0 );
+ ENSURE_SYSTEM_( pthread_getschedparam( th->watchdogThread, &policy, &wdSpm ), 0 );
/* Check if priority is right, policy could potentially differ from SCHED_FIFO (but that's alright) */
if( wdSpm.sched_priority != prio )
{
@@ -516,6 +573,10 @@ static const PaAlsaDeviceInfo *GetDeviceInfo( const PaUtilHostApiRepresentation
return (const PaAlsaDeviceInfo *)hostApi->deviceInfos[device];
}
+static void AlsaErrorHandler(const char *file, int line, const char *function, int err, const char *fmt, ...)
+{
+}
+
PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
{
PaError result = paNoError;
@@ -535,6 +596,8 @@ PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex
(*hostApi)->OpenStream = OpenStream;
(*hostApi)->IsFormatSupported = IsFormatSupported;
+ ENSURE_( snd_lib_error_set_handler(AlsaErrorHandler), paUnanticipatedHostError );
+
PA_ENSURE( BuildDeviceList( alsaHostApi ) );
PaUtil_InitializeStreamInterface( &alsaHostApi->callbackStreamInterface,
@@ -588,28 +651,49 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
snd_config_update_free_global();
}
-/*! Determine max channels and default latencies.
+/** Determine max channels and default latencies.
*
* This function provides functionality to grope an opened (might be opened for capture or playback) pcm device for
* traits like max channels, suitable default latencies and default sample rate. Upon error, max channels is set to zero,
* and a suitable result returned. The device is closed before returning.
*/
-static PaError GropeDevice( snd_pcm_t *pcm, int *minChannels, int *maxChannels, double *defaultLowLatency,
- double *defaultHighLatency, double *defaultSampleRate, int isPlug )
+static PaError GropeDevice( snd_pcm_t* pcm, int isPlug, StreamDirection mode, int openBlocking,
+ PaAlsaDeviceInfo* devInfo, int* canMmap )
{
PaError result = paNoError;
snd_pcm_hw_params_t *hwParams;
snd_pcm_uframes_t lowLatency = 512, highLatency = 2048;
unsigned int minChans, maxChans;
+ int* minChannels, * maxChannels;
+ double * defaultLowLatency, * defaultHighLatency, * defaultSampleRate =
+ &devInfo->baseDeviceInfo.defaultSampleRate;
double defaultSr = *defaultSampleRate;
assert( pcm );
+ if( StreamDirection_In == mode )
+ {
+ minChannels = &devInfo->minInputChannels;
+ maxChannels = &devInfo->baseDeviceInfo.maxInputChannels;
+ defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowInputLatency;
+ defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighInputLatency;
+ }
+ else
+ {
+ minChannels = &devInfo->minOutputChannels;
+ maxChannels = &devInfo->baseDeviceInfo.maxOutputChannels;
+ defaultLowLatency = &devInfo->baseDeviceInfo.defaultLowOutputLatency;
+ defaultHighLatency = &devInfo->baseDeviceInfo.defaultHighOutputLatency;
+ }
+
ENSURE_( snd_pcm_nonblock( pcm, 0 ), paUnanticipatedHostError );
snd_pcm_hw_params_alloca( &hwParams );
snd_pcm_hw_params_any( pcm, hwParams );
+ *canMmap = snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_INTERLEAVED ) >= 0 ||
+ snd_pcm_hw_params_test_access( pcm, hwParams, SND_PCM_ACCESS_MMAP_NONINTERLEAVED ) >= 0;
+
if( defaultSr >= 0 )
{
/* Could be that the device opened in one mode supports samplerates that the other mode wont have,
@@ -624,10 +708,14 @@ static PaError GropeDevice( snd_pcm_t *pcm, int *minChannels, int *maxChannels,
if( defaultSr < 0. ) /* Default sample rate not set */
{
unsigned int sampleRate = 44100; /* Will contain approximate rate returned by alsa-lib */
- ENSURE_( snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ), paUnanticipatedHostError );
+ if( snd_pcm_hw_params_set_rate_near( pcm, hwParams, &sampleRate, NULL ) < 0)
+ {
+ result = paUnanticipatedHostError;
+ goto error;
+ }
ENSURE_( GetExactSampleRate( hwParams, &defaultSr ), paUnanticipatedHostError );
}
-
+
ENSURE_( snd_pcm_hw_params_get_channels_min( hwParams, &minChans ), paUnanticipatedHostError );
ENSURE_( snd_pcm_hw_params_get_channels_max( hwParams, &maxChans ), paUnanticipatedHostError );
assert( maxChans <= INT_MAX );
@@ -723,22 +811,22 @@ error:
return result;
}
-/* Disregard standard plugins
- * XXX: Might want to make the "default" plugin available, if we can make it work
+/* Disregard some standard plugins
*/
static int IgnorePlugin( const char *pluginId )
{
-#define numIgnored 10
- static const char *ignoredPlugins[numIgnored] = {"hw", "plughw", "plug", "default", "dsnoop", "dmix", "tee",
- "file", "null", "shm"};
- int i;
-
- for( i = 0; i < numIgnored; ++i )
+ /* XXX: dmix and default ignored because after opening and closing, they seem to keep hogging resources.
+ */
+ static const char *ignoredPlugins[] = {"hw", "plughw", "plug", "dsnoop", "tee",
+ "file", "null", "shm", "cards", "dmix", "default", NULL};
+ int i = 0;
+ while( ignoredPlugins[i] )
{
if( !strcmp( pluginId, ignoredPlugins[i] ) )
{
return 1;
}
+ ++i;
}
return 0;
@@ -747,7 +835,7 @@ static int IgnorePlugin( const char *pluginId )
/* Build PaDeviceInfo list, ignore devices for which we cannot determine capabilities (possibly busy, sigh) */
static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
{
- PaUtilHostApiRepresentation *commonApi = &alsaApi->commonHostApiRep;
+ PaUtilHostApiRepresentation *baseApi = &alsaApi->baseHostApiRep;
PaAlsaDeviceInfo *deviceInfoArray;
int cardIdx = -1, devIdx = 0;
snd_ctl_card_info_t *cardInfo;
@@ -763,8 +851,8 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
blocking = 0;
/* These two will be set to the first working input and output device, respectively */
- commonApi->info.defaultInputDevice = paNoDevice;
- commonApi->info.defaultOutputDevice = paNoDevice;
+ baseApi->info.defaultInputDevice = paNoDevice;
+ baseApi->info.defaultOutputDevice = paNoDevice;
/* count the devices by enumerating all the card numbers */
@@ -788,7 +876,10 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
/* Acquire name of card */
if( snd_ctl_open( &ctl, alsaCardName, 0 ) < 0 )
- continue; /* Unable to open card :( */
+ {
+ /* Unable to open card :( */
+ continue;
+ }
snd_ctl_card_info( ctl, cardInfo );
PA_ENSURE( PaAlsa_StrDup( alsaApi, &cardName, snd_ctl_card_info_get_name( cardInfo )) );
@@ -805,11 +896,15 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
snd_pcm_info_set_subdevice( pcmInfo, 0 );
snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_CAPTURE );
if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
+ {
hasCapture = 1;
+ }
snd_pcm_info_set_stream( pcmInfo, SND_PCM_STREAM_PLAYBACK );
if( snd_ctl_pcm_info( ctl, pcmInfo ) >= 0 )
+ {
hasPlayback = 1;
+ }
if( !hasPlayback && !hasCapture )
{
@@ -843,29 +938,42 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
}
/* Iterate over plugin devices */
- snd_config_update();
+ if( NULL == snd_config )
+ {
+ /* snd_config_update is called implicitly by some functions, if this hasn't happened snd_config will be NULL (bleh) */
+ ENSURE_( snd_config_update(), paUnanticipatedHostError );
+ PA_DEBUG(( "Updating snd_config\n" ));
+ }
+ assert( snd_config );
if( (res = snd_config_search( snd_config, "pcm", &topNode )) >= 0 )
{
snd_config_iterator_t i, next;
snd_config_for_each( i, next, topNode )
{
- const char *tpStr = NULL, *idStr = NULL;
- char *alsaDeviceName, *deviceName;
- snd_config_t *n = snd_config_iterator_entry( i ), *tp = NULL;
- if( snd_config_get_type( n ) != SND_CONFIG_TYPE_COMPOUND )
- continue;
+ const char *tpStr = "unknown", *idStr = NULL;
+ int err = 0;
- ENSURE_( snd_config_search( n, "type", &tp ), paUnanticipatedHostError );
- ENSURE_( snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError );
+ char *alsaDeviceName, *deviceName;
+ snd_config_t *n = snd_config_iterator_entry( i ), * tp = NULL;;
+ if( (err = snd_config_search( n, "type", &tp )) < 0 )
+ {
+ if( -ENOENT != err )
+ {
+ ENSURE_(err, paUnanticipatedHostError);
+ }
+ }
+ else
+ {
+ ENSURE_( snd_config_get_string( tp, &tpStr ), paUnanticipatedHostError );
+ }
ENSURE_( snd_config_get_id( n, &idStr ), paUnanticipatedHostError );
if( IgnorePlugin( idStr ) )
{
PA_DEBUG(( "%s: Ignoring ALSA plugin device %s of type %s\n", __FUNCTION__, idStr, tpStr ));
continue;
}
-
PA_DEBUG(( "%s: Found plugin %s of type %s\n", __FUNCTION__, idStr, tpStr ));
PA_UNLESS( alsaDeviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
@@ -894,7 +1002,7 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
PA_DEBUG(( "%s: Iterating over ALSA plugins failed: %s\n", __FUNCTION__, snd_strerror( res ) ));
/* allocate deviceInfo memory based on the number of devices */
- PA_UNLESS( commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ PA_UNLESS( baseApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
alsaApi->allocations, sizeof(PaDeviceInfo*) * (numDeviceNames) ), paInsufficientMemory );
/* allocate all device info structs in a contiguous block */
@@ -909,10 +1017,11 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
{
snd_pcm_t *pcm;
PaAlsaDeviceInfo *deviceInfo = &deviceInfoArray[devIdx];
- PaDeviceInfo *commonDeviceInfo = &deviceInfo->commonDeviceInfo;
+ PaDeviceInfo *baseDeviceInfo = &deviceInfo->baseDeviceInfo;
+ int canMmap = -1;
/* Zero fields */
- InitializeDeviceInfo( commonDeviceInfo );
+ InitializeDeviceInfo( baseDeviceInfo );
/* to determine device capabilities, we must open the device and query the
* hardware parameter configuration space */
@@ -921,50 +1030,63 @@ static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
if( deviceNames[i].hasCapture &&
snd_pcm_open( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_CAPTURE, blocking ) >= 0 )
{
- if( GropeDevice( pcm, &deviceInfo->minInputChannels, &commonDeviceInfo->maxInputChannels,
- &commonDeviceInfo->defaultLowInputLatency, &commonDeviceInfo->defaultHighInputLatency,
- &commonDeviceInfo->defaultSampleRate, deviceNames[i].isPlug ) != paNoError )
- continue; /* Error */
+ if( GropeDevice( pcm, deviceNames[i].isPlug, StreamDirection_In, blocking, deviceInfo,
+ &canMmap ) != paNoError )
+ {
+ /* Error */
+ PA_DEBUG(("%s: Failed groping %s for capture\n", __FUNCTION__, deviceNames[i].alsaName));
+ continue;
+ }
}
/* Query playback */
if( deviceNames[i].hasPlayback &&
snd_pcm_open( &pcm, deviceNames[i].alsaName, SND_PCM_STREAM_PLAYBACK, blocking ) >= 0 )
{
- if( GropeDevice( pcm, &deviceInfo->minOutputChannels, &commonDeviceInfo->maxOutputChannels,
- &commonDeviceInfo->defaultLowOutputLatency, &commonDeviceInfo->defaultHighOutputLatency,
- &commonDeviceInfo->defaultSampleRate, deviceNames[i].isPlug ) != paNoError )
- continue; /* Error */
+ if( GropeDevice( pcm, deviceNames[i].isPlug, StreamDirection_Out, blocking, deviceInfo,
+ &canMmap ) != paNoError )
+ {
+ /* Error */
+ PA_DEBUG(("%s: Failed groping %s for playback\n", __FUNCTION__, deviceNames[i].alsaName));
+ continue;
+ }
+ }
+
+ if( 0 == canMmap )
+ {
+ PA_DEBUG(("%s: Device %s doesn't support mmap\n", __FUNCTION__, deviceNames[i].alsaName));
+ continue;
}
- commonDeviceInfo->structVersion = 2;
- commonDeviceInfo->hostApi = alsaApi->hostApiIndex;
- commonDeviceInfo->name = deviceNames[i].name;
+ baseDeviceInfo->structVersion = 2;
+ baseDeviceInfo->hostApi = alsaApi->hostApiIndex;
+ baseDeviceInfo->name = deviceNames[i].name;
deviceInfo->alsaName = deviceNames[i].alsaName;
deviceInfo->isPlug = deviceNames[i].isPlug;
/* A: Storing pointer to PaAlsaDeviceInfo object as pointer to PaDeviceInfo object.
* Should now be safe to add device info, unless the device supports neither capture nor playback
*/
- if( commonDeviceInfo->maxInputChannels > 0 || commonDeviceInfo->maxOutputChannels > 0 )
+ if( baseDeviceInfo->maxInputChannels > 0 || baseDeviceInfo->maxOutputChannels > 0 )
{
- if( commonApi->info.defaultInputDevice == paNoDevice && commonDeviceInfo->maxInputChannels > 0 )
- commonApi->info.defaultInputDevice = devIdx;
- if( commonApi->info.defaultOutputDevice == paNoDevice && commonDeviceInfo->maxOutputChannels > 0 )
- commonApi->info.defaultOutputDevice = devIdx;
-
- commonApi->deviceInfos[devIdx++] = (PaDeviceInfo *) deviceInfo;
+ if( baseApi->info.defaultInputDevice == paNoDevice && baseDeviceInfo->maxInputChannels > 0 )
+ baseApi->info.defaultInputDevice = devIdx;
+ if( baseApi->info.defaultOutputDevice == paNoDevice && baseDeviceInfo->maxOutputChannels > 0 )
+ baseApi->info.defaultOutputDevice = devIdx;
+ PA_DEBUG(("%s: Adding device %s\n", __FUNCTION__, deviceNames[i].name));
+ baseApi->deviceInfos[devIdx++] = (PaDeviceInfo *) deviceInfo;
}
}
free( deviceNames );
- commonApi->info.deviceCount = devIdx; /* Number of successfully queried devices */
+ baseApi->info.deviceCount = devIdx; /* Number of successfully queried devices */
end:
return result;
error:
- goto end; /* No particular action */
+ /* No particular action */
+ goto end;
}
/* Check against known device capabilities */
@@ -988,14 +1110,16 @@ static PaError ValidateParameters( const PaStreamParameters *parameters, PaUtilH
PA_UNLESS( parameters->device == paUseHostApiSpecificDeviceSpecification, paInvalidDevice );
PA_UNLESS( streamInfo->size == sizeof (PaAlsaStreamInfo) && streamInfo->version == 1,
paIncompatibleHostApiSpecificStreamInfo );
+ PA_UNLESS( streamInfo->deviceString != NULL, paInvalidDevice );
- return paNoError; /* Skip further checking */
+ /* Skip further checking */
+ return paNoError;
}
assert( deviceInfo );
assert( parameters->hostApiSpecificStreamInfo == NULL );
- maxChans = (StreamDirection_In == mode ? deviceInfo->commonDeviceInfo.maxInputChannels :
- deviceInfo->commonDeviceInfo.maxOutputChannels);
+ maxChans = (StreamDirection_In == mode ? deviceInfo->baseDeviceInfo.maxInputChannels :
+ deviceInfo->baseDeviceInfo.maxOutputChannels);
PA_UNLESS( parameters->channelCount <= maxChans, paInvalidChannelCount );
error:
@@ -1003,7 +1127,6 @@ error:
}
/* Given an open stream, what sample formats are available? */
-
static PaSampleFormat GetAvailableFormats( snd_pcm_t *pcm )
{
PaSampleFormat available = 0;
@@ -1091,10 +1214,12 @@ static PaError AlsaOpen( const PaUtilHostApiRepresentation *hostApi, const PaStr
else
deviceName = streamInfo->deviceString;
+ PA_DEBUG(( "%s: Opening device %s\n", __FUNCTION__, deviceName ));
if( (ret = snd_pcm_open( pcm, deviceName, streamDir == StreamDirection_In ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK )) < 0 )
{
- *pcm = NULL; /* Not to be closed */
+ /* Not to be closed */
+ *pcm = NULL;
ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable : paBadIODeviceCombination );
}
ENSURE_( snd_pcm_nonblock( *pcm, 0 ), paUnanticipatedHostError );
@@ -1148,11 +1273,20 @@ static PaError TestParameters( const PaUtilHostApiRepresentation *hostApi, const
PA_ENSURE( hostFormat = PaUtil_SelectClosestAvailableFormat( availableFormats, parameters->sampleFormat ) );
ENSURE_( snd_pcm_hw_params_set_format( pcm, hwParams, Pa2AlsaFormat( hostFormat ) ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );
+ {
+ /* It happens that this call fails because the device is busy */
+ int ret = 0;
+ if( (ret = snd_pcm_hw_params( pcm, hwParams )) < 0)
+ {
+ ENSURE_( ret, ret == -EBUSY ? paDeviceUnavailable : paUnanticipatedHostError );
+ }
+ }
end:
if( pcm )
+ {
snd_pcm_close( pcm );
+ }
return result;
error:
@@ -1215,7 +1349,7 @@ static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, Pa
if( NULL == params->hostApiSpecificStreamInfo )
{
- const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->commonHostApiRep, params->device );
+ const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( &alsaApi->baseHostApiRep, params->device );
self->numHostChannels = PA_MAX( params->channelCount, StreamDirection_In == streamDir ? devInfo->minInputChannels
: devInfo->minOutputChannels );
}
@@ -1225,7 +1359,7 @@ static PaError PaAlsaStreamComponent_Initialize( PaAlsaStreamComponent *self, Pa
self->numHostChannels = params->channelCount;
}
- PA_ENSURE( AlsaOpen( &alsaApi->commonHostApiRep, params, streamDir, &self->pcm ) );
+ PA_ENSURE( AlsaOpen( &alsaApi->baseHostApiRep, params, streamDir, &self->pcm ) );
self->nfds = snd_pcm_poll_descriptors_count( self->pcm );
hostSampleFormat = PaUtil_SelectClosestAvailableFormat( GetAvailableFormats( self->pcm ), userSampleFormat );
@@ -1253,25 +1387,18 @@ static void PaAlsaStreamComponent_Terminate( PaAlsaStreamComponent *self )
PaUtil_FreeMemory( self->userBuffers );
}
-/** Configure the associated ALSA pcm.
+int nearbyint_(float value) {
+ if( value - (int)value > .5 )
+ return (int)ceil( value );
+ return (int)floor( value );
+}
+
+/** Initiate configuration, preparing for determining a period size suitable for both capture and playback components.
*
*/
-static PaError PaAlsaStreamComponent_Configure( PaAlsaStreamComponent *self, const PaStreamParameters *params, unsigned long
- framesPerHostBuffer, int primeBuffers, int callbackMode, double *sampleRate, PaTime *returnedLatency )
+static PaError PaAlsaStreamComponent_InitialConfigure( PaAlsaStreamComponent *self, const PaStreamParameters *params,
+ int primeBuffers, snd_pcm_hw_params_t *hwParams, double *sampleRate )
{
- /*
- int numPeriods;
-
- if( getenv("PA_NUMPERIODS") != NULL )
- numPeriods = atoi( getenv("PA_NUMPERIODS") );
- else
- numPeriods = ( (latency * sampleRate) / *framesPerBuffer ) + 1;
-
- PA_DEBUG(( "latency: %f, rate: %f, framesPerBuffer: %d\n", latency, sampleRate, *framesPerBuffer ));
- if( numPeriods <= 1 )
- numPeriods = 2;
- */
-
/* Configuration consists of setting all of ALSA's parameters.
* These parameters come in two flavors: hardware parameters
* and software paramters. Hardware parameters will affect
@@ -1279,28 +1406,23 @@ static PaError PaAlsaStreamComponent_Configure( PaAlsaStreamComponent *self, con
* affect the way ALSA interacts with me, the user-level client.
*/
- snd_pcm_hw_params_t *hwParams;
- snd_pcm_sw_params_t *swParams;
PaError result = paNoError;
snd_pcm_access_t accessMode, alternateAccessMode;
- unsigned int numPeriods, minPeriods = 2;
int dir = 0;
snd_pcm_t *pcm = self->pcm;
- PaTime latency = params->suggestedLatency;
double sr = *sampleRate;
- *returnedLatency = -1.;
+ unsigned int minPeriods = 2;
- snd_pcm_hw_params_alloca( &hwParams );
- snd_pcm_sw_params_alloca( &swParams );
-
- self->framesPerBuffer = framesPerHostBuffer;
+ /* self->framesPerBuffer = framesPerHostBuffer; */
/* ... fill up the configuration space with all possibile
* combinations of parameters this device will accept */
ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );
+ /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError );
if( self->userInterleaved )
{
@@ -1312,11 +1434,23 @@ static PaError PaAlsaStreamComponent_Configure( PaAlsaStreamComponent *self, con
accessMode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
alternateAccessMode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
}
-
/* If requested access mode fails, try alternate mode */
if( snd_pcm_hw_params_set_access( pcm, hwParams, accessMode ) < 0 )
{
- ENSURE_( snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode ), paUnanticipatedHostError );
+ int err = 0;
+ if( (err = snd_pcm_hw_params_set_access( pcm, hwParams, alternateAccessMode )) < 0)
+ {
+ result = paUnanticipatedHostError;
+ if( -EINVAL == err )
+ {
+ PaUtil_SetLastHostErrorInfo( paALSA, err, "PA ALSA requires that a device supports mmap access" );
+ }
+ else
+ {
+ PaUtil_SetLastHostErrorInfo( paALSA, err, snd_strerror( err ) );
+ }
+ goto error;
+ }
/* Flip mode */
self->hostInterleaved = !self->userInterleaved;
}
@@ -1334,56 +1468,64 @@ static PaError PaAlsaStreamComponent_Configure( PaAlsaStreamComponent *self, con
ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, self->numHostChannels ), paInvalidChannelCount );
- /* I think there should be at least 2 periods (even though ALSA doesn't appear to enforce this) */
- dir = 0;
- ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParams, &minPeriods, &dir ), paUnanticipatedHostError );
- dir = 0;
- ENSURE_( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &self->framesPerBuffer, &dir ), paUnanticipatedHostError );
-
- /* Find an acceptable number of periods */
- numPeriods = (latency * sr) / self->framesPerBuffer + 1;
- dir = 0;
- ENSURE_( snd_pcm_hw_params_set_periods_near( pcm, hwParams, &numPeriods, &dir ), paUnanticipatedHostError );
- /* Minimum of periods should already be 2 */
- PA_UNLESS( numPeriods >= 2, paInternalError );
+ *sampleRate = sr;
+
+end:
+ return result;
+
+error:
+ /* No particular action */
+ goto end;
+}
+
+/** Finish the configuration of the component's ALSA device.
+ *
+ * As part of this method, the component's bufferSize attribute will be set.
+ * @param latency: The latency for this component.
+ */
+static PaError PaAlsaStreamComponent_FinishConfigure( PaAlsaStreamComponent *self, snd_pcm_hw_params_t* hwParams,
+ const PaStreamParameters *params, int primeBuffers, double sampleRate, PaTime* latency )
+{
+ PaError result = paNoError;
+ snd_pcm_sw_params_t* swParams;
+ snd_pcm_uframes_t bufSz = 0;
+ *latency = -1.;
+
+ snd_pcm_sw_params_alloca( &swParams );
+
+ bufSz = (params->suggestedLatency * sampleRate) + self->framesPerBuffer; /* One period does not count as latency */
+ ENSURE_( snd_pcm_hw_params_set_buffer_size_near( self->pcm, hwParams, &bufSz ), paUnanticipatedHostError );
/* Set the parameters! */
- ENSURE_( snd_pcm_hw_params( pcm, hwParams ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_hw_params( self->pcm, hwParams ), paUnanticipatedHostError );
ENSURE_( snd_pcm_hw_params_get_buffer_size( hwParams, &self->bufferSize ), paUnanticipatedHostError );
-
/* Latency in seconds, one period is not counted as latency */
- latency = (numPeriods - 1) * self->framesPerBuffer / sr;
+ *latency = (self->bufferSize - self->framesPerBuffer) / sampleRate;
/* Now software parameters... */
- ENSURE_( snd_pcm_sw_params_current( pcm, swParams ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_sw_params_current( self->pcm, swParams ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_start_threshold( pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_stop_threshold( pcm, swParams, self->bufferSize ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_sw_params_set_start_threshold( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_sw_params_set_stop_threshold( self->pcm, swParams, self->bufferSize ), paUnanticipatedHostError );
/* Silence buffer in the case of underrun */
if( !primeBuffers ) /* XXX: Make sense? */
{
snd_pcm_uframes_t boundary;
ENSURE_( snd_pcm_sw_params_get_boundary( swParams, &boundary ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_silence_threshold( pcm, swParams, 0 ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_silence_size( pcm, swParams, boundary ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_sw_params_set_silence_threshold( self->pcm, swParams, 0 ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_sw_params_set_silence_size( self->pcm, swParams, boundary ), paUnanticipatedHostError );
}
- ENSURE_( snd_pcm_sw_params_set_avail_min( pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_xfer_align( pcm, swParams, 1 ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_sw_params_set_tstamp_mode( pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_sw_params_set_avail_min( self->pcm, swParams, self->framesPerBuffer ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_sw_params_set_xfer_align( self->pcm, swParams, 1 ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_sw_params_set_tstamp_mode( self->pcm, swParams, SND_PCM_TSTAMP_MMAP ), paUnanticipatedHostError );
/* Set the parameters! */
- ENSURE_( snd_pcm_sw_params( pcm, swParams ), paUnanticipatedHostError );
-
- *sampleRate = sr;
- *returnedLatency = latency;
-
-end:
- return result;
+ ENSURE_( snd_pcm_sw_params( self->pcm, swParams ), paUnanticipatedHostError );
error:
- goto end; /* No particular action */
+ return result;
}
static PaError PaAlsaStream_Initialize( PaAlsaStream *self, PaAlsaHostApiRepresentation *alsaApi, const PaStreamParameters *inParams,
@@ -1475,78 +1617,171 @@ static int CalculatePollTimeout( const PaAlsaStream *stream, unsigned long frame
return (int)ceil( 1000 * frames / stream->streamRepresentation.streamInfo.sampleRate );
}
-/** Set up ALSA stream parameters.
+/** Determine size per host buffer.
*
+ * During this method call, the component's framesPerBuffer attribute gets computed, and the corresponding period size
+ * gets configured for the device.
+ * @param accurate: If the configured period size is non-integer, this will be set to 0.
*/
-static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters
- *outParams, double sampleRate, unsigned long framesPerHostBuffer, double *inputLatency, double *outputLatency,
- unsigned long *maxHostBufferSize )
+static PaError PaAlsaStreamComponent_DetermineFramesPerBuffer( PaAlsaStreamComponent* self, const PaStreamParameters* params,
+ unsigned long framesPerUserBuffer, double sampleRate, snd_pcm_hw_params_t* hwParams, int* accurate )
{
PaError result = paNoError;
- double realSr = sampleRate;
-
- if( self->capture.pcm )
- PA_ENSURE( PaAlsaStreamComponent_Configure( &self->capture, inParams, framesPerHostBuffer, self->primeBuffers,
- self->callbackMode, &realSr, inputLatency ) );
- if( self->playback.pcm )
- PA_ENSURE( PaAlsaStreamComponent_Configure( &self->playback, outParams, framesPerHostBuffer, self->primeBuffers,
- self->callbackMode, &realSr, outputLatency ) );
+ unsigned long bufferSize = params->suggestedLatency * sampleRate, framesPerHostBuffer;
+ int dir = 0;
+
+ {
+ snd_pcm_uframes_t tmp;
+ snd_pcm_hw_params_get_buffer_size_min( hwParams, &tmp );
+ bufferSize = PA_MAX( bufferSize, tmp );
+ snd_pcm_hw_params_get_buffer_size_max( hwParams, &tmp );
+ bufferSize = PA_MIN( bufferSize, tmp );
+ }
- /* Should be exact now */
- self->streamRepresentation.streamInfo.sampleRate = realSr;
+ assert( bufferSize > 0 );
- /* this will cause the two streams to automatically start/stop/prepare in sync.
- * We only need to execute these operations on one of the pair.
- * A: We don't want to do this on a blocking stream.
- */
- if( self->callbackMode && self->capture.pcm && self->playback.pcm )
+ if( framesPerUserBuffer != paFramesPerBufferUnspecified )
{
- int err = snd_pcm_link( self->capture.pcm, self->playback.pcm );
- if( err >= 0 )
- self->pcmsSynced = 1;
- else
- PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, snd_strerror( err ) ));
- }
+ /* Preferably the host buffer size should be a multiple of the user buffer size */
- /* Frames per host buffer for the stream is set as a compromise between the two directions */
- framesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerBuffer : ULONG_MAX,
- self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX );
- self->pollTimeout = CalculatePollTimeout( self, framesPerHostBuffer ); /* Period in msecs, rounded up */
+ if( bufferSize > framesPerUserBuffer )
+ {
+ snd_pcm_uframes_t remainder = bufferSize % framesPerUserBuffer;
+ if( remainder > framesPerUserBuffer / 2. )
+ bufferSize += framesPerUserBuffer - remainder;
+ else
+ bufferSize -= remainder;
- *maxHostBufferSize = PA_MAX( self->capture.pcm ? self->capture.bufferSize : 0,
- self->playback.pcm ? self->playback.bufferSize : 0 );
+ assert( bufferSize % framesPerUserBuffer == 0 );
+ }
+ else if( framesPerUserBuffer % bufferSize != 0 )
+ {
+ /* Find a good compromise between user specified latency and buffer size */
+ if( bufferSize > framesPerUserBuffer * .75 )
+ {
+ bufferSize = framesPerUserBuffer;
+ }
+ else
+ {
+ snd_pcm_uframes_t newSz = framesPerUserBuffer;
+ while( newSz / 2 >= bufferSize )
+ {
+ if( framesPerUserBuffer % (newSz / 2) != 0 )
+ {
+ /* No use dividing any further */
+ break;
+ }
+ newSz /= 2;
+ }
+ bufferSize = newSz;
+ }
- /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */
- self->threading.throttledSleepTime = (unsigned long) (framesPerHostBuffer / sampleRate / 4 * 1000);
+ assert( framesPerUserBuffer % bufferSize == 0 );
+ }
+ }
- if( self->callbackMode )
+ /* Using 5 as a base number of periods, we try to approximate the suggested latency (+1 period),
+ finding a combination of period/buffer size which best fits these constraints */
{
- /* If the user expects a certain number of frames per callback we will either have to rely on block adaption
- * (framesPerHostBuffer is not an integer multiple of framesPerBuffer) or we can simply align the number
- * of host buffer frames with what the user specified */
- if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )
+ unsigned numPeriods = 4, maxPeriods = 0;
+ /* It may be that the device only supports 2 periods for instance */
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_get_periods_max( hwParams, &maxPeriods, &dir ), paUnanticipatedHostError );
+ assert( maxPeriods > 1 );
+ /* One period is not counted as latency */
+ maxPeriods -= 1;
+ numPeriods = PA_MIN( maxPeriods, numPeriods );
+
+ if( framesPerUserBuffer != paFramesPerBufferUnspecified )
{
- /* self->alignFrames = 1; */
+ framesPerHostBuffer = framesPerUserBuffer;
+ if( framesPerHostBuffer < bufferSize )
+ {
+ while( bufferSize / framesPerHostBuffer > numPeriods )
+ {
+ framesPerHostBuffer *= 2;
+ }
+ }
+ else
+ {
+ while( bufferSize / framesPerHostBuffer < numPeriods )
+ {
+ if( framesPerUserBuffer % (framesPerHostBuffer / 2) != 0 )
+ {
+ /* Can't be divided any further */
+ break;
+ }
+ framesPerHostBuffer /= 2;
+ }
+ }
- /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely
- * on block adaption */
- /*
- if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm &&
- self->capture.framesPerBuffer != self->playback.framesPerBuffer) )
- self->useBlockAdaption = 1;
+ if( framesPerHostBuffer < framesPerUserBuffer )
+ {
+ assert( framesPerUserBuffer % framesPerHostBuffer == 0 );
+ if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
+ {
+ if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer * 2, 0 ) == 0 )
+ framesPerHostBuffer *= 2;
+ else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer / 2, 0 ) == 0 )
+ framesPerHostBuffer /= 2;
+ }
+ }
else
- self->alignFrames = 1;
- */
+ {
+ assert( framesPerHostBuffer % framesPerUserBuffer == 0 );
+ if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer, 0 ) < 0 )
+ {
+ if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer + framesPerUserBuffer, 0 ) == 0 )
+ framesPerHostBuffer += framesPerUserBuffer;
+ else if( snd_pcm_hw_params_test_period_size( self->pcm, hwParams, framesPerHostBuffer - framesPerUserBuffer, 0 ) == 0 )
+ framesPerHostBuffer -= framesPerUserBuffer;
+ }
+ }
+ }
+ else
+ {
+ framesPerHostBuffer = bufferSize / numPeriods;
+ }
+ }
+
+ assert( framesPerHostBuffer > 0 );
+ {
+ snd_pcm_uframes_t min = 0, max = 0;
+ ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParams, &min, NULL ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParams, &max, NULL ), paUnanticipatedHostError );
+
+ if( framesPerHostBuffer < min )
+ {
+ framesPerHostBuffer = min;
+ PA_DEBUG(( "%s: The determined period size (%lu) is less than minimum (%lu)\n", __FUNCTION__,
+ framesPerHostBuffer, min ));
+ }
+ else if( framesPerHostBuffer > max )
+ {
+ framesPerHostBuffer = max;
+ PA_DEBUG(( "%s: The determined period size (%lu) is greater than maximum (%lu)\n", __FUNCTION__,
+ framesPerHostBuffer, max ));
+ }
+
+ assert( framesPerHostBuffer >= min && framesPerHostBuffer <= max );
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_set_period_size_near( self->pcm, hwParams, &framesPerHostBuffer, &dir ),
+ paUnanticipatedHostError );
+ if( dir != 0 )
+ {
+ PA_DEBUG(( "%s: The configured period size is non-integer.\n", __FUNCTION__, dir ));
+ *accurate = 0;
}
}
+ self->framesPerBuffer = framesPerHostBuffer;
error:
return result;
}
-/* We need to determine how many frames per host buffer to use. Our
+/* We need to determine how many frames per host buffer (period) to use. Our
* goals are to provide the best possible performance, but also to
- * most closely honor the requested latency settings. Therefore this
+ * honor the requested latency settings as closely as we can. Therefore this
* decision is based on:
*
* - the period sizes that playback and/or capture support. The
@@ -1556,6 +1791,18 @@ error:
* We want to make period_size*(num_periods-1) to be as close as possible
* to latency*rate for both playback and capture.
*
+ * This method will determine suitable period sizes for capture and playback handles, and report the maximum number of
+ * frames per host buffer. The latter is relevant, in case we should be so unfortunate that the period size differs
+ * between capture and playback. If this should happen, the stream's hostBufferSizeMode attribute will be set to
+ * paUtilBoundedHostBufferSize, because the best we can do is limit the size of individual host buffers to the upper
+ * bound. The size of host buffers scheduled for processing should only matter if the user has specified a buffer size,
+ * but when he/she does we must strive for an optimal configuration. By default we'll opt for a fixed host buffer size,
+ * which should be fine if the period size is the same for capture and playback. In general, if there is a specified user
+ * buffer size, this method tries it best to determine a period size which is a multiple of the user buffer size.
+ *
+ * The framesPerBuffer attributes of the individual capture and playback components of the stream are set to corresponding
+ * values determined here. Since these should be reported as
+ *
* This is one of those blocks of code that will just take a lot of
* refinement to be any good.
*
@@ -1563,175 +1810,273 @@ error:
* to find a number of frames per buffer acceptable to both devices
* TODO: Implement an algorithm to find the value closest to acceptance
* by both devices, to minimize difference between period sizes?
+ *
+ * @param determinedFramesPerHostBuffer: The determined host buffer size.
*/
-static PaError DetermineFramesPerBuffer( const PaAlsaStream *stream, double sampleRate, const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters, unsigned long *determinedFrames, const PaUtilHostApiRepresentation *hostApi )
+static PaError PaAlsaStream_DetermineFramesPerBuffer( PaAlsaStream* self, double sampleRate, const PaStreamParameters* inputParameters,
+ const PaStreamParameters* outputParameters, unsigned long framesPerUserBuffer, snd_pcm_hw_params_t* hwParamsCapture,
+ snd_pcm_hw_params_t* hwParamsPlayback, PaUtilHostBufferSizeMode* hostBufferSizeMode )
{
PaError result = paNoError;
- unsigned long framesPerBuffer = 0;
- int numHostInputChannels = 0, numHostOutputChannels = 0;
-
- /* XXX: Clean this up */
- if( stream->capture.pcm )
- {
- const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, inputParameters->device );
- numHostInputChannels = PA_MAX( inputParameters->channelCount, devInfo->minInputChannels );
- }
- if( stream->playback.pcm )
- {
- const PaAlsaDeviceInfo *devInfo = GetDeviceInfo( hostApi, outputParameters->device );
- numHostOutputChannels = PA_MAX( outputParameters->channelCount, devInfo->minOutputChannels );
- }
+ unsigned long framesPerHostBuffer = 0;
+ int dir = 0;
+ int accurate = 1;
- if( stream->capture.pcm && stream->playback.pcm )
+ if( self->capture.pcm && self->playback.pcm )
{
- snd_pcm_uframes_t desiredLatency, e;
- snd_pcm_uframes_t minPeriodSize, minPlayback, minCapture, maxPeriodSize, maxPlayback, maxCapture,
- optimalPeriodSize, periodSize;
- int dir = 0;
- unsigned int minPeriods = 2;
+ if( framesPerUserBuffer == paFramesPerBufferUnspecified )
+ {
+ snd_pcm_uframes_t desiredLatency, e, minPeriodSize, maxPeriodSize, optimalPeriodSize, periodSize,
+ minCapture, minPlayback, maxCapture, maxPlayback;
+
+ /* Come up with a common desired latency */
+
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );
+ minPeriodSize = PA_MAX( minPlayback, minCapture );
+ maxPeriodSize = PA_MIN( maxPlayback, maxCapture );
+ PA_UNLESS( minPeriodSize <= maxPeriodSize, paBadIODeviceCombination );
+
+ desiredLatency = (snd_pcm_uframes_t)(PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )
+ * sampleRate);
+ /* Clamp desiredLatency */
+ {
+ snd_pcm_uframes_t maxBufferSize;
+ snd_pcm_uframes_t maxBufferSizeCapture, maxBufferSizePlayback;
+ ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &maxBufferSizeCapture ), paUnanticipatedHostError );
+ ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSizePlayback ), paUnanticipatedHostError );
+ maxBufferSize = PA_MIN( maxBufferSizeCapture, maxBufferSizePlayback );
- snd_pcm_t *pcm;
- snd_pcm_hw_params_t *hwParamsPlayback, *hwParamsCapture;
+ desiredLatency = PA_MIN( desiredLatency, maxBufferSize );
+ }
- snd_pcm_hw_params_alloca( &hwParamsPlayback );
- snd_pcm_hw_params_alloca( &hwParamsCapture );
+ /* Find the closest power of 2 */
+ e = ilogb( minPeriodSize );
+ if( minPeriodSize & (minPeriodSize - 1) )
+ e += 1;
+ periodSize = (snd_pcm_uframes_t)pow( 2, e );
- /* Come up with a common desired latency */
- pcm = stream->playback.pcm;
- snd_pcm_hw_params_any( pcm, hwParamsPlayback );
- ENSURE_( SetApproximateSampleRate( pcm, hwParamsPlayback, sampleRate ), paInvalidSampleRate );
- ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParamsPlayback, numHostOutputChannels ),
- paBadIODeviceCombination );
+ while( periodSize <= maxPeriodSize )
+ {
+ if( snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&
+ snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 )
+ break; /* Ok! */
- ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParamsPlayback ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParamsPlayback ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParamsPlayback, &minPeriods, &dir ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsPlayback, &minPlayback, &dir ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsPlayback, &maxPlayback, &dir ), paUnanticipatedHostError );
+ periodSize *= 2;
+ }
- pcm = stream->capture.pcm;
- ENSURE_( snd_pcm_hw_params_any( pcm, hwParamsCapture ), paUnanticipatedHostError );
- ENSURE_( SetApproximateSampleRate( pcm, hwParamsCapture, sampleRate ), paBadIODeviceCombination );
- ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParamsCapture, numHostInputChannels ),
- paBadIODeviceCombination );
+ /* 4 periods considered optimal */
+ optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );
+ optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
- ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParamsCapture ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParamsCapture ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_periods_min( pcm, hwParamsCapture, &minPeriods, &dir ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_period_size_min( hwParamsCapture, &minCapture, &dir ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_period_size_max( hwParamsCapture, &maxCapture, &dir ), paUnanticipatedHostError );
+ /* Find the closest power of 2 */
+ e = ilogb( optimalPeriodSize );
+ if( optimalPeriodSize & (optimalPeriodSize - 1) )
+ e += 1;
+ optimalPeriodSize = (snd_pcm_uframes_t)pow( 2, e );
- minPeriodSize = PA_MAX( minPlayback, minCapture );
- maxPeriodSize = PA_MIN( maxPlayback, maxCapture );
+ while( optimalPeriodSize >= periodSize )
+ {
+ if( snd_pcm_hw_params_test_period_size( self->capture.pcm, hwParamsCapture, optimalPeriodSize, 0 ) < 0 )
+ continue;
+ if( snd_pcm_hw_params_test_period_size( self->playback.pcm, hwParamsPlayback, optimalPeriodSize, 0 ) >= 0 )
+ break;
+ optimalPeriodSize /= 2;
+ }
+ if( optimalPeriodSize > periodSize )
+ periodSize = optimalPeriodSize;
- desiredLatency = (snd_pcm_uframes_t) (PA_MIN( outputParameters->suggestedLatency, inputParameters->suggestedLatency )
- * sampleRate);
- /* Clamp desiredLatency */
+ if( periodSize <= maxPeriodSize )
+ {
+ /* Looks good, the periodSize _should_ be acceptable by both devices */
+ ENSURE_( snd_pcm_hw_params_set_period_size( self->capture.pcm, hwParamsCapture, periodSize, 0 ),
+ paUnanticipatedHostError );
+ ENSURE_( snd_pcm_hw_params_set_period_size( self->playback.pcm, hwParamsPlayback, periodSize, 0 ),
+ paUnanticipatedHostError );
+ self->capture.framesPerBuffer = self->playback.framesPerBuffer = periodSize;
+ framesPerHostBuffer = periodSize;
+ }
+ else
+ {
+ /* Unable to find a common period size, oh well */
+ optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );
+ optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
+
+ self->capture.framesPerBuffer = optimalPeriodSize;
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_set_period_size_near( self->capture.pcm, hwParamsCapture, &self->capture.framesPerBuffer, &dir ),
+ paUnanticipatedHostError );
+ self->playback.framesPerBuffer = optimalPeriodSize;
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_set_period_size_near( self->playback.pcm, hwParamsPlayback, &self->playback.framesPerBuffer, &dir ),
+ paUnanticipatedHostError );
+ framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer );
+ *hostBufferSizeMode = paUtilBoundedHostBufferSize;
+ }
+ }
+ else
{
- snd_pcm_uframes_t tmp, maxBufferSize = ULONG_MAX;
- ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsPlayback, &maxBufferSize ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_get_buffer_size_max( hwParamsCapture, &tmp ), paUnanticipatedHostError );
- maxBufferSize = PA_MIN( maxBufferSize, tmp );
+ /* We choose the simple route and determine a suitable number of frames per buffer for one component of
+ * the stream, then we hope that this will work for the other component too (it should!).
+ */
- desiredLatency = PA_MIN( desiredLatency, maxBufferSize );
- }
+ unsigned maxPeriods = 0;
+ PaAlsaStreamComponent* first = &self->capture, * second = &self->playback;
+ const PaStreamParameters* firstStreamParams = inputParameters;
+ snd_pcm_hw_params_t* firstHwParams = hwParamsCapture, * secondHwParams = hwParamsPlayback;
- /* Find the closest power of 2 */
- e = ilogb( minPeriodSize );
- if( minPeriodSize & (minPeriodSize - 1) )
- e += 1;
- periodSize = (snd_pcm_uframes_t) pow( 2, e );
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_get_periods_max( hwParamsPlayback, &maxPeriods, &dir ), paUnanticipatedHostError );
+ if( maxPeriods < 4 )
+ {
+ /* The playback component is trickier to get right, try that first */
+ first = &self->playback;
+ second = &self->capture;
+ firstStreamParams = outputParameters;
+ firstHwParams = hwParamsPlayback;
+ secondHwParams = hwParamsCapture;
+ }
- while( periodSize <= maxPeriodSize )
- {
- if( snd_pcm_hw_params_test_period_size( stream->playback.pcm, hwParamsPlayback, periodSize, 0 ) >= 0 &&
- snd_pcm_hw_params_test_period_size( stream->capture.pcm, hwParamsCapture, periodSize, 0 ) >= 0 )
- break; /* Ok! */
+ PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( first, firstStreamParams, framesPerUserBuffer,
+ sampleRate, firstHwParams, &accurate ) );
- periodSize *= 2;
+ second->framesPerBuffer = first->framesPerBuffer;
+ dir = 0;
+ ENSURE_( snd_pcm_hw_params_set_period_size_near( second->pcm, secondHwParams, &second->framesPerBuffer, &dir ),
+ paUnanticipatedHostError );
+ if( self->capture.framesPerBuffer == self->playback.framesPerBuffer )
+ {
+ framesPerHostBuffer = self->capture.framesPerBuffer;
+ }
+ else
+ {
+ framesPerHostBuffer = PA_MAX( self->capture.framesPerBuffer, self->playback.framesPerBuffer );
+ *hostBufferSizeMode = paUtilBoundedHostBufferSize;
+ }
+ }
+ }
+ else /* half-duplex is a slightly simpler case */
+ {
+ if( self->capture.pcm )
+ {
+ PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->capture, inputParameters, framesPerUserBuffer,
+ sampleRate, hwParamsCapture, &accurate) );
+ framesPerHostBuffer = self->capture.framesPerBuffer;
+ }
+ else
+ {
+ assert( self->playback.pcm );
+ PA_ENSURE( PaAlsaStreamComponent_DetermineFramesPerBuffer( &self->playback, outputParameters, framesPerUserBuffer,
+ sampleRate, hwParamsPlayback, &accurate ) );
+ framesPerHostBuffer = self->playback.framesPerBuffer;
}
+ }
- /* 4 periods considered optimal */
- optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );
- optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
+ PA_UNLESS( framesPerHostBuffer != 0, paInternalError );
+ self->maxFramesPerHostBuffer = framesPerHostBuffer;
- /* Find the closest power of 2 */
- e = ilogb( optimalPeriodSize );
- if( optimalPeriodSize & (optimalPeriodSize - 1) )
- e += 1;
- optimalPeriodSize = (snd_pcm_uframes_t) pow( 2, e );
+ if( !accurate )
+ {
+ /* Don't know the exact size per host buffer */
+ *hostBufferSizeMode = paUtilBoundedHostBufferSize;
+ /* Raise upper bound */
+ ++self->maxFramesPerHostBuffer;
+ }
- while( optimalPeriodSize >= periodSize )
- {
- pcm = stream->playback.pcm;
- if( snd_pcm_hw_params_test_period_size( pcm, hwParamsPlayback, optimalPeriodSize, 0 ) < 0 )
- continue;
+error:
+ return result;
+}
- pcm = stream->capture.pcm;
- if( snd_pcm_hw_params_test_period_size( pcm, hwParamsCapture, optimalPeriodSize, 0 ) >= 0 )
- break;
+/** Set up ALSA stream parameters.
+ *
+ */
+static PaError PaAlsaStream_Configure( PaAlsaStream *self, const PaStreamParameters *inParams, const PaStreamParameters*
+ outParams, double sampleRate, unsigned long framesPerUserBuffer, double* inputLatency, double* outputLatency,
+ PaUtilHostBufferSizeMode* hostBufferSizeMode )
+{
+ PaError result = paNoError;
+ double realSr = sampleRate;
+ snd_pcm_hw_params_t* hwParamsCapture, * hwParamsPlayback;
- optimalPeriodSize /= 2;
- }
+ snd_pcm_hw_params_alloca( &hwParamsCapture );
+ snd_pcm_hw_params_alloca( &hwParamsPlayback );
- if( optimalPeriodSize > periodSize )
- periodSize = optimalPeriodSize;
+ if( self->capture.pcm )
+ PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->capture, inParams, self->primeBuffers, hwParamsCapture,
+ &realSr ) );
+ if( self->playback.pcm )
+ PA_ENSURE( PaAlsaStreamComponent_InitialConfigure( &self->playback, outParams, self->primeBuffers, hwParamsPlayback,
+ &realSr ) );
- if( periodSize <= maxPeriodSize )
- {
- /* Looks good */
- framesPerBuffer = periodSize;
- }
- else
- {
- /* Unable to find a common period size, oh well */
- optimalPeriodSize = PA_MAX( desiredLatency / 4, minPeriodSize );
- optimalPeriodSize = PA_MIN( optimalPeriodSize, maxPeriodSize );
+ PA_ENSURE( PaAlsaStream_DetermineFramesPerBuffer( self, realSr, inParams, outParams, framesPerUserBuffer,
+ hwParamsCapture, hwParamsPlayback, hostBufferSizeMode ) );
- /* ConfigureStream should find individual period sizes acceptable for each device */
- framesPerBuffer = optimalPeriodSize;
- /* PA_ENSURE( paBadIODeviceCombination ); */
- }
+ if( self->capture.pcm )
+ {
+ assert( self->capture.framesPerBuffer != 0 );
+ PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->capture, hwParamsCapture, inParams, self->primeBuffers, realSr,
+ inputLatency ) );
+ PA_DEBUG(( "%s: Capture period size: %lu, latency: %f\n", __FUNCTION__, self->capture.framesPerBuffer, *inputLatency ));
}
- else /* half-duplex is a slightly simpler case */
+ if( self->playback.pcm )
{
- unsigned long bufferSize, channels;
- snd_pcm_t *pcm;
- snd_pcm_hw_params_t *hwParams;
+ assert( self->playback.framesPerBuffer != 0 );
+ PA_ENSURE( PaAlsaStreamComponent_FinishConfigure( &self->playback, hwParamsPlayback, outParams, self->primeBuffers, realSr,
+ outputLatency ) );
+ PA_DEBUG(( "%s: Playback period size: %lu, latency: %f\n", __FUNCTION__, self->playback.framesPerBuffer, *outputLatency ));
+ }
- snd_pcm_hw_params_alloca( &hwParams );
+ /* Should be exact now */
+ self->streamRepresentation.streamInfo.sampleRate = realSr;
- if( stream->capture.pcm )
- {
- pcm = stream->capture.pcm;
- bufferSize = inputParameters->suggestedLatency * sampleRate;
- channels = numHostInputChannels;
- }
+ /* this will cause the two streams to automatically start/stop/prepare in sync.
+ * We only need to execute these operations on one of the pair.
+ * A: We don't want to do this on a blocking stream.
+ */
+ if( self->callbackMode && self->capture.pcm && self->playback.pcm )
+ {
+ int err = snd_pcm_link( self->capture.pcm, self->playback.pcm );
+ if( err == 0 )
+ self->pcmsSynced = 1;
else
- {
- pcm = stream->playback.pcm;
- bufferSize = outputParameters->suggestedLatency * sampleRate;
- channels = numHostOutputChannels;
- }
-
- ENSURE_( snd_pcm_hw_params_any( pcm, hwParams ), paUnanticipatedHostError );
- ENSURE_( SetApproximateSampleRate( pcm, hwParams, sampleRate ), paInvalidSampleRate );
- ENSURE_( snd_pcm_hw_params_set_channels( pcm, hwParams, channels ), paBadIODeviceCombination );
+ PA_DEBUG(( "%s: Unable to sync pcms: %s\n", __FUNCTION__, snd_strerror( err ) ));
+ }
- ENSURE_( snd_pcm_hw_params_set_period_size_integer( pcm, hwParams ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_periods_integer( pcm, hwParams ), paUnanticipatedHostError );
+ {
+ unsigned long minFramesPerHostBuffer = PA_MIN( self->capture.pcm ? self->capture.framesPerBuffer : ULONG_MAX,
+ self->playback.pcm ? self->playback.framesPerBuffer : ULONG_MAX );
+ self->pollTimeout = CalculatePollTimeout( self, minFramesPerHostBuffer ); /* Period in msecs, rounded up */
- /* Using 5 as a base number of periods, we try to approximate the suggested latency (+1 period),
- finding a combination of period/buffer size which best fits these constraints */
- framesPerBuffer = bufferSize / 4;
- bufferSize += framesPerBuffer; /* One period doesn't count as latency */
- ENSURE_( snd_pcm_hw_params_set_buffer_size_near( pcm, hwParams, &bufferSize ), paUnanticipatedHostError );
- ENSURE_( snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &framesPerBuffer, NULL ), paUnanticipatedHostError );
+ /* Time before watchdog unthrottles realtime thread == 1/4 of period time in msecs */
+ self->threading.throttledSleepTime = (unsigned long) (minFramesPerHostBuffer / sampleRate / 4 * 1000);
}
- PA_UNLESS( framesPerBuffer != 0, paInternalError );
- *determinedFrames = framesPerBuffer;
+ if( self->callbackMode )
+ {
+ /* If the user expects a certain number of frames per callback we will either have to rely on block adaption
+ * (framesPerHostBuffer is not an integer multiple of framesPerBuffer) or we can simply align the number
+ * of host buffer frames with what the user specified */
+ if( self->framesPerUserBuffer != paFramesPerBufferUnspecified )
+ {
+ /* self->alignFrames = 1; */
+
+ /* Unless the ratio between number of host and user buffer frames is an integer we will have to rely
+ * on block adaption */
+ /*
+ if( framesPerHostBuffer % framesPerBuffer != 0 || (self->capture.pcm && self->playback.pcm &&
+ self->capture.framesPerBuffer != self->playback.framesPerBuffer) )
+ self->useBlockAdaption = 1;
+ else
+ self->alignFrames = 1;
+ */
+ }
+ }
error:
return result;
@@ -1744,7 +2089,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
double sampleRate,
unsigned long framesPerBuffer,
PaStreamFlags streamFlags,
- PaStreamCallback *callback,
+ PaStreamCallback* callback,
void *userData )
{
PaError result = paNoError;
@@ -1754,9 +2099,9 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaSampleFormat inputSampleFormat = 0, outputSampleFormat = 0;
int numInputChannels = 0, numOutputChannels = 0;
PaTime inputLatency, outputLatency;
- unsigned long framesPerHostBuffer;
- PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilBoundedHostBufferSize;
- unsigned long maxHostBufferSize; /* Upper bound of host buffer size */
+ /* Operate with fixed host buffer size by default, since other modes will invariably lead to block adaption */
+ /* XXX: Use Bounded by default? Output tends to get stuttery with Fixed ... */
+ PaUtilHostBufferSizeMode hostBufferSizeMode = paUtilFixedHostBufferSize;
if( (streamFlags & paPlatformSpecificFlags) != 0 )
return paInvalidFlag;
@@ -1782,37 +2127,20 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PA_DEBUG(( "%s: Getting framesPerBuffer from environment\n", __FUNCTION__ ));
framesPerBuffer = atoi( getenv("PA_ALSA_PERIODSIZE") );
}
- framesPerHostBuffer = framesPerBuffer;
PA_UNLESS( stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) ), paInsufficientMemory );
PA_ENSURE( PaAlsaStream_Initialize( stream, alsaHostApi, inputParameters, outputParameters, sampleRate,
framesPerBuffer, callback, streamFlags, userData ) );
- /* If the number of frames per buffer is unspecified, we have to come up with
- * one. This is both a blessing and a curse: a blessing because we can optimize
- * the number to best meet the requirements, but a curse because that's really
- * hard to do well. For this reason we also support an interface where the user
- * specifies these by setting environment variables. */
- if( framesPerBuffer == paFramesPerBufferUnspecified )
- {
- PA_ENSURE( DetermineFramesPerBuffer( stream, sampleRate, inputParameters, outputParameters, &framesPerHostBuffer,
- hostApi ) );
- }
-
- PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerHostBuffer,
- &inputLatency, &outputLatency, &maxHostBufferSize ) );
+ PA_ENSURE( PaAlsaStream_Configure( stream, inputParameters, outputParameters, sampleRate, framesPerBuffer,
+ &inputLatency, &outputLatency, &hostBufferSizeMode ) );
hostInputSampleFormat = stream->capture.hostSampleFormat;
hostOutputSampleFormat = stream->playback.hostSampleFormat;
- if( framesPerHostBuffer != framesPerBuffer )
- {
- PA_DEBUG(( "%s: Number of frames per user and host buffer differs\n", __FUNCTION__ ));
- }
-
PA_ENSURE( PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
numInputChannels, inputSampleFormat, hostInputSampleFormat,
numOutputChannels, outputSampleFormat, hostOutputSampleFormat,
- sampleRate, streamFlags, framesPerBuffer, maxHostBufferSize,
+ sampleRate, streamFlags, framesPerBuffer, stream->maxFramesPerHostBuffer,
hostBufferSizeMode, callback, userData ) );
/* Ok, buffer processor is initialized, now we can deduce it's latency */
@@ -1829,7 +2157,10 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
error:
if( stream )
+ {
+ PA_DEBUG(( "%s: Stream in error, terminating\n", __FUNCTION__ ));
PaAlsaStream_Terminate( stream );
+ }
return result;
}
@@ -1907,7 +2238,7 @@ static int IsRunning( PaAlsaStream *stream )
{
int result = 0;
- ASSERT_CALL_( pthread_mutex_lock( &stream->stateMtx ), 0 ); /* Synchronize access to pcm state */
+ LockMutex( &stream->stateMtx );
if( stream->capture.pcm )
{
snd_pcm_state_t capture_state = snd_pcm_state( stream->capture.pcm );
@@ -1933,7 +2264,7 @@ static int IsRunning( PaAlsaStream *stream )
}
end:
- ASSERT_CALL_( pthread_mutex_unlock( &stream->stateMtx ), 0 );
+ ASSERT_CALL_( UnlockMutex( &stream->stateMtx ), paNoError );
return result;
}
@@ -1966,14 +2297,14 @@ static PaError StartStream( PaStream *s )
/* Since we'll be holding a lock on the startMtx (when not waiting on the condition), IsRunning won't be checking
* stream state at the same time as the callback thread affects it. We also check IsStreamActive, in the unlikely
* case the callback thread exits in the meantime (the stream will be considered inactive after the thread exits) */
- ASSERT_CALL_( pthread_mutex_lock( &stream->startMtx ), 0 );
+ PA_ENSURE( LockMutex( &stream->startMtx ) );
/* Due to possible spurious wakeups, we enclose in a loop */
while( !IsRunning( stream ) && IsStreamActive( s ) && !res )
{
res = pthread_cond_timedwait( &stream->startCond, &stream->startMtx, &ts );
}
- ASSERT_CALL_( pthread_mutex_unlock( &stream->startMtx ), 0 );
+ PA_ENSURE( UnlockMutex( &stream->startMtx ) );
PA_UNLESS( !res || res == ETIMEDOUT, paInternalError );
PA_DEBUG(( "%s: Waited for %g seconds for stream to start\n", __FUNCTION__, PaUtil_GetTime() - pt ));
@@ -2006,18 +2337,34 @@ static PaError AlsaStop( PaAlsaStream *stream, int abort )
if( abort )
{
if( stream->playback.pcm )
+ {
ENSURE_( snd_pcm_drop( stream->playback.pcm ), paUnanticipatedHostError );
+ }
if( stream->capture.pcm && !stream->pcmsSynced )
+ {
ENSURE_( snd_pcm_drop( stream->capture.pcm ), paUnanticipatedHostError );
+ }
- PA_DEBUG(( "Dropped frames\n" ));
+ PA_DEBUG(( "%s: Dropped frames\n", __FUNCTION__ ));
}
else
{
if( stream->playback.pcm )
- ENSURE_( snd_pcm_drain( stream->playback.pcm ), paUnanticipatedHostError );
+ {
+ ENSURE_( snd_pcm_nonblock( stream->playback.pcm, 0 ), paUnanticipatedHostError );
+ if( snd_pcm_drain( stream->playback.pcm ) < 0 )
+ {
+ PA_DEBUG(( "%s: Draining playback handle failed!\n", __FUNCTION__ ));
+ }
+ }
if( stream->capture.pcm && !stream->pcmsSynced )
- ENSURE_( snd_pcm_drain( stream->capture.pcm ), paUnanticipatedHostError );
+ {
+ /* We don't need to retrieve any remaining frames */
+ if( snd_pcm_drop( stream->capture.pcm ) < 0 )
+ {
+ PA_DEBUG(( "%s: Draining capture handle failed!\n", __FUNCTION__ ));
+ }
+ }
}
end:
@@ -2108,7 +2455,7 @@ static PaTime GetStreamTime( PaStream *s )
PaAlsaStream *stream = (PaAlsaStream*)s;
snd_timestamp_t timestamp;
- snd_pcm_status_t *status;
+ snd_pcm_status_t* status;
snd_pcm_status_alloca( &status );
/* TODO: what if we have both? does it really matter? */
@@ -2127,7 +2474,7 @@ static PaTime GetStreamTime( PaStream *s )
}
snd_pcm_status_get_tstamp( status, &timestamp );
- return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1000000.0;
+ return timestamp.tv_sec + (PaTime)timestamp.tv_usec / 1e6;
}
static double GetStreamCpuLoad( PaStream* s )
@@ -2180,14 +2527,15 @@ static PaError AlsaRestart( PaAlsaStream *stream )
{
PaError result = paNoError;
- ASSERT_CALL_( pthread_mutex_lock( &stream->stateMtx ), 0 );
+ PA_ENSURE( LockMutex( &stream->stateMtx ) );
PA_ENSURE( AlsaStop( stream, 0 ) );
PA_ENSURE( AlsaStart( stream, 0 ) );
PA_DEBUG(( "%s: Restarted audio\n", __FUNCTION__ ));
error:
- ASSERT_CALL_( pthread_mutex_unlock( &stream->stateMtx ), 0 );
+ PA_ENSURE( UnlockMutex( &stream->stateMtx ) );
+
return result;
}
@@ -2300,10 +2648,11 @@ static void OnExit( void *data )
PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
stream->callback_finished = 1; /* Let the outside world know stream was stopped in callback */
+ PA_DEBUG(( "%s: Stopping ALSA handles\n", __FUNCTION__ ));
AlsaStop( stream, stream->callbackAbort );
stream->callbackAbort = 0; /* Clear state */
- PA_DEBUG(( "OnExit: Stoppage\n" ));
+ PA_DEBUG(( "%s: Stoppage\n", __FUNCTION__ ));
/* Eventually notify user all buffers have played */
if( stream->streamRepresentation.streamFinishedCallback )
@@ -2516,10 +2865,11 @@ error:
/** Fill in pollfd objects.
*/
-static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent *self, struct pollfd *pfds )
+static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent* self, struct pollfd* pfds )
{
PaError result = paNoError;
int ret = snd_pcm_poll_descriptors( self->pcm, pfds, self->nfds );
+ (void)ret; /* Prevent unused variable warning if asserts are turned off */
assert( ret == self->nfds );
self->ready = 0;
@@ -2533,7 +2883,7 @@ static PaError PaAlsaStreamComponent_BeginPolling( PaAlsaStreamComponent *self,
* @param shouldPoll Should we continue to poll
* @param xrun Has an xrun occurred
*/
-static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent *self, struct pollfd *pfds, int *shouldPoll, int *xrun )
+static PaError PaAlsaStreamComponent_EndPolling( PaAlsaStreamComponent* self, struct pollfd* pfds, int* shouldPoll, int* xrun )
{
PaError result = paNoError;
unsigned short revents;
@@ -2592,6 +2942,7 @@ static PaError PaAlsaStream_GetAvailableFrames( PaAlsaStream *self, int queryCap
if( queryCapture && queryPlayback )
{
*available = PA_MIN( captureFrames, playbackFrames );
+ /*PA_DEBUG(("capture: %lu, playback: %lu, combined: %lu\n", captureFrames, playbackFrames, *available));*/
}
else if( queryCapture )
{
@@ -2668,11 +3019,13 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
PA_ENSURE( PaAlsaStreamComponent_BeginPolling( &self->playback, playbackPfds ) );
totalFds += self->playback.nfds;
}
-
+
if( poll( self->pfds, totalFds, pollTimeout ) < 0 )
{
/* XXX: Depend on preprocessor condition? */
- if( errno == EINTR ) { /* gdb */
+ if( errno == EINTR )
+ {
+ /* gdb */
continue;
}
@@ -2715,8 +3068,8 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
{
/* Get the number of available frames for the pcms that are marked ready.
* @concern FullDuplex If only one direction is marked ready (from poll), the number of frames available for
- * the other direction is returned. This under the assumption that input is dropped earlier if paNeverDropInput
- * is not specified.
+ * the other direction is returned. Output is normally preferred over capture however, so capture frames may be
+ * discarded to avoid overrun unless paNeverDropInput is specified.
*/
int captureReady = self->capture.pcm ? self->capture.ready : 0,
playbackReady = self->playback.pcm ? self->playback.ready : 0;
@@ -2726,9 +3079,18 @@ static PaError PaAlsaStream_WaitForFrames( PaAlsaStream *self, unsigned long *fr
{
if( !self->playback.ready && !self->neverDropInput )
{
- /* TODO: Drop input */
+ /* Drop input, a period's worth */
+ assert( self->capture.ready );
+ PaAlsaStreamComponent_EndProcessing( &self->capture, PA_MIN( self->capture.framesPerBuffer,
+ *framesAvail ), &xrun );
+ *framesAvail = 0;
+ self->capture.ready = 0;
}
}
+ else if( self->capture.pcm )
+ assert( self->capture.ready );
+ else
+ assert( self->playback.ready );
}
end:
@@ -2739,6 +3101,14 @@ error:
PA_ENSURE( PaAlsaStream_HandleXrun( self ) );
*framesAvail = 0;
}
+ else
+ {
+ if( 0 != *framesAvail )
+ {
+ /* If we're reporting frames eligible for processing, one of the handles better be ready */
+ PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError );
+ }
+ }
*xrunOccurred = xrun;
return result;
@@ -2751,8 +3121,8 @@ error:
*
* @param numFrames On entrance the number of requested frames, on exit the number of contiguously accessible frames.
*/
-static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent *self, PaUtilBufferProcessor *bp,
- unsigned long *numFrames, int *xrun )
+static PaError PaAlsaStreamComponent_RegisterChannels( PaAlsaStreamComponent* self, PaUtilBufferProcessor* bp,
+ unsigned long* numFrames, int* xrun )
{
PaError result = paNoError;
const snd_pcm_channel_area_t *areas, *area;
@@ -2812,12 +3182,20 @@ error:
* @param numFrames On entrance the number of available frames, on exit the number of received frames
* @param xrunOccurred Return whether an xrun has occurred
*/
-static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream *self, unsigned long *numFrames, int *xrunOccurred )
+static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream* self, unsigned long* numFrames, int* xrunOccurred )
{
PaError result = paNoError;
unsigned long captureFrames = ULONG_MAX, playbackFrames = ULONG_MAX, commonFrames = 0;
int xrun = 0;
+ if( *xrunOccurred )
+ {
+ *numFrames = 0;
+ return result;
+ }
+ /* If we got here at least one of the pcm's should be marked ready */
+ PA_UNLESS( self->capture.ready || self->playback.ready, paInternalError );
+
/* Extract per-channel ALSA buffer pointers and register them with the buffer processor.
* It is possible that a direction is not marked ready however, because it is out of sync with the other.
*/
@@ -2841,7 +3219,24 @@ static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream *self, unsigned long *num
}
commonFrames = PA_MIN( captureFrames, playbackFrames );
- assert( commonFrames <= *numFrames );
+ /* assert( commonFrames <= *numFrames ); */
+ if( commonFrames > *numFrames )
+ {
+ /* Hmmm ... how come there are more frames available than we requested!? Blah. */
+ PA_DEBUG(( "%s: Common available frames are reported to be more than number requested: %lu, %lu, callbackMode: %d\n", __FUNCTION__,
+ commonFrames, *numFrames, self->callbackMode ));
+ if( self->capture.pcm )
+ {
+ PA_DEBUG(( "%s: captureFrames: %lu, capture.ready: %d\n", __FUNCTION__, captureFrames, self->capture.ready ));
+ }
+ if( self->playback.pcm )
+ {
+ PA_DEBUG(( "%s: playbackFrames: %lu, playback.ready: %d\n", __FUNCTION__, playbackFrames, self->playback.ready ));
+ }
+
+ commonFrames = 0;
+ goto end;
+ }
/* Inform PortAudio of the number of frames we got.
* @concern FullDuplex We might be experiencing underflow in either end; if its an input underflow, we go on
@@ -2869,7 +3264,9 @@ static PaError PaAlsaStream_SetUpBuffers( PaAlsaStream *self, unsigned long *num
else
{
/* We have output underflow, but keeping input data (paNeverDropInput) */
- /* assert( self->neverDropInput ); */
+ assert( self->neverDropInput );
+ assert( self->capture.pcm != NULL );
+ PA_DEBUG(( "%s: Setting output buffers to NULL\n", __FUNCTION__ ));
PaUtil_SetNoOutput( &self->bufferProcessor );
}
}
@@ -2934,10 +3331,11 @@ static void *CallbackThreadFunc( void *userData )
}
else
{
- ASSERT_CALL_( pthread_mutex_lock( &stream->startMtx ), 0 );
- PA_ENSURE( AlsaStart( stream, 0 ) ); /* Buffer will be zeroed */
- ASSERT_CALL_( pthread_cond_signal( &stream->startCond ), 0 );
- ASSERT_CALL_( pthread_mutex_unlock( &stream->startMtx ), 0 );
+ PA_ENSURE( LockMutex( &stream->startMtx ) );
+ /* Buffer will be zeroed */
+ PA_ENSURE( AlsaStart( stream, 0 ) );
+ ENSURE_SYSTEM_( pthread_cond_signal( &stream->startCond ), 0 );
+ PA_ENSURE( UnlockMutex( &stream->startMtx ) );
streamStarted = 1;
}
@@ -2962,7 +3360,7 @@ static void *CallbackThreadFunc( void *userData )
{
stream->callbackAbort = (paAbort == callbackResult);
if( stream->callbackAbort ||
- /** @concern BlockAdaption Go on if adaption buffers are empty */
+ /** @concern BlockAdaption: Go on if adaption buffers are empty */
PaUtil_IsBufferProcessorOutputEmpty( &stream->bufferProcessor ) )
goto end;
@@ -3031,23 +3429,31 @@ static void *CallbackThreadFunc( void *userData )
PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
framesGot = framesAvail;
+ if( paUtilFixedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode )
+ {
+ /* We've committed to a fixed host buffer size, stick to that */
+ framesGot = framesGot >= stream->maxFramesPerHostBuffer ? stream->maxFramesPerHostBuffer : 0;
+ }
+ else
+ {
+ /* We've committed to an upper bound on the size of host buffers */
+ assert( paUtilBoundedHostBufferSize == stream->bufferProcessor.hostBufferSizeMode );
+ framesGot = PA_MIN( framesGot, stream->maxFramesPerHostBuffer );
+ }
PA_ENSURE( PaAlsaStream_SetUpBuffers( stream, &framesGot, &xrun ) );
+ /* Check the host buffer size against the buffer processor configuration */
framesAvail -= framesGot;
if( framesGot > 0 )
{
assert( !xrun );
-
PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
PA_ENSURE( PaAlsaStream_EndProcessing( stream, framesGot, &xrun ) );
}
PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesGot );
- if( framesGot == 0 )
+ if( 0 == framesGot )
{
- if( !xrun )
- PA_DEBUG(( "%s: Received less frames than reported from ALSA!\n", __FUNCTION__ ));
-
/* Go back to polling for more frames */
break;
@@ -3062,6 +3468,7 @@ static void *CallbackThreadFunc( void *userData )
pthread_cleanup_pop( 1 );
end:
+ PA_DEBUG(( "%s: Thread %d exiting\n ", __FUNCTION__, pthread_self() ));
pthread_exit( pres );
error:
@@ -3096,7 +3503,9 @@ static PaError ReadStream( PaStream* s, void *buffer, unsigned long frames )
}
if( stream->capture.userInterleaved )
+ {
userBuffer = buffer;
+ }
else
{
/* Copy channels into local array */
@@ -3178,12 +3587,13 @@ static PaError WriteStream( PaStream* s, const void *buffer, unsigned long frame
frames -= framesGot;
}
+ /* Start stream after one period of samples worth */
+
/* Frames residing in buffer */
PA_ENSURE( err = GetStreamWriteAvailable( stream ) );
framesAvail = err;
hwAvail = stream->playback.bufferSize - framesAvail;
- /* Start stream after one period of samples worth */
if( snd_pcm_state( stream->playback.pcm ) == SND_PCM_STATE_PREPARED &&
hwAvail >= stream->playback.framesPerBuffer )
{
diff --git a/pd/portaudio/pa_mac_core/notes.txt b/pd/portaudio/pa_mac_core/notes.txt
index c79b90e6..ad66f358 100644
--- a/pd/portaudio/pa_mac_core/notes.txt
+++ b/pd/portaudio/pa_mac_core/notes.txt
@@ -1,8 +1,23 @@
-Notes on Core Audio Implementation of PortAudio
+Notes on status of CoreAudio Implementation of PortAudio
+
+Document Last Updated December 9, 2005
+
+There are currently two implementations of PortAudio for Mac Core Audio.
+
+The original is in pa_mac_core_old.c, and the newer, default implementation
+is in pa_mac_core.c.
+Only pa_mac_core.c is currently developed and supported as it uses apple's
+current core audio technology. To select use the old implementation, replace
+pa_mac_core.c with pa_mac_core_old.c (eg. "cp pa_mac_core_auhal.c
+pa_mac_core.c"), then run configure and make as usual.
+
+----------------------------------------
+
+Notes on Original implementation:
by Phil Burk and Darren Gibbs
-Document last updated March 20, 2002
+Last updated March 20, 2002
WHAT WORKS
@@ -18,7 +33,7 @@ KNOWN BUGS OR LIMITATIONS
We do not yet support simultaneous input and output on different
devices. Note that some CoreAudio devices like the Roland UH30 look
like one device but are actually two different CoreAudio devices. The
-BuiltIn audio is typically one CoreAudio device.
+Built-In audio is typically one CoreAudio device.
Mono doesn't work.
@@ -32,3 +47,99 @@ input, output or both.
When we query devices, we first get a list of CoreAudio devices. Then
we scan the list and add a PortAudio device for each CoreAudio device
that supports input. Then we make a scan for output devices.
+
+-------------------------------------------
+
+Notes on Newer/Default AUHAL implementation:
+
+by Bjorn Roche
+
+Last Updated December 9, 2005
+
+Principle of Operation:
+
+This implementation uses AUHAL for audio I/O. To some extent, it also
+operates at the "HAL" Layer, though this behavior can be limited by
+platform specific flags (see pa_mac_core.h for details). The default
+settings should be reasonable: they don't change the SR of the device and
+don't cause interruptions if other devices are using the device.
+
+Major Software Elements Used: Apple's HAL AUs provide output SR
+conversion transparently, however, only on output, so this
+implementation uses AudioConverters to convert the sample rate on input.
+A PortAudio ring buffer is used to buffer input when sample rate
+conversion is required or when separate audio units are used for duplex
+IO. Finally, a PortAudio buffer processor is used to convert formats and
+provide additional buffers if needed. Internally, interleaved floating
+point data streams are used exclusively - the audio unit converts from
+the audio hardware's native format to interleaved float PCM and
+PortAudio's Buffer processor is used for conversion to user formats.
+
+Simplex Input: Simplex input uses a single callback. If sample rate
+conversion is required, a ring buffer and AudioConverter are used as
+well.
+
+Simplex output: Simplex output uses a single callback. No ring buffer or
+audio converter is used because AUHAL does its own output SR conversion.
+
+Duplex, one device (no SR conversion): When one device is used, a single
+callback is used. This achieves very low latency.
+
+Duplex, separate devices or SR conversion: When SR conversion is
+required, data must be buffered before it is converted and data is not
+always available at the same times on input and output, so SR conversion
+requires the same treatment as separate devices. The input callback
+reads data and puts it in the ring buffer. The output callback reads the
+data off the ring buffer, into an audio converter and finally to the
+buffer processor.
+
+Platform Specific Options:
+
+By using the flags in pa_mac_core.h, the user may specify several options.
+For example, the user can specify the sample-rate conversion quality, and
+the extent to which PA will attempt to "play nice" and to what extent it
+will interrupt other apps to improve performance. For example, if 44100 Hz
+sample rate is requested but the device is set at 48000 Hz, PA can either
+change the device for optimal playback ("Pro" mode), which may interrupt
+other programs playing back audio, or simple use a sample-rate coversion,
+which allows for friendlier sharing of the device ("Play Nice" mode).
+
+
+Known issues:
+
+- Latency: Latency settings are ignored in most cases. Exceptions are when
+doing I/O between different devices and as a hint for selecting a realtively
+low or relatively high latency in conjunction with
+paHostFramesPerBufferUnspecified. Latency settings are always automatically
+bound to "safe" values, however, so setting extreme values here should not be
+an issue.
+
+- Buffer Size: paHostFramesPerBufferUnspecified and specific host buffer sizes
+are supported. paHostFramesPerBufferUnspecified works best in "pro" mode,
+where the buffer size and sample rate of the audio device is most likely
+to match the expected values.
+
+- Timing info. It reports on stream time, but I'm probably doing something
+wrong since patest_sine_time often reports negative latency numbers.
+
+- xrun detection: The only xrun detection performed is when reading
+and writing the ring buffer. There is probably more that can be done.
+
+- abort/stop issues: stopping a stream is always a complete operation,
+but latency should be low enough to make the lack of a separate abort
+unnecessary. Apple clarifies its AudioOutputUnitStop() call here:
+http://lists.apple.com/archives/coreaudio-api/2005/Dec/msg00055.html
+
+- blocking interface: Not implemented.
+
+- multichannel: It has been tested successfully on multichannel hardware
+from MOTU: traveler and 896HD.
+
+- sample rate conversion quality: By default, SR conversion is the maximum
+available. This can be tweaked using flags pa_mac_core.h. Note that the AU
+render quyality property is used to set the sample rat conversion quality
+as "documented" here:
+http://lists.apple.com/archives/coreaudio-api/2004/Jan/msg00141.html
+
+- x86: I haven't tested it on an x86 Mac myself, but users have reported
+being able to comiple and run it.
diff --git a/pd/portaudio/pa_mac_core/pa_mac_core.c b/pd/portaudio/pa_mac_core/pa_mac_core.c
index 77451a5d..16eb0824 100644
--- a/pd/portaudio/pa_mac_core/pa_mac_core.c
+++ b/pd/portaudio/pa_mac_core/pa_mac_core.c
@@ -1,13 +1,19 @@
/*
- * $Id: pa_mac_core.c,v 1.8.2.3 2005/06/19 22:12:38 tgrill Exp $
- * pa_mac_core.c
- * Implementation of PortAudio for Mac OS X CoreAudio
- *
- * PortAudio Portable Real-Time Audio Library
- * Latest Version at: http://www.portaudio.com
+ * This is the AUHAL implementation of portaudio. Hopefully this will
+ * one day replace pa_mac_core.
*
- * Authors: Ross Bencina and Phil Burk
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ * Written by Bjorn Roche of XO Audio LLC, from PA skeleton code.
+ * Portions copied from code by Dominic Mazzoni (who wrote a HAL implementation)
+ *
+ * Dominic's code was based on code by Phil Burk, Darren Gibbs,
+ * Gord Peters, Stephane Letz, and Greg Pfiel.
+ *
+ * Bjorn Roche and XO Audio LLC reserve no rights to this code.
+ * The maintainers of PortAudio may redistribute and modify the code and
+ * licenses as they deam appropriate.
+ *
+ * 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
@@ -31,600 +37,1009 @@
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
*/
-#include <CoreAudio/CoreAudio.h>
+/**
+ @file pa_mac_core
+ @author Bjorn Roche
+ @brief AUHAL implementation of PortAudio
+*/
+
+#include <string.h> /* strlen(), memcmp() etc. */
+
+#include <AudioUnit/AudioUnit.h>
#include <AudioToolbox/AudioToolbox.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <assert.h>
-#include "portaudio.h"
-#include "pa_trace.h"
+
#include "pa_util.h"
#include "pa_allocation.h"
#include "pa_hostapi.h"
#include "pa_stream.h"
#include "pa_cpuload.h"
#include "pa_process.h"
+#include "../pablio/ringbuffer.h"
+#include "pa_mac_core.h"
-// ===== constants =====
+#ifndef MIN
+#define MIN(a, b) (((a)<(b))?(a):(b))
+#endif
-// ===== structs =====
-#pragma mark structs
+#ifndef MAX
+#define MAX(a, b) (((a)<(b))?(b):(a))
+#endif
-// PaMacCoreHostApiRepresentation - host api datastructure specific to this implementation
-typedef struct PaMacCore_HAR
+/* prototypes for functions declared in this file */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#define ERR(mac_error) PaMacCore_SetError(mac_error, __LINE__, 1 )
+#define WARNING(mac_error) PaMacCore_SetError(mac_error, __LINE__, 0 )
+
+/* Help keep track of AUHAL element numbers */
+#define INPUT_ELEMENT (1)
+#define OUTPUT_ELEMENT (0)
+
+/* Normal level of debugging: fine for most apps that don't mind the occational warning being printf'ed */
+/*
+ */
+#define MAC_CORE_DEBUG
+#ifdef MAC_CORE_DEBUG
+# define DBUG(MSG) do { printf("||PaMacCore (AUHAL)|| "); printf MSG ; fflush(stdout); } while(0)
+#else
+# define DBUG(MSG)
+#endif
+
+/* Verbose Debugging: useful for developement */
+/*
+#define MAC_CORE_VERBOSE_DEBUG
+ */
+#ifdef MAC_CORE_VERBOSE_DEBUG
+# define VDBUG(MSG) do { printf("||PaMacCore (v )|| "); printf MSG ; fflush(stdout); } while(0)
+#else
+# define VDBUG(MSG)
+#endif
+
+/* Very Verbose Debugging: Traces every call. */
+/*
+#define MAC_CORE_VERY_VERBOSE_DEBUG
+ */
+#ifdef MAC_CORE_VERY_VERBOSE_DEBUG
+# define VVDBUG(MSG) do { printf("||PaMacCore (vv)|| "); printf MSG ; fflush(stdout); } while(0)
+#else
+# define VVDBUG(MSG)
+#endif
+
+#define RING_BUFFER_ADVANCE_DENOMINATOR (4)
+
+/* Some utilities that sort of belong here, but were getting too unweildy */
+#include "pa_mac_core_utilities.c"
+/* Special purpose ring buffer just for pa_mac_core input processing. */
+/* #include "pa_mac_core_input_ring_buffer.c" */
+#include "../pablio/ringbuffer.c"
+
+
+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 void setStreamStartTime( PaStream *stream );
+static OSStatus AudioIOProc( void *inRefCon,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList *ioData );
+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 );
+/* PaMacAUHAL - host api datastructure specific to this implementation */
+typedef struct
{
PaUtilHostApiRepresentation inheritedHostApiRep;
PaUtilStreamInterface callbackStreamInterface;
PaUtilStreamInterface blockingStreamInterface;
-
+
PaUtilAllocationGroup *allocations;
- AudioDeviceID *macCoreDeviceIds;
-}
-PaMacCoreHostApiRepresentation;
-typedef struct PaMacCore_DI
-{
- PaDeviceInfo inheritedDeviceInfo;
+ /* implementation specific data goes here */
+ long devCount;
+ AudioDeviceID *devIds; /*array of all audio devices*/
+ AudioDeviceID defaultIn;
+ AudioDeviceID defaultOut;
}
-PaMacCoreDeviceInfo;
+PaMacAUHAL;
-// PaMacCoreStream - a stream data structure specifically for this implementation
-typedef struct PaMacCore_S
+/* stream data structure specifically for this implementation */
+typedef struct PaMacCoreStream
{
PaUtilStreamRepresentation streamRepresentation;
PaUtilCpuLoadMeasurer cpuLoadMeasurer;
PaUtilBufferProcessor bufferProcessor;
-
- int primeStreamUsingCallback;
-
+
+ /* implementation specific data goes here */
+ bool bufferProcessorIsInitialized;
+ AudioUnit inputUnit;
+ AudioUnit outputUnit;
AudioDeviceID inputDevice;
AudioDeviceID outputDevice;
-
- // Processing thread management --------------
-// HANDLE abortEvent;
-// HANDLE processingThread;
-// DWORD processingThreadId;
-
- char throttleProcessingThreadOnOverload; // 0 -> don't throtte, non-0 -> throttle
- int processingThreadPriority;
- int highThreadPriority;
- int throttledThreadPriority;
- unsigned long throttledSleepMsecs;
-
- int isStopped;
- volatile int isActive;
- volatile int stopProcessing; // stop thread once existing buffers have been returned
- volatile int abortProcessing; // stop thread immediately
-
-// DWORD allBuffersDurationMs; // used to calculate timeouts
+ size_t userInChan;
+ size_t userOutChan;
+ size_t inputFramesPerBuffer;
+ size_t outputFramesPerBuffer;
+ /* We use this ring buffer when input and out devs are different. */
+ RingBuffer inputRingBuffer;
+ /* We may need to do SR conversion on input. */
+ AudioConverterRef inputSRConverter;
+ /* We need to preallocate an inputBuffer for reading data. */
+ AudioBufferList inputAudioBufferList;
+ AudioTimeStamp startTime;
+ //volatile bool isTimeSet;
+ volatile PaStreamCallbackFlags xrunFlags;
+ volatile enum {
+ STOPPED = 0, /* playback is completely stopped,
+ and the user has called StopStream(). */
+ CALLBACK_STOPPED = 1, /* callback has requested stop,
+ but user has not yet called StopStream(). */
+ STOPPING = 2, /* The stream is in the process of closing.
+ This state is just used internally;
+ externally it is indistinguishable from
+ ACTIVE.*/
+ ACTIVE = 3 /* The stream is active and running. */
+ } state;
+ double sampleRate;
}
PaMacCoreStream;
-// Data needed by the CoreAudio callback functions
-typedef struct PaMacCore_CD
-{
- PaMacCoreStream *stream;
- PaStreamCallback *callback;
- void *userData;
- PaUtilConverter *inputConverter;
- PaUtilConverter *outputConverter;
- void *inputBuffer;
- void *outputBuffer;
- int inputChannelCount;
- int outputChannelCount;
- PaSampleFormat inputSampleFormat;
- PaSampleFormat outputSampleFormat;
- PaUtilTriangularDitherGenerator *ditherGenerator;
-}
-PaMacClientData;
+static PaError OpenAndSetupOneAudioUnit(
+ const PaStreamParameters *inStreamParams,
+ const PaStreamParameters *outStreamParams,
+ const unsigned long requestedFramesPerBuffer,
+ unsigned long *actualInputFramesPerBuffer,
+ unsigned long *actualOutputFramesPerBuffer,
+ const PaMacAUHAL *auhalHostApi,
+ AudioUnit *audioUnit,
+ AudioConverterRef *srConverter,
+ AudioDeviceID *audioDevice,
+ const double sampleRate,
+ void *refCon );
-// ===== CoreAudio-PortAudio bridge functions =====
-#pragma mark CoreAudio-PortAudio bridge functions
+/* for setting errors. */
+#define PA_AUHAL_SET_LAST_HOST_ERROR( errorCode, errorText ) \
+ PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
-// Maps CoreAudio OSStatus codes to PortAudio PaError codes
-static PaError conv_err(OSStatus error)
-{
- PaError result;
-
- switch (error) {
- case kAudioHardwareNoError:
- result = paNoError; break;
- case kAudioHardwareNotRunningError:
- result = paInternalError; break;
- case kAudioHardwareUnspecifiedError:
- result = paInternalError; break;
- case kAudioHardwareUnknownPropertyError:
- result = paInternalError; break;
- case kAudioHardwareBadPropertySizeError:
- result = paInternalError; break;
- case kAudioHardwareIllegalOperationError:
- result = paInternalError; break;
- case kAudioHardwareBadDeviceError:
- result = paInvalidDevice; break;
- case kAudioHardwareBadStreamError:
- result = paBadStreamPtr; break;
- case kAudioHardwareUnsupportedOperationError:
- result = paInternalError; break;
- case kAudioDeviceUnsupportedFormatError:
- result = paSampleFormatNotSupported; break;
- case kAudioDevicePermissionsError:
- result = paDeviceUnavailable; break;
- default:
- result = paInternalError;
- }
-
- return result;
-}
-
-static AudioStreamBasicDescription *InitializeStreamDescription(const PaStreamParameters *parameters, double sampleRate)
-{
- struct AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(sizeof(AudioStreamBasicDescription));
- streamDescription->mSampleRate = sampleRate;
- streamDescription->mFormatID = kAudioFormatLinearPCM;
- streamDescription->mFormatFlags = 0;
- streamDescription->mFramesPerPacket = 1;
-
- if (parameters->sampleFormat & paNonInterleaved) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsNonInterleaved;
- streamDescription->mChannelsPerFrame = 1;
- streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat);
- streamDescription->mBytesPerPacket = Pa_GetSampleSize(parameters->sampleFormat);
- }
- else {
- streamDescription->mChannelsPerFrame = parameters->channelCount;
- }
-
- streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat) * streamDescription->mChannelsPerFrame;
- streamDescription->mBytesPerPacket = streamDescription->mBytesPerFrame * streamDescription->mFramesPerPacket;
-
- if (parameters->sampleFormat & paFloat32) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsFloat;
- streamDescription->mBitsPerChannel = 32;
- }
- else if (parameters->sampleFormat & paInt32) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
- streamDescription->mBitsPerChannel = 32;
- }
- else if (parameters->sampleFormat & paInt24) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
- streamDescription->mBitsPerChannel = 24;
- }
- else if (parameters->sampleFormat & paInt16) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
- streamDescription->mBitsPerChannel = 16;
- }
- else if (parameters->sampleFormat & paInt8) {
- streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
- streamDescription->mBitsPerChannel = 8;
- }
- else if (parameters->sampleFormat & paInt32) {
- streamDescription->mBitsPerChannel = 8;
- }
-
- return streamDescription;
-}
-static PaStreamCallbackTimeInfo *InitializeTimeInfo(const AudioTimeStamp* now, const AudioTimeStamp* inputTime, const AudioTimeStamp* outputTime)
-{
- PaStreamCallbackTimeInfo *timeInfo = PaUtil_AllocateMemory(sizeof(PaStreamCallbackTimeInfo));
-
- timeInfo->inputBufferAdcTime = inputTime->mSampleTime;
- timeInfo->currentTime = now->mSampleTime;
- timeInfo->outputBufferDacTime = outputTime->mSampleTime;
-
- return timeInfo;
-}
-// ===== support functions =====
-#pragma mark support functions
-static void CleanUp(PaMacCoreHostApiRepresentation *macCoreHostApi)
+/*currently, this is only used in initialization, but it might be modified
+ to be used when the list of devices changes.*/
+static PaError gatherDeviceInfo(PaMacAUHAL *auhalHostApi)
{
- if( macCoreHostApi->allocations )
+ UInt32 size;
+ UInt32 propsize;
+ VVDBUG(("gatherDeviceInfo()\n"));
+ /* -- free any previous allocations -- */
+ if( auhalHostApi->devIds )
+ PaUtil_GroupFreeMemory(auhalHostApi->allocations, auhalHostApi->devIds);
+ auhalHostApi->devIds = NULL;
+
+ /* -- figure out how many devices there are -- */
+ AudioHardwareGetPropertyInfo( kAudioHardwarePropertyDevices,
+ &propsize,
+ NULL );
+ auhalHostApi->devCount = propsize / sizeof( AudioDeviceID );
+
+ VDBUG( ( "Found %ld device(s).\n", auhalHostApi->devCount ) );
+
+ /* -- copy the device IDs -- */
+ auhalHostApi->devIds = (AudioDeviceID *)PaUtil_GroupAllocateMemory(
+ auhalHostApi->allocations,
+ propsize );
+ if( !auhalHostApi->devIds )
+ return paInsufficientMemory;
+ AudioHardwareGetProperty( kAudioHardwarePropertyDevices,
+ &propsize,
+ auhalHostApi->devIds );
+#ifdef MAC_CORE_VERBOSE_DEBUG
{
- PaUtil_FreeAllAllocations( macCoreHostApi->allocations );
- PaUtil_DestroyAllocationGroup( macCoreHostApi->allocations );
+ int i;
+ for( i=0; i<auhalHostApi->devCount; ++i )
+ printf( "Device %d\t: %ld\n", i, auhalHostApi->devIds[i] );
}
-
- PaUtil_FreeMemory( macCoreHostApi );
+#endif
+
+ size = sizeof(AudioDeviceID);
+ auhalHostApi->defaultIn = kAudioDeviceUnknown;
+ auhalHostApi->defaultOut = kAudioDeviceUnknown;
+ /* FEEDBACK: these calls could fail, in which case default in and out will
+ be unknown devices or could be undefined. Do I need to be more
+ rigorous here? */
+ AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice,
+ &size,
+ &auhalHostApi->defaultIn);
+ AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
+ &size,
+ &auhalHostApi->defaultOut);
+ VDBUG( ( "Default in : %ld\n", auhalHostApi->defaultIn ) );
+ VDBUG( ( "Default out: %ld\n", auhalHostApi->defaultOut ) );
+
+ return paNoError;
}
-static PaError GetChannelInfo(PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput)
+static PaError GetChannelInfo( PaMacAUHAL *auhalHostApi,
+ PaDeviceInfo *deviceInfo,
+ AudioDeviceID macCoreDeviceId,
+ int isInput)
{
UInt32 propSize;
PaError err = paNoError;
UInt32 i;
int numChannels = 0;
AudioBufferList *buflist;
+ UInt32 frameLatency;
+
+ VVDBUG(("GetChannelInfo()\n"));
+
+ /* Get the number of channels from the stream configuration.
+ Fail if we can't get this. */
+
+ err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL));
+ if (err)
+ return err;
- err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL));
buflist = PaUtil_AllocateMemory(propSize);
- err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist));
- if (!err) {
- for (i = 0; i < buflist->mNumberBuffers; ++i) {
- numChannels += buflist->mBuffers[i].mNumberChannels;
- }
-
- if (isInput)
- deviceInfo->maxInputChannels = numChannels;
- else
- deviceInfo->maxOutputChannels = numChannels;
-
- int frameLatency;
- propSize = sizeof(UInt32);
- err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency));
- if (!err) {
- double secondLatency = frameLatency / deviceInfo->defaultSampleRate;
- if (isInput) {
- deviceInfo->defaultLowInputLatency = secondLatency;
- deviceInfo->defaultHighInputLatency = secondLatency;
- }
- else {
- deviceInfo->defaultLowOutputLatency = secondLatency;
- deviceInfo->defaultHighOutputLatency = secondLatency;
- }
- }
+ err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist));
+ if (err)
+ return err;
+
+ for (i = 0; i < buflist->mNumberBuffers; ++i)
+ numChannels += buflist->mBuffers[i].mNumberChannels;
+
+ if (isInput)
+ deviceInfo->maxInputChannels = numChannels;
+ else
+ deviceInfo->maxOutputChannels = numChannels;
+
+ if (numChannels > 0) // do not try to retrieve the latency if there is no channels.
+ {
+ /* Get the latency. Don't fail if we can't get this. */
+ /* default to something reasonable */
+ deviceInfo->defaultLowInputLatency = .01;
+ deviceInfo->defaultHighInputLatency = .01;
+ deviceInfo->defaultLowOutputLatency = .01;
+ deviceInfo->defaultHighOutputLatency = .01;
+ propSize = sizeof(UInt32);
+ err = WARNING(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency));
+ if (!err)
+ {
+ double secondLatency = frameLatency / deviceInfo->defaultSampleRate;
+ if (isInput)
+ {
+ deviceInfo->defaultLowInputLatency = secondLatency;
+ deviceInfo->defaultHighInputLatency = secondLatency;
+ }
+ else
+ {
+ deviceInfo->defaultLowOutputLatency = secondLatency;
+ deviceInfo->defaultHighOutputLatency = secondLatency;
+ }
+ }
}
- PaUtil_FreeMemory(buflist);
-
- return err;
+ return paNoError;
}
-static PaError InitializeDeviceInfo(PaMacCoreDeviceInfo *macCoreDeviceInfo, AudioDeviceID macCoreDeviceId, PaHostApiIndex hostApiIndex )
+static PaError InitializeDeviceInfo( PaMacAUHAL *auhalHostApi,
+ PaDeviceInfo *deviceInfo,
+ AudioDeviceID macCoreDeviceId,
+ PaHostApiIndex hostApiIndex )
{
- PaDeviceInfo *deviceInfo = &macCoreDeviceInfo->inheritedDeviceInfo;
- deviceInfo->structVersion = 2;
- deviceInfo->hostApi = hostApiIndex;
-
+ Float64 sampleRate;
+ char *name;
PaError err = paNoError;
UInt32 propSize;
- err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL));
- // FIXME: this allocation should be part of the allocations group
- char *name = PaUtil_AllocateMemory(propSize);
- err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name));
- if (!err) {
- deviceInfo->name = name;
- }
-
- Float64 sampleRate;
+ VVDBUG(("InitializeDeviceInfo(): macCoreDeviceId=%ld\n", macCoreDeviceId));
+
+ memset(deviceInfo, 0, sizeof(deviceInfo));
+
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+
+ /* Get the device name. Fail if we can't get it. */
+ err = ERR(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL));
+ if (err)
+ return err;
+
+ name = PaUtil_GroupAllocateMemory(auhalHostApi->allocations,propSize);
+ if ( !name )
+ return paInsufficientMemory;
+ err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name));
+ if (err)
+ return err;
+ deviceInfo->name = name;
+
+ /* Try to get the default sample rate. Don't fail if we can't get this. */
propSize = sizeof(Float64);
- err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate));
- if (!err) {
+ err = ERR(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate));
+ if (err)
+ deviceInfo->defaultSampleRate = 0.0;
+ else
deviceInfo->defaultSampleRate = sampleRate;
- }
+ /* Get the maximum number of input and output channels. Fail if we can't get this. */
+
+ err = GetChannelInfo(auhalHostApi, deviceInfo, macCoreDeviceId, 1);
+ if (err)
+ return err;
- // Get channel info
- err = GetChannelInfo(deviceInfo, macCoreDeviceId, 1);
- err = GetChannelInfo(deviceInfo, macCoreDeviceId, 0);
+ err = GetChannelInfo(auhalHostApi, deviceInfo, macCoreDeviceId, 0);
+ if (err)
+ return err;
- return err;
+ return paNoError;
}
-static PaError InitializeDeviceInfos( PaMacCoreHostApiRepresentation *macCoreHostApi, PaHostApiIndex hostApiIndex )
+PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
{
PaError result = paNoError;
- PaUtilHostApiRepresentation *hostApi;
- PaMacCoreDeviceInfo *deviceInfoArray;
-
- // initialise device counts and default devices under the assumption that there are no devices. These values are incremented below if and when devices are successfully initialized.
- hostApi = &macCoreHostApi->inheritedHostApiRep;
- hostApi->info.deviceCount = 0;
- hostApi->info.defaultInputDevice = paNoDevice;
- hostApi->info.defaultOutputDevice = paNoDevice;
-
- UInt32 propsize;
- AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propsize, NULL);
- int numDevices = propsize / sizeof(AudioDeviceID);
- hostApi->info.deviceCount = numDevices;
- if (numDevices > 0) {
- hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
- macCoreHostApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
- if( !hostApi->deviceInfos )
+ int i;
+ PaMacAUHAL *auhalHostApi;
+ PaDeviceInfo *deviceInfoArray;
+
+ VVDBUG(("PaMacCore_Initialize(): hostApiIndex=%d\n", hostApiIndex));
+
+ auhalHostApi = (PaMacAUHAL*)PaUtil_AllocateMemory( sizeof(PaMacAUHAL) );
+ if( !auhalHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ auhalHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !auhalHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ auhalHostApi->devIds = NULL;
+ auhalHostApi->devCount = 0;
+
+ /* get the info we need about the devices */
+ result = gatherDeviceInfo( auhalHostApi );
+ if( result != paNoError )
+ goto error;
+
+ *hostApi = &auhalHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paCoreAudio;
+ (*hostApi)->info.name = "Core Audio";
+
+ (*hostApi)->info.defaultInputDevice = paNoDevice;
+ (*hostApi)->info.defaultOutputDevice = paNoDevice;
+
+ (*hostApi)->info.deviceCount = 0;
+
+ if( auhalHostApi->devCount > 0 )
+ {
+ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ auhalHostApi->allocations, sizeof(PaDeviceInfo*) * auhalHostApi->devCount);
+ if( !(*hostApi)->deviceInfos )
{
- return paInsufficientMemory;
+ result = paInsufficientMemory;
+ goto error;
}
- // allocate all device info structs in a contiguous block
- deviceInfoArray = (PaMacCoreDeviceInfo*)PaUtil_GroupAllocateMemory(
- macCoreHostApi->allocations, sizeof(PaMacCoreDeviceInfo) * numDevices );
+ /* allocate all device info structs in a contiguous block */
+ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ auhalHostApi->allocations, sizeof(PaDeviceInfo) * auhalHostApi->devCount );
if( !deviceInfoArray )
{
- return paInsufficientMemory;
+ result = paInsufficientMemory;
+ goto error;
}
-
- macCoreHostApi->macCoreDeviceIds = PaUtil_GroupAllocateMemory(macCoreHostApi->allocations, propsize);
- AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propsize, macCoreHostApi->macCoreDeviceIds);
- AudioDeviceID defaultInputDevice, defaultOutputDevice;
- propsize = sizeof(AudioDeviceID);
- AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propsize, &defaultInputDevice);
- AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propsize, &defaultOutputDevice);
-
- UInt32 i;
- for (i = 0; i < numDevices; ++i) {
- if (macCoreHostApi->macCoreDeviceIds[i] == defaultInputDevice) {
- hostApi->info.defaultInputDevice = i;
+ for( i=0; i < auhalHostApi->devCount; ++i )
+ {
+ int err;
+ err = InitializeDeviceInfo( auhalHostApi, &deviceInfoArray[i],
+ auhalHostApi->devIds[i],
+ hostApiIndex );
+ if (err == paNoError)
+ { /* copy some info and set the defaults */
+ (*hostApi)->deviceInfos[(*hostApi)->info.deviceCount] = &deviceInfoArray[i];
+ if (auhalHostApi->devIds[i] == auhalHostApi->defaultIn)
+ (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
+ if (auhalHostApi->devIds[i] == auhalHostApi->defaultOut)
+ (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
+ (*hostApi)->info.deviceCount++;
}
- if (macCoreHostApi->macCoreDeviceIds[i] == defaultOutputDevice) {
- hostApi->info.defaultOutputDevice = i;
+ else
+ { /* there was an error. we need to shift the devices down, so we ignore this one */
+ int j;
+ auhalHostApi->devCount--;
+ for( j=i; j<auhalHostApi->devCount; ++j )
+ auhalHostApi->devIds[j] = auhalHostApi->devIds[j+1];
+ i--;
}
- InitializeDeviceInfo(&deviceInfoArray[i], macCoreHostApi->macCoreDeviceIds[i], hostApiIndex);
- hostApi->deviceInfos[i] = &(deviceInfoArray[i].inheritedDeviceInfo);
}
}
- return result;
-}
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &auhalHostApi->callbackStreamInterface,
+ CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped,
+ IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyRead, PaUtil_DummyWrite,
+ PaUtil_DummyGetReadAvailable,
+ PaUtil_DummyGetWriteAvailable );
+
+ PaUtil_InitializeStreamInterface( &auhalHostApi->blockingStreamInterface,
+ CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped,
+ IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream,
+ GetStreamReadAvailable,
+ GetStreamWriteAvailable );
-static OSStatus CheckFormat(AudioDeviceID macCoreDeviceId, const PaStreamParameters *parameters, double sampleRate, int isInput)
-{
- UInt32 propSize = sizeof(AudioStreamBasicDescription);
- AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(propSize);
-
- streamDescription->mSampleRate = sampleRate;
- streamDescription->mFormatID = 0;
- streamDescription->mFormatFlags = 0;
- streamDescription->mBytesPerPacket = 0;
- streamDescription->mFramesPerPacket = 0;
- streamDescription->mBytesPerFrame = 0;
- streamDescription->mChannelsPerFrame = 0;
- streamDescription->mBitsPerChannel = 0;
- streamDescription->mReserved = 0;
-
- OSStatus result = AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &propSize, streamDescription);
- PaUtil_FreeMemory(streamDescription);
return result;
-}
-static OSStatus CopyInputData(PaMacClientData* destination, const AudioBufferList *source, unsigned long frameCount)
-{
- int frameSpacing, channelSpacing;
- if (destination->inputSampleFormat & paNonInterleaved) {
- frameSpacing = 1;
- channelSpacing = destination->inputChannelCount;
- }
- else {
- frameSpacing = destination->inputChannelCount;
- channelSpacing = 1;
- }
-
- AudioBuffer const *inputBuffer = &source->mBuffers[0];
- void *coreAudioBuffer = inputBuffer->mData;
- void *portAudioBuffer = destination->inputBuffer;
- UInt32 i, streamNumber, streamChannel;
- for (i = streamNumber = streamChannel = 0; i < destination->inputChannelCount; ++i, ++streamChannel) {
- if (streamChannel >= inputBuffer->mNumberChannels) {
- ++streamNumber;
- inputBuffer = &source->mBuffers[streamNumber];
- coreAudioBuffer = inputBuffer->mData;
- streamChannel = 0;
+error:
+ if( auhalHostApi )
+ {
+ if( auhalHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( auhalHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( auhalHostApi->allocations );
}
- destination->inputConverter(portAudioBuffer, frameSpacing, coreAudioBuffer, inputBuffer->mNumberChannels, frameCount, destination->ditherGenerator);
- coreAudioBuffer += sizeof(Float32);
- portAudioBuffer += Pa_GetSampleSize(destination->inputSampleFormat) * channelSpacing;
+
+ PaUtil_FreeMemory( auhalHostApi );
}
+ return result;
}
-static OSStatus CopyOutputData(AudioBufferList* destination, PaMacClientData *source, unsigned long frameCount)
-{
- int frameSpacing, channelSpacing;
- if (source->outputSampleFormat & paNonInterleaved) {
- frameSpacing = 1;
- channelSpacing = source->outputChannelCount;
- }
- else {
- frameSpacing = source->outputChannelCount;
- channelSpacing = 1;
- }
-
- AudioBuffer *outputBuffer = &destination->mBuffers[0];
- void *coreAudioBuffer = outputBuffer->mData;
- void *portAudioBuffer = source->outputBuffer;
- UInt32 i, streamNumber, streamChannel;
- for (i = streamNumber = streamChannel = 0; i < source->outputChannelCount; ++i, ++streamChannel) {
- if (streamChannel >= outputBuffer->mNumberChannels) {
- ++streamNumber;
- outputBuffer = &destination->mBuffers[streamNumber];
- coreAudioBuffer = outputBuffer->mData;
- streamChannel = 0;
- }
- source->outputConverter(coreAudioBuffer, outputBuffer->mNumberChannels, portAudioBuffer, frameSpacing, frameCount, NULL);
- coreAudioBuffer += sizeof(Float32);
- portAudioBuffer += Pa_GetSampleSize(source->outputSampleFormat) * channelSpacing;
- }
-}
-static OSStatus AudioIOProc( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* inClientData)
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
{
- PaMacClientData *clientData = (PaMacClientData *)inClientData;
- PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
-
- PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
-
- AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
- unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
+ PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi;
- if (clientData->inputBuffer) {
- CopyInputData(clientData, inInputData, frameCount);
- }
- PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
- if (clientData->outputBuffer) {
- CopyOutputData(outOutputData, clientData, frameCount);
- }
+ VVDBUG(("Terminate()\n"));
- PaUtil_FreeMemory(timeInfo);
- PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
-
- if (result == paComplete || result == paAbort) {
- Pa_StopStream(clientData->stream);
- }
-}
+ /*
+ IMPLEMENT ME:
+ - clean up any resources not handled by the allocation group
+ TODO: Double check that everything is handled by alloc group
+ */
-// This is not for input-only streams, this is for streams where the input device is different from the output device
-// TODO: This needs to store the output data in a buffer, to be written to the device the next time AudioOutputProc is called
-static OSStatus AudioInputProc( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* inClientData)
-{
- PaMacClientData *clientData = (PaMacClientData *)inClientData;
- PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
-
- PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
-
- AudioBuffer const *inputBuffer = &inInputData->mBuffers[0];
- unsigned long frameCount = inputBuffer->mDataByteSize / (inputBuffer->mNumberChannels * sizeof(Float32));
+ if( auhalHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( auhalHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( auhalHostApi->allocations );
+ }
- CopyInputData(clientData, inInputData, frameCount);
- clientData->callback(clientData->inputBuffer, NULL, frameCount, timeInfo, paNoFlag, clientData->userData);
-
- PaUtil_FreeMemory(timeInfo);
- PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
+ PaUtil_FreeMemory( auhalHostApi );
}
-// This is not for output-only streams, this is for streams where the input device is different from the output device
-static OSStatus AudioOutputProc( AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* inClientData)
+
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
{
- PaMacClientData *clientData = (PaMacClientData *)inClientData;
- PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ VVDBUG(("IsFormatSupported(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld sampleRate=%g\n",
+ inputParameters ? inputParameters->channelCount : -1,
+ inputParameters ? inputParameters->sampleFormat : -1,
+ outputParameters ? outputParameters->channelCount : -1,
+ outputParameters ? outputParameters->sampleFormat : -1,
+ (float) sampleRate ));
+
+ /** These first checks are standard PA checks. We do some fancier checks
+ later. */
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* all standard sample formats are supported by the buffer adapter,
+ this implementation doesn't support any custom sample formats */
+ if( inputSampleFormat & paCustomFormat )
+ return paSampleFormatNotSupported;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
- PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
- AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
- unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
+ /* all standard sample formats are supported by the buffer adapter,
+ this implementation doesn't support any custom sample formats */
+ if( outputSampleFormat & paCustomFormat )
+ return paSampleFormatNotSupported;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
- clientData->callback(NULL, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
- CopyOutputData(outOutputData, clientData, frameCount);
- PaUtil_FreeMemory(timeInfo);
- PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
-}
+ /* check that output device can support outputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
-static PaError SetSampleRate(AudioDeviceID device, double sampleRate, int isInput)
-{
- PaError result = paNoError;
-
- double actualSampleRate;
- UInt32 propSize = sizeof(double);
- result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyNominalSampleRate, propSize, &sampleRate));
-
- result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSampleRate));
-
- if (result == paNoError && actualSampleRate != sampleRate) {
- result = paInvalidSampleRate;
}
-
- return result;
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ /* FEEDBACK */
+ /* I think the only way to check a given format SR combo is */
+ /* to try opening it. This could be disruptive, is that Okay? */
+ /* The alternative is to just read off available sample rates, */
+ /* but this will not work %100 of the time (eg, a device that */
+ /* supports N output at one rate but only N/2 at a higher rate.)*/
+
+ /* The following code opens the device with the requested parameters to
+ see if it works. */
+ {
+ PaError err;
+ PaStream *s;
+ err = OpenStream( hostApi, &s, inputParameters, outputParameters,
+ sampleRate, 1024, 0, (PaStreamCallback *)1, NULL );
+ if( err != paNoError && err != paInvalidSampleRate )
+ DBUG( ( "OpenStream @ %g returned: %d: %s\n",
+ (float) sampleRate, err, Pa_GetErrorText( err ) ) );
+ if( err )
+ return err;
+ err = CloseStream( s );
+ if( err ) {
+ /* FEEDBACK: is this more serious? should we assert? */
+ DBUG( ( "WARNING: could not close Stream. %d: %s\n",
+ err, Pa_GetErrorText( err ) ) );
+ }
+ }
+
+ return paFormatIsSupported;
}
-static PaError SetFramesPerBuffer(AudioDeviceID device, unsigned long framesPerBuffer, int isInput)
+static PaError OpenAndSetupOneAudioUnit(
+ const PaStreamParameters *inStreamParams,
+ const PaStreamParameters *outStreamParams,
+ const unsigned long requestedFramesPerBuffer,
+ unsigned long *actualInputFramesPerBuffer,
+ unsigned long *actualOutputFramesPerBuffer,
+ const PaMacAUHAL *auhalHostApi,
+ AudioUnit *audioUnit,
+ AudioConverterRef *srConverter,
+ AudioDeviceID *audioDevice,
+ const double sampleRate,
+ void *refCon )
{
- PaError result = paNoError;
- UInt32 preferredFramesPerBuffer = framesPerBuffer;
- // while (preferredFramesPerBuffer > UINT32_MAX) {
- // preferredFramesPerBuffer /= 2;
- // }
-
- UInt32 actualFramesPerBuffer;
- UInt32 propSize = sizeof(UInt32);
- result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propSize, &preferredFramesPerBuffer));
-
- result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &actualFramesPerBuffer));
-
- if (result != paNoError) {
- // do nothing
+ ComponentDescription desc;
+ Component comp;
+ /*An Apple TN suggests using CAStreamBasicDescription, but that is C++*/
+ AudioStreamBasicDescription desiredFormat;
+ OSErr result = noErr;
+ PaError paResult = paNoError;
+ int line;
+ UInt32 callbackKey;
+ AURenderCallbackStruct rcbs;
+ unsigned long macInputStreamFlags = paMacCorePlayNice;
+ unsigned long macOutputStreamFlags = paMacCorePlayNice;
+
+ VVDBUG(("OpenAndSetupOneAudioUnit(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld, requestedFramesPerBuffer=%ld\n",
+ inStreamParams ? inStreamParams->channelCount : -1,
+ inStreamParams ? inStreamParams->sampleFormat : -1,
+ outStreamParams ? outStreamParams->channelCount : -1,
+ outStreamParams ? outStreamParams->sampleFormat : -1,
+ requestedFramesPerBuffer ));
+
+ /* -- handle the degenerate case -- */
+ if( !inStreamParams && !outStreamParams ) {
+ *audioUnit = NULL;
+ *audioDevice = kAudioDeviceUnknown;
+ return paNoError;
}
- else if (actualFramesPerBuffer > framesPerBuffer) {
- result = paBufferTooSmall;
+
+ /* -- get the user's api specific info, if they set any -- */
+ if( inStreamParams && inStreamParams->hostApiSpecificStreamInfo )
+ macInputStreamFlags=
+ ((paMacCoreStreamInfo*)inStreamParams->hostApiSpecificStreamInfo)
+ ->flags;
+ if( outStreamParams && outStreamParams->hostApiSpecificStreamInfo )
+ macOutputStreamFlags=
+ ((paMacCoreStreamInfo*)outStreamParams->hostApiSpecificStreamInfo)
+ ->flags;
+ /* Override user's flags here, if desired for testing. */
+
+ /*
+ * The HAL AU is a Mac OS style "component".
+ * the first few steps deal with that.
+ * Later steps work on a combination of Mac OS
+ * components and the slightly lower level
+ * HAL.
+ */
+
+ /* -- describe the output type AudioUnit -- */
+ /* Note: for the default AudioUnit, we could use the
+ * componentSubType value kAudioUnitSubType_DefaultOutput;
+ * but I don't think that's relevant here.
+ */
+ desc.componentType = kAudioUnitType_Output;
+ desc.componentSubType = kAudioUnitSubType_HALOutput;
+ desc.componentManufacturer = kAudioUnitManufacturer_Apple;
+ desc.componentFlags = 0;
+ desc.componentFlagsMask = 0;
+ /* -- find the component -- */
+ comp = FindNextComponent( NULL, &desc );
+ if( !comp )
+ {
+ DBUG( ( "AUHAL component not found." ) );
+ *audioUnit = NULL;
+ *audioDevice = kAudioDeviceUnknown;
+ return paUnanticipatedHostError;
}
- else if (actualFramesPerBuffer < framesPerBuffer) {
- result = paBufferTooBig;
+ /* -- open it -- */
+ result = OpenAComponent( comp, audioUnit );
+ if( result )
+ {
+ DBUG( ( "Failed to open AUHAL component." ) );
+ *audioUnit = NULL;
+ *audioDevice = kAudioDeviceUnknown;
+ return ERR( result );
}
-
- return result;
-}
-
-static PaError SetUpUnidirectionalStream(AudioDeviceID device, double sampleRate, unsigned long framesPerBuffer, int isInput)
-{
- PaError err = paNoError;
- err = SetSampleRate(device, sampleRate, isInput);
- if( err == paNoError )
- err = SetFramesPerBuffer(device, framesPerBuffer, isInput);
- return err;
-}
-
-// ===== PortAudio functions =====
-#pragma mark PortAudio functions
+ /* -- prepare a little error handling logic / hackery -- */
+#define ERR_WRAP(mac_err) do { result = mac_err ; line = __LINE__ ; if ( result != noErr ) goto error ; } while(0)
-#ifdef __cplusplus
-extern "C"
-{
-#endif // __cplusplus
-
- PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
+ /* -- if there is input, we have to explicitly enable input -- */
+ if( inStreamParams )
+ {
+ UInt32 enableIO;
+ enableIO = 1;
+ ERR_WRAP( AudioUnitSetProperty( *audioUnit,
+ kAudioOutputUnitProperty_EnableIO,
+ kAudioUnitScope_Input,
+ INPUT_ELEMENT,
+ &enableIO,
+ sizeof(enableIO) ) );
+ }
+ /* -- if there is no output, we must explicitly disable output -- */
+ if( !outStreamParams )
+ {
+ UInt32 enableIO;
+ enableIO = 0;
+ ERR_WRAP( AudioUnitSetProperty( *audioUnit,
+ kAudioOutputUnitProperty_EnableIO,
+ kAudioUnitScope_Output,
+ OUTPUT_ELEMENT,
+ &enableIO,
+ sizeof(enableIO) ) );
+ }
+ /* -- set the devices -- */
+ /* make sure input and output are the same device if we are doing input and
+ output. */
+ if( inStreamParams && outStreamParams )
+ assert( outStreamParams->device == inStreamParams->device );
+ if( inStreamParams )
+ {
+ *audioDevice = auhalHostApi->devIds[inStreamParams->device] ;
+ ERR_WRAP( AudioUnitSetProperty( *audioUnit,
+ kAudioOutputUnitProperty_CurrentDevice,
+ kAudioUnitScope_Global,
+ INPUT_ELEMENT,
+ audioDevice,
+ sizeof(AudioDeviceID) ) );
+ }
+ if( outStreamParams )
+ {
+ *audioDevice = auhalHostApi->devIds[outStreamParams->device] ;
+ ERR_WRAP( AudioUnitSetProperty( *audioUnit,
+ kAudioOutputUnitProperty_CurrentDevice,
+ kAudioUnitScope_Global,
+ OUTPUT_ELEMENT,
+ audioDevice,
+ sizeof(AudioDeviceID) ) );
+ }
-static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
-{
- PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
-
- CleanUp(macCoreHostApi);
-}
+ /* -- set format -- */
+ bzero( &desiredFormat, sizeof(desiredFormat) );
+ desiredFormat.mFormatID = kAudioFormatLinearPCM ;
+ desiredFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
+ desiredFormat.mFramesPerPacket = 1;
+ desiredFormat.mBitsPerChannel = sizeof( float ) * 8;
+
+ result = 0;
+ /* set device format first, but only touch the device if the user asked */
+ if( inStreamParams ) {
+ /*The callback never calls back if we don't set the FPB */
+ /*This seems wierd, because I would think setting anything on the device
+ would be disruptive.*/
+ paResult = setBestFramesPerBuffer( *audioDevice, FALSE,
+ requestedFramesPerBuffer,
+ actualInputFramesPerBuffer );
+ if( paResult ) goto error;
+ if( macInputStreamFlags & paMacCore_ChangeDeviceParameters ) {
+ bool requireExact;
+ requireExact=macInputStreamFlags&paMacCore_FailIfConversionRequired;
+ paResult = setBestSampleRateForDevice( *audioDevice, FALSE,
+ requireExact, sampleRate );
+ if( paResult ) goto error;
+ }
+ if( actualInputFramesPerBuffer && actualOutputFramesPerBuffer )
+ *actualOutputFramesPerBuffer = *actualInputFramesPerBuffer ;
+ }
+ if( outStreamParams && !inStreamParams ) {
+ /*The callback never calls back if we don't set the FPB */
+ /*This seems wierd, because I would think setting anything on the device
+ would be disruptive.*/
+ paResult = setBestFramesPerBuffer( *audioDevice, TRUE,
+ requestedFramesPerBuffer,
+ actualOutputFramesPerBuffer );
+ if( paResult ) goto error;
+ if( macOutputStreamFlags & paMacCore_ChangeDeviceParameters ) {
+ bool requireExact;
+ requireExact=macOutputStreamFlags&paMacCore_FailIfConversionRequired;
+ paResult = setBestSampleRateForDevice( *audioDevice, TRUE,
+ requireExact, sampleRate );
+ if( paResult ) goto error;
+ }
+ }
-static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
- const PaStreamParameters *inputParameters,
- const PaStreamParameters *outputParameters,
- double sampleRate )
-{
- PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
- PaDeviceInfo *deviceInfo;
-
- PaError result = paNoError;
- if (inputParameters) {
- deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
- if (inputParameters->channelCount > deviceInfo->maxInputChannels)
- result = paInvalidChannelCount;
- else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[inputParameters->device], inputParameters, sampleRate, 1) != kAudioHardwareNoError) {
- result = paInvalidSampleRate;
- }
+ /* -- set the quality of the output converter -- */
+ if( outStreamParams ) {
+ UInt32 value = kAudioConverterQuality_Max;
+ switch( macOutputStreamFlags & 0x0700 ) {
+ case 0x0100: /*paMacCore_ConversionQualityMin:*/
+ value=kRenderQuality_Min;
+ break;
+ case 0x0200: /*paMacCore_ConversionQualityLow:*/
+ value=kRenderQuality_Low;
+ break;
+ case 0x0300: /*paMacCore_ConversionQualityMedium:*/
+ value=kRenderQuality_Medium;
+ break;
+ case 0x0400: /*paMacCore_ConversionQualityHigh:*/
+ value=kRenderQuality_High;
+ break;
+ }
+ ERR_WRAP( AudioUnitSetProperty( *audioUnit,
+ kAudioUnitProperty_RenderQuality,
+ kAudioUnitScope_Global,
+ OUTPUT_ELEMENT,
+ &value,
+ sizeof(value) ) );
}
- if (outputParameters && result == paNoError) {
- deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
- if (outputParameters->channelCount > deviceInfo->maxOutputChannels)
- result = paInvalidChannelCount;
- else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[outputParameters->device], outputParameters, sampleRate, 0) != kAudioHardwareNoError) {
- result = paInvalidSampleRate;
- }
+ /* now set the format on the Audio Units. */
+ if( outStreamParams )
+ {
+ desiredFormat.mSampleRate =sampleRate;
+ desiredFormat.mBytesPerPacket=sizeof(float)*outStreamParams->channelCount;
+ desiredFormat.mBytesPerFrame =sizeof(float)*outStreamParams->channelCount;
+ desiredFormat.mChannelsPerFrame = outStreamParams->channelCount;
+ ERR_WRAP( AudioUnitSetProperty( *audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ OUTPUT_ELEMENT,
+ &desiredFormat,
+ sizeof(AudioStreamBasicDescription) ) );
+ }
+ if( inStreamParams )
+ {
+ AudioStreamBasicDescription sourceFormat;
+ UInt32 size = sizeof( AudioStreamBasicDescription );
+
+ /* keep the sample rate of the device, or we confuse AUHAL */
+ ERR_WRAP( AudioUnitGetProperty( *audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ INPUT_ELEMENT,
+ &sourceFormat,
+ &size ) );
+ desiredFormat.mSampleRate = sourceFormat.mSampleRate;
+ desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount;
+ desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount;
+ desiredFormat.mChannelsPerFrame = inStreamParams->channelCount;
+ ERR_WRAP( AudioUnitSetProperty( *audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Output,
+ INPUT_ELEMENT,
+ &desiredFormat,
+ sizeof(AudioStreamBasicDescription) ) );
+ }
+ /* set the maximumFramesPerSlice */
+ /* not doing this causes real problems
+ (eg. the callback might not be called). The idea of setting both this
+ and the frames per buffer on the device is that we'll be most likely
+ to actually get the frame size we requested in the callback with the
+ minimum latency. */
+ if( outStreamParams ) {
+ UInt32 size = sizeof( *actualOutputFramesPerBuffer );
+ ERR_WRAP( AudioUnitSetProperty( *audioUnit,
+ kAudioUnitProperty_MaximumFramesPerSlice,
+ kAudioUnitScope_Input,
+ OUTPUT_ELEMENT,
+ actualOutputFramesPerBuffer,
+ sizeof(unsigned long) ) );
+ ERR_WRAP( AudioUnitGetProperty( *audioUnit,
+ kAudioUnitProperty_MaximumFramesPerSlice,
+ kAudioUnitScope_Global,
+ OUTPUT_ELEMENT,
+ actualOutputFramesPerBuffer,
+ &size ) );
+ }
+ if( inStreamParams ) {
+ /*UInt32 size = sizeof( *actualInputFramesPerBuffer );*/
+ ERR_WRAP( AudioUnitSetProperty( *audioUnit,
+ kAudioUnitProperty_MaximumFramesPerSlice,
+ kAudioUnitScope_Output,
+ INPUT_ELEMENT,
+ actualInputFramesPerBuffer,
+ sizeof(unsigned long) ) );
+/* Don't know why this causes problems
+ ERR_WRAP( AudioUnitGetProperty( *audioUnit,
+ kAudioUnitProperty_MaximumFramesPerSlice,
+ kAudioUnitScope_Global, //Output,
+ INPUT_ELEMENT,
+ actualInputFramesPerBuffer,
+ &size ) );
+*/
}
- return result;
+ /* -- if we have input, we may need to setup an SR converter -- */
+ /* even if we got the sample rate we asked for, we need to do
+ the conversion in case another program changes the underlying SR. */
+ /* FIXME: I think we need to monitor stream and change the converter if the incoming format changes. */
+ if( inStreamParams ) {
+ AudioStreamBasicDescription desiredFormat;
+ AudioStreamBasicDescription sourceFormat;
+ UInt32 sourceSize = sizeof( sourceFormat );
+ bzero( &desiredFormat, sizeof(desiredFormat) );
+ desiredFormat.mSampleRate = sampleRate;
+ desiredFormat.mFormatID = kAudioFormatLinearPCM ;
+ desiredFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
+ desiredFormat.mFramesPerPacket = 1;
+ desiredFormat.mBitsPerChannel = sizeof( float ) * 8;
+ desiredFormat.mBytesPerPacket=sizeof(float)*inStreamParams->channelCount;
+ desiredFormat.mBytesPerFrame =sizeof(float)*inStreamParams->channelCount;
+ desiredFormat.mChannelsPerFrame = inStreamParams->channelCount;
+
+ /* get the source format */
+ ERR_WRAP( AudioUnitGetProperty(
+ *audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Output,
+ INPUT_ELEMENT,
+ &sourceFormat,
+ &sourceSize ) );
+
+ if( desiredFormat.mSampleRate != sourceFormat.mSampleRate )
+ {
+ UInt32 value = kAudioConverterQuality_Max;
+ switch( macInputStreamFlags & 0x0700 ) {
+ case 0x0100: /*paMacCore_ConversionQualityMin:*/
+ value=kAudioConverterQuality_Min;
+ break;
+ case 0x0200: /*paMacCore_ConversionQualityLow:*/
+ value=kAudioConverterQuality_Low;
+ break;
+ case 0x0300: /*paMacCore_ConversionQualityMedium:*/
+ value=kAudioConverterQuality_Medium;
+ break;
+ case 0x0400: /*paMacCore_ConversionQualityHigh:*/
+ value=kAudioConverterQuality_High;
+ break;
+ }
+ VDBUG(( "Creating sample rate converter for input"
+ " to convert from %g to %g\n",
+ (float)sourceFormat.mSampleRate,
+ (float)desiredFormat.mSampleRate ) );
+ /* create our converter */
+ ERR_WRAP( AudioConverterNew(
+ &sourceFormat,
+ &desiredFormat,
+ srConverter ) );
+ /* Set quality */
+ ERR_WRAP( AudioConverterSetProperty(
+ *srConverter,
+ kAudioConverterSampleRateConverterQuality,
+ sizeof( value ),
+ &value ) );
+ }
+ }
+ /* -- set IOProc (callback) -- */
+ callbackKey = outStreamParams ? kAudioUnitProperty_SetRenderCallback
+ : kAudioOutputUnitProperty_SetInputCallback ;
+ rcbs.inputProc = AudioIOProc;
+ rcbs.inputProcRefCon = refCon;
+ ERR_WRAP( AudioUnitSetProperty(
+ *audioUnit,
+ callbackKey,
+ kAudioUnitScope_Output,
+ outStreamParams ? OUTPUT_ELEMENT : INPUT_ELEMENT,
+ &rcbs,
+ sizeof(rcbs)) );
+
+ if( inStreamParams && outStreamParams && *srConverter )
+ ERR_WRAP( AudioUnitSetProperty(
+ *audioUnit,
+ kAudioOutputUnitProperty_SetInputCallback,
+ kAudioUnitScope_Output,
+ INPUT_ELEMENT,
+ &rcbs,
+ sizeof(rcbs)) );
+
+ /*IMPLEMENTME: may need to worry about channel mapping.*/
+
+ /* initialize the audio unit */
+ ERR_WRAP( AudioUnitInitialize(*audioUnit) );
+
+ if( inStreamParams && outStreamParams )
+ VDBUG( ("Opened device %ld for input and output.\n", *audioDevice ) );
+ else if( inStreamParams )
+ VDBUG( ("Opened device %ld for input.\n", *audioDevice ) );
+ else if( outStreamParams )
+ VDBUG( ("Opened device %ld for output.\n", *audioDevice ) );
+ return paNoError;
+#undef ERR_WRAP
+
+ error:
+ CloseComponent( *audioUnit );
+ *audioUnit = NULL;
+ if( result )
+ return PaMacCore_SetError( result, line, 1 );
+ return paResult;
}
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaStream** s,
const PaStreamParameters *inputParameters,
@@ -635,192 +1050,1012 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaStreamCallback *streamCallback,
void *userData )
{
- PaError err = paNoError;
- PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)hostApi;
- PaMacCoreStream *stream = PaUtil_AllocateMemory(sizeof(PaMacCoreStream));
- stream->isActive = 0;
- stream->isStopped = 1;
- stream->inputDevice = kAudioDeviceUnknown;
- stream->outputDevice = kAudioDeviceUnknown;
-
- PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
- ( (streamCallback)
- ? &macCoreHostApi->callbackStreamInterface
- : &macCoreHostApi->blockingStreamInterface ),
- streamCallback, userData );
- PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
-
- *s = (PaStream*)stream;
- PaMacClientData *clientData = PaUtil_AllocateMemory(sizeof(PaMacClientData));
- clientData->stream = stream;
- clientData->callback = streamCallback;
- clientData->userData = userData;
- clientData->inputBuffer = 0;
- clientData->outputBuffer = 0;
- clientData->ditherGenerator = PaUtil_AllocateMemory(sizeof(PaUtilTriangularDitherGenerator));
- PaUtil_InitializeTriangularDitherState(clientData->ditherGenerator);
-
- if (inputParameters != NULL) {
- stream->inputDevice = macCoreHostApi->macCoreDeviceIds[inputParameters->device];
- clientData->inputConverter = PaUtil_SelectConverter(paFloat32, inputParameters->sampleFormat, streamFlags);
- clientData->inputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(inputParameters->sampleFormat) * framesPerBuffer * inputParameters->channelCount);
- clientData->inputChannelCount = inputParameters->channelCount;
- clientData->inputSampleFormat = inputParameters->sampleFormat;
- err = SetUpUnidirectionalStream(stream->inputDevice, sampleRate, framesPerBuffer, 1);
+ PaError result = paNoError;
+ PaMacAUHAL *auhalHostApi = (PaMacAUHAL*)hostApi;
+ PaMacCoreStream *stream = 0;
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+ PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
+ VVDBUG(("OpenStream(): in chan=%d, in fmt=%ld, out chan=%d, out fmt=%ld SR=%g, FPB=%ld\n",
+ inputParameters ? inputParameters->channelCount : -1,
+ inputParameters ? inputParameters->sampleFormat : -1,
+ outputParameters ? outputParameters->channelCount : -1,
+ outputParameters ? outputParameters->sampleFormat : -1,
+ (float) sampleRate,
+ framesPerBuffer ));
+ VDBUG( ("Opening Stream.\n") );
+
+ /*These first few bits of code are from paSkeleton with few modifications.*/
+ 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;
+
+ /* Host supports interleaved float32 */
+ hostInputSampleFormat = paFloat32;
}
-
- if (err == paNoError && outputParameters != NULL) {
- stream->outputDevice = macCoreHostApi->macCoreDeviceIds[outputParameters->device];
- clientData->outputConverter = PaUtil_SelectConverter(outputParameters->sampleFormat, paFloat32, streamFlags);
- clientData->outputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(outputParameters->sampleFormat) * framesPerBuffer * outputParameters->channelCount);
- clientData->outputChannelCount = outputParameters->channelCount;
- clientData->outputSampleFormat = outputParameters->sampleFormat;
- err = SetUpUnidirectionalStream(stream->outputDevice, sampleRate, framesPerBuffer, 0);
+ else
+ {
+ inputChannelCount = 0;
+ inputSampleFormat = hostInputSampleFormat = paInt16; /* Surpress 'uninitialised var' warnings. */
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* Host supports interleaved float32 */
+ hostOutputSampleFormat = paFloat32;
+ }
+ else
+ {
+ outputChannelCount = 0;
+ outputSampleFormat = hostOutputSampleFormat = paFloat32; /* Surpress 'uninitialized var' warnings. */
}
- if (inputParameters == NULL || outputParameters == NULL || stream->inputDevice == stream->outputDevice) {
- AudioDeviceID device = (inputParameters == NULL) ? stream->outputDevice : stream->inputDevice;
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
- AudioDeviceAddIOProc(device, AudioIOProc, clientData);
+ stream = (PaMacCoreStream*)PaUtil_AllocateMemory( sizeof(PaMacCoreStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* If we fail after this point, we my be left in a bad state, with
+ some data structures setup and others not. So, first thing we
+ do is initialize everything so that if we fail, we know what hasn't
+ been touched.
+ */
+
+ stream->inputAudioBufferList.mBuffers[0].mData = NULL;
+ stream->inputRingBuffer.buffer = NULL;
+ stream->inputSRConverter = NULL;
+ stream->inputUnit = NULL;
+ stream->outputUnit = NULL;
+ stream->inputFramesPerBuffer = 0;
+ stream->outputFramesPerBuffer = 0;
+ stream->bufferProcessorIsInitialized = FALSE;
+
+ assert( streamCallback ) ; /* only callback mode is implemented */
+ if( streamCallback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &auhalHostApi->callbackStreamInterface, streamCallback, userData );
}
- else {
- // using different devices for input and output
- AudioDeviceAddIOProc(stream->inputDevice, AudioInputProc, clientData);
- AudioDeviceAddIOProc(stream->outputDevice, AudioOutputProc, clientData);
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &auhalHostApi->blockingStreamInterface, streamCallback, userData );
}
-
- return err;
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+ /* -- handle paFramesPerBufferUnspecified -- */
+ if( framesPerBuffer == paFramesPerBufferUnspecified ) {
+ long requested = 64;
+ if( inputParameters )
+ requested = MAX( requested, inputParameters->suggestedLatency * sampleRate / 2 );
+ if( outputParameters )
+ requested = MAX( requested, outputParameters->suggestedLatency *sampleRate / 2 );
+ VDBUG( ("Block Size unspecified. Based on Latency, the user wants a Block Size near: %ld.\n",
+ requested ) );
+ if( requested <= 64 ) {
+ /*requested a realtively low latency. make sure this is in range of devices */
+ /*try to get the device's min natural buffer size and use that (but no smaller than 64).*/
+ AudioValueRange audioRange;
+ size_t size = sizeof( audioRange );
+ if( inputParameters ) {
+ WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device],
+ 0,
+ false,
+ kAudioDevicePropertyBufferFrameSizeRange,
+ &size, &audioRange ) );
+ if( result )
+ requested = MAX( requested, audioRange.mMinimum );
+ }
+ if( outputParameters ) {
+ WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device],
+ 0,
+ false,
+ kAudioDevicePropertyBufferFrameSizeRange,
+ &size, &audioRange ) );
+ if( result )
+ requested = MAX( requested, audioRange.mMinimum );
+ }
+ } else {
+ /* requested a realtively high latency. make sure this is in range of devices */
+ /*try to get the device's max natural buffer size and use that (but no larger than 1024).*/
+ AudioValueRange audioRange;
+ size_t size = sizeof( audioRange );
+ requested = MIN( requested, 1024 );
+ if( inputParameters ) {
+ WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[inputParameters->device],
+ 0,
+ false,
+ kAudioDevicePropertyBufferFrameSizeRange,
+ &size, &audioRange ) );
+ if( result )
+ requested = MIN( requested, audioRange.mMaximum );
+ }
+ if( outputParameters ) {
+ WARNING( result = AudioDeviceGetProperty( auhalHostApi->devIds[outputParameters->device],
+ 0,
+ false,
+ kAudioDevicePropertyBufferFrameSizeRange,
+ &size, &audioRange ) );
+ if( result )
+ requested = MIN( requested, audioRange.mMaximum );
+ }
+ }
+ /* -- double check ranges -- */
+ if( requested > 1024 ) requested = 1024;
+ if( requested < 64 ) requested = 64;
+ VDBUG(("After querying hardware, setting block size to %ld.\n", requested));
+ framesPerBuffer = requested;
+ }
+
+ /* -- Now we actually open and setup streams. -- */
+ if( inputParameters && outputParameters && outputParameters->device == inputParameters->device )
+ { /* full duplex. One device. */
+ result = OpenAndSetupOneAudioUnit( inputParameters,
+ outputParameters,
+ framesPerBuffer,
+ &(stream->inputFramesPerBuffer),
+ &(stream->outputFramesPerBuffer),
+ auhalHostApi,
+ &(stream->inputUnit),
+ &(stream->inputSRConverter),
+ &(stream->inputDevice),
+ sampleRate,
+ stream );
+ stream->outputUnit = stream->inputUnit;
+ stream->outputDevice = stream->inputDevice;
+ if( result != paNoError )
+ goto error;
+ }
+ else
+ { /* full duplex, different devices OR simplex */
+ result = OpenAndSetupOneAudioUnit( NULL,
+ outputParameters,
+ framesPerBuffer,
+ NULL,
+ &(stream->outputFramesPerBuffer),
+ auhalHostApi,
+ &(stream->outputUnit),
+ NULL,
+ &(stream->outputDevice),
+ sampleRate,
+ stream );
+ if( result != paNoError )
+ goto error;
+ result = OpenAndSetupOneAudioUnit( inputParameters,
+ NULL,
+ framesPerBuffer,
+ &(stream->inputFramesPerBuffer),
+ NULL,
+ auhalHostApi,
+ &(stream->inputUnit),
+ &(stream->inputSRConverter),
+ &(stream->inputDevice),
+ sampleRate,
+ stream );
+ if( result != paNoError )
+ goto error;
+ }
+
+ if( stream->inputUnit ) {
+ const size_t szfl = sizeof(float);
+ /* setup the AudioBufferList used for input */
+ bzero( &stream->inputAudioBufferList, sizeof( AudioBufferList ) );
+ stream->inputAudioBufferList.mNumberBuffers = 1;
+ stream->inputAudioBufferList.mBuffers[0].mNumberChannels
+ = inputChannelCount;
+ stream->inputAudioBufferList.mBuffers[0].mDataByteSize
+ = stream->inputFramesPerBuffer*inputChannelCount*szfl;
+ stream->inputAudioBufferList.mBuffers[0].mData
+ = (float *) calloc(
+ stream->inputFramesPerBuffer*inputChannelCount,
+ szfl );
+ if( !stream->inputAudioBufferList.mBuffers[0].mData )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /*
+ * If input and output devs are different or we are doing SR conversion,
+ * we also need a
+ * ring buffer to store inpt data while waiting for output
+ * data.
+ */
+ if( (stream->outputUnit && stream->inputUnit != stream->outputUnit)
+ || stream->inputSRConverter )
+ {
+ /* May want the ringSize ot initial position in
+ ring buffer to depend somewhat on sample rate change */
+ /* Calculate an appropriate ring buffer size. It must be at least
+ 3x framesPerBuffer and 2x suggested latency and it must be a
+ power of 2. FEEDBACK: too liberal/conservative/another way?*/
+ double latency;
+ int index, i;
+ void *data;
+ long ringSize;
+ if( !outputParameters )
+ latency = inputParameters->suggestedLatency;
+ else
+ latency = MAX( inputParameters->suggestedLatency,
+ outputParameters->suggestedLatency );
+ ringSize = latency * sampleRate * 2 * inputChannelCount;
+ VDBUG( ( "suggested latency: %d\n", (int) (latency*sampleRate) ) );
+ if( ringSize < stream->inputFramesPerBuffer * 3 )
+ ringSize = stream->inputFramesPerBuffer * 3 * inputChannelCount;
+ if( outputParameters && ringSize < stream->outputFramesPerBuffer * 3 )
+ ringSize = stream->outputFramesPerBuffer * 3 * inputChannelCount;
+ VDBUG(("inFramesPerBuffer:%d\n",(int)stream->inputFramesPerBuffer));
+ if( outputParameters )
+ VDBUG(("outFramesPerBuffer:%d\n",
+ (int)stream->outputFramesPerBuffer));
+ VDBUG(("Ringbuffer size (1): %d\n", (int)ringSize ));
+
+ /* round up to the next power of 2 */
+ index = -1;
+ for( i=0; i<sizeof(long)*8; ++i )
+ if( ringSize >> i & 0x01 )
+ index = i;
+ assert( index > 0 );
+ if( ringSize <= ( 0x01 << index ) )
+ ringSize = 0x01 << index ;
+ else
+ ringSize = 0x01 << ( index + 1 );
+
+ /*ringSize <<= 4; *//*16x bigger, for testing */
+
+ VDBUG(( "Final Ringbuffer size (2): %d\n", (int)ringSize ));
+
+ /*now, we need to allocate memory for the ring buffer*/
+ data = calloc( ringSize, szfl );
+ if( !data )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* now we can initialize the ring buffer */
+ assert( 0 ==
+ RingBuffer_Init( &stream->inputRingBuffer,
+ ringSize*szfl, data ) );
+ /* advance the read point a little, so we are reading from the
+ middle of the buffer */
+ if( stream->outputUnit )
+ RingBuffer_AdvanceWriteIndex( &stream->inputRingBuffer, ringSize*szfl / RING_BUFFER_ADVANCE_DENOMINATOR );
+ }
+ }
+
+ /* -- initialize Buffer Processor -- */
+ {
+ unsigned long maxHostFrames = stream->inputFramesPerBuffer;
+ if( stream->outputFramesPerBuffer > maxHostFrames )
+ maxHostFrames = stream->outputFramesPerBuffer;
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ inputChannelCount, inputSampleFormat,
+ hostInputSampleFormat,
+ outputChannelCount, outputSampleFormat,
+ hostOutputSampleFormat,
+ sampleRate,
+ streamFlags,
+ framesPerBuffer,
+ /* If sample rate conversion takes place, the buffer size
+ will not be known. */
+ maxHostFrames,
+ stream->inputSRConverter
+ ? paUtilUnknownHostBufferSize
+ : paUtilBoundedHostBufferSize,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+ }
+ stream->bufferProcessorIsInitialized = TRUE;
+
+ /*
+ IMPLEMENT ME: initialise the following fields with estimated or actual
+ values.
+ I think this is okay the way it is br 12/1/05
+ maybe need to change input latency estimate if IO devs differ
+ */
+ stream->streamRepresentation.streamInfo.inputLatency =
+ PaUtil_GetBufferProcessorInputLatency(&stream->bufferProcessor);
+ stream->streamRepresentation.streamInfo.outputLatency =
+ PaUtil_GetBufferProcessorOutputLatency(&stream->bufferProcessor);
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+ stream->sampleRate = sampleRate;
+ stream->userInChan = inputChannelCount;
+ stream->userOutChan = outputChannelCount;
+
+ //stream->isTimeSet = FALSE;
+ stream->state = STOPPED;
+ stream->xrunFlags = 0;
+
+ *s = (PaStream*)stream;
+
+ setStreamStartTime( stream );
+
+ return result;
+
+error:
+ CloseStream( stream );
+ return result;
}
-// Note: When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted.
-static PaError CloseStream( PaStream* s )
+PaTime GetStreamTime( PaStream *s )
{
- PaError err = paNoError;
+ /* FIXME: I am not at all sure this timing info stuff is right.
+ patest_sine_time reports negative latencies, which is wierd.*/
PaMacCoreStream *stream = (PaMacCoreStream*)s;
+ AudioTimeStamp timeStamp;
- PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
+ VVDBUG(("GetStreamTime()\n"));
- if (stream->inputDevice != kAudioDeviceUnknown) {
- if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
- err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioIOProc));
- }
- else {
- err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioInputProc));
- err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioOutputProc));
- }
- }
- else {
- err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioIOProc));
+ //if ( !stream->isTimeSet )
+ // return (PaTime)0;
+
+ if ( stream->outputDevice )
+ AudioDeviceGetCurrentTime( stream->outputDevice, &timeStamp);
+ else if ( stream->inputDevice )
+ AudioDeviceGetCurrentTime( stream->inputDevice, &timeStamp);
+ else
+ return (PaTime)0;
+
+ return (PaTime)(timeStamp.mSampleTime - stream->startTime.mSampleTime)/stream->sampleRate;
+}
+
+static void setStreamStartTime( PaStream *stream )
+{
+ /* FIXME: I am not at all sure this timing info stuff is right.
+ patest_sine_time reports negative latencies, which is wierd.*/
+ VVDBUG(("setStreamStartTime()\n"));
+ PaMacCoreStream *s = (PaMacCoreStream *) stream;
+ if( s->inputDevice )
+ AudioDeviceGetCurrentTime( s->inputDevice, &s->startTime);
+ else
+ AudioDeviceGetCurrentTime( s->outputDevice, &s->startTime);
+}
+
+
+static PaTime TimeStampToSecs(PaMacCoreStream *stream, const AudioTimeStamp* timeStamp)
+{
+ VVDBUG(("TimeStampToSecs()\n"));
+ if (timeStamp->mFlags & kAudioTimeStampSampleTimeValid)
+ return (timeStamp->mSampleTime / stream->sampleRate);
+ else
+ return 0;
+}
+
+#define RING_BUFFER_EMPTY (1000)
+
+static OSStatus ringBufferIOProc( AudioConverterRef inAudioConverter,
+ UInt32*ioDataSize,
+ void** outData,
+ void*inUserData )
+{
+ void *dummyData;
+ long dummySize;
+ RingBuffer *rb = (RingBuffer *) inUserData;
+
+ VVDBUG(("ringBufferIOProc()\n"));
+
+ assert( sizeof( UInt32 ) == sizeof( long ) );
+ if( RingBuffer_GetReadAvailable( rb ) == 0 ) {
+ *outData = NULL;
+ *ioDataSize = 0;
+ return RING_BUFFER_EMPTY;
+ }
+ RingBuffer_GetReadRegions( rb, *ioDataSize,
+ outData, (long *)ioDataSize,
+ &dummyData, &dummySize );
+
+ assert( *ioDataSize );
+ RingBuffer_AdvanceReadIndex( rb, *ioDataSize );
+
+ return noErr;
+}
+
+/*
+ * Called by the AudioUnit API to process audio from the sound card.
+ * This is where the magic happens.
+ */
+/* FEEDBACK: there is a lot of redundant code here because of how all the cases differ. This makes it hard to maintain, so if there are suggestinos for cleaning it up, I'm all ears. */
+static OSStatus AudioIOProc( void *inRefCon,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList *ioData )
+{
+ unsigned long framesProcessed = 0;
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0};
+ PaMacCoreStream *stream = (PaMacCoreStream*)inRefCon;
+ const bool isRender = inBusNumber == OUTPUT_ELEMENT;
+ int callbackResult = paContinue ;
+
+ VVDBUG(("AudioIOProc()\n"));
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ //if( !stream->isTimeSet )
+ // setStreamStartTime( stream );
+ //stream->isTimeSet = TRUE;
+
+
+ /* -----------------------------------------------------------------*\
+ This output may be useful for debugging,
+ But printing durring the callback is a bad enough idea that
+ this is not enabled by enableing the usual debugging calls.
+ \* -----------------------------------------------------------------*/
+ /*
+ static int renderCount = 0;
+ static int inputCount = 0;
+ printf( "------------------- starting reder/input\n" );
+ if( isRender )
+ printf("Render callback (%d):\t", ++renderCount);
+ else
+ printf("Input callback (%d):\t", ++inputCount);
+ printf( "Call totals: %d (input), %d (render)\n", inputCount, renderCount );
+
+ printf( "--- inBusNumber: %lu\n", inBusNumber );
+ printf( "--- inNumberFrames: %lu\n", inNumberFrames );
+ printf( "--- %x ioData\n", (unsigned) ioData );
+ if( ioData )
+ {
+ int i=0;
+ printf( "--- ioData.mNumBuffers %lu: \n", ioData->mNumberBuffers );
+ for( i=0; i<ioData->mNumberBuffers; ++i )
+ printf( "--- ioData buffer %d size: %lu.\n", i, ioData->mBuffers[i].mDataByteSize );
+ }
+ ----------------------------------------------------------------- */
+
+ if( isRender ) {
+ AudioTimeStamp currentTime;
+ timeInfo.outputBufferDacTime = TimeStampToSecs(stream, inTimeStamp);
+ AudioDeviceGetCurrentTime(stream->outputDevice, &currentTime);
+ timeInfo.currentTime = TimeStampToSecs(stream, &currentTime);
+ }
+ if( isRender && stream->inputUnit == stream->outputUnit )
+ timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp);
+ if( !isRender ) {
+ AudioTimeStamp currentTime;
+ timeInfo.inputBufferAdcTime = TimeStampToSecs(stream, inTimeStamp);
+ AudioDeviceGetCurrentTime(stream->inputDevice, &currentTime);
+ timeInfo.currentTime = TimeStampToSecs(stream, &currentTime);
+ }
+
+
+ if( isRender && stream->inputUnit == stream->outputUnit
+ && !stream->inputSRConverter )
+ {
+ /* --------- Full Duplex, One Device, no SR Conversion -------
+ *
+ * This is the lowest latency case, and also the simplest.
+ * Input data and output data are available at the same time.
+ * we do not use the input SR converter or the input ring buffer.
+ *
+ */
+ OSErr err = 0;
+ unsigned long frames;
+
+ /* -- start processing -- */
+ PaUtil_BeginBufferProcessing( &(stream->bufferProcessor),
+ &timeInfo,
+ stream->xrunFlags );
+ stream->xrunFlags = 0;
+
+ /* -- compute frames. do some checks -- */
+ assert( ioData->mNumberBuffers == 1 );
+ assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan );
+ frames = ioData->mBuffers[0].mDataByteSize;
+ frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels;
+ /* -- copy and process input data -- */
+ err= AudioUnitRender(stream->inputUnit,
+ ioActionFlags,
+ inTimeStamp,
+ INPUT_ELEMENT,
+ inNumberFrames,
+ &stream->inputAudioBufferList );
+ /* FEEDBACK: I'm not sure what to do when this call fails */
+ assert( !err );
+
+ PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames );
+ PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
+ 0,
+ stream->inputAudioBufferList.mBuffers[0].mData,
+ stream->inputAudioBufferList.mBuffers[0].mNumberChannels);
+ /* -- Copy and process output data -- */
+ PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames );
+ PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor),
+ 0,
+ ioData->mBuffers[0].mData,
+ ioData->mBuffers[0].mNumberChannels);
+ /* -- complete processing -- */
+ framesProcessed =
+ PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
+ &callbackResult );
+ }
+ else if( isRender )
+ {
+ /* -------- Output Side of Full Duplex (Separate Devices or SR Conversion)
+ * -- OR Simplex Output
+ *
+ * This case handles output data as in the full duplex case,
+ * and, if there is input data, reads it off the ring buffer
+ * and into the PA buffer processor. If sample rate conversion
+ * is required on input, that is done here as well.
+ */
+ unsigned long frames;
+
+ /* Sometimes, when stopping a duplex stream we get erroneous
+ xrun flags, so if this is our last run, clear the flags. */
+ int xrunFlags = stream->xrunFlags;
+ if( xrunFlags & paInputUnderflow )
+ printf( "input underflow.\n" );
+ if( xrunFlags & paInputOverflow )
+ printf( "input overflow.\n" );
+ if( stream->state == STOPPING || stream->state == CALLBACK_STOPPED )
+ xrunFlags = 0;
+
+ /* -- start processing -- */
+ PaUtil_BeginBufferProcessing( &(stream->bufferProcessor),
+ &timeInfo,
+ xrunFlags );
+ stream->xrunFlags = 0; /* FEEDBACK: we only send flags to Buf Proc once */
+
+ /* -- Copy and process output data -- */
+ assert( ioData->mNumberBuffers == 1 );
+ frames = ioData->mBuffers[0].mDataByteSize;
+ frames /= sizeof( float ) * ioData->mBuffers[0].mNumberChannels;
+ assert( ioData->mBuffers[0].mNumberChannels == stream->userOutChan );
+ PaUtil_SetOutputFrameCount( &(stream->bufferProcessor), frames );
+ PaUtil_SetInterleavedOutputChannels( &(stream->bufferProcessor),
+ 0,
+ ioData->mBuffers[0].mData,
+ ioData->mBuffers[0].mNumberChannels);
+
+ /* -- copy and process input data, and complete processing -- */
+ if( stream->inputUnit ) {
+ const int flsz = sizeof( float );
+ /* Here, we read the data out of the ring buffer, through the
+ audio converter. */
+ int inChan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels;
+ if( stream->inputSRConverter )
+ {
+ OSStatus err;
+ UInt32 size;
+ float data[ inChan * frames ];
+ size = sizeof( data );
+ err = AudioConverterFillBuffer(
+ stream->inputSRConverter,
+ ringBufferIOProc,
+ &stream->inputRingBuffer,
+ &size,
+ (void *)&data );
+ if( err == RING_BUFFER_EMPTY )
+ { /*the ring buffer callback underflowed */
+ err = 0;
+ bzero( ((char *)data) + size, sizeof(data)-size );
+ stream->xrunFlags |= paInputUnderflow;
+ }
+ ERR( err );
+ assert( !err );
+
+ PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames );
+ PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
+ 0,
+ data,
+ inChan );
+ framesProcessed =
+ PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
+ &callbackResult );
+ }
+ else
+ {
+ /* Without the AudioConverter is actually a bit more complex
+ because we have to do a little buffer processing that the
+ AudioConverter would otherwise handle for us. */
+ void *data1, *data2;
+ long size1, size2;
+ RingBuffer_GetReadRegions( &stream->inputRingBuffer,
+ inChan*frames*flsz,
+ &data1, &size1,
+ &data2, &size2 );
+ if( size1 / ( flsz * inChan ) == frames ) {
+ /* simplest case: all in first buffer */
+ PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames );
+ PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
+ 0,
+ data1,
+ inChan );
+ framesProcessed =
+ PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
+ &callbackResult );
+ RingBuffer_AdvanceReadIndex(&stream->inputRingBuffer, size1 );
+ } else if( ( size1 + size2 ) / ( flsz * inChan ) < frames ) {
+ /*we underflowed. take what data we can, zero the rest.*/
+ float data[frames*inChan];
+ if( size1 )
+ memcpy( data, data1, size1 );
+ if( size2 )
+ memcpy( data+size1, data2, size2 );
+ bzero( data+size1+size2, frames*flsz*inChan - size1 - size2 );
+
+ PaUtil_SetInputFrameCount( &(stream->bufferProcessor), frames );
+ PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
+ 0,
+ data,
+ inChan );
+ framesProcessed =
+ PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
+ &callbackResult );
+ RingBuffer_AdvanceReadIndex( &stream->inputRingBuffer,
+ size1+size2 );
+ /* flag underflow */
+ stream->xrunFlags |= paInputUnderflow;
+ } else {
+ /*we got all the data, but split between buffers*/
+ PaUtil_SetInputFrameCount( &(stream->bufferProcessor),
+ size1 / ( flsz * inChan ) );
+ PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
+ 0,
+ data1,
+ inChan );
+ PaUtil_Set2ndInputFrameCount( &(stream->bufferProcessor),
+ size2 / ( flsz * inChan ) );
+ PaUtil_Set2ndInterleavedInputChannels( &(stream->bufferProcessor),
+ 0,
+ data2,
+ inChan );
+ framesProcessed =
+ PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
+ &callbackResult );
+ RingBuffer_AdvanceReadIndex(&stream->inputRingBuffer, size1+size2 );
+ }
+ }
+ } else {
+ framesProcessed =
+ PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
+ &callbackResult );
+ }
+
+ }
+ else
+ {
+ /* ------------------ Input
+ *
+ * First, we read off the audio data and put it in the ring buffer.
+ * if this is an input-only stream, we need to process it more,
+ * otherwise, we let the output case deal with it.
+ */
+ OSErr err = 0;
+ int chan = stream->inputAudioBufferList.mBuffers[0].mNumberChannels ;
+ /* FIXME: looping here may not actually be necessary, but it was something I tried in testing. */
+ do {
+ err= AudioUnitRender(stream->inputUnit,
+ ioActionFlags,
+ inTimeStamp,
+ INPUT_ELEMENT,
+ inNumberFrames,
+ &stream->inputAudioBufferList );
+ if( err == -10874 )
+ inNumberFrames /= 2;
+ } while( err == -10874 && inNumberFrames > 1 );
+ /* FEEDBACK: I'm not sure what to do when this call fails */
+ ERR( err );
+ assert( !err );
+ if( stream->inputSRConverter || stream->outputUnit )
+ {
+ /* If this is duplex or we use a converter, put the data
+ into the ring buffer. */
+ long bytesIn, bytesOut;
+ bytesIn = sizeof( float ) * inNumberFrames * chan;
+ bytesOut = RingBuffer_Write( &stream->inputRingBuffer,
+ stream->inputAudioBufferList.mBuffers[0].mData,
+ bytesIn );
+ if( bytesIn != bytesOut )
+ stream->xrunFlags |= paInputOverflow ;
+ }
+ else
+ {
+ /* for simplex input w/o SR conversion,
+ just pop the data into the buffer processor.*/
+ PaUtil_BeginBufferProcessing( &(stream->bufferProcessor),
+ &timeInfo,
+ stream->xrunFlags );
+ stream->xrunFlags = 0;
+
+ PaUtil_SetInputFrameCount( &(stream->bufferProcessor), inNumberFrames);
+ PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
+ 0,
+ stream->inputAudioBufferList.mBuffers[0].mData,
+ chan );
+ framesProcessed =
+ PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
+ &callbackResult );
+ }
+ if( !stream->outputUnit && stream->inputSRConverter )
+ {
+ /* ------------------ Simplex Input w/ SR Conversion
+ *
+ * if this is a simplex input stream, we need to read off the buffer,
+ * do our sample rate conversion and pass the results to the buffer
+ * processor.
+ * The logic here is complicated somewhat by the fact that we don't
+ * know how much data is available, so we loop on reasonably sized
+ * chunks, and let the BufferProcessor deal with the rest.
+ *
+ */
+ /*This might be too big or small depending on SR conversion*/
+ float data[ chan * inNumberFrames ];
+ OSStatus err;
+ do
+ { /*Run the buffer processor until we are out of data*/
+ UInt32 size;
+ long f;
+
+ size = sizeof( data );
+ err = AudioConverterFillBuffer(
+ stream->inputSRConverter,
+ ringBufferIOProc,
+ &stream->inputRingBuffer,
+ &size,
+ (void *)data );
+ if( err != RING_BUFFER_EMPTY )
+ ERR( err );
+ assert( err == 0 || err == RING_BUFFER_EMPTY );
+
+ f = size / ( chan * sizeof(float) );
+ PaUtil_SetInputFrameCount( &(stream->bufferProcessor), f );
+ if( f )
+ {
+ PaUtil_BeginBufferProcessing( &(stream->bufferProcessor),
+ &timeInfo,
+ stream->xrunFlags );
+ stream->xrunFlags = 0;
+
+ PaUtil_SetInterleavedInputChannels( &(stream->bufferProcessor),
+ 0,
+ data,
+ chan );
+ framesProcessed =
+ PaUtil_EndBufferProcessing( &(stream->bufferProcessor),
+ &callbackResult );
+ }
+ } while( callbackResult == paContinue && !err );
+ }
+ }
+
+ switch( callbackResult )
+ {
+ case paContinue: break;
+ case paComplete:
+ case paAbort:
+ stream->state = CALLBACK_STOPPED ;
+ if( stream->outputUnit )
+ AudioOutputUnitStop(stream->outputUnit);
+ if( stream->inputUnit )
+ AudioOutputUnitStop(stream->inputUnit);
+ break;
+ }
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+ return noErr;
+}
+
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ /* This may be called from a failed OpenStream.
+ Therefore, each piece of info is treated seperately. */
+ PaError result = paNoError;
+ PaMacCoreStream *stream = (PaMacCoreStream*)s;
+
+ VVDBUG(("CloseStream()\n"));
+ VDBUG( ( "Closing stream.\n" ) );
+
+ if( stream ) {
+ if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) {
+ AudioUnitUninitialize( stream->outputUnit );
+ CloseComponent( stream->outputUnit );
+ }
+ stream->outputUnit = NULL;
+ if( stream->inputUnit )
+ {
+ AudioUnitUninitialize( stream->inputUnit );
+ CloseComponent( stream->inputUnit );
+ stream->inputUnit = NULL;
+ }
+ if( stream->inputRingBuffer.buffer )
+ free( stream->inputRingBuffer.buffer );
+ stream->inputRingBuffer.buffer = NULL;
+ /*TODO: is there more that needs to be done on error
+ from AudioConverterDispose?*/
+ if( stream->inputSRConverter )
+ ERR( AudioConverterDispose( stream->inputSRConverter ) );
+ stream->inputSRConverter = NULL;
+ if( stream->inputAudioBufferList.mBuffers[0].mData )
+ free( stream->inputAudioBufferList.mBuffers[0].mData );
+ stream->inputAudioBufferList.mBuffers[0].mData = NULL;
+
+ if( stream->bufferProcessorIsInitialized )
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
}
-
- return err;
+
+ return result;
}
static PaError StartStream( PaStream *s )
{
- PaError err = paNoError;
PaMacCoreStream *stream = (PaMacCoreStream*)s;
+ OSErr result = noErr;
+ VVDBUG(("StartStream()\n"));
+ VDBUG( ( "Starting stream.\n" ) );
- if (stream->inputDevice != kAudioDeviceUnknown) {
- if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
- err = conv_err(AudioDeviceStart(stream->inputDevice, AudioIOProc));
- }
- else {
- err = conv_err(AudioDeviceStart(stream->inputDevice, AudioInputProc));
- err = conv_err(AudioDeviceStart(stream->outputDevice, AudioOutputProc));
- }
+#define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0)
+
+ /*FIXME: maybe want to do this on close/abort for faster start? */
+ PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
+ if( stream->inputSRConverter )
+ ERR_WRAP( AudioConverterReset( stream->inputSRConverter ) );
+
+ /* -- start -- */
+ stream->state = ACTIVE;
+ if( stream->inputUnit ) {
+ ERR_WRAP( AudioOutputUnitStart(stream->inputUnit) );
}
- else {
- err = conv_err(AudioDeviceStart(stream->outputDevice, AudioIOProc));
+ if( stream->outputUnit && stream->outputUnit != stream->inputUnit ) {
+ ERR_WRAP( AudioOutputUnitStart(stream->outputUnit) );
}
-
- stream->isActive = 1;
- stream->isStopped = 0;
- return err;
+
+ return paNoError;
+#undef ERR_WRAP
}
-static PaError AbortStream( PaStream *s )
+
+static PaError StopStream( PaStream *s )
{
- PaError err = paNoError;
PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- if (stream->inputDevice != kAudioDeviceUnknown) {
- if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
- err = conv_err(AudioDeviceStop(stream->inputDevice, AudioIOProc));
- }
- else {
- err = conv_err(AudioDeviceStop(stream->inputDevice, AudioInputProc));
- err = conv_err(AudioDeviceStop(stream->outputDevice, AudioOutputProc));
- }
+ OSErr result = noErr;
+ VVDBUG(("StopStream()\n"));
+ VDBUG( ( "Stopping stream.\n" ) );
+
+ stream->state = STOPPING;
+
+#define ERR_WRAP(mac_err) do { result = mac_err ; if ( result != noErr ) return ERR(result) ; } while(0)
+ /* -- stop and reset -- */
+ if( stream->inputUnit == stream->outputUnit && stream->inputUnit )
+ {
+ ERR_WRAP( AudioOutputUnitStop(stream->inputUnit) );
+ ERR_WRAP( AudioUnitReset(stream->inputUnit, kAudioUnitScope_Global, 1) );
+ ERR_WRAP( AudioUnitReset(stream->inputUnit, kAudioUnitScope_Global, 0) );
}
- else {
- err = conv_err(AudioDeviceStop(stream->outputDevice, AudioIOProc));
+ else
+ {
+ if( stream->inputUnit )
+ {
+ ERR_WRAP(AudioOutputUnitStop(stream->inputUnit) );
+ ERR_WRAP(AudioUnitReset(stream->inputUnit,kAudioUnitScope_Global,1));
+ }
+ if( stream->outputUnit )
+ {
+ ERR_WRAP(AudioOutputUnitStop(stream->outputUnit));
+ ERR_WRAP(AudioUnitReset(stream->outputUnit,kAudioUnitScope_Global,0));
+ }
+ }
+ if( stream->inputRingBuffer.buffer ) {
+ RingBuffer_Flush( &stream->inputRingBuffer );
+ bzero(stream->inputRingBuffer.buffer,stream->inputRingBuffer.bufferSize);
+ /* advance the write point a little, so we are reading from the
+ middle of the buffer. We'll need extra at the end because
+ testing has shown that this helps. */
+ if( stream->outputUnit )
+ RingBuffer_AdvanceWriteIndex( &stream->inputRingBuffer,
+ stream->inputRingBuffer.bufferSize
+ / RING_BUFFER_ADVANCE_DENOMINATOR );
}
-
- stream->isActive = 0;
- stream->isStopped = 1;
- return err;
-}
-static PaError StopStream( PaStream *s )
-{
- // TODO: this should be nicer than abort
- return AbortStream(s);
+ //stream->isTimeSet = FALSE;
+ stream->xrunFlags = 0;
+ stream->state = STOPPED;
+
+ VDBUG( ( "Stream Stopped.\n" ) );
+ return paNoError;
+#undef ERR_WRAP
}
-static PaError IsStreamStopped( PaStream *s )
+static PaError AbortStream( PaStream *s )
{
- PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- return stream->isStopped;
+ VVDBUG(("AbortStream()->StopStream()\n"));
+ VDBUG( ( "Aborting stream.\n" ) );
+ /* We have nothing faster than StopStream. */
+ return StopStream(s);
}
-static PaError IsStreamActive( PaStream *s )
+static PaError IsStreamStopped( PaStream *s )
{
PaMacCoreStream *stream = (PaMacCoreStream*)s;
+ VVDBUG(("IsStreamStopped()\n"));
- return stream->isActive;
+ return stream->state == STOPPED ? 1 : 0;
}
-static PaTime GetStreamTime( PaStream *s )
+static PaError IsStreamActive( PaStream *s )
{
- OSStatus err;
- PaTime result;
PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
- AudioTimeStamp *timeStamp = PaUtil_AllocateMemory(sizeof(AudioTimeStamp));
- if (stream->inputDevice != kAudioDeviceUnknown) {
- err = AudioDeviceGetCurrentTime(stream->inputDevice, timeStamp);
- }
- else {
- err = AudioDeviceGetCurrentTime(stream->outputDevice, timeStamp);
- }
-
- result = err ? 0 : timeStamp->mSampleTime;
- PaUtil_FreeMemory(timeStamp);
-
- return result;
+ VVDBUG(("IsStreamActive()\n"));
+ return ( stream->state == ACTIVE || stream->state == STOPPING );
}
static double GetStreamCpuLoad( PaStream* s )
{
PaMacCoreStream *stream = (PaMacCoreStream*)s;
-
+ VVDBUG(("GetStreamCpuLoad()\n"));
+
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.
+/*
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams. IMPLEMENTME: no blocking interface yet!
+*/
static PaError ReadStream( PaStream* s,
void *buffer,
unsigned long frames )
{
- return paInternalError;
+ PaMacCoreStream *stream = (PaMacCoreStream*)s;
+ VVDBUG(("ReadStream()\n"));
+
+ /* suppress unused variable warnings */
+ (void) buffer;
+ (void) frames;
+ (void) stream;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return paNoError;
}
@@ -828,71 +2063,43 @@ static PaError WriteStream( PaStream* s,
const void *buffer,
unsigned long frames )
{
- return paInternalError;
+ PaMacCoreStream *stream = (PaMacCoreStream*)s;
+ VVDBUG(("WriteStream()\n"));
+
+ /* suppress unused variable warnings */
+ (void) buffer;
+ (void) frames;
+ (void) stream;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return paNoError;
}
static signed long GetStreamReadAvailable( PaStream* s )
{
- return paInternalError;
+ PaMacCoreStream *stream = (PaMacCoreStream*)s;
+ VVDBUG(("GetStreamReadAvailable()\n"));
+
+ /* suppress unused variable warnings */
+ (void) stream;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
}
static signed long GetStreamWriteAvailable( PaStream* s )
{
- return paInternalError;
-}
+ PaMacCoreStream *stream = (PaMacCoreStream*)s;
+ VVDBUG(("GetStreamWriteAvailable()\n"));
-// HostAPI-specific initialization function
-PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
-{
- PaError result = paNoError;
- PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaMacCoreHostApiRepresentation) );
- if( !macCoreHostApi )
- {
- result = paInsufficientMemory;
- goto error;
- }
+ /* suppress unused variable warnings */
+ (void) stream;
- macCoreHostApi->allocations = PaUtil_CreateAllocationGroup();
- if( !macCoreHostApi->allocations )
- {
- result = paInsufficientMemory;
- goto error;
- }
-
- *hostApi = &macCoreHostApi->inheritedHostApiRep;
- (*hostApi)->info.structVersion = 1;
- (*hostApi)->info.type = paCoreAudio;
- (*hostApi)->info.name = "CoreAudio";
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
- result = InitializeDeviceInfos(macCoreHostApi, hostApiIndex);
- if (result != paNoError) {
- goto error;
- }
-
- // Set up the proper callbacks to this HostApi's functions
- (*hostApi)->Terminate = Terminate;
- (*hostApi)->OpenStream = OpenStream;
- (*hostApi)->IsFormatSupported = IsFormatSupported;
-
- PaUtil_InitializeStreamInterface( &macCoreHostApi->callbackStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, GetStreamCpuLoad,
- PaUtil_DummyRead, PaUtil_DummyWrite,
- PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
-
- PaUtil_InitializeStreamInterface( &macCoreHostApi->blockingStreamInterface, CloseStream, StartStream,
- StopStream, AbortStream, IsStreamStopped, IsStreamActive,
- GetStreamTime, PaUtil_DummyGetCpuLoad,
- ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
-
- return result;
-
-error:
- if( macCoreHostApi ) {
- CleanUp(macCoreHostApi);
- }
-
- return result;
+ return 0;
}
diff --git a/pd/portaudio/pa_win_ds/pa_win_ds.c b/pd/portaudio/pa_win_ds/pa_win_ds.c
index d1bc698a..ef970906 100644
--- a/pd/portaudio/pa_win_ds/pa_win_ds.c
+++ b/pd/portaudio/pa_win_ds/pa_win_ds.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_win_ds.c,v 1.1.2.49 2004/05/16 04:08:55 rossbencina Exp $
+ * $Id: pa_win_ds.c,v 1.1.2.51 2006/01/26 01:13:18 rossbencina Exp $
* Portable Audio I/O Library DirectSound implementation
*
* Based on the Open Source API proposed by Ross Bencina
@@ -75,11 +75,17 @@
#pragma comment( lib, "winmm.lib" )
#endif
+/*
+ provided in newer platform sdks and x64
+ */
+#ifndef DWORD_PTR
+#define DWORD_PTR DWORD
+#endif
-#define PRINT(x) /* { printf x; fflush(stdout); } */
+#define PRINT(x) PA_DEBUG(x);
#define ERR_RPT(x) PRINT(x)
-#define DBUG(x) /* PRINT(x) */
-#define DBUGX(x) /* PRINT(x) */
+#define DBUG(x) PRINT(x)
+#define DBUGX(x) PRINT(x)
#define PA_USE_HIGH_LATENCY (0)
#if PA_USE_HIGH_LATENCY
@@ -366,6 +372,15 @@ static BOOL CALLBACK CollectGUIDsProc(LPGUID lpGUID,
}
+/*
+ GUIDs for emulated devices which we blacklist below.
+ are there more than two of them??
+*/
+
+GUID IID_IRolandVSCEmulated1 = {0xc2ad1800, 0xb243, 0x11ce, 0xa8, 0xa4, 0x00, 0xaa, 0x00, 0x6c, 0x45, 0x01};
+GUID IID_IRolandVSCEmulated2 = {0xc2ad1800, 0xb243, 0x11ce, 0xa8, 0xa4, 0x00, 0xaa, 0x00, 0x6c, 0x45, 0x02};
+
+
#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ (13) /* must match array length below */
static double defaultSampleRateSearchOrder_[] =
{ 44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0, 192000.0,
@@ -404,6 +419,16 @@ static PaError AddOutputDeviceInfoFromDirectSound(
}
+ if( lpGUID )
+ {
+ if (IsEqualGUID (&IID_IRolandVSCEmulated1,lpGUID) ||
+ IsEqualGUID (&IID_IRolandVSCEmulated2,lpGUID) )
+ {
+ PA_DEBUG(("BLACKLISTED: %s \n",name));
+ return paNoError;
+ }
+ }
+
/* Create a DirectSound object for the specified GUID
Note that using CoCreateInstance doesn't work on windows CE.
*/
@@ -427,7 +452,24 @@ static PaError AddOutputDeviceInfoFromDirectSound(
if( hr != DS_OK )
{
+ if (hr == DSERR_ALLOCATED)
+ PA_DEBUG(("AddOutputDeviceInfoFromDirectSound %s DSERR_ALLOCATED\n",name));
DBUG(("Cannot create DirectSound for %s. Result = 0x%x\n", name, hr ));
+ if (lpGUID)
+ DBUG(("%s's GUID: {0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x, 0x%x} \n",
+ name,
+ lpGUID->Data1,
+ lpGUID->Data2,
+ lpGUID->Data3,
+ lpGUID->Data4[0],
+ lpGUID->Data4[1],
+ lpGUID->Data4[2],
+ lpGUID->Data4[3],
+ lpGUID->Data4[4],
+ lpGUID->Data4[5],
+ lpGUID->Data4[6],
+ lpGUID->Data4[7]));
+
deviceOK = FALSE;
}
else
@@ -491,7 +533,7 @@ static PaError AddOutputDeviceInfoFromDirectSound(
*/
deviceInfo->defaultSampleRate = 44100.0f;
- DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex ));
+ DBUG(("PA - Reported rates both zero. Setting to fake values for device #%s\n", name ));
}
else
{
@@ -505,7 +547,7 @@ static PaError AddOutputDeviceInfoFromDirectSound(
** So when we see a ridiculous set of rates, assume it is a range.
*/
deviceInfo->defaultSampleRate = 44100.0f;
- DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex ));
+ DBUG(("PA - Sample rate range used instead of two odd values for device #%s\n", name ));
}
else deviceInfo->defaultSampleRate = caps.dwMaxSecondarySampleRate;
@@ -1511,7 +1553,7 @@ error2:
return result;
}
/*******************************************************************/
-static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD dw1, DWORD dw2)
{
PaWinDsStream *stream;
@@ -1635,7 +1677,7 @@ static PaError StartStream( PaStream *s )
else if( msecPerWakeup > 100 ) msecPerWakeup = 100;
resolution = msecPerWakeup/4;
stream->timerID = timeSetEvent( msecPerWakeup, resolution, (LPTIMECALLBACK) Pa_TimerCallback,
- (DWORD) stream, TIME_PERIODIC );
+ (DWORD_PTR) stream, TIME_PERIODIC );
}
if( stream->timerID == 0 )
{
diff --git a/pd/portaudio/pa_win_wdmks/pa_win_wdmks.c b/pd/portaudio/pa_win_wdmks/pa_win_wdmks.c
index be7d8a7a..ff05e384 100644
--- a/pd/portaudio/pa_win_wdmks/pa_win_wdmks.c
+++ b/pd/portaudio/pa_win_wdmks/pa_win_wdmks.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_win_wdmks.c,v 1.3 2005-12-31 20:55:25 millerpuckette Exp $
+ * $Id: pa_win_wdmks.c,v 1.4 2006-06-03 19:13:07 millerpuckette Exp $
* PortAudio Windows WDM-KS interface
*
* Author: Andrew Baldwin
@@ -51,8 +51,8 @@
#ifdef __GNUC__
#include <initguid.h>
- #define _WIN32_WINNT 0x0501
- #define WINVER 0x0501
+ #define _WIN32_WINNT 0x0501
+ #define WINVER 0x0501
#endif
#include <string.h> /* strlen() */
@@ -71,10 +71,10 @@
#ifdef __GNUC__
- #undef PA_LOGE_
- #define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__))
- #undef PA_LOGL_
- #define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__))
+ #undef PA_LOGE_
+ #define PA_LOGE_ PA_DEBUG(("%s {\n",__FUNCTION__))
+ #undef PA_LOGL_
+ #define PA_LOGL_ PA_DEBUG(("} %s\n",__FUNCTION__))
/* These defines are set in order to allow the WIndows DirectX
* headers to compile with a GCC compiler such as MinGW
* NOTE: The headers may generate a few warning in GCC, but
@@ -93,15 +93,15 @@
#define WAVE_FORMAT_MULAW 0x0007
#define WAVE_FORMAT_MPEG 0x0050
#define WAVE_FORMAT_DRM 0x0009
- #define DYNAMIC_GUID_THUNK(l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
- #define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data)
+ #define DYNAMIC_GUID_THUNK(l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+ #define DYNAMIC_GUID(data) DYNAMIC_GUID_THUNK(data)
#endif
#ifdef _MSC_VER
- #define DYNAMIC_GUID(data) {data}
+ #define DYNAMIC_GUID(data) {data}
#define _INC_MMREG
#define _NTRTL_ /* Turn off default definition of DEFINE_GUIDEX */
- #undef DEFINE_GUID
+ #undef DEFINE_GUID
#define DEFINE_GUID(n,data) EXTERN_C const GUID n = {data}
#define DEFINE_GUID_THUNK(n,data) DEFINE_GUID(n,data)
#define DEFINE_GUIDEX(n) DEFINE_GUID_THUNK(n, STATIC_##n)
@@ -157,75 +157,75 @@ PaWinWdmPin;
* A filter has a number of pins and a "friendly name" */
struct __PaWinWdmFilter
{
- HANDLE handle;
- int pinCount;
- PaWinWdmPin** pins;
- TCHAR filterName[MAX_PATH];
- TCHAR friendlyName[MAX_PATH];
- int maxInputChannels;
- int maxOutputChannels;
- unsigned long formats;
- int usageCount;
- int bestSampleRate;
+ HANDLE handle;
+ int pinCount;
+ PaWinWdmPin** pins;
+ TCHAR filterName[MAX_PATH];
+ TCHAR friendlyName[MAX_PATH];
+ int maxInputChannels;
+ int maxOutputChannels;
+ unsigned long formats;
+ int usageCount;
+ int bestSampleRate;
};
/* PaWinWdmHostApiRepresentation - host api datastructure specific to this implementation */
typedef struct __PaWinWdmHostApiRepresentation
{
- PaUtilHostApiRepresentation inheritedHostApiRep;
- PaUtilStreamInterface callbackStreamInterface;
- PaUtilStreamInterface blockingStreamInterface;
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
- PaUtilAllocationGroup *allocations;
- PaWinWdmFilter** filters;
- int filterCount;
+ PaUtilAllocationGroup* allocations;
+ PaWinWdmFilter** filters;
+ int filterCount;
}
PaWinWdmHostApiRepresentation;
typedef struct __PaWinWdmDeviceInfo
{
- PaDeviceInfo inheritedDeviceInfo;
- PaWinWdmFilter* filter;
+ PaDeviceInfo inheritedDeviceInfo;
+ PaWinWdmFilter* filter;
}
PaWinWdmDeviceInfo;
typedef struct __DATAPACKET
{
- KSSTREAM_HEADER Header;
- OVERLAPPED Signal;
+ KSSTREAM_HEADER Header;
+ OVERLAPPED Signal;
} DATAPACKET;
/* PaWinWdmStream - a stream data structure specifically for this implementation */
typedef struct __PaWinWdmStream
{
- PaUtilStreamRepresentation streamRepresentation;
- PaUtilCpuLoadMeasurer cpuLoadMeasurer;
- PaUtilBufferProcessor bufferProcessor;
-
- PaWinWdmPin* recordingPin;
- PaWinWdmPin* playbackPin;
- char* hostBuffer;
- unsigned long framesPerHostIBuffer;
- unsigned long framesPerHostOBuffer;
- int bytesPerInputFrame;
- int bytesPerOutputFrame;
- int streamStarted;
- int streamActive;
- int streamStop;
- int streamAbort;
- int oldProcessPriority;
- HANDLE streamThread;
- HANDLE events[5]; /* 2 play + 2 record packets + abort events */
- DATAPACKET packets[4]; /* 2 play + 2 record */
- PaStreamFlags streamFlags;
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ PaWinWdmPin* recordingPin;
+ PaWinWdmPin* playbackPin;
+ char* hostBuffer;
+ unsigned long framesPerHostIBuffer;
+ unsigned long framesPerHostOBuffer;
+ int bytesPerInputFrame;
+ int bytesPerOutputFrame;
+ int streamStarted;
+ int streamActive;
+ int streamStop;
+ int streamAbort;
+ int oldProcessPriority;
+ HANDLE streamThread;
+ HANDLE events[5]; /* 2 play + 2 record packets + abort events */
+ DATAPACKET packets[4]; /* 2 play + 2 record */
+ PaStreamFlags streamFlags;
/* These values handle the case where the user wants to use fewer
* channels than the device has */
- int userInputChannels;
- int deviceInputChannels;
- int userOutputChannels;
- int deviceOutputChannels;
- int inputSampleSize;
- int outputSampleSize;
+ int userInputChannels;
+ int deviceInputChannels;
+ int userOutputChannels;
+ int deviceOutputChannels;
+ int inputSampleSize;
+ int outputSampleSize;
}
PaWinWdmStream;
@@ -326,19 +326,21 @@ static void FilterRelease(
/* Interface functions */
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 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 );
@@ -347,8 +349,14 @@ 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 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 );
@@ -365,7 +373,7 @@ static DWORD WINAPI ProcessingThread(LPVOID pParam);
static unsigned long GetWfexSize(const WAVEFORMATEX* wfex)
{
- if ( wfex->wFormatTag == WAVE_FORMAT_PCM )
+ if( wfex->wFormatTag == WAVE_FORMAT_PCM )
{
return sizeof( WAVEFORMATEX );
}
@@ -378,7 +386,8 @@ static unsigned long GetWfexSize(const WAVEFORMATEX* wfex)
/*
Low level pin/filter access functions
*/
-static PaError WdmSyncIoctl(HANDLE handle,
+static PaError WdmSyncIoctl(
+ HANDLE handle,
unsigned long ioctlNumber,
void* inBuffer,
unsigned long inBufferCount,
@@ -392,39 +401,39 @@ static PaError WdmSyncIoctl(HANDLE handle,
unsigned long dummyBytesReturned;
unsigned long error;
- if (!bytesReturned)
+ if( !bytesReturned )
{
/* User a dummy as the caller hasn't supplied one */
bytesReturned = &dummyBytesReturned;
}
- FillMemory((void *)&overlapped,sizeof(overlapped),0);
+ FillMemory((void *)&overlapped,sizeof(overlapped),0);
overlapped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
- if ( !overlapped.hEvent )
+ if( !overlapped.hEvent )
{
- result = paInsufficientMemory;
+ result = paInsufficientMemory;
goto error;
}
overlapped.hEvent = (HANDLE)((DWORD_PTR)overlapped.hEvent | 0x1);
boolResult = DeviceIoControl(handle, ioctlNumber, inBuffer, inBufferCount,
- outBuffer, outBufferCount, bytesReturned, &overlapped);
- if ( !boolResult )
+ outBuffer, outBufferCount, bytesReturned, &overlapped);
+ if( !boolResult )
{
error = GetLastError();
- if ( error == ERROR_IO_PENDING )
+ if( error == ERROR_IO_PENDING )
{
error = WaitForSingleObject(overlapped.hEvent,INFINITE);
- if ( error != WAIT_OBJECT_0 )
+ if( error != WAIT_OBJECT_0 )
{
result = paUnanticipatedHostError;
goto error;
}
}
- else if ((( error == ERROR_INSUFFICIENT_BUFFER ) ||
- ( error == ERROR_MORE_DATA )) &&
- ( ioctlNumber == IOCTL_KS_PROPERTY ) &&
- ( outBufferCount == 0 ))
+ else if((( error == ERROR_INSUFFICIENT_BUFFER ) ||
+ ( error == ERROR_MORE_DATA )) &&
+ ( ioctlNumber == IOCTL_KS_PROPERTY ) &&
+ ( outBufferCount == 0 ))
{
boolResult = TRUE;
}
@@ -433,47 +442,47 @@ static PaError WdmSyncIoctl(HANDLE handle,
result = paUnanticipatedHostError;
}
}
- if ( !boolResult )
+ if( !boolResult )
*bytesReturned = 0;
error:
- if ( overlapped.hEvent )
+ if( overlapped.hEvent )
{
- CloseHandle( overlapped.hEvent );
- }
- return result;
+ CloseHandle( overlapped.hEvent );
+ }
+ return result;
}
static PaError WdmGetPropertySimple(HANDLE handle,
const GUID* const guidPropertySet,
- unsigned long property,
- void* value,
- unsigned long valueCount,
- void* instance,
- unsigned long instanceCount)
+ unsigned long property,
+ void* value,
+ unsigned long valueCount,
+ void* instance,
+ unsigned long instanceCount)
{
PaError result;
KSPROPERTY* ksProperty;
unsigned long propertyCount;
propertyCount = sizeof(KSPROPERTY) + instanceCount;
- ksProperty = (KSPROPERTY*)PaUtil_AllocateMemory( propertyCount );
+ ksProperty = (KSPROPERTY*)PaUtil_AllocateMemory( propertyCount );
if( !ksProperty )
{
- return paInsufficientMemory;
+ return paInsufficientMemory;
}
- FillMemory((void*)ksProperty,sizeof(ksProperty),0);
+ FillMemory((void*)ksProperty,sizeof(ksProperty),0);
ksProperty->Set = *guidPropertySet;
ksProperty->Id = property;
ksProperty->Flags = KSPROPERTY_TYPE_GET;
- if ( instance )
- {
- memcpy( (void*)(((char*)ksProperty)+sizeof(KSPROPERTY)), instance, instanceCount );
- }
+ if( instance )
+ {
+ memcpy( (void*)(((char*)ksProperty)+sizeof(KSPROPERTY)), instance, instanceCount );
+ }
- result = WdmSyncIoctl(
+ result = WdmSyncIoctl(
handle,
IOCTL_KS_PROPERTY,
ksProperty,
@@ -482,12 +491,12 @@ static PaError WdmGetPropertySimple(HANDLE handle,
valueCount,
NULL);
- PaUtil_FreeMemory( ksProperty );
+ PaUtil_FreeMemory( ksProperty );
return result;
}
static PaError WdmSetPropertySimple(
- HANDLE handle,
+ HANDLE handle,
const GUID* const guidPropertySet,
unsigned long property,
void* value,
@@ -500,17 +509,17 @@ static PaError WdmSetPropertySimple(
unsigned long propertyCount = 0;
propertyCount = sizeof(KSPROPERTY) + instanceCount;
- ksProperty = (KSPROPERTY*)PaUtil_AllocateMemory( propertyCount );
+ ksProperty = (KSPROPERTY*)PaUtil_AllocateMemory( propertyCount );
if( !ksProperty )
{
- return paInsufficientMemory;
+ return paInsufficientMemory;
}
ksProperty->Set = *guidPropertySet;
ksProperty->Id = property;
ksProperty->Flags = KSPROPERTY_TYPE_SET;
- if ( instance )
+ if( instance )
{
memcpy((void*)((char*)ksProperty + sizeof(KSPROPERTY)), instance, instanceCount);
}
@@ -524,12 +533,12 @@ static PaError WdmSetPropertySimple(
valueCount,
NULL);
- PaUtil_FreeMemory( ksProperty );
+ PaUtil_FreeMemory( ksProperty );
return result;
}
static PaError WdmGetPinPropertySimple(
- HANDLE handle,
+ HANDLE handle,
unsigned long pinId,
const GUID* const guidPropertySet,
unsigned long property,
@@ -546,26 +555,26 @@ static PaError WdmGetPinPropertySimple(
ksPProp.Reserved = 0;
result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksPProp,
- sizeof(KSP_PIN),
- value,
- valueCount,
- NULL);
+ handle,
+ IOCTL_KS_PROPERTY,
+ &ksPProp,
+ sizeof(KSP_PIN),
+ value,
+ valueCount,
+ NULL);
return result;
}
static PaError WdmGetPinPropertyMulti(
- HANDLE handle,
+ HANDLE handle,
unsigned long pinId,
const GUID* const guidPropertySet,
unsigned long property,
KSMULTIPLE_ITEM** ksMultipleItem)
{
PaError result;
- unsigned long multipleItemSize = 0;
+ unsigned long multipleItemSize = 0;
KSP_PIN ksPProp;
ksPProp.Property.Set = *guidPropertySet;
@@ -575,36 +584,36 @@ static PaError WdmGetPinPropertyMulti(
ksPProp.Reserved = 0;
result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksPProp.Property,
- sizeof(KSP_PIN),
- NULL,
- 0,
- &multipleItemSize);
- if ( result != paNoError )
- {
- return result;
- }
-
- *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
+ handle,
+ IOCTL_KS_PROPERTY,
+ &ksPProp.Property,
+ sizeof(KSP_PIN),
+ NULL,
+ 0,
+ &multipleItemSize);
+ if( result != paNoError )
+ {
+ return result;
+ }
+
+ *ksMultipleItem = (KSMULTIPLE_ITEM*)PaUtil_AllocateMemory( multipleItemSize );
if( !*ksMultipleItem )
{
- return paInsufficientMemory;
+ return paInsufficientMemory;
}
result = WdmSyncIoctl(
- handle,
- IOCTL_KS_PROPERTY,
- &ksPProp,
- sizeof(KSP_PIN),
- (void*)*ksMultipleItem,
- multipleItemSize,
- NULL);
+ handle,
+ IOCTL_KS_PROPERTY,
+ &ksPProp,
+ sizeof(KSP_PIN),
+ (void*)*ksMultipleItem,
+ multipleItemSize,
+ NULL);
- if ( result != paNoError )
+ if( result != paNoError )
{
- PaUtil_FreeMemory( ksMultipleItem );
+ PaUtil_FreeMemory( ksMultipleItem );
}
return result;
@@ -652,23 +661,23 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
}
/* Configure the connect structure with default values */
- pin->pinConnect->Interface.Set = KSINTERFACESETID_Standard;
- pin->pinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
- pin->pinConnect->Interface.Flags = 0;
- pin->pinConnect->Medium.Set = KSMEDIUMSETID_Standard;
- pin->pinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
- pin->pinConnect->Medium.Flags = 0;
- pin->pinConnect->PinId = pinId;
- pin->pinConnect->PinToHandle = NULL;
- pin->pinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
- pin->pinConnect->Priority.PrioritySubClass = 1;
+ pin->pinConnect->Interface.Set = KSINTERFACESETID_Standard;
+ pin->pinConnect->Interface.Id = KSINTERFACE_STANDARD_STREAMING;
+ pin->pinConnect->Interface.Flags = 0;
+ pin->pinConnect->Medium.Set = KSMEDIUMSETID_Standard;
+ pin->pinConnect->Medium.Id = KSMEDIUM_TYPE_ANYINSTANCE;
+ pin->pinConnect->Medium.Flags = 0;
+ pin->pinConnect->PinId = pinId;
+ pin->pinConnect->PinToHandle = NULL;
+ pin->pinConnect->Priority.PriorityClass = KSPRIORITY_NORMAL;
+ pin->pinConnect->Priority.PrioritySubClass = 1;
pin->ksDataFormatWfx = (KSDATAFORMAT_WAVEFORMATEX*)(pin->pinConnect + 1);
- pin->ksDataFormatWfx->DataFormat.FormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
- pin->ksDataFormatWfx->DataFormat.Flags = 0;
- pin->ksDataFormatWfx->DataFormat.Reserved = 0;
+ pin->ksDataFormatWfx->DataFormat.FormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
+ pin->ksDataFormatWfx->DataFormat.Flags = 0;
+ pin->ksDataFormatWfx->DataFormat.Reserved = 0;
pin->ksDataFormatWfx->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
- pin->ksDataFormatWfx->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
- pin->ksDataFormatWfx->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
+ pin->ksDataFormatWfx->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
+ pin->ksDataFormatWfx->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;
pin->frameSize = 0; /* Unknown until we instantiate pin */
@@ -680,10 +689,10 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
KSPROPERTY_PIN_COMMUNICATION,
&pin->communication,
sizeof(KSPIN_COMMUNICATION));
- if ( result != paNoError )
+ if( result != paNoError )
goto error;
- if ( /*(pin->communication != KSPIN_COMMUNICATION_SOURCE) &&*/
+ if( /*(pin->communication != KSPIN_COMMUNICATION_SOURCE) &&*/
(pin->communication != KSPIN_COMMUNICATION_SINK) &&
(pin->communication != KSPIN_COMMUNICATION_BOTH) )
{
@@ -701,7 +710,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
&pin->dataFlow,
sizeof(KSPIN_DATAFLOW));
- if ( result != paNoError )
+ if( result != paNoError )
goto error;
/* Get the INTERFACE property list */
@@ -712,16 +721,16 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
KSPROPERTY_PIN_INTERFACES,
&item);
- if ( result != paNoError )
+ if( result != paNoError )
goto error;
identifier = (KSIDENTIFIER*)(item+1);
/* Check that at least one interface is STANDARD_STREAMING */
result = paUnanticipatedHostError;
- for ( i = 0; i < item->Count; i++ )
+ for( i = 0; i < item->Count; i++ )
{
- if ( !memcmp( (void*)&identifier[i].Set, (void*)&KSINTERFACESETID_Standard, sizeof( GUID ) ) &&
+ if( !memcmp( (void*)&identifier[i].Set, (void*)&KSINTERFACESETID_Standard, sizeof( GUID ) ) &&
( identifier[i].Id == KSINTERFACE_STANDARD_STREAMING ) )
{
result = paNoError;
@@ -729,7 +738,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
}
}
- if ( result != paNoError )
+ if( result != paNoError )
{
PA_DEBUG(("No standard streaming\n"));
goto error;
@@ -747,16 +756,16 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
KSPROPERTY_PIN_MEDIUMS,
&item);
- if ( result != paNoError )
+ if( result != paNoError )
goto error;
identifier = (KSIDENTIFIER*)(item+1); /* Not actually necessary... */
/* Check that at least one medium is STANDARD_DEVIO */
result = paUnanticipatedHostError;
- for ( i = 0; i < item->Count; i++ )
+ for( i = 0; i < item->Count; i++ )
{
- if ( !memcmp( (void*)&identifier[i].Set, (void*)&KSMEDIUMSETID_Standard, sizeof( GUID ) ) &&
+ if( !memcmp( (void*)&identifier[i].Set, (void*)&KSMEDIUMSETID_Standard, sizeof( GUID ) ) &&
( identifier[i].Id == KSMEDIUM_STANDARD_DEVIO ) )
{
result = paNoError;
@@ -764,7 +773,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
}
}
- if ( result != paNoError )
+ if( result != paNoError )
{
PA_DEBUG(("No standard devio\n"));
goto error;
@@ -781,7 +790,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
KSPROPERTY_PIN_DATARANGES,
&pin->dataRangesItem);
- if ( result != paNoError )
+ if( result != paNoError )
goto error;
pin->dataRanges = (KSDATARANGE*)(pin->dataRangesItem +1);
@@ -791,13 +800,12 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
dataRange = pin->dataRanges;
pin->maxChannels = 0;
pin->bestSampleRate = 0;
- pin->formats = 0;
- for ( i = 0; i <pin->dataRangesItem->Count; i++)
+ pin->formats = 0;
+ for( i = 0; i <pin->dataRangesItem->Count; i++)
{
PA_DEBUG(("DR major format %x\n",*(unsigned long*)(&(dataRange->MajorFormat))));
/* Check that subformat is WAVEFORMATEX, PCM or WILDCARD */
- if (
- IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) ||
+ if( IS_VALID_WAVEFORMATEX_GUID(&dataRange->SubFormat) ||
!memcmp((void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_PCM, sizeof ( GUID ) ) ||
( !memcmp((void*)&dataRange->SubFormat, (void*)&KSDATAFORMAT_SUBTYPE_WILDCARD, sizeof ( GUID ) ) &&
( !memcmp((void*)&dataRange->MajorFormat, (void*)&KSDATAFORMAT_TYPE_AUDIO, sizeof ( GUID ) ) ) ) )
@@ -805,32 +813,30 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
result = paNoError;
/* Record the maximum possible channels with this pin */
PA_DEBUG(("MaxChannel: %d\n",pin->maxChannels));
- if ((int)((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels)
+ if( (int)((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels > pin->maxChannels )
{
pin->maxChannels = ((KSDATARANGE_AUDIO*)dataRange)->MaximumChannels;
/*PA_DEBUG(("MaxChannel: %d\n",pin->maxChannels));*/
}
/* Record the formats (bit depths) that are supported */
- if (((KSDATARANGE_AUDIO*)dataRange)->MinimumBitsPerSample <= 16)
+ if( ((KSDATARANGE_AUDIO*)dataRange)->MinimumBitsPerSample <= 16 )
{
pin->formats |= paInt16;
PA_DEBUG(("Format 16 bit supported\n"));
}
- if (((KSDATARANGE_AUDIO*)dataRange)->MaximumBitsPerSample >= 24)
+ if( ((KSDATARANGE_AUDIO*)dataRange)->MaximumBitsPerSample >= 24 )
{
pin->formats |= paInt24;
PA_DEBUG(("Format 24 bit supported\n"));
}
- if (
- ( pin->bestSampleRate != 48000) &&
+ if( ( pin->bestSampleRate != 48000) &&
(((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency >= 48000) &&
(((KSDATARANGE_AUDIO*)dataRange)->MinimumSampleFrequency <= 48000) )
{
pin->bestSampleRate = 48000;
PA_DEBUG(("48kHz supported\n"));
}
- else if (
- ( pin->bestSampleRate != 48000) && ( pin->bestSampleRate != 44100 ) &&
+ else if(( pin->bestSampleRate != 48000) && ( pin->bestSampleRate != 44100 ) &&
(((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency >= 44100) &&
(((KSDATARANGE_AUDIO*)dataRange)->MinimumSampleFrequency <= 44100) )
{
@@ -845,7 +851,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize);
}
- if ( result != paNoError )
+ if( result != paNoError )
goto error;
/* Get instance information */
@@ -857,7 +863,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa
&pin->instances,
sizeof(KSPIN_CINSTANCES));
- if ( result != paNoError )
+ if( result != paNoError )
goto error;
/* Success */
@@ -871,7 +877,7 @@ error:
Error cleanup
*/
PaUtil_FreeMemory( item );
- if ( pin )
+ if( pin )
{
PaUtil_FreeMemory( pin->pinConnect );
PaUtil_FreeMemory( pin->dataRangesItem );
@@ -888,14 +894,14 @@ Safely free all resources associated with the pin
static void PinFree(PaWinWdmPin* pin)
{
PA_LOGE_;
- if ( pin )
+ if( pin )
{
PinClose(pin);
- if ( pin->pinConnect )
+ if( pin->pinConnect )
{
PaUtil_FreeMemory( pin->pinConnect );
}
- if ( pin->dataRangesItem )
+ if( pin->dataRangesItem )
{
PaUtil_FreeMemory( pin->dataRangesItem );
}
@@ -910,13 +916,13 @@ If the pin handle is open, close it
static void PinClose(PaWinWdmPin* pin)
{
PA_LOGE_;
- if ( pin == NULL )
+ if( pin == NULL )
{
PA_DEBUG(("Closing NULL pin!"));
PA_LOGL_;
return;
}
- if ( pin->handle != NULL )
+ if( pin->handle != NULL )
{
PinSetState( pin, KSSTATE_PAUSE );
PinSetState( pin, KSSTATE_STOP );
@@ -935,9 +941,9 @@ static PaError PinSetState(PaWinWdmPin* pin, KSSTATE state)
PaError result;
PA_LOGE_;
- if ( pin == NULL )
+ if( pin == NULL )
return paInternalError;
- if ( pin->handle == NULL )
+ if( pin->handle == NULL )
return paInternalError;
result = WdmSetPropertySimple(
@@ -961,9 +967,9 @@ static PaError PinInstantiate(PaWinWdmPin* pin)
PA_LOGE_;
- if ( pin == NULL )
+ if( pin == NULL )
return paInternalError;
- if (!pin->pinConnect)
+ if(!pin->pinConnect)
return paInternalError;
FilterUse(pin->parentFilter);
@@ -976,7 +982,7 @@ static PaError PinInstantiate(PaWinWdmPin* pin)
);
PA_DEBUG(("Pin create result = %x\n",createResult));
- if ( createResult != ERROR_SUCCESS )
+ if( createResult != ERROR_SUCCESS )
{
FilterRelease(pin->parentFilter);
pin->handle = NULL;
@@ -992,7 +998,7 @@ static PaError PinInstantiate(PaWinWdmPin* pin)
NULL,
0);
- if ( result != paNoError )
+ if( result != paNoError )
{
result = WdmGetPropertySimple(
pin->handle,
@@ -1002,7 +1008,7 @@ static PaError PinInstantiate(PaWinWdmPin* pin)
sizeof(ksafex),
NULL,
0);
- if ( result == paNoError )
+ if( result == paNoError )
{
pin->frameSize = ksafex.FramingItem[0].FramingRange.Range.MinFrameSize;
}
@@ -1022,11 +1028,11 @@ static PaError PinGetState(PaWinWdmPin* pin, KSSTATE* state)
{
PaError result;
- if ( state == NULL )
+ if( state == NULL )
return paInternalError;
- if ( pin == NULL )
+ if( pin == NULL )
return paInternalError;
- if ( pin->handle == NULL )
+ if( pin->handle == NULL )
return paInternalError;
result = WdmGetPropertySimple(
@@ -1048,17 +1054,17 @@ static PaError PinSetFormat(PaWinWdmPin* pin, const WAVEFORMATEX* format)
PA_LOGE_;
- if ( pin == NULL )
+ if( pin == NULL )
return paInternalError;
- if ( format == NULL )
+ if( format == NULL )
return paInternalError;
size = GetWfexSize(format) + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX);
- if ( pin->pinConnectSize != size )
+ if( pin->pinConnectSize != size )
{
newConnect = PaUtil_AllocateMemory( size );
- if ( newConnect == NULL )
+ if( newConnect == NULL )
return paInsufficientMemory;
memcpy( newConnect, (void*)pin->pinConnect, min(pin->pinConnectSize,size) );
PaUtil_FreeMemory( pin->pinConnect );
@@ -1085,21 +1091,21 @@ static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format
PA_LOGE_;
- if ( format->wFormatTag == WAVE_FORMAT_EXTENSIBLE )
+ if( format->wFormatTag == WAVE_FORMAT_EXTENSIBLE )
{
guid = ((WAVEFORMATEXTENSIBLE*)format)->SubFormat;
}
dataRange = (KSDATARANGE_AUDIO*)pin->dataRanges;
- for (count = 0; count<pin->dataRangesItem->Count; count++)
+ for(count = 0; count<pin->dataRangesItem->Count; count++)
{
- if (( !memcmp(&(dataRange->DataRange.MajorFormat),&KSDATAFORMAT_TYPE_AUDIO,sizeof(GUID)) ) ||
+ if(( !memcmp(&(dataRange->DataRange.MajorFormat),&KSDATAFORMAT_TYPE_AUDIO,sizeof(GUID)) ) ||
( !memcmp(&(dataRange->DataRange.MajorFormat),&KSDATAFORMAT_TYPE_WILDCARD,sizeof(GUID)) ))
{
/* This is an audio or wildcard datarange... */
- if (( !memcmp(&(dataRange->DataRange.SubFormat),&KSDATAFORMAT_SUBTYPE_WILDCARD,sizeof(GUID)) ) ||
+ if(( !memcmp(&(dataRange->DataRange.SubFormat),&KSDATAFORMAT_SUBTYPE_WILDCARD,sizeof(GUID)) ) ||
( !memcmp(&(dataRange->DataRange.SubFormat),&guid,sizeof(GUID)) ))
{
- if (( !memcmp(&(dataRange->DataRange.Specifier),&KSDATAFORMAT_SPECIFIER_WILDCARD,sizeof(GUID)) ) ||
+ if(( !memcmp(&(dataRange->DataRange.Specifier),&KSDATAFORMAT_SPECIFIER_WILDCARD,sizeof(GUID)) ) ||
( !memcmp(&(dataRange->DataRange.Specifier),&KSDATAFORMAT_SPECIFIER_WAVEFORMATEX,sizeof(GUID) )))
{
@@ -1109,27 +1115,27 @@ static PaError PinIsFormatSupported(PaWinWdmPin* pin, const WAVEFORMATEX* format
PA_DEBUG(("\tBits:%d-%d\n",dataRange->MinimumBitsPerSample,dataRange->MaximumBitsPerSample));
PA_DEBUG(("\tSampleRate:%d-%d\n",dataRange->MinimumSampleFrequency,dataRange->MaximumSampleFrequency));
- if ( dataRange->MaximumChannels < format->nChannels )
+ if( dataRange->MaximumChannels < format->nChannels )
{
result = paInvalidChannelCount;
continue;
}
- if ( dataRange->MinimumBitsPerSample > format->wBitsPerSample )
+ if( dataRange->MinimumBitsPerSample > format->wBitsPerSample )
{
result = paSampleFormatNotSupported;
continue;
}
- if ( dataRange->MaximumBitsPerSample < format->wBitsPerSample )
+ if( dataRange->MaximumBitsPerSample < format->wBitsPerSample )
{
result = paSampleFormatNotSupported;
continue;
}
- if ( dataRange->MinimumSampleFrequency > format->nSamplesPerSec )
+ if( dataRange->MinimumSampleFrequency > format->nSamplesPerSec )
{
result = paInvalidSampleRate;
continue;
}
- if ( dataRange->MaximumSampleFrequency < format->nSamplesPerSec )
+ if( dataRange->MaximumSampleFrequency < format->nSamplesPerSec )
{
result = paInvalidSampleRate;
continue;
@@ -1178,7 +1184,7 @@ static PaWinWdmFilter* FilterNew(TCHAR* filterName, TCHAR* friendlyName, PaError
/* Open the filter handle */
result = FilterUse(filter);
- if ( result != paNoError )
+ if( result != paNoError )
{
goto error;
}
@@ -1194,7 +1200,7 @@ static PaWinWdmFilter* FilterNew(TCHAR* filterName, TCHAR* friendlyName, PaError
sizeof(filter->pinCount)
);
- if ( result != paNoError)
+ if( result != paNoError)
{
goto error;
}
@@ -1213,51 +1219,51 @@ static PaWinWdmFilter* FilterNew(TCHAR* filterName, TCHAR* friendlyName, PaError
filter->bestSampleRate = 0;
valid = 0;
- for (pinId = 0; pinId < filter->pinCount; pinId++)
+ for(pinId = 0; pinId < filter->pinCount; pinId++)
{
/* Create the pin with this Id */
PaWinWdmPin* newPin;
newPin = PinNew(filter, pinId, &result);
- if ( result == paInsufficientMemory )
+ if( result == paInsufficientMemory )
goto error;
- if ( newPin != NULL )
+ if( newPin != NULL )
{
filter->pins[pinId] = newPin;
valid = 1;
/* Get the max output channel count */
- if (( newPin->dataFlow == KSPIN_DATAFLOW_IN ) &&
+ if(( newPin->dataFlow == KSPIN_DATAFLOW_IN ) &&
(( newPin->communication == KSPIN_COMMUNICATION_SINK) ||
( newPin->communication == KSPIN_COMMUNICATION_BOTH)))
{
- if (newPin->maxChannels > filter->maxOutputChannels)
+ if(newPin->maxChannels > filter->maxOutputChannels)
filter->maxOutputChannels = newPin->maxChannels;
filter->formats |= newPin->formats;
}
/* Get the max input channel count */
- if (( newPin->dataFlow == KSPIN_DATAFLOW_OUT ) &&
+ if(( newPin->dataFlow == KSPIN_DATAFLOW_OUT ) &&
(( newPin->communication == KSPIN_COMMUNICATION_SINK) ||
( newPin->communication == KSPIN_COMMUNICATION_BOTH)))
{
- if (newPin->maxChannels > filter->maxInputChannels)
+ if(newPin->maxChannels > filter->maxInputChannels)
filter->maxInputChannels = newPin->maxChannels;
filter->formats |= newPin->formats;
}
- if (newPin->bestSampleRate > filter->bestSampleRate)
+ if(newPin->bestSampleRate > filter->bestSampleRate)
{
filter->bestSampleRate = newPin->bestSampleRate;
}
}
}
- if (( filter->maxInputChannels == 0) && ( filter->maxOutputChannels == 0))
+ if(( filter->maxInputChannels == 0) && ( filter->maxOutputChannels == 0))
{
/* No input or output... not valid */
valid = 0;
}
- if ( !valid )
+ if( !valid )
{
/* No valid pin was found on this filter so we destroy it */
result = paDeviceUnavailable;
@@ -1275,12 +1281,12 @@ error:
/*
Error cleanup
*/
- if ( filter )
+ if( filter )
{
- for ( pinId = 0; pinId < filter->pinCount; pinId++ )
+ for( pinId = 0; pinId < filter->pinCount; pinId++ )
PinFree(filter->pins[pinId]);
PaUtil_FreeMemory( filter->pins );
- if ( filter->handle )
+ if( filter->handle )
CloseHandle( filter->handle );
PaUtil_FreeMemory( filter );
}
@@ -1295,12 +1301,12 @@ static void FilterFree(PaWinWdmFilter* filter)
{
int pinId;
PA_LOGL_;
- if ( filter )
+ if( filter )
{
- for ( pinId = 0; pinId < filter->pinCount; pinId++ )
+ for( pinId = 0; pinId < filter->pinCount; pinId++ )
PinFree(filter->pins[pinId]);
PaUtil_FreeMemory( filter->pins );
- if ( filter->handle )
+ if( filter->handle )
CloseHandle( filter->handle );
PaUtil_FreeMemory( filter );
}
@@ -1315,7 +1321,7 @@ static PaError FilterUse(PaWinWdmFilter* filter)
assert( filter );
PA_LOGE_;
- if ( filter->handle == NULL )
+ if( filter->handle == NULL )
{
/* Open the filter */
filter->handle = CreateFile(
@@ -1327,7 +1333,7 @@ static PaError FilterUse(PaWinWdmFilter* filter)
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
- if ( filter->handle == NULL )
+ if( filter->handle == NULL )
{
return paDeviceUnavailable;
}
@@ -1347,9 +1353,9 @@ static void FilterRelease(PaWinWdmFilter* filter)
PA_LOGE_;
filter->usageCount--;
- if ( filter->usageCount == 0 )
+ if( filter->usageCount == 0 )
{
- if ( filter->handle != NULL )
+ if( filter->handle != NULL )
{
CloseHandle( filter->handle );
filter->handle = NULL;
@@ -1371,17 +1377,17 @@ static PaWinWdmPin* FilterCreateRenderPin(PaWinWdmFilter* filter,
assert( filter );
pin = FilterFindViableRenderPin(filter,wfex,&result);
- if (!pin)
+ if(!pin)
{
goto error;
}
result = PinSetFormat(pin,wfex);
- if ( result != paNoError )
+ if( result != paNoError )
{
goto error;
}
result = PinInstantiate(pin);
- if ( result != paNoError )
+ if( result != paNoError )
{
goto error;
}
@@ -1408,17 +1414,17 @@ static PaWinWdmPin* FilterFindViableRenderPin(PaWinWdmFilter* filter,
assert( filter );
- for ( pinId = 0; pinId<filter->pinCount; pinId++ )
+ for( pinId = 0; pinId<filter->pinCount; pinId++ )
{
pin = filter->pins[pinId];
- if ( pin != NULL )
+ if( pin != NULL )
{
- if (( pin->dataFlow == KSPIN_DATAFLOW_IN ) &&
+ if(( pin->dataFlow == KSPIN_DATAFLOW_IN ) &&
(( pin->communication == KSPIN_COMMUNICATION_SINK) ||
( pin->communication == KSPIN_COMMUNICATION_BOTH)))
{
result = PinIsFormatSupported( pin, wfex );
- if ( result == paNoError )
+ if( result == paNoError )
{
return pin;
}
@@ -1462,19 +1468,19 @@ static PaWinWdmPin* FilterCreateCapturePin(PaWinWdmFilter* filter,
assert( filter );
pin = FilterFindViableCapturePin(filter,wfex,&result);
- if (!pin)
+ if(!pin)
{
goto error;
}
result = PinSetFormat(pin,wfex);
- if ( result != paNoError )
+ if( result != paNoError )
{
goto error;
}
result = PinInstantiate(pin);
- if ( result != paNoError )
+ if( result != paNoError )
{
goto error;
}
@@ -1501,17 +1507,17 @@ static PaWinWdmPin* FilterFindViableCapturePin(PaWinWdmFilter* filter,
assert( filter );
- for ( pinId = 0; pinId<filter->pinCount; pinId++ )
+ for( pinId = 0; pinId<filter->pinCount; pinId++ )
{
pin = filter->pins[pinId];
- if ( pin != NULL )
+ if( pin != NULL )
{
- if (( pin->dataFlow == KSPIN_DATAFLOW_OUT ) &&
+ if(( pin->dataFlow == KSPIN_DATAFLOW_OUT ) &&
(( pin->communication == KSPIN_COMMUNICATION_SINK) ||
( pin->communication == KSPIN_COMMUNICATION_BOTH)))
{
result = PinIsFormatSupported( pin, wfex );
- if ( result == paNoError )
+ if( result == paNoError )
{
return pin;
}
@@ -1575,7 +1581,7 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
/* Open a handle to search for devices (filters) */
handle = SetupDiGetClassDevs(category,NULL,NULL,DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- if ( handle == NULL )
+ if( handle == NULL )
{
return paUnanticipatedHostError;
}
@@ -1583,7 +1589,7 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
/* First let's count the number of devices so we can allocate a list */
invalidDevices = 0;
- for ( device = 0;;device++ )
+ for( device = 0;;device++ )
{
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
interfaceData.Reserved = 0;
@@ -1591,16 +1597,16 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
aliasData.Reserved = 0;
noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
PA_DEBUG(("Enum called\n"));
- if ( !noError )
+ if( !noError )
break; /* No more devices */
/* Check this one has the render or capture alias */
hasAlias = 0;
noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
PA_DEBUG(("noError = %d\n",noError));
- if (noError)
+ if(noError)
{
- if (aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
+ if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
{
PA_DEBUG(("Device %d has render alias\n",device));
hasAlias |= 1; /* Has render alias */
@@ -1611,9 +1617,9 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
}
}
noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
- if (noError)
+ if(noError)
{
- if (aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
+ if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
{
PA_DEBUG(("Device %d has capture alias\n",device));
hasAlias |= 2; /* Has capture alias */
@@ -1623,7 +1629,7 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
PA_DEBUG(("Device %d has no capture alias\n",device));
}
}
- if (!hasAlias)
+ if(!hasAlias)
invalidDevices++; /* This was not a valid capture or render audio device */
}
@@ -1636,14 +1642,14 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
wdmHostApi->filters = (PaWinWdmFilter**)PaUtil_AllocateMemory( sizeof(PaWinWdmFilter*) * device );
if( !wdmHostApi->filters )
{
- if (handle != NULL)
+ if(handle != NULL)
SetupDiDestroyDeviceInfoList(handle);
return paInsufficientMemory;
}
/* Now create filter objects for each interface found */
slot = 0;
- for ( device = 0;;device++ )
+ for( device = 0;;device++ )
{
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
interfaceData.Reserved = 0;
@@ -1653,34 +1659,34 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
devInfoData.Reserved = 0;
noError = SetupDiEnumDeviceInterfaces(handle,NULL,category,device,&interfaceData);
- if ( !noError )
+ if( !noError )
break; /* No more devices */
/* Check this one has the render or capture alias */
hasAlias = 0;
noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_render,&aliasData);
- if (noError)
+ if(noError)
{
- if (aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
+ if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
{
PA_DEBUG(("Device %d has render alias\n",device));
hasAlias |= 1; /* Has render alias */
}
}
noError = SetupDiGetDeviceInterfaceAlias(handle,&interfaceData,alias_capture,&aliasData);
- if (noError)
+ if(noError)
{
- if (aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
+ if(aliasData.Flags && (!(aliasData.Flags & SPINT_REMOVED)))
{
PA_DEBUG(("Device %d has capture alias\n",device));
hasAlias |= 2; /* Has capture alias */
}
}
- if (!hasAlias)
+ if(!hasAlias)
continue; /* This was not a valid capture or render audio device */
noError = SetupDiGetDeviceInterfaceDetail(handle,&interfaceData,devInterfaceDetails,sizeInterface,NULL,&devInfoData);
- if ( noError )
+ if( noError )
{
/* Try to get the "friendly name" for this interface */
sizeFriendlyName = sizeof(friendlyName);
@@ -1689,10 +1695,10 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
* as its causes failure when running without admin rights
* and it was not required */
hkey=SetupDiOpenDeviceInterfaceRegKey(handle,&interfaceData,0,KEY_QUERY_VALUE);
- if (hkey!=INVALID_HANDLE_VALUE)
+ if(hkey!=INVALID_HANDLE_VALUE)
{
noError = RegQueryValueEx(hkey,TEXT("FriendlyName"),0,&type,(BYTE*)friendlyName,&sizeFriendlyName);
- if ( noError == ERROR_SUCCESS )
+ if( noError == ERROR_SUCCESS )
{
PA_DEBUG(("Interface %d, Name: %s\n",device,friendlyName));
RegCloseKey(hkey);
@@ -1703,7 +1709,7 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
}
}
newFilter = FilterNew(devInterfaceDetails->DevicePath,friendlyName,&result);
- if ( result == paNoError )
+ if( result == paNoError )
{
PA_DEBUG(("Filter created\n"));
wdmHostApi->filters[slot] = newFilter;
@@ -1720,7 +1726,7 @@ static PaError BuildFilterList(PaWinWdmHostApiRepresentation* wdmHostApi)
}
/* Clean up */
- if (handle != NULL)
+ if(handle != NULL)
SetupDiDestroyDeviceInfoList(handle);
return paNoError;
@@ -1736,22 +1742,22 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
PaWinWdmDeviceInfo *wdmDeviceInfo;
PaDeviceInfo *deviceInfo;
- PA_LOGE_;
+ PA_LOGE_;
- /*
- Attempt to load the KSUSER.DLL without which we cannot create pins
- We will unload this on termination
- */
- if (DllKsUser == NULL)
- {
- DllKsUser = LoadLibrary(TEXT("ksuser.dll"));
- if (DllKsUser == NULL)
- goto error;
- }
+ /*
+ Attempt to load the KSUSER.DLL without which we cannot create pins
+ We will unload this on termination
+ */
+ if(DllKsUser == NULL)
+ {
+ DllKsUser = LoadLibrary(TEXT("ksuser.dll"));
+ if(DllKsUser == NULL)
+ goto error;
+ }
- FunctionKsCreatePin = (KSCREATEPIN*)GetProcAddress(DllKsUser, "KsCreatePin");
- if (FunctionKsCreatePin == NULL)
- goto error;
+ FunctionKsCreatePin = (KSCREATEPIN*)GetProcAddress(DllKsUser, "KsCreatePin");
+ if(FunctionKsCreatePin == NULL)
+ goto error;
wdmHostApi = (PaWinWdmHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinWdmHostApiRepresentation) );
if( !wdmHostApi )
@@ -1768,7 +1774,7 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
}
result = BuildFilterList( wdmHostApi );
- if ( result != paNoError )
+ if( result != paNoError )
{
goto error;
}
@@ -1778,7 +1784,7 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
(*hostApi)->info.structVersion = 1;
(*hostApi)->info.type = paWDMKS;
(*hostApi)->info.name = "Windows WDM-KS";
-
+ (*hostApi)->info.defaultInputDevice = paNoDevice;
(*hostApi)->info.defaultOutputDevice = paNoDevice;
if( deviceCount > 0 )
@@ -1804,8 +1810,8 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
{
wdmDeviceInfo = &deviceInfoArray[i];
deviceInfo = &wdmDeviceInfo->inheritedDeviceInfo;
- pFilter = wdmHostApi->filters[i];
- if ( pFilter == NULL )
+ pFilter = wdmHostApi->filters[i];
+ if( pFilter == NULL )
continue;
wdmDeviceInfo->filter = pFilter;
deviceInfo->structVersion = 2;
@@ -1813,24 +1819,24 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
deviceInfo->name = (char*)pFilter->friendlyName;
PA_DEBUG(("Device found name: %s\n",(char*)pFilter->friendlyName));
deviceInfo->maxInputChannels = pFilter->maxInputChannels;
- if (deviceInfo->maxInputChannels > 0)
+ if(deviceInfo->maxInputChannels > 0)
{
/* Set the default input device to the first device we find with
* more than zero input channels
**/
- if ((*hostApi)->info.defaultInputDevice == paNoDevice)
+ if((*hostApi)->info.defaultInputDevice == paNoDevice)
{
(*hostApi)->info.defaultInputDevice = i;
}
}
deviceInfo->maxOutputChannels = pFilter->maxOutputChannels;
- if (deviceInfo->maxOutputChannels > 0)
+ if(deviceInfo->maxOutputChannels > 0)
{
/* Set the default output device to the first device we find with
* more than zero output channels
**/
- if ((*hostApi)->info.defaultOutputDevice == paNoDevice)
+ if((*hostApi)->info.defaultOutputDevice == paNoDevice)
{
(*hostApi)->info.defaultOutputDevice = i;
}
@@ -1850,7 +1856,6 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
deviceInfo->defaultSampleRate = (double)(pFilter->bestSampleRate);
(*hostApi)->deviceInfos[i] = deviceInfo;
- ++(*hostApi)->info.deviceCount;
}
}
@@ -1871,15 +1876,15 @@ PaError PaWinWdm_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiInd
GetStreamTime, PaUtil_DummyGetCpuLoad,
ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
- PA_LOGL_;
+ PA_LOGL_;
return result;
error:
- if ( DllKsUser != NULL )
- {
- FreeLibrary( DllKsUser );
- DllKsUser = NULL;
- }
+ if( DllKsUser != NULL )
+ {
+ FreeLibrary( DllKsUser );
+ DllKsUser = NULL;
+ }
if( wdmHostApi )
{
@@ -1900,19 +1905,19 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
{
PaWinWdmHostApiRepresentation *wdmHostApi = (PaWinWdmHostApiRepresentation*)hostApi;
int i;
- PA_LOGE_;
+ PA_LOGE_;
- if( wdmHostApi->filters )
- {
- for ( i=0; i<wdmHostApi->filterCount; i++)
+ if( wdmHostApi->filters )
+ {
+ for( i=0; i<wdmHostApi->filterCount; i++)
{
- if ( wdmHostApi->filters[i] != NULL )
+ if( wdmHostApi->filters[i] != NULL )
{
FilterFree( wdmHostApi->filters[i] );
wdmHostApi->filters[i] = NULL;
}
}
- }
+ }
PaUtil_FreeMemory( wdmHostApi->filters );
if( wdmHostApi->allocations )
{
@@ -1924,20 +1929,20 @@ static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
}
static void FillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat, double sampleRate, int channelCount)
- {
- PA_LOGE_;
- PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat ));
- PA_DEBUG(( "sampleRate = %f\n" , sampleRate ));
- PA_DEBUG(( "chanelCount = %d\n", channelCount ));
+{
+ PA_LOGE_;
+ PA_DEBUG(( "sampleFormat = %lx\n" , sampleFormat ));
+ PA_DEBUG(( "sampleRate = %f\n" , sampleRate ));
+ PA_DEBUG(( "chanelCount = %d\n", channelCount ));
pwfext->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
pwfext->Format.nChannels = channelCount;
pwfext->Format.nSamplesPerSec = (int)sampleRate;
- if (channelCount == 1)
- pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
+ if(channelCount == 1)
+ pwfext->dwChannelMask = KSAUDIO_SPEAKER_DIRECTOUT;
else
- pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
- if (sampleFormat == paFloat32)
+ pwfext->dwChannelMask = KSAUDIO_SPEAKER_STEREO;
+ if(sampleFormat == paFloat32)
{
pwfext->Format.nBlockAlign = channelCount * 4;
pwfext->Format.wBitsPerSample = 32;
@@ -1945,7 +1950,7 @@ static void FillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat
pwfext->Samples.wValidBitsPerSample = 32;
pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
}
- else if (sampleFormat == paInt32)
+ else if(sampleFormat == paInt32)
{
pwfext->Format.nBlockAlign = channelCount * 4;
pwfext->Format.wBitsPerSample = 32;
@@ -1953,7 +1958,7 @@ static void FillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat
pwfext->Samples.wValidBitsPerSample = 32;
pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
}
- else if (sampleFormat == paInt24)
+ else if(sampleFormat == paInt24)
{
pwfext->Format.nBlockAlign = channelCount * 3;
pwfext->Format.wBitsPerSample = 24;
@@ -1961,7 +1966,7 @@ static void FillWFEXT( WAVEFORMATEXTENSIBLE* pwfext, PaSampleFormat sampleFormat
pwfext->Samples.wValidBitsPerSample = 24;
pwfext->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
}
- else if (sampleFormat == paInt16)
+ else if(sampleFormat == paInt16)
{
pwfext->Format.nBlockAlign = channelCount * 2;
pwfext->Format.wBitsPerSample = 16;
@@ -1986,7 +1991,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
int result = paFormatIsSupported;
WAVEFORMATEXTENSIBLE wfx;
- PA_LOGE_;
+ PA_LOGE_;
if( inputParameters )
{
@@ -2016,8 +2021,8 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
FillWFEXT(&wfx,paInt16,sampleRate,inputChannelCount);
pFilter = wdmHostApi->filters[inputParameters->device];
- result = FilterCanCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx);
- if ( result != paNoError )
+ result = FilterCanCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx);
+ if( result != paNoError )
{
/* Try a WAVE_FORMAT_PCM instead */
wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
@@ -2026,7 +2031,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
wfx.dwChannelMask = 0;
wfx.SubFormat = GUID_NULL;
result = FilterCanCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx);
- if ( result != paNoError )
+ if( result != paNoError )
return result;
}
}
@@ -2063,8 +2068,8 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
FillWFEXT(&wfx,paInt16,sampleRate,outputChannelCount);
pFilter = wdmHostApi->filters[outputParameters->device];
- result = FilterCanCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx);
- if ( result != paNoError )
+ result = FilterCanCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx);
+ if( result != paNoError )
{
/* Try a WAVE_FORMAT_PCM instead */
wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
@@ -2073,7 +2078,7 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
wfx.dwChannelMask = 0;
wfx.SubFormat = GUID_NULL;
result = FilterCanCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx);
- if ( result != paNoError )
+ if( result != paNoError )
return result;
}
@@ -2103,11 +2108,11 @@ static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
we have the capability to convert from outputSampleFormat to
a native format
*/
- if ((inputChannelCount == 0)&&(outputChannelCount == 0))
- result = paSampleFormatNotSupported; /* Not right error */
+ if((inputChannelCount == 0)&&(outputChannelCount == 0))
+ result = paSampleFormatNotSupported; /* Not right error */
- PA_LOGL_;
- return result;
+ PA_LOGL_;
+ return result;
}
/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
@@ -2129,13 +2134,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaSampleFormat inputSampleFormat, outputSampleFormat;
PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
int userInputChannels,userOutputChannels;
- int size;
+ int size;
PaWinWdmFilter* pFilter;
WAVEFORMATEXTENSIBLE wfx;
- PA_LOGE_;
- PA_DEBUG(("sampleRate = %f;",sampleRate));
- PA_DEBUG(("framesPerBuffer = %lu;",framesPerBuffer));
+ PA_LOGE_;
+ PA_DEBUG(("OpenStream:sampleRate = %f\n",sampleRate));
+ PA_DEBUG(("OpenStream:framesPerBuffer = %lu\n",framesPerBuffer));
if( inputParameters )
{
@@ -2216,22 +2221,44 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
/* Instantiate the input pin if necessary */
- if (userInputChannels > 0)
+ if(userInputChannels > 0)
{
- stream->userInputChannels = userInputChannels;
+ result = paSampleFormatNotSupported;
pFilter = wdmHostApi->filters[inputParameters->device];
- hostInputSampleFormat =
- PaUtil_SelectClosestAvailableFormat( pFilter->formats, inputSampleFormat );
- if ( hostInputSampleFormat == paInt16 )
- stream->inputSampleSize = 2;
- else
- stream->inputSampleSize = 3;
- FillWFEXT(&wfx,hostInputSampleFormat,sampleRate,stream->userInputChannels);
- stream->bytesPerInputFrame = wfx.Format.nBlockAlign;
- stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
- stream->deviceInputChannels = stream->userInputChannels;
- if (result != paNoError)
- {
+ stream->userInputChannels = userInputChannels;
+
+ if(((inputSampleFormat & ~paNonInterleaved) & pFilter->formats) != 0)
+ { /* inputSampleFormat is supported, so try to use it */
+ hostInputSampleFormat = inputSampleFormat;
+ FillWFEXT(&wfx, hostInputSampleFormat, sampleRate, stream->userInputChannels);
+ stream->bytesPerInputFrame = wfx.Format.nBlockAlign;
+ stream->recordingPin = FilterCreateCapturePin(pFilter, (const WAVEFORMATEX*)&wfx, &result);
+ stream->deviceInputChannels = stream->userInputChannels;
+ }
+
+ if(result != paNoError)
+ { /* Search through all PaSampleFormats to find one that works */
+ hostInputSampleFormat = paFloat32;
+
+ do {
+ FillWFEXT(&wfx, hostInputSampleFormat, sampleRate, stream->userInputChannels);
+ stream->bytesPerInputFrame = wfx.Format.nBlockAlign;
+ stream->recordingPin = FilterCreateCapturePin(pFilter, (const WAVEFORMATEX*)&wfx, &result);
+ stream->deviceInputChannels = stream->userInputChannels;
+
+ if(stream->recordingPin == NULL) result = paSampleFormatNotSupported;
+ if(result != paNoError) hostInputSampleFormat <<= 1;
+ }
+ while(result != paNoError && hostInputSampleFormat <= paUInt8);
+ }
+
+ if(result != paNoError)
+ { /* None of the PaSampleFormats worked. Set the hostInputSampleFormat to the best fit
+ * and try a PCM format.
+ **/
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( pFilter->formats, inputSampleFormat );
+
/* Try a WAVE_FORMAT_PCM instead */
wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
wfx.Format.cbSize = 0;
@@ -2239,36 +2266,49 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
wfx.dwChannelMask = 0;
wfx.SubFormat = GUID_NULL;
stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
- if ( result != paNoError )
+ if(stream->recordingPin == NULL) result = paSampleFormatNotSupported;
+ }
+
+ if( result != paNoError )
+ {
+ /* Some or all KS devices can only handle the exact number of channels
+ * they specify. But PortAudio clients expect to be able to
+ * at least specify mono I/O on a multi-channel device
+ * If this is the case, then we will do the channel mapping internally
+ **/
+ if( stream->userInputChannels < pFilter->maxInputChannels )
{
- /* Some or all KS devices can only handle the exact number of channels
- * they specify. But PortAudio clients expect to be able to
- * at least specify mono I/O on a multi-channel device
- * If this is the case, then we will do the channel mapping internally
- **/
- if ( stream->userInputChannels < pFilter->maxInputChannels )
+ FillWFEXT(&wfx,hostInputSampleFormat,sampleRate,pFilter->maxInputChannels);
+ stream->bytesPerInputFrame = wfx.Format.nBlockAlign;
+ stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
+ stream->deviceInputChannels = pFilter->maxInputChannels;
+
+ if( result != paNoError )
{
- FillWFEXT(&wfx,hostInputSampleFormat,sampleRate,pFilter->maxInputChannels);
- stream->bytesPerInputFrame = wfx.Format.nBlockAlign;
+ /* Try a WAVE_FORMAT_PCM instead */
+ wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.Format.cbSize = 0;
+ wfx.Samples.wValidBitsPerSample = 0;
+ wfx.dwChannelMask = 0;
+ wfx.SubFormat = GUID_NULL;
stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
- stream->deviceInputChannels = pFilter->maxInputChannels;
- if ( result != paNoError )
- {
- /* Try a WAVE_FORMAT_PCM instead */
- wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
- wfx.Format.cbSize = 0;
- wfx.Samples.wValidBitsPerSample = 0;
- wfx.dwChannelMask = 0;
- wfx.SubFormat = GUID_NULL;
- stream->recordingPin = FilterCreateCapturePin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
- }
}
}
}
- if (stream->recordingPin == NULL)
+
+ if(stream->recordingPin == NULL)
{
goto error;
}
+
+ switch(hostInputSampleFormat)
+ {
+ case paInt16: stream->inputSampleSize = 2; break;
+ case paInt24: stream->inputSampleSize = 3; break;
+ case paInt32:
+ case paFloat32: stream->inputSampleSize = 4; break;
+ }
+
stream->recordingPin->frameSize /= stream->bytesPerInputFrame;
PA_DEBUG(("Pin output frames: %d\n",stream->recordingPin->frameSize));
}
@@ -2279,22 +2319,42 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
}
/* Instantiate the output pin if necessary */
- if (userOutputChannels > 0)
+ if(userOutputChannels > 0)
{
- stream->userOutputChannels = userOutputChannels;
+ result = paSampleFormatNotSupported;
pFilter = wdmHostApi->filters[outputParameters->device];
- hostOutputSampleFormat =
- PaUtil_SelectClosestAvailableFormat( pFilter->formats/*paInt16*/, outputSampleFormat );
- if ( hostOutputSampleFormat == paInt16 )
- stream->outputSampleSize = 2;
- else
- stream->outputSampleSize = 3;
- FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,stream->userOutputChannels);
- stream->bytesPerOutputFrame = wfx.Format.nBlockAlign;
- stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result);
- stream->deviceOutputChannels = stream->userOutputChannels;
- if (result != paNoError)
+ stream->userOutputChannels = userOutputChannels;
+
+ if(((outputSampleFormat & ~paNonInterleaved) & pFilter->formats) != 0)
+ {
+ hostOutputSampleFormat = outputSampleFormat;
+ FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,stream->userOutputChannels);
+ stream->bytesPerOutputFrame = wfx.Format.nBlockAlign;
+ stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result);
+ stream->deviceOutputChannels = stream->userOutputChannels;
+ }
+
+ if(result != paNoError)
{
+ hostOutputSampleFormat = paFloat32;
+
+ do {
+ FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,stream->userOutputChannels);
+ stream->bytesPerOutputFrame = wfx.Format.nBlockAlign;
+ stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result);
+ stream->deviceOutputChannels = stream->userOutputChannels;
+
+ if(stream->playbackPin == NULL) result = paSampleFormatNotSupported;
+ if(result != paNoError) hostOutputSampleFormat <<= 1;
+ }
+ while(result != paNoError && hostOutputSampleFormat <= paUInt8);
+ }
+
+ if(result != paNoError)
+ {
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( pFilter->formats, outputSampleFormat );
+
/* Try a WAVE_FORMAT_PCM instead */
wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
wfx.Format.cbSize = 0;
@@ -2302,36 +2362,48 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
wfx.dwChannelMask = 0;
wfx.SubFormat = GUID_NULL;
stream->playbackPin = FilterCreateRenderPin(pFilter,(WAVEFORMATEX*)&wfx,&result);
- if ( result != paNoError )
+ if(stream->playbackPin == NULL) result = paSampleFormatNotSupported;
+ }
+
+ if( result != paNoError )
+ {
+ /* Some or all KS devices can only handle the exact number of channels
+ * they specify. But PortAudio clients expect to be able to
+ * at least specify mono I/O on a multi-channel device
+ * If this is the case, then we will do the channel mapping internally
+ **/
+ if( stream->userOutputChannels < pFilter->maxOutputChannels )
{
- /* Some or all KS devices can only handle the exact number of channels
- * they specify. But PortAudio clients expect to be able to
- * at least specify mono I/O on a multi-channel device
- * If this is the case, then we will do the channel mapping internally
- **/
- if ( stream->userOutputChannels < pFilter->maxOutputChannels )
+ FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,pFilter->maxOutputChannels);
+ stream->bytesPerOutputFrame = wfx.Format.nBlockAlign;
+ stream->playbackPin = FilterCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
+ stream->deviceOutputChannels = pFilter->maxOutputChannels;
+ if( result != paNoError )
{
- FillWFEXT(&wfx,hostOutputSampleFormat,sampleRate,pFilter->maxOutputChannels);
- stream->bytesPerOutputFrame = wfx.Format.nBlockAlign;
+ /* Try a WAVE_FORMAT_PCM instead */
+ wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.Format.cbSize = 0;
+ wfx.Samples.wValidBitsPerSample = 0;
+ wfx.dwChannelMask = 0;
+ wfx.SubFormat = GUID_NULL;
stream->playbackPin = FilterCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
- stream->deviceOutputChannels = pFilter->maxOutputChannels;
- if ( result != paNoError )
- {
- /* Try a WAVE_FORMAT_PCM instead */
- wfx.Format.wFormatTag = WAVE_FORMAT_PCM;
- wfx.Format.cbSize = 0;
- wfx.Samples.wValidBitsPerSample = 0;
- wfx.dwChannelMask = 0;
- wfx.SubFormat = GUID_NULL;
- stream->playbackPin = FilterCreateRenderPin(pFilter,(const WAVEFORMATEX*)&wfx,&result);
- }
}
}
}
- if (stream->playbackPin == NULL)
+
+ if(stream->playbackPin == NULL)
{
goto error;
}
+
+ switch(hostOutputSampleFormat)
+ {
+ case paInt16: stream->outputSampleSize = 2; break;
+ case paInt24: stream->outputSampleSize = 3; break;
+ case paInt32:
+ case paFloat32: stream->outputSampleSize = 4; break;
+ }
+
stream->playbackPin->frameSize /= stream->bytesPerOutputFrame;
PA_DEBUG(("Pin output frames: %d\n",stream->playbackPin->frameSize));
}
@@ -2341,49 +2413,41 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
stream->bytesPerOutputFrame = 0;
}
- /* Calculate the framesPerHostXxxxBuffer size based upon the suggested latency values */
+ /* Calculate the framesPerHostXxxxBuffer size based upon the suggested latency values */
- /* Record the buffer length */
- if (inputParameters)
- {
+ /* Record the buffer length */
+ if(inputParameters)
+ {
/* Calculate the frames from the user's value - add a bit to round up */
- stream->framesPerHostIBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001);
- if (stream->framesPerHostIBuffer > (unsigned long)sampleRate)
+ stream->framesPerHostIBuffer = (unsigned long)((inputParameters->suggestedLatency*sampleRate)+0.0001);
+ if(stream->framesPerHostIBuffer > (unsigned long)sampleRate)
{ /* Upper limit is 1 second */
- stream->framesPerHostIBuffer = (unsigned long)sampleRate;
+ stream->framesPerHostIBuffer = (unsigned long)sampleRate;
}
- /* Uncomment the following code to make the device-reported
- * frame size the lower limit*/
- /*
- else if (stream->framesPerHostIBuffer < stream->recordingPin->frameSize)
- {
- stream->framesPerHostIBuffer = stream->recordingPin->frameSize;
+ else if(stream->framesPerHostIBuffer < stream->recordingPin->frameSize)
+ {
+ stream->framesPerHostIBuffer = stream->recordingPin->frameSize;
}
- */
PA_DEBUG(("Input frames chosen:%ld\n",stream->framesPerHostIBuffer));
}
- if (outputParameters)
- {
+ if(outputParameters)
+ {
/* Calculate the frames from the user's value - add a bit to round up */
stream->framesPerHostOBuffer = (unsigned long)((outputParameters->suggestedLatency*sampleRate)+0.0001);
- if (stream->framesPerHostOBuffer > (unsigned long)sampleRate)
+ if(stream->framesPerHostOBuffer > (unsigned long)sampleRate)
{ /* Upper limit is 1 second */
- stream->framesPerHostOBuffer = (unsigned long)sampleRate;
+ stream->framesPerHostOBuffer = (unsigned long)sampleRate;
}
- /* Uncomment the following code to make the device-reported
- * frame size the lower limit*/
- /*
- else if (stream->framesPerHostOBuffer < stream->playbackPin->frameSize)
+ else if(stream->framesPerHostOBuffer < stream->playbackPin->frameSize)
{
- stream->framesPerHostOBuffer = stream->playbackPin->frameSize;
- }
- */
+ stream->framesPerHostOBuffer = stream->playbackPin->frameSize;
+ }
PA_DEBUG(("Output frames chosen:%ld\n",stream->framesPerHostOBuffer));
- }
+ }
- /* Host buffer size is bounded to the largest of the input and output
- frame sizes */
+ /* Host buffer size is bounded to the largest of the input and output
+ frame sizes */
result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
stream->userInputChannels, inputSampleFormat, hostInputSampleFormat,
@@ -2401,14 +2465,13 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
((double)stream->framesPerHostOBuffer) / sampleRate;
stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+ PA_DEBUG(("BytesPerInputFrame = %d\n",stream->bytesPerInputFrame));
+ PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->bytesPerOutputFrame));
- PA_DEBUG(("BytesPerInputFrame = %d\n",stream->bytesPerInputFrame));
- PA_DEBUG(("BytesPerOutputFrame = %d\n",stream->bytesPerOutputFrame));
-
- /* Allocate all the buffers for host I/O */
- size = 2 * (stream->framesPerHostIBuffer*stream->bytesPerInputFrame + stream->framesPerHostOBuffer*stream->bytesPerOutputFrame);
- PA_DEBUG(("Buffer size = %d\n",size));
- stream->hostBuffer = (char*)PaUtil_AllocateMemory(size);
+ /* Allocate all the buffers for host I/O */
+ size = 2 * (stream->framesPerHostIBuffer*stream->bytesPerInputFrame + stream->framesPerHostOBuffer*stream->bytesPerOutputFrame);
+ PA_DEBUG(("Buffer size = %d\n",size));
+ stream->hostBuffer = (char*)PaUtil_AllocateMemory(size);
PA_DEBUG(("Buffer allocated\n"));
if( !stream->hostBuffer )
{
@@ -2419,7 +2482,7 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
PA_DEBUG(("Buffer start = %p\n",stream->hostBuffer));
/* memset(stream->hostBuffer,0,size); */
- /* Set up the packets */
+ /* Set up the packets */
stream->events[0] = CreateEvent(NULL, FALSE, FALSE, NULL);
ResetEvent(stream->events[0]); /* Record buffer 1 */
stream->events[1] = CreateEvent(NULL, FALSE, FALSE, NULL);
@@ -2430,18 +2493,19 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
ResetEvent(stream->events[3]); /* Play buffer 2 */
stream->events[4] = CreateEvent(NULL, FALSE, FALSE, NULL);
ResetEvent(stream->events[4]); /* Abort event */
- if (stream->userInputChannels > 0)
- {
- DATAPACKET *p = &(stream->packets[0]);
- p->Signal.hEvent = stream->events[0];
+ if(stream->userInputChannels > 0)
+ {
+ DATAPACKET *p = &(stream->packets[0]);
+ p->Signal.hEvent = stream->events[0];
p->Header.Data = stream->hostBuffer;
p->Header.FrameExtent = stream->framesPerHostIBuffer*stream->bytesPerInputFrame;
p->Header.DataUsed = 0;
p->Header.Size = sizeof(p->Header);
p->Header.PresentationTime.Numerator = 1;
p->Header.PresentationTime.Denominator = 1;
- p = &(stream->packets[1]);
- p->Signal.hEvent = stream->events[1];
+
+ p = &(stream->packets[1]);
+ p->Signal.hEvent = stream->events[1];
p->Header.Data = stream->hostBuffer + stream->framesPerHostIBuffer*stream->bytesPerInputFrame;
p->Header.FrameExtent = stream->framesPerHostIBuffer*stream->bytesPerInputFrame;
p->Header.DataUsed = 0;
@@ -2449,60 +2513,61 @@ static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
p->Header.PresentationTime.Numerator = 1;
p->Header.PresentationTime.Denominator = 1;
}
- if (stream->userOutputChannels > 0)
- {
- DATAPACKET *p = &(stream->packets[2]);
- p->Signal.hEvent = stream->events[2];
+ if(stream->userOutputChannels > 0)
+ {
+ DATAPACKET *p = &(stream->packets[2]);
+ p->Signal.hEvent = stream->events[2];
p->Header.Data = stream->hostBuffer + 2*stream->framesPerHostIBuffer*stream->bytesPerInputFrame;
p->Header.FrameExtent = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame;
p->Header.DataUsed = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame;
p->Header.Size = sizeof(p->Header);
p->Header.PresentationTime.Numerator = 1;
p->Header.PresentationTime.Denominator = 1;
- p = &(stream->packets[3]);
- p->Signal.hEvent = stream->events[3];
+
+ p = &(stream->packets[3]);
+ p->Signal.hEvent = stream->events[3];
p->Header.Data = stream->hostBuffer + 2*stream->framesPerHostIBuffer*stream->bytesPerInputFrame + stream->framesPerHostOBuffer*stream->bytesPerOutputFrame;
p->Header.FrameExtent = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame;
p->Header.DataUsed = stream->framesPerHostOBuffer*stream->bytesPerOutputFrame;
p->Header.Size = sizeof(p->Header);
p->Header.PresentationTime.Numerator = 1;
p->Header.PresentationTime.Denominator = 1;
- }
+ }
- stream->streamStarted = 0;
- stream->streamActive = 0;
- stream->streamStop = 0;
- stream->streamAbort = 0;
- stream->streamFlags = streamFlags;
- stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
+ stream->streamStarted = 0;
+ stream->streamActive = 0;
+ stream->streamStop = 0;
+ stream->streamAbort = 0;
+ stream->streamFlags = streamFlags;
+ stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
*s = (PaStream*)stream;
- PA_LOGL_;
+ PA_LOGL_;
return result;
error:
- size = 5;
- while (size--)
- {
- if (stream->events[size] != NULL)
- {
- CloseHandle(stream->events[size]);
- stream->events[size] = NULL;
- }
- }
- if (stream->hostBuffer)
+ size = 5;
+ while(size--)
+ {
+ if(stream->events[size] != NULL)
+ {
+ CloseHandle(stream->events[size]);
+ stream->events[size] = NULL;
+ }
+ }
+ if(stream->hostBuffer)
PaUtil_FreeMemory( stream->hostBuffer );
- if (stream->playbackPin)
- PinClose(stream->playbackPin);
- if (stream->recordingPin)
- PinClose(stream->recordingPin);
+ if(stream->playbackPin)
+ PinClose(stream->playbackPin);
+ if(stream->recordingPin)
+ PinClose(stream->recordingPin);
if( stream )
PaUtil_FreeMemory( stream );
- PA_LOGL_;
+ PA_LOGL_;
return result;
}
@@ -2514,35 +2579,35 @@ static PaError CloseStream( PaStream* s )
{
PaError result = paNoError;
PaWinWdmStream *stream = (PaWinWdmStream*)s;
- int size;
+ int size;
- PA_LOGE_;
+ PA_LOGE_;
- assert(!stream->streamStarted);
- assert(!stream->streamActive);
+ assert(!stream->streamStarted);
+ assert(!stream->streamActive);
PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
- size = 5;
- while (size--)
- {
- if (stream->events[size] != NULL)
- {
- CloseHandle(stream->events[size]);
- stream->events[size] = NULL;
- }
- }
- if (stream->hostBuffer)
+ size = 5;
+ while(size--)
+ {
+ if(stream->events[size] != NULL)
+ {
+ CloseHandle(stream->events[size]);
+ stream->events[size] = NULL;
+ }
+ }
+ if(stream->hostBuffer)
PaUtil_FreeMemory( stream->hostBuffer );
- if (stream->playbackPin)
- PinClose(stream->playbackPin);
- if (stream->recordingPin)
- PinClose(stream->recordingPin);
+ if(stream->playbackPin)
+ PinClose(stream->playbackPin);
+ if(stream->recordingPin)
+ PinClose(stream->recordingPin);
PaUtil_FreeMemory( stream );
- PA_LOGL_;
+ PA_LOGL_;
return result;
}
@@ -2555,7 +2620,7 @@ static BOOL PinWrite(HANDLE h, DATAPACKET* p)
{
unsigned long cbReturned = 0;
return DeviceIoControl(h,IOCTL_KS_WRITE_STREAM,NULL,0,
- &p->Header,p->Header.Size,&cbReturned,&p->Signal);
+ &p->Header,p->Header.Size,&cbReturned,&p->Signal);
}
/*
@@ -2567,7 +2632,7 @@ static BOOL PinRead(HANDLE h, DATAPACKET* p)
{
unsigned long cbReturned = 0;
return DeviceIoControl(h,IOCTL_KS_READ_STREAM,NULL,0,
- &p->Header,p->Header.Size,&cbReturned,&p->Signal);
+ &p->Header,p->Header.Size,&cbReturned,&p->Signal);
}
/*
@@ -2578,11 +2643,11 @@ static void DuplicateFirstChannelInt16(void* buffer, int channels, int samples)
unsigned short* data = (unsigned short*)buffer;
int channel;
unsigned short sourceSample;
- while ( samples-- )
+ while( samples-- )
{
sourceSample = *data++;
channel = channels-1;
- while ( channel-- )
+ while( channel-- )
{
*data++ = sourceSample;
}
@@ -2597,14 +2662,14 @@ static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples)
unsigned char* data = (unsigned char*)buffer;
int channel;
unsigned char sourceSample[3];
- while ( samples-- )
+ while( samples-- )
{
sourceSample[0] = data[0];
sourceSample[1] = data[1];
sourceSample[2] = data[2];
data += 3;
channel = channels-1;
- while ( channel-- )
+ while( channel-- )
{
data[0] = sourceSample[0];
data[1] = sourceSample[1];
@@ -2614,6 +2679,25 @@ static void DuplicateFirstChannelInt24(void* buffer, int channels, int samples)
}
}
+/*
+Copy the first interleaved channel of 32 bit data to the other channels
+*/
+static void DuplicateFirstChannelInt32(void* buffer, int channels, int samples)
+{
+ unsigned long* data = (unsigned long*)buffer;
+ int channel;
+ unsigned long sourceSample;
+ while( samples-- )
+ {
+ sourceSample = *data++;
+ channel = channels-1;
+ while( channel-- )
+ {
+ *data++ = sourceSample;
+ }
+ }
+}
+
static DWORD WINAPI ProcessingThread(LPVOID pParam)
{
PaWinWdmStream *stream = (PaWinWdmStream*)pParam;
@@ -2623,12 +2707,12 @@ static DWORD WINAPI ProcessingThread(LPVOID pParam)
int outbuf = 0;
int pending = 0;
PaError result;
- unsigned long wait;
- unsigned long eventSignaled;
- int fillPlaybuf = 0;
- int emptyRecordbuf = 0;
- int framesProcessed;
- unsigned long timeout;
+ unsigned long wait;
+ unsigned long eventSignaled;
+ int fillPlaybuf = 0;
+ int emptyRecordbuf = 0;
+ int framesProcessed;
+ unsigned long timeout;
int i;
int doChannelCopy;
int priming = 0;
@@ -2640,56 +2724,55 @@ static DWORD WINAPI ProcessingThread(LPVOID pParam)
ti.currentTime = 0.0;
ti.outputBufferDacTime = 0.0;
- /* Get double buffering going */
+ /* Get double buffering going */
/* Submit buffers */
- if (stream->playbackPin)
+ if(stream->playbackPin)
{
- result = PinSetState(stream->playbackPin, KSSTATE_RUN);
+ result = PinSetState(stream->playbackPin, KSSTATE_RUN);
- PA_DEBUG(("play state run = %d;",(int)result));
- SetEvent(stream->events[outbuf+2]);
- outbuf = (outbuf+1)&1;
- SetEvent(stream->events[outbuf+2]);
- outbuf = (outbuf+1)&1;
- pending += 2;
+ PA_DEBUG(("play state run = %d;",(int)result));
+ SetEvent(stream->events[outbuf+2]);
+ outbuf = (outbuf+1)&1;
+ SetEvent(stream->events[outbuf+2]);
+ outbuf = (outbuf+1)&1;
+ pending += 2;
priming += 4;
}
- if (stream->recordingPin)
+ if(stream->recordingPin)
{
- result = PinSetState(stream->recordingPin, KSSTATE_RUN);
+ result = PinSetState(stream->recordingPin, KSSTATE_RUN);
- PA_DEBUG(("recording state run = %d;",(int)result));
- PinRead(stream->recordingPin->handle,&stream->packets[inbuf]);
- inbuf = (inbuf+1)&1; // Increment and wrap
- PinRead(stream->recordingPin->handle,&stream->packets[inbuf]);
- inbuf = (inbuf+1)&1; // Increment and wrap
- /* FIXME - do error checking */
- pending += 2;
+ PA_DEBUG(("recording state run = %d;",(int)result));
+ PinRead(stream->recordingPin->handle,&stream->packets[inbuf]);
+ inbuf = (inbuf+1)&1; /* Increment and wrap */
+ PinRead(stream->recordingPin->handle,&stream->packets[inbuf]);
+ inbuf = (inbuf+1)&1; /* Increment and wrap */
+ /* FIXME - do error checking */
+ pending += 2;
}
PA_DEBUG(("Out buffer len:%f\n",(2000*stream->framesPerHostOBuffer) / stream->streamRepresentation.streamInfo.sampleRate));
PA_DEBUG(("In buffer len:%f\n",(2000*stream->framesPerHostIBuffer) / stream->streamRepresentation.streamInfo.sampleRate));
timeout = max(
- ((2000*(DWORD)stream->framesPerHostOBuffer) / (DWORD)stream->streamRepresentation.streamInfo.sampleRate),
- ((2000*(DWORD)stream->framesPerHostIBuffer) / (DWORD)stream->streamRepresentation.streamInfo.sampleRate)
- );
+ ((2000*(DWORD)stream->framesPerHostOBuffer) / (DWORD)stream->streamRepresentation.streamInfo.sampleRate),
+ ((2000*(DWORD)stream->framesPerHostIBuffer) / (DWORD)stream->streamRepresentation.streamInfo.sampleRate));
timeout = max(timeout,1);
- PA_DEBUG(("Timeout = %ld ",timeout));
+ PA_DEBUG(("Timeout = %ld\n",timeout));
while(!stream->streamAbort)
{
- fillPlaybuf = 0;
- emptyRecordbuf = 0;
+ fillPlaybuf = 0;
+ emptyRecordbuf = 0;
- /* Wait for next input or output buffer to be finished with*/
- assert(pending>0);
+ /* Wait for next input or output buffer to be finished with*/
+ assert(pending>0);
- if (stream->streamStop)
- {
- PA_DEBUG(("ss1:pending=%d ",pending));
- }
+ if(stream->streamStop)
+ {
+ PA_DEBUG(("ss1:pending=%d ",pending));
+ }
wait = WaitForMultipleObjects(5, stream->events, FALSE, 0);
- if ( wait == WAIT_TIMEOUT )
+ if( wait == WAIT_TIMEOUT )
{
/* No (under|over)flow has ocurred */
wait = WaitForMultipleObjects(5, stream->events, FALSE, timeout);
@@ -2698,96 +2781,97 @@ static DWORD WINAPI ProcessingThread(LPVOID pParam)
else
{
eventSignaled = wait - WAIT_OBJECT_0;
- if ( eventSignaled < 2 )
+ if( eventSignaled < 2 )
{
underover |= paInputOverflow;
PA_DEBUG(("Input overflow\n"));
}
- else if (( eventSignaled < 4 )&&(!priming))
+ else if(( eventSignaled < 4 )&&(!priming))
{
underover |= paOutputUnderflow;
PA_DEBUG(("Output underflow\n"));
}
}
- if (stream->streamStop)
- {
- PA_DEBUG(("ss2:wait=%ld",wait));
- }
- if (wait == WAIT_FAILED)
- {
- PA_DEBUG(("Wait fail = %ld! ",wait));
+ if(stream->streamStop)
+ {
+ PA_DEBUG(("ss2:wait=%ld",wait));
+ }
+ if(wait == WAIT_FAILED)
+ {
+ PA_DEBUG(("Wait fail = %ld! ",wait));
break;
- }
- if (wait == WAIT_TIMEOUT)
+ }
+ if(wait == WAIT_TIMEOUT)
{
continue;
}
- if (eventSignaled < 2)
- { /* Recording input buffer has been filled */
- PA_DEBUG(("R"));
- if (stream->playbackPin)
+ if(eventSignaled < 2)
+ { /* Recording input buffer has been filled */
+ if(stream->playbackPin)
{
/* First check if also the next playback buffer has been signaled */
- wait = WaitForSingleObject(stream->events[outbuf+2],0);
- if (wait == WAIT_OBJECT_0)
- {
+ wait = WaitForSingleObject(stream->events[outbuf+2],0);
+ if(wait == WAIT_OBJECT_0)
+ {
/* Yes, so do both buffers at same time */
fillPlaybuf = 1;
- pending--;
+ pending--;
/* Was this an underflow situation? */
- if ( underover )
+ if( underover )
underover |= paOutputUnderflow; /* Yes! */
- }
- }
+ }
+ }
emptyRecordbuf = 1;
pending--;
- }
- else if (eventSignaled < 4)
- { /* Playback output buffer has been emptied */
- if (stream->recordingPin)
- {
- /* First check if also the next recording buffer has been signaled */
- wait = WaitForSingleObject(stream->events[inbuf],0);
- if (wait == WAIT_OBJECT_0)
- { /* Yes, so do both buffers at same time */
- emptyRecordbuf = 1;
- pending--;
+ }
+ else if(eventSignaled < 4)
+ { /* Playback output buffer has been emptied */
+ if(stream->recordingPin)
+ {
+ /* First check if also the next recording buffer has been signaled */
+ wait = WaitForSingleObject(stream->events[inbuf],0);
+ if(wait == WAIT_OBJECT_0)
+ { /* Yes, so do both buffers at same time */
+ emptyRecordbuf = 1;
+ pending--;
/* Was this an overflow situation? */
- if ( underover )
+ if( underover )
underover |= paInputOverflow; /* Yes! */
- }
- }
- fillPlaybuf = 1;
- pending--;
- }
- else
- {
+ }
+ }
+ fillPlaybuf = 1;
+ pending--;
+ }
+ else
+ {
/* Abort event! */
assert(stream->streamAbort); /* Should have been set */
- PA_DEBUG(("ABORTING "));
- break;
- }
- ResetEvent(stream->events[eventSignaled]);
-
- if (stream->streamStop)
- {
- PA_DEBUG(("Stream stop! pending=%d",pending));
- cbResult = paComplete; /* Stop, but play remaining buffers */
- }
-
- /* Do necessary buffer processing (which will invoke user callback if necessary */
+ PA_DEBUG(("ABORTING "));
+ break;
+ }
+ ResetEvent(stream->events[eventSignaled]);
+
+ if(stream->streamStop)
+ {
+ PA_DEBUG(("Stream stop! pending=%d",pending));
+ cbResult = paComplete; /* Stop, but play remaining buffers */
+ }
+
+ /* Do necessary buffer processing (which will invoke user callback if necessary */
doChannelCopy = 0;
- if (cbResult==paContinue)
- {
- PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
- PaUtil_BeginBufferProcessing(&stream->bufferProcessor,&ti,underover);
+ if(cbResult==paContinue)
+ {
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+ if((stream->bufferProcessor.hostInputFrameCount[0] + stream->bufferProcessor.hostInputFrameCount[1]) ==
+ (stream->bufferProcessor.hostOutputFrameCount[0] + stream->bufferProcessor.hostOutputFrameCount[1]) )
+ PaUtil_BeginBufferProcessing(&stream->bufferProcessor,&ti,underover);
underover = 0; /* Reset the (under|over)flow status */
- if (fillPlaybuf)
- {
- PaUtil_SetOutputFrameCount(&stream->bufferProcessor,0);
- if ( stream->userOutputChannels == 1 )
+ if(fillPlaybuf)
+ {
+ PaUtil_SetOutputFrameCount(&stream->bufferProcessor,0);
+ if( stream->userOutputChannels == 1 )
{
/* Write the single user channel to the first interleaved block */
PaUtil_SetOutputChannel(&stream->bufferProcessor,0,stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels);
@@ -2796,87 +2880,97 @@ static DWORD WINAPI ProcessingThread(LPVOID pParam)
}
else
{
- for (i=0;i<stream->userOutputChannels;i++)
+ for(i=0;i<stream->userOutputChannels;i++)
{
- /* Only write the user output channels. Leave the rest blank */
- PaUtil_SetOutputChannel(&stream->bufferProcessor,i,((unsigned char*)(stream->packets[outbuf+2].Header.Data))+(i*stream->outputSampleSize),stream->deviceOutputChannels);
+ /* Only write the user output channels. Leave the rest blank */
+ PaUtil_SetOutputChannel(&stream->bufferProcessor,i,((unsigned char*)(stream->packets[outbuf+2].Header.Data))+(i*stream->outputSampleSize),stream->deviceOutputChannels);
}
}
- }
- if (emptyRecordbuf)
- {
- PaUtil_SetInputFrameCount(&stream->bufferProcessor,stream->packets[inbuf].Header.DataUsed/stream->bytesPerInputFrame);
- for (i=0;i<stream->userInputChannels;i++)
+ }
+ if(emptyRecordbuf)
+ {
+ PaUtil_SetInputFrameCount(&stream->bufferProcessor,stream->packets[inbuf].Header.DataUsed/stream->bytesPerInputFrame);
+ for(i=0;i<stream->userInputChannels;i++)
{
/* Only read as many channels as the user wants */
PaUtil_SetInputChannel(&stream->bufferProcessor,i,((unsigned char*)(stream->packets[inbuf].Header.Data))+(i*stream->inputSampleSize),stream->deviceInputChannels);
}
- }
- framesProcessed = PaUtil_EndBufferProcessing(&stream->bufferProcessor,&cbResult);
- if ( doChannelCopy )
+ }
+ /* Only call the EndBufferProcessing function is the total input frames == total output frames */
+ if((stream->bufferProcessor.hostInputFrameCount[0] + stream->bufferProcessor.hostInputFrameCount[1]) ==
+ (stream->bufferProcessor.hostOutputFrameCount[0] + stream->bufferProcessor.hostOutputFrameCount[1]) )
+ framesProcessed = PaUtil_EndBufferProcessing(&stream->bufferProcessor,&cbResult);
+ else framesProcessed = 0;
+ if( doChannelCopy )
{
/* Copy the first output channel to the other channels */
- if ( stream->outputSampleSize == 2 )
+ switch(stream->outputSampleSize)
{
- DuplicateFirstChannelInt16(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer);
+ case 2:
+ DuplicateFirstChannelInt16(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer);
+ break;
+ case 3:
+ DuplicateFirstChannelInt24(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer);
+ break;
+ case 4:
+ DuplicateFirstChannelInt32(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer);
+ break;
+ default:
+ assert(0); /* Unsupported format! */
+ break;
}
- else if ( stream->outputSampleSize == 3 )
- {
- DuplicateFirstChannelInt24(stream->packets[outbuf+2].Header.Data,stream->deviceOutputChannels,stream->framesPerHostOBuffer);
- }
- else
- assert(0); /* Unsupported format! */
}
- PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
- }
- else
- {
- fillPlaybuf = 0;
- emptyRecordbuf = 0;
- }
- /*
- if (cbResult != paContinue)
- {
- PA_DEBUG(("cbResult=%d, pending=%d:",cbResult,pending));
- }
- */
- /* Submit buffers */
- if ((fillPlaybuf)&&(cbResult!=paAbort))
- {
- if (!PinWrite(stream->playbackPin->handle,&stream->packets[outbuf+2]))
- outbuf = (outbuf+1)&1; /* Increment and wrap */
- pending++;
- if ( priming )
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+ }
+ else
+ {
+ fillPlaybuf = 0;
+ emptyRecordbuf = 0;
+ }
+
+ /*
+ if(cbResult != paContinue)
+ {
+ PA_DEBUG(("cbResult=%d, pending=%d:",cbResult,pending));
+ }
+ */
+ /* Submit buffers */
+ if((fillPlaybuf)&&(cbResult!=paAbort))
+ {
+ if(!PinWrite(stream->playbackPin->handle,&stream->packets[outbuf+2]))
+ outbuf = (outbuf+1)&1; /* Increment and wrap */
+ pending++;
+ if( priming )
priming--; /* Have to prime twice */
- }
- if ((emptyRecordbuf)&&(cbResult==paContinue))
- {
- stream->packets[inbuf].Header.DataUsed = 0; /* Reset for reuse */
- PinRead(stream->recordingPin->handle,&stream->packets[inbuf]);
- inbuf = (inbuf+1)&1; /* Increment and wrap */
- pending++;
- }
- if (pending==0)
- {
- PA_DEBUG(("pending==0 finished...;"));
- break;
- }
- if ((!stream->playbackPin)&&(cbResult!=paContinue))
- {
- PA_DEBUG(("record only cbResult=%d...;",cbResult));
- break;
- }
+ }
+ if((emptyRecordbuf)&&(cbResult==paContinue))
+ {
+ stream->packets[inbuf].Header.DataUsed = 0; /* Reset for reuse */
+ PinRead(stream->recordingPin->handle,&stream->packets[inbuf]);
+ inbuf = (inbuf+1)&1; /* Increment and wrap */
+ pending++;
+ }
+ if(pending==0)
+ {
+ PA_DEBUG(("pending==0 finished...;"));
+ break;
+ }
+ if((!stream->playbackPin)&&(cbResult!=paContinue))
+ {
+ PA_DEBUG(("record only cbResult=%d...;",cbResult));
+ break;
+ }
}
PA_DEBUG(("Finished thread"));
/* Finished, either normally or aborted */
- if (stream->playbackPin)
+ if(stream->playbackPin)
{
result = PinSetState(stream->playbackPin, KSSTATE_PAUSE);
result = PinSetState(stream->playbackPin, KSSTATE_STOP);
}
- if (stream->recordingPin)
+ if(stream->recordingPin)
{
result = PinSetState(stream->recordingPin, KSSTATE_PAUSE);
result = PinSetState(stream->recordingPin, KSSTATE_STOP);
@@ -2884,73 +2978,73 @@ static DWORD WINAPI ProcessingThread(LPVOID pParam)
stream->streamActive = 0;
- if ((!stream->streamStop)&&(!stream->streamAbort))
+ if((!stream->streamStop)&&(!stream->streamAbort))
{
- /* Invoke the user stream finished callback */
- /* Only do it from here if not being stopped/aborted by user */
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+ /* Invoke the user stream finished callback */
+ /* Only do it from here if not being stopped/aborted by user */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
}
- stream->streamStop = 0;
- stream->streamAbort = 0;
+ stream->streamStop = 0;
+ stream->streamAbort = 0;
- /* Reset process priority if necessary */
- if (stream->oldProcessPriority != REALTIME_PRIORITY_CLASS)
- {
- SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority);
- stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
- }
+ /* Reset process priority if necessary */
+ if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS)
+ {
+ SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority);
+ stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
+ }
PA_LOGL_;
ExitThread(0);
- return 0;
+ return 0;
}
static PaError StartStream( PaStream *s )
{
PaError result = paNoError;
PaWinWdmStream *stream = (PaWinWdmStream*)s;
- DWORD dwID;
- BOOL ret;
- int size;
-
- PA_LOGE_;
-
- stream->streamStop = 0;
- stream->streamAbort = 0;
- size = 5;
- while (size--)
- {
- if (stream->events[size] != NULL)
- {
- ResetEvent(stream->events[size]);
- }
- }
+ DWORD dwID;
+ BOOL ret;
+ int size;
+
+ PA_LOGE_;
+
+ stream->streamStop = 0;
+ stream->streamAbort = 0;
+ size = 5;
+ while(size--)
+ {
+ if(stream->events[size] != NULL)
+ {
+ ResetEvent(stream->events[size]);
+ }
+ }
PaUtil_ResetBufferProcessor( &stream->bufferProcessor );
- stream->oldProcessPriority = GetPriorityClass(GetCurrentProcess());
+ stream->oldProcessPriority = GetPriorityClass(GetCurrentProcess());
/* Uncomment the following line to enable dynamic boosting of the process
* priority to real time for best low latency support
* Disabled by default because RT processes can easily block the OS */
- /*ret = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
- PA_DEBUG(("Class ret = %d;",ret));*/
-
- stream->streamStarted = 1;
- stream->streamThread = CreateThread(NULL, 0, ProcessingThread, stream, 0, &dwID);
- if (stream->streamThread == NULL)
- {
- stream->streamStarted = 0;
- result = paInsufficientMemory;
- goto end;
- }
- ret = SetThreadPriority(stream->streamThread,THREAD_PRIORITY_TIME_CRITICAL);
- PA_DEBUG(("Priority ret = %d;",ret));
+ /*ret = SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS);
+ PA_DEBUG(("Class ret = %d;",ret));*/
+
+ stream->streamStarted = 1;
+ stream->streamThread = CreateThread(NULL, 0, ProcessingThread, stream, 0, &dwID);
+ if(stream->streamThread == NULL)
+ {
+ stream->streamStarted = 0;
+ result = paInsufficientMemory;
+ goto end;
+ }
+ ret = SetThreadPriority(stream->streamThread,THREAD_PRIORITY_TIME_CRITICAL);
+ PA_DEBUG(("Priority ret = %d;",ret));
/* Make the stream active */
stream->streamActive = 1;
end:
- PA_LOGL_;
+ PA_LOGL_;
return result;
}
@@ -2961,44 +3055,44 @@ static PaError StopStream( PaStream *s )
PaWinWdmStream *stream = (PaWinWdmStream*)s;
int doCb = 0;
- PA_LOGE_;
+ PA_LOGE_;
- if (stream->streamActive)
- {
- doCb = 1;
- stream->streamStop = 1;
- while (stream->streamActive)
- {
- PA_DEBUG(("W."));
- Sleep(10); /* Let thread sleep for 10 msec */
- }
- }
+ if(stream->streamActive)
+ {
+ doCb = 1;
+ stream->streamStop = 1;
+ while(stream->streamActive)
+ {
+ PA_DEBUG(("W."));
+ Sleep(10); /* Let thread sleep for 10 msec */
+ }
+ }
- PA_DEBUG(("Terminating thread"));
- if (stream->streamStarted && stream->streamThread)
- {
- TerminateThread(stream->streamThread,0);
- stream->streamThread = NULL;
- }
+ PA_DEBUG(("Terminating thread"));
+ if(stream->streamStarted && stream->streamThread)
+ {
+ TerminateThread(stream->streamThread,0);
+ stream->streamThread = NULL;
+ }
- stream->streamStarted = 0;
+ stream->streamStarted = 0;
- if (stream->oldProcessPriority != REALTIME_PRIORITY_CLASS)
- {
- SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority);
- stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
- }
+ if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS)
+ {
+ SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority);
+ stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
+ }
- if (doCb)
+ if(doCb)
{
- /* Do user callback now after all state has been reset */
- /* This means it should be safe for the called function */
- /* to invoke e.g. StartStream */
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+ /* Do user callback now after all state has been reset */
+ /* This means it should be safe for the called function */
+ /* to invoke e.g. StartStream */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
}
- PA_LOGL_;
+ PA_LOGL_;
return result;
}
@@ -3008,46 +3102,46 @@ static PaError AbortStream( PaStream *s )
PaWinWdmStream *stream = (PaWinWdmStream*)s;
int doCb = 0;
- PA_LOGE_;
-
- if (stream->streamActive)
- {
- doCb = 1;
- stream->streamAbort = 1;
- SetEvent(stream->events[4]); /* Signal immediately */
- while (stream->streamActive)
- {
- Sleep(10);
- }
- }
-
- if (stream->streamStarted && stream->streamThread)
- {
- TerminateThread(stream->streamThread,0);
- stream->streamThread = NULL;
- }
+ PA_LOGE_;
+
+ if(stream->streamActive)
+ {
+ doCb = 1;
+ stream->streamAbort = 1;
+ SetEvent(stream->events[4]); /* Signal immediately */
+ while(stream->streamActive)
+ {
+ Sleep(10);
+ }
+ }
+
+ if(stream->streamStarted && stream->streamThread)
+ {
+ TerminateThread(stream->streamThread,0);
+ stream->streamThread = NULL;
+ }
stream->streamStarted = 0;
- if (stream->oldProcessPriority != REALTIME_PRIORITY_CLASS)
- {
- SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority);
- stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
- }
+ if(stream->oldProcessPriority != REALTIME_PRIORITY_CLASS)
+ {
+ SetPriorityClass(GetCurrentProcess(),stream->oldProcessPriority);
+ stream->oldProcessPriority = REALTIME_PRIORITY_CLASS;
+ }
- if (doCb)
+ if(doCb)
{
- /* Do user callback now after all state has been reset */
- /* This means it should be safe for the called function */
- /* to invoke e.g. StartStream */
- if( stream->streamRepresentation.streamFinishedCallback != 0 )
- stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+ /* Do user callback now after all state has been reset */
+ /* This means it should be safe for the called function */
+ /* to invoke e.g. StartStream */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
}
- stream->streamActive = 0;
- stream->streamStarted = 0;
+ stream->streamActive = 0;
+ stream->streamStarted = 0;
- PA_LOGL_;
+ PA_LOGL_;
return result;
}
@@ -3055,14 +3149,14 @@ static PaError AbortStream( PaStream *s )
static PaError IsStreamStopped( PaStream *s )
{
PaWinWdmStream *stream = (PaWinWdmStream*)s;
- int result = 0;
+ int result = 0;
- PA_LOGE_;
+ PA_LOGE_;
- if (!stream->streamStarted)
- result = 1;
+ if(!stream->streamStarted)
+ result = 1;
- PA_LOGL_;
+ PA_LOGL_;
return result;
}
@@ -3070,21 +3164,21 @@ static PaError IsStreamStopped( PaStream *s )
static PaError IsStreamActive( PaStream *s )
{
PaWinWdmStream *stream = (PaWinWdmStream*)s;
- int result = 0;
+ int result = 0;
- PA_LOGE_;
+ PA_LOGE_;
- if (stream->streamActive)
- result = 1;
+ if(stream->streamActive)
+ result = 1;
- PA_LOGL_;
+ PA_LOGL_;
return result;
}
static PaTime GetStreamTime( PaStream* s )
{
- PA_LOGE_;
+ PA_LOGE_;
PA_LOGL_;
(void)s;
return PaUtil_GetTime();
@@ -3094,11 +3188,11 @@ static PaTime GetStreamTime( PaStream* s )
static double GetStreamCpuLoad( PaStream* s )
{
PaWinWdmStream *stream = (PaWinWdmStream*)s;
- double result;
- PA_LOGE_;
+ double result;
+ PA_LOGE_;
result = PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
- PA_LOGL_;
- return result;
+ PA_LOGL_;
+ return result;
}
@@ -3114,7 +3208,7 @@ static PaError ReadStream( PaStream* s,
{
PaWinWdmStream *stream = (PaWinWdmStream*)s;
- PA_LOGE_;
+ PA_LOGE_;
/* suppress unused variable warnings */
(void) buffer;
@@ -3122,7 +3216,7 @@ static PaError ReadStream( PaStream* s,
(void) stream;
/* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
+ PA_LOGL_;
return paNoError;
}
@@ -3133,7 +3227,7 @@ static PaError WriteStream( PaStream* s,
{
PaWinWdmStream *stream = (PaWinWdmStream*)s;
- PA_LOGE_;
+ PA_LOGE_;
/* suppress unused variable warnings */
(void) buffer;
@@ -3141,7 +3235,7 @@ static PaError WriteStream( PaStream* s,
(void) stream;
/* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
+ PA_LOGL_;
return paNoError;
}
@@ -3150,13 +3244,13 @@ static signed long GetStreamReadAvailable( PaStream* s )
{
PaWinWdmStream *stream = (PaWinWdmStream*)s;
- PA_LOGE_;
+ PA_LOGE_;
/* suppress unused variable warnings */
(void) stream;
/* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
+ PA_LOGL_;
return 0;
}
@@ -3165,15 +3259,11 @@ static signed long GetStreamWriteAvailable( PaStream* s )
{
PaWinWdmStream *stream = (PaWinWdmStream*)s;
- PA_LOGE_;
+ PA_LOGE_;
/* suppress unused variable warnings */
(void) stream;
/* IMPLEMENT ME, see portaudio.h for required behavior*/
- PA_LOGL_;
+ PA_LOGL_;
return 0;
-}
-
-
-
-
+} \ No newline at end of file
diff --git a/pd/portaudio/pa_win_wdmks/readme.txt b/pd/portaudio/pa_win_wdmks/readme.txt
index 2fc6c75c..1a381fe7 100644
--- a/pd/portaudio/pa_win_wdmks/readme.txt
+++ b/pd/portaudio/pa_win_wdmks/readme.txt
@@ -3,6 +3,17 @@ Notes about WDM-KS host API
Status history
--------------
+10th November 2005:
+Made following changes:
+ * OpenStream: Try all PaSampleFormats internally if the the chosen
+ format is not supported natively. This fixed several problems
+ with soundcards that soundcards that did not take kindly to
+ using 24-bit 3-byte formats.
+ * OpenStream: Make the minimum framesPerHostIBuffer (and framesPerHostOBuffer)
+ the default frameSize for the playback/recording pin.
+ * ProcessingThread: Added a switch to only call PaUtil_EndBufferProcessing
+ if the total input frames equals the total output frames
+
5th September 2004:
This is the first public version of the code. It should be considered
an alpha release with zero guarantee not to crash on any particular
diff --git a/pd/portaudio/pa_win_wmme/pa_win_wmme.c b/pd/portaudio/pa_win_wmme/pa_win_wmme.c
index c3d7fe6d..1a9ea59e 100644
--- a/pd/portaudio/pa_win_wmme/pa_win_wmme.c
+++ b/pd/portaudio/pa_win_wmme/pa_win_wmme.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_win_wmme.c,v 1.6.2.86 2004/02/21 11:38:28 rossbencina Exp $
+ * $Id: pa_win_wmme.c,v 1.6.2.88 2006/02/16 01:56:45 rossbencina Exp $
* pa_win_wmme.c
* Implementation of PortAudio for Windows MultiMedia Extensions (WMME)
*
@@ -128,6 +128,13 @@ Non-critical stuff for the future:
#pragma comment(lib, "winmm.lib")
#endif
+/*
+ provided in newer platform sdks
+ */
+#ifndef DWORD_PTR
+#define DWORD_PTR DWORD
+#endif
+
/************************************************* Constants ********/
#define PA_MME_USE_HIGH_DEFAULT_LATENCY_ (0) /* For debugging glitches. */
@@ -1555,10 +1562,10 @@ static PaError InitializeWaveHandles( PaWinMmeHostApiRepresentation *winMmeHostA
if( isInput )
mmresult = waveInOpen( &((HWAVEIN*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,
- (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );
+ (DWORD_PTR)handlesAndBuffers->bufferEvent, (DWORD_PTR)0, CALLBACK_EVENT );
else
mmresult = waveOutOpen( &((HWAVEOUT*)handlesAndBuffers->waveHandles)[i], winMmeDeviceId, &wfx,
- (DWORD)handlesAndBuffers->bufferEvent, (DWORD)0, CALLBACK_EVENT );
+ (DWORD_PTR)handlesAndBuffers->bufferEvent, (DWORD_PTR)0, CALLBACK_EVENT );
if( mmresult != MMSYSERR_NOERROR )
{
@@ -1616,11 +1623,15 @@ static PaError TerminateWaveHandles( PaWinMmeSingleDirectionHandlesAndBuffers *h
{
if( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] )
mmresult = waveInClose( ((HWAVEIN*)handlesAndBuffers->waveHandles)[i] );
+ else
+ mmresult = MMSYSERR_NOERROR;
}
else
{
if( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] )
mmresult = waveOutClose( ((HWAVEOUT*)handlesAndBuffers->waveHandles)[i] );
+ else
+ mmresult = MMSYSERR_NOERROR;
}
if( mmresult != MMSYSERR_NOERROR &&
diff --git a/pd/portaudio/pablio/ringbuffer.h b/pd/portaudio/pablio/ringbuffer.h
index 2d522277..8e16f2c7 100644
--- a/pd/portaudio/pablio/ringbuffer.h
+++ b/pd/portaudio/pablio/ringbuffer.h
@@ -6,7 +6,7 @@ extern "C"
#endif /* __cplusplus */
/*
- * $Id: ringbuffer.h,v 1.3 2006-03-10 11:04:58 ggeiger Exp $
+ * $Id: ringbuffer.h,v 1.4 2006-06-03 19:13:07 millerpuckette Exp $
* ringbuffer.h
* Ring Buffer utility..
*
diff --git a/pd/portmidi/pm_mac/pmmacosxcm.c b/pd/portmidi/pm_mac/pmmacosxcm.c
index e0555fe5..0847596e 100644
--- a/pd/portmidi/pm_mac/pmmacosxcm.c
+++ b/pd/portmidi/pm_mac/pmmacosxcm.c
@@ -5,7 +5,7 @@
* and subsequent work by Andrew Zeldis and Zico Kolter
* and Roger B. Dannenberg
*
- * $Id: pmmacosxcm.c,v 1.3 2005-12-31 20:55:25 millerpuckette Exp $
+ * $Id: pmmacosxcm.c,v 1.4 2006-06-03 19:13:07 millerpuckette Exp $
*/
/* Notes:
diff --git a/pd/src/configure.in b/pd/src/configure.in
index 5e43a990..6656f493 100644
--- a/pd/src/configure.in
+++ b/pd/src/configure.in
@@ -6,6 +6,7 @@ AC_SUBST(jack, no)
AC_SUBST(portaudio, no)
AC_SUBST(portmidi, no)
AC_SUBST(binarymode, -m755)
+AC_SUBST(fftw, no)
AC_SUBST(PDLIB)
AC_SUBST(MORECFLAGS)
AC_SUBST(EXT)
@@ -38,7 +39,9 @@ AC_ARG_ENABLE(static, [ --enable-static link statically],
static=$enableval)
AC_ARG_ENABLE(setuid, [ --enable-setuid install as setuid (linux)],
setuid=$enableval)
-
+AC_ARG_ENABLE(fftw, [ --enable-fftw use FFTW package],
+ fftw=$enableval)
+
dnl Checks for programs.
AC_PROG_CC
AC_PROG_INSTALL
@@ -79,6 +82,13 @@ dnl Checking for `pthread_create' function in -pthread
AC_CHECK_LIB(pthread, pthread_create,PDLIB="$PDLIB -lpthread",
echo "pthreads required" || exit 1)
+dnl Check for fftw package
+if test x$fftw == "xyes";
+then
+AC_CHECK_LIB(fftw, fftw_one,PDLIB="$PDLIB -lfftw",
+ echo "fftw package not found - using built-in FFT"; fftw=no)
+fi
+
dnl look for tcl 8.x... do I really have to go through all this!?
foundit=no
@@ -161,7 +171,7 @@ dnl This should be fixed so Pd can use ALSA shared libraries where appropriate.
LDFLAGS="$LDFLAGS -static"
fi
EXT=pd_linux
- MORECFLAGS="-DDL_OPEN -DPA_USE_OSS -DPA_LITTLE_ENDIAN -DUNIX -DUNISTD\
+ MORECFLAGS="-DDL_OPEN -DPA_USE_OSS -DUNIX -DUNISTD\
-DUSEAPI_OSS \
-I../portaudio/pa_common -I../portaudio/pablio \
-I../portmidi/pm_common \
@@ -213,17 +223,7 @@ dnl This should be fixed so Pd can use ALSA shared libraries where appropriate.
OPT_CFLAGS="-g"
else
OPT_CFLAGS="-O6 -funroll-loops -fomit-frame-pointer"
-
- if test x$jack == "xyes";
- then
- LDFLAGS=$LDFLAGS" -lrt -ljack"
fi
- if test x$jack == "xrun";
- then
- LDFLAGS=$LDFLAGS" -lrt -ljack"
- fi
- fi
-
if test x$jack == "xyes";
then
LDFLAGS=$LDFLAGS" -lrt -ljack"
@@ -232,26 +232,10 @@ dnl This should be fixed so Pd can use ALSA shared libraries where appropriate.
then
LDFLAGS=$LDFLAGS" -lrt -ljack"
fi
+
echo OPT_CFLAGS --------------- $OPT_CFLAGS
OSNUMBER=0
- if test x$jack == "xyes";
- then
- LDFLAGS=$LDFLAGS" -lrt -ljack"
- fi
- if test x$jack == "xrun";
- then
- LDFLAGS=$LDFLAGS" -lrt -ljack"
- fi
- fi
-
- if test x$jack == "xyes";
- then
- LDFLAGS=$LDFLAGS" -lrt -ljack"
- fi
- if test x$jack == "xrun";
- then
- LDFLAGS=$LDFLAGS" -lrt -ljack"
fi
if test `uname -s` = Darwin;
@@ -265,7 +249,7 @@ then
-I../portmidi/pm_common -I../portmidi/pm_mac \
-I../portmidi/porttime \
-Wno-error \
- -DUSEAPI_PORTAUDIO -DPA_BIG_ENDIAN -DPA19 -DPA_USE_COREAUDIO"
+ -DUSEAPI_PORTAUDIO -DPA19 -DPA_USE_COREAUDIO"
SYSSRC="s_midi_pm.c s_audio_pa.c \
s_audio_pablio.c \
s_audio_paring.c \
@@ -313,7 +297,12 @@ then
OPT_CFLAGS="-O2"
fi
OSNUMBER=2
- EXTERNTARGET=pd_darwin
+ if test `uname -m` = i386;
+ then
+ EXTERNTARGET=pd_imac
+ else
+ EXTERNTARGET=pd_darwin
+ fi
if test x$jack == "xyes";
then
LDFLAGS=$LDFLAGS" -weak_framework Jack"
@@ -337,6 +326,14 @@ then
SYSSRC=$SYSSRC" s_audio_jack.c"
fi
+if test x$fftw == "xyes";
+then
+ SYSSRC=$SYSSRC" d_fft_fftw.c d_fftroutine.c"
+ LDFLAGS=$LDFLAGS" -lfftw"
+else
+ SYSSRC=$SYSSRC" d_fft_mayer.c d_fftroutine.c"
+fi
+
# extra flags for alpha machines
if test `uname -m | awk '{print $1}'` = alpha;
then
diff --git a/pd/src/d_fft.c b/pd/src/d_fft.c
index fa2590ea..006a985a 100644
--- a/pd/src/d_fft.c
+++ b/pd/src/d_fft.c
@@ -1,9 +1,16 @@
-/* Copyright (c) 1997-1999 Miller Puckette and others.
+/* Copyright (c) 1997- Miller Puckette and others.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
#include "m_pd.h"
+/* This file interfaces to one of the Mayer, Ooura, or fftw FFT packages
+to implement the "fft~", etc, Pd objects. If using Mayer, also compile
+d_fft_mayer.c; if ooura, use d_fft_fftsg.c instead; if fftw, use d_fft_fftw.c
+and also link in the fftw library. You can only have one of these three
+linked in. The configure script can be used to select which one.
+*/
+
/* ---------------- utility functions for DSP chains ---------------------- */
/* swap two arrays */
diff --git a/pd/src/d_soundfile.c b/pd/src/d_soundfile.c
index f0216126..562979f8 100644
--- a/pd/src/d_soundfile.c
+++ b/pd/src/d_soundfile.c
@@ -1790,7 +1790,6 @@ static t_int *readsf_perform(t_int *w)
}
else
{
- idle:
for (i = 0; i < noutlets; i++)
for (j = vecsize, fp = x->x_outvec[i]; j--; )
*fp++ = 0;
diff --git a/pd/src/g_array.c b/pd/src/g_array.c
index cf577010..fdbb6416 100644
--- a/pd/src/g_array.c
+++ b/pd/src/g_array.c
@@ -133,6 +133,7 @@ struct _garray
char x_usedindsp; /* true if some DSP routine is using this */
char x_saveit; /* true if we should save this with parent */
char x_listviewing; /* true if list view window is open */
+ char x_hidename; /* don't print name above graph */
};
static t_pd *garray_arraytemplatecanvas;
@@ -245,10 +246,11 @@ static t_array *garray_getarray_floatonly(t_garray *x,
return (a);
}
- /* get the array's name */
-t_symbol *garray_getname(t_garray *x)
+ /* get the array's name. Return nonzero if it should be hidden */
+int garray_getname(t_garray *x, t_symbol **namep)
{
- return (x->x_name);
+ *namep = x->x_name;
+ return (x->x_hidename);
}
/* if there is one garray in a graph, reset the graph's coordinates
@@ -320,6 +322,7 @@ t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *templateargsym,
}
saveit = ((flags & 1) != 0);
x = graph_scalar(gl, s, templatesym, saveit);
+ x->x_hidename = ((flags & 8) >> 3);
if (n <= 0)
n = 100;
@@ -486,14 +489,16 @@ void garray_arrayviewlist_new(t_garray *x)
}
void garray_arrayviewlist_fillpage(t_garray *x,
- t_float page)
+ t_float page,
+ t_float fTopItem)
{
- int i, xonset=0, yonset=0, type=0, elemsize=0;
+ int i, xonset=0, yonset=0, type=0, elemsize=0, topItem;
float yval;
char cmdbuf[200];
t_symbol *arraytype;
t_array *a = garray_getarray_floatonly(x, &yonset, &elemsize);
-
+
+ topItem = (int)fTopItem;
if (!a)
{
/* FIXME */
@@ -527,6 +532,9 @@ void garray_arrayviewlist_fillpage(t_garray *x,
i,
yval);
}
+ sys_vgui(".%sArrayWindow.lb yview %d\n",
+ x->x_realname->s_name,
+ topItem);
}
void garray_arrayviewlist_close(t_garray *x)
@@ -540,8 +548,9 @@ void garray_arrayviewlist_close(t_garray *x)
static void garray_free(t_garray *x)
{
t_pd *x2;
+ sys_unqueuegui(&x->x_gobj);
/* jsarlo { */
- if (x->x_listviewing)
+ if (x->x_listviewing)
{
garray_arrayviewlist_close(x);
}
@@ -1028,7 +1037,8 @@ static void garray_save(t_gobj *z, t_binbuf *b)
filestyle = (style == PLOTSTYLE_POINTS ? 1 :
(style == PLOTSTYLE_POLY ? 0 : style));
binbuf_addv(b, "sssisi;", gensym("#X"), gensym("array"),
- x->x_name, array->a_n, &s_float, x->x_saveit + 2 * filestyle);
+ x->x_name, array->a_n, &s_float,
+ x->x_saveit + 2 * filestyle + 8*x->x_hidename);
if (x->x_saveit)
{
int n = array->a_n, n2 = 0;
@@ -1494,7 +1504,7 @@ void g_array_setup(void)
class_addmethod(garray_class, (t_method)garray_arrayviewlist_new,
gensym("arrayviewlistnew"), A_NULL);
class_addmethod(garray_class, (t_method)garray_arrayviewlist_fillpage,
- gensym("arrayviewlistfillpage"), A_FLOAT, A_NULL);
+ gensym("arrayviewlistfillpage"), A_FLOAT, A_DEFFLOAT, A_NULL);
class_addmethod(garray_class, (t_method)garray_arrayviewlist_close,
gensym("arrayviewclose"), A_NULL);
/* } jsarlo */
diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c
index 15acc44b..edc387a4 100644
--- a/pd/src/g_canvas.c
+++ b/pd/src/g_canvas.c
@@ -1494,7 +1494,7 @@ void g_canvas_setup(void)
class_addmethod(canvas_class, (t_method)glist_scalar,
gensym("scalar"), A_GIMME, A_NULL);
- /* -------------- Thomas Musil's GUI objects ------------ */
+/* -------------- IEMGUI: button, toggle, slider, etc. ------------ */
class_addmethod(canvas_class, (t_method)canvas_bng, gensym("bng"),
A_GIMME, A_NULL);
class_addmethod(canvas_class, (t_method)canvas_toggle, gensym("toggle"),
diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c
index 0db0c140..77eaf156 100644
--- a/pd/src/g_editor.c
+++ b/pd/src/g_editor.c
@@ -785,10 +785,13 @@ static t_gobj *canvas_findhitbox(t_canvas *x, int xpos, int ypos,
int *x1p, int *y1p, int *x2p, int *y2p)
{
t_gobj *y, *rval = 0;
+ int x1, y1, x2, y2;
+ *x1p = -0x7fffffff;
for (y = x->gl_list; y; y = y->g_next)
{
- if (canvas_hitbox(x, y, xpos, ypos, x1p, y1p, x2p, y2p))
- rval = y;
+ if (canvas_hitbox(x, y, xpos, ypos, &x1, &y1, &x2, &y2)
+ && (x1 > *x1p))
+ *x1p = x1, *y1p = y1, *x2p = x2, *y2p = y2, rval = y;
}
return (rval);
}
diff --git a/pd/src/g_graph.c b/pd/src/g_graph.c
index 305da6aa..97fe71e7 100644
--- a/pd/src/g_graph.c
+++ b/pd/src/g_graph.c
@@ -672,7 +672,7 @@ void glist_redraw(t_glist *x)
/* --------------------------- widget behavior ------------------- */
extern t_widgetbehavior text_widgetbehavior;
-t_symbol *garray_getname(t_garray *x);
+int garray_getname(t_garray *x, t_symbol **namep);
/* Note that some code in here would also be useful for drawing
@@ -726,6 +726,7 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
float f;
t_gobj *g;
t_symbol *arrayname;
+ t_garray *ga;
/* draw a rectangle around the graph */
sys_vgui(".x%lx.c create line\
%d %d %d %d %d %d %d %d %d %d -tags %s\n",
@@ -734,13 +735,14 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
/* if there's just one "garray" in the graph, write its name
along the top */
- if ((g = x->gl_list) && !g->g_next && (g->g_pd == garray_class))
+ for (i = (y1 < y2 ? y1 : y2)-1, g = x->gl_list; g; g = g->g_next)
+ if (g->g_pd == garray_class &&
+ !garray_getname((t_garray *)g, &arrayname))
{
- int ymin = (y1 < y2 ? y1 : y2);
- t_symbol *s = garray_getname((t_garray *)g);
- sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor sw\
+ i -= sys_fontheight(glist_getfont(x));
+ sys_vgui(".x%lx.c create text %d %d -text {%s} -anchor nw\
-font -*-courier-bold--normal--%d-* -tags %s\n",
- (long)glist_getcanvas(x), x1, ymin, s->s_name,
+ (long)glist_getcanvas(x), x1, i, arrayname->s_name,
sys_hostfontsize(glist_getfont(x)), tag);
}
diff --git a/pd/src/g_template.c b/pd/src/g_template.c
index 05cede66..b2b359d3 100644
--- a/pd/src/g_template.c
+++ b/pd/src/g_template.c
@@ -1082,6 +1082,7 @@ static void curve_activate(t_gobj *z, t_glist *glist,
/* fill in later */
}
+#if 0
static int rangecolor(int n) /* 0 to 9 in 5 steps */
{
int n2 = n/2; /* 0 to 4 */
@@ -1089,6 +1090,15 @@ static int rangecolor(int n) /* 0 to 9 in 5 steps */
if (ret > 255) ret = 255;
return (ret);
}
+#endif
+
+static int rangecolor(int n) /* 0 to 9 in 5 steps */
+{
+ int n2 = (n == 9 ? 8 : n); /* 0 to 8 */
+ int ret = (n2 << 5); /* 0 to 256 in 9 steps */
+ if (ret > 255) ret = 255;
+ return (ret);
+}
static void numbertocolor(int n, char *s)
{
diff --git a/pd/src/g_traversal.c b/pd/src/g_traversal.c
index 375b5123..9ec8ca90 100644
--- a/pd/src/g_traversal.c
+++ b/pd/src/g_traversal.c
@@ -1036,8 +1036,6 @@ static void append_float(t_append *x, t_float f)
sc->sc_gobj.g_next = glist->gl_list;
glist->gl_list = &sc->sc_gobj;
}
- if (glist_isvisible(glist_getcanvas(glist)))
- gobj_vis(&sc->sc_gobj, glist, 1);
gp->gp_un.gp_scalar = sc;
vec = sc->sc_vec;
@@ -1046,7 +1044,10 @@ static void append_float(t_append *x, t_float f)
template_setfloat(template, vp->gv_sym, vec, vp->gv_f, 1);
}
- scalar_redraw(sc, glist);
+ if (glist_isvisible(glist_getcanvas(glist)))
+ gobj_vis(&sc->sc_gobj, glist, 1);
+ /* scalar_redraw(sc, glist); ... have to do 'vis' instead here because
+ redraw assumes we're already visible??? ... */
outlet_pointer(x->x_obj.ob_outlet, gp);
}
diff --git a/pd/src/m_atom.c b/pd/src/m_atom.c
index 8ba13131..95e2216c 100644
--- a/pd/src/m_atom.c
+++ b/pd/src/m_atom.c
@@ -88,8 +88,7 @@ void atom_string(t_atom *a, char *buf, unsigned int bufsize)
int quote;
for (sp = a->a_w.w_symbol->s_name, len = 0, quote = 0; *sp; sp++, len++)
if (*sp == ';' || *sp == ',' || *sp == '\\' ||
- (*sp == '$' && sp == a->a_w.w_symbol->s_name && sp[1] >= '0'
- && sp[1] <= '9'))
+ (*sp == '$' && sp[1] >= '0' && sp[1] <= '9'))
quote = 1;
if (quote)
{
@@ -98,7 +97,7 @@ void atom_string(t_atom *a, char *buf, unsigned int bufsize)
while (bp < ep && *sp)
{
if (*sp == ';' || *sp == ',' || *sp == '\\' ||
- (*sp == '$' && bp == buf && sp[1] >= '0' && sp[1] <= '9'))
+ (*sp == '$' && sp[1] >= '0' && sp[1] <= '9'))
*bp++ = '\\';
*bp++ = *sp++;
}
@@ -121,7 +120,8 @@ void atom_string(t_atom *a, char *buf, unsigned int bufsize)
sprintf(buf, "$%d", a->a_w.w_index);
break;
case A_DOLLSYM:
- sprintf(buf, "$%s", a->a_w.w_symbol->s_name);
+ snprintf(buf, bufsize-1, "%s", a->a_w.w_symbol->s_name);
+ buf[bufsize-1] = 0;
break;
default:
bug("atom_string");
diff --git a/pd/src/m_binbuf.c b/pd/src/m_binbuf.c
index 37362360..6afbb931 100644
--- a/pd/src/m_binbuf.c
+++ b/pd/src/m_binbuf.c
@@ -149,14 +149,14 @@ void binbuf_text(t_binbuf *x, char *text, size_t size)
&& *textp != '\t' &&*textp != ',' && *textp != ';')));
*bufp = 0;
#if 0
- post("buf %s", buf);
+ post("binbuf_text: buf %s", buf);
#endif
if (*buf == '$' && buf[1] >= '0' && buf[1] <= '9' && !firstslash)
{
for (bufp = buf+2; *bufp; bufp++)
if (*bufp < '0' || *bufp > '9')
{
- SETDOLLSYM(ap, gensym(buf+1));
+ SETDOLLSYM(ap, gensym(buf));
goto didit;
}
SETDOLLAR(ap, atoi(buf+1));
@@ -307,7 +307,7 @@ void binbuf_addbinbuf(t_binbuf *x, t_binbuf *y)
SETSYMBOL(ap, gensym(tbuf));
break;
case A_DOLLSYM:
- sprintf(tbuf, "$%s", ap->a_w.w_symbol->s_name);
+ atom_string(ap, tbuf, MAXPDSTRING);
SETSYMBOL(ap, gensym(tbuf));
break;
case A_SYMBOL:
@@ -363,7 +363,7 @@ void binbuf_restore(t_binbuf *x, int argc, t_atom *argv)
if (*str2 < '0' || *str2 > '9')
dollsym = 1;
if (dollsym)
- SETDOLLSYM(ap, gensym(str + 1));
+ SETDOLLSYM(ap, gensym(str));
else
{
int dollar = 0;
@@ -413,26 +413,106 @@ t_atom *binbuf_getvec(t_binbuf *x)
int canvas_getdollarzero( void);
+/* JMZ:
+ * s points to the first character after the $
+ * (e.g. if the org.symbol is "$1-bla", then s will point to "1-bla")
+ * (e.g. org.symbol="hu-$1mu", s="1mu")
+ * LATER: think about more complex $args, like ${$1+3}
+ *
+ * the return value holds the length of the $arg (in most cases: 1)
+ * buf holds the expanded $arg
+ *
+ * if some error occured, "-1" is returned
+ *
+ * e.g. "$1-bla" with list "10 20 30"
+ * s="1-bla"
+ * buf="10"
+ * return value = 1; (s+1=="-bla")
+ */
+int binbuf_expanddollsym(char*s, char*buf,t_atom dollar0, int ac, t_atom *av, int tonew)
+{
+ int argno=atol(s);
+ int arglen=0;
+ char*cs=s;
+ char c=*cs;
+ *buf=0;
+
+ while(c&&(c>='0')&&(c<='9')){
+ c=*cs++;
+ arglen++;
+ }
+
+ if (cs==s) { /* invalid $-expansion (like "$bla") */
+ sprintf(buf, "$");
+ return 0;
+ }
+ else if (argno < 0 || argno > ac) /* undefined argument */
+ {
+ if(!tonew)return 0;
+ sprintf(buf, "$%d", argno);
+ }
+ else if (argno == 0){ /* $0 */
+ atom_string(&dollar0, buf, MAXPDSTRING/2-1);
+ }
+ else{ /* fine! */
+ atom_string(av+(argno-1), buf, MAXPDSTRING/2-1);
+ }
+ return (arglen-1);
+}
+
/* LATER remove the dependence on the current canvas for $0; should be another
argument. */
t_symbol *binbuf_realizedollsym(t_symbol *s, int ac, t_atom *av, int tonew)
{
- int argno = atol(s->s_name), lastnum;
- char buf[MAXPDSTRING], c, *sp;
- for (lastnum = 0, sp = s->s_name; ((c = *sp) && c >= '0' && c <= '9');
- sp++, lastnum++)
- if (!c || argno < 0 || argno > ac)
- {
- if (!tonew)
- return (0);
- else sprintf(buf, "$%d", argno);
+ char buf[MAXPDSTRING];
+ char buf2[MAXPDSTRING];
+ char*str=s->s_name;
+ char*substr;
+ int next=0, i=MAXPDSTRING;
+ t_atom dollarnull;
+ SETFLOAT(&dollarnull, canvas_getdollarzero());
+ while(i--)buf2[i]=0;
+
+#if 1
+ /* JMZ: currently, a symbol is detected to be A_DOLLSYM if it starts with '$'
+ * the leading $ is stripped and the rest stored in "s"
+ * i would suggest to NOT strip the leading $
+ * and make everything a A_DOLLSYM that contains(!) a $
+ *
+ * whenever this happened, enable this code
+ */
+ substr=strchr(str, '$');
+ if(substr){
+ strncat(buf2, str, (substr-str));
+ str=substr+1;
}
- else if (argno == 0)
- sprintf(buf, "%d", canvas_getdollarzero());
- else
- atom_string(av+(argno-1), buf, MAXPDSTRING/2-1);
- strncat(buf, sp, MAXPDSTRING/2-1);
- return (gensym(buf));
+#endif
+
+ while((next=binbuf_expanddollsym(str, buf, dollarnull, ac, av, tonew))>=0)
+ {
+ /*
+ * JMZ: i am not sure what this means, so i might have broken it
+ * it seems like that if "tonew" is set and the $arg cannot be expanded (or the dollarsym is in reality a A_DOLLAR)
+ * 0 is returned from binbuf_realizedollsym
+ * this happens, when expanding in a message-box, but does not happen when the A_DOLLSYM is the name of a subpatch
+ */
+ if(!tonew&&(0==next)&&(0==*buf)){
+ return 0; /* JMZ: this should mimick the original behaviour */
+ }
+
+ strncat(buf2, buf, MAXPDSTRING/2-1);
+ str+=next;
+ substr=strchr(str, '$');
+ if(substr){
+ strncat(buf2, str, (substr-str));
+ str=substr+1;
+ } else {
+ strcat(buf2, str);
+
+ return gensym(buf2);
+ }
+ }
+ return (gensym(buf2));
}
void binbuf_eval(t_binbuf *x, t_pd *target, int argc, t_atom *argv)
@@ -817,7 +897,7 @@ static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd)
else if (nextmess[i].a_type == A_DOLLSYM)
{
char buf[100];
- sprintf(buf, "$%s", nextmess[i].a_w.w_symbol->s_name);
+ sprintf(buf, "%s", nextmess[i].a_w.w_symbol->s_name);
SETSYMBOL(nextmess+i, gensym(buf));
}
}
diff --git a/pd/src/makefile.in b/pd/src/makefile.in
index b28b844a..6f644237 100644
--- a/pd/src/makefile.in
+++ b/pd/src/makefile.in
@@ -49,13 +49,12 @@ SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
s_main.c s_inter.c s_file.c s_print.c \
s_loader.c s_path.c s_entry.c s_audio.c s_midi.c \
d_ugen.c d_ctl.c d_arithmetic.c d_osc.c d_filter.c d_dac.c d_misc.c \
- d_math.c d_fft.c d_mayer_fft.c d_fftroutine.c d_array.c d_global.c \
+ d_math.c d_fft.c d_array.c d_global.c \
d_delay.c d_resample.c \
x_arithmetic.c x_connective.c x_interface.c x_midi.c x_misc.c \
x_time.c x_acoustics.c x_net.c x_qlist.c x_gui.c x_list.c d_soundfile.c \
$(SYSSRC)
-
OBJ = $(SRC:.c=.o)
GSRC = t_main.c t_tkcmd.c
@@ -165,7 +164,7 @@ install: all
local-clean:
-rm -f ../obj/* $(BIN_DIR)/pd $(BIN_DIR)/$(GUINAME) $(BIN_DIR)/pdsend \
$(BIN_DIR)/pdreceive $(BIN_DIR)/pd-watchdog m_stamp.c
- -rm -f `find ../portaudio ../portaudio_v18 -name "*.o"`
+ -rm -f `find ../portaudio -name "*.o"`
-rm -f *~
-(cd ../doc/6.externs; rm -f *.pd_linux)
-rm -f makefile.dependencies
@@ -179,7 +178,7 @@ extra-clean:
clean: extra-clean local-clean
distclean: clean
- -rm -f config.cache config.log config.status makefile configure tags \
+ -rm -f config.cache config.log config.status makefile tags \
autom4te.cache/output.* autom4te.cache/traces.* autom4te.cache/requests
-rmdir autom4te.cache
-rm -rf autom4te-*.cache
diff --git a/pd/src/makefile.nt b/pd/src/makefile.nt
index e696e751..56b94a0a 100644
--- a/pd/src/makefile.nt
+++ b/pd/src/makefile.nt
@@ -4,7 +4,7 @@ all: pd gui ..\bin\pd.tk ..\bin\pdsend.exe ..\bin\pdreceive.exe
VC = "C:\Program Files\Microsoft Visual Studio\VC98"
#VC="\Program Files\DevStudio\Vc"
-INCLUDE = -I.\ -I..\Tcl\include -I$(VC)\include
+INCLUDE = -I.\ -I..\Tcl\include -I\DXSDK\include -I$(VC)\include
LDIR = $(VC)\lib
@@ -12,7 +12,7 @@ LIB = /NODEFAULTLIB:libc /NODEFAULTLIB:oldnames /NODEFAULTLIB:kernel \
/NODEFAULTLIB:uuid \
$(LDIR)\libc.lib $(LDIR)\oldnames.lib $(LDIR)\kernel32.lib \
$(LDIR)\wsock32.lib $(LDIR)\winmm.lib $(LDIR)\advapi32.lib \
- ..\bin\pthreadVC.lib
+ $(LDIR)\setupapi.lib ..\bin\pthreadVC.lib
GLIB = $(LIB) ..\bin\tcl84.lib ..\bin\tk84.lib
CFLAGS = /nologo /W3 /DMSW /DNT /DPD /DPD_INTERNAL /DWIN32 /DWINDOWS /Ox \
@@ -50,7 +50,8 @@ SRCPA = $(PADIR)/pa_common/pa_stream.c \
$(PADIR)/pa_common/pa_allocation.c \
$(PADIR)/pa_win/pa_win_util.c \
$(PADIR)/pa_win/pa_win_hostapis.c \
- $(PADIR)/pa_win_wmme/pa_win_wmme.c
+ $(PADIR)/pa_win_wmme/pa_win_wmme.c
+# $(PADIR)/pa_win_wdmks/pa_win_wdmks.c
SRCASIO = $(PADIR)/pa_asio/pa_asio.cpp
@@ -63,7 +64,8 @@ $(LDIR)\odbc32.lib $(LDIR)\odbccp32.lib ..\lib\asio\asiolib.lib
PAOBJ = pa_stream.obj pa_trace.obj pa_skeleton.obj pa_process.obj \
pa_front.obj pa_dither.obj pa_cpuload.obj pa_converters.obj \
pa_allocation.obj pa_win_util.obj pa_win_hostapis.obj pa_asio.obj \
- pa_win_wmme.obj
+ pa_win_wmme.obj
+# pa_win_wdmks.obj
PMDIR = ..\portmidi
INCPM = -I$(PMDIR)\pm_common -I$(PMDIR)\pm_win -I$(PMDIR)\porttime
@@ -150,6 +152,10 @@ pa_win_hostapis.obj: $(PADIR)\pa_win\pa_win_hostapis.c
cl /c $(ALLCF) $(PADIR)\pa_win\pa_win_hostapis.c
pa_win_wmme.obj: $(PADIR)\pa_win_wmme\pa_win_wmme.c
cl /c $(ALLCF) $(PADIR)\pa_win_wmme\pa_win_wmme.c
+pa_win_wdmks.obj: $(PADIR)\pa_win_wdmks\pa_win_wdmks.c
+ cl /c $(ALLCF) \
+ -DWINVER=0x400 -DKSAUDIO_SPEAKER_DIRECTOUT \
+ $(PADIR)\pa_win_wdmks\pa_win_wdmks.c
pa_asio.obj: $(PADIR)\pa_asio\pa_asio.cpp
cl /c $(ALLCF) $(PADIR)\pa_asio\pa_asio.cpp
diff --git a/pd/src/notes.txt b/pd/src/notes.txt
index 034849a5..4c3b1997 100644
--- a/pd/src/notes.txt
+++ b/pd/src/notes.txt
@@ -7,6 +7,14 @@ windows:
check the right-click-on-empty-canvas
MIDI I/O (inc. sysex)
what does OSX do when jack is compiled into Pd but not installed??
+turn on paMacCore_ChangeDeviceParameters for mac (pa_mac_core.h)
+
+done:
+openpanel directory
+big-soundfile support
+escaping filenames for wierdly named externs
+infrastructure for adding externs in non-ascii languages
+'$' patch (multiple dollar-sign expansion)
doc:
object list
@@ -15,8 +23,17 @@ vibrato example
block resampling arguments
document tabwrite~_start
"list" to signal inlet (e.g., "*~") or float inlet (f) complains.
+$-expansion changed
problems:
+crashed Pd putting vec and template in wrong order in array element of struct
+z.pd - list to numbox misbehaves (inlet and object but object is noinlet)
+floor, ciel functions in expr misdeclared
+graphics updates in data sometimes don't happen?
+graph names don't appear until graph moved? (invis/vis on new array/rename)
+flag to defeat .pdsettings
+'{' bug
+"-audiodev" with no args in registry can't start up in MSW
"save as" with spaces in filename still messes up
don't filter locked click() through getrect
better scalar hit detection (getrect is too greedy)
@@ -43,9 +60,12 @@ check if _vsnprintf with zero argument in windows works any better...
detect adc~ and dac~ reblocking
features:
+sprout inlet for "route", "sel" if one arg; also send
+list length and nth functions
+poly inlet to turn stealing on/off
.dll to .msw32 or .pd_msw (then offer .pd_msw64, .pd_lnx64, etc.)
integrate video into tilde objects
-flag to suppress printing array name above graph
+graph "hide name" flag controllable from dialog
flag to suppress scrollbars in canvases
fix copyright notices
pixel font sizes
@@ -97,6 +117,9 @@ append doesn't do symbols yet.
more features:
+"-march=pentium4 -O2 -mfpmath=sse -msse -msse2 -mmmx" ?
+try to improve for AMD - try "-march=athlon-xp -msse2"
+search for -mcpu=cpu-type in man gcc.
-Wno-unused to -Wno-unused-paramter and clean up unused automatic variables
security module system in 2.6 - see the kernel module replacing jackstart
signal inlets to sense signals; fix +~ etc, vcf~, biquad~, other filters
diff --git a/pd/src/s_audio.c b/pd/src/s_audio.c
index cbfd6f0c..8d4683f8 100644
--- a/pd/src/s_audio.c
+++ b/pd/src/s_audio.c
@@ -608,7 +608,7 @@ static void sys_listaudiodevs(void )
{
post("input devices:");
for (i = 0; i < nindevs; i++)
- post("%d. %s", i+1, indevlist + i * DEVDESCSIZE);
+ post("%d. %s", i + DEVONSET, indevlist + i * DEVDESCSIZE);
}
if (!noutdevs)
post("no audio output devices found");
diff --git a/pd/src/s_audio_pa.c b/pd/src/s_audio_pa.c
index 15699556..627b0015 100644
--- a/pd/src/s_audio_pa.c
+++ b/pd/src/s_audio_pa.c
@@ -274,12 +274,16 @@ void pa_getdevs(char *indevlist, int *nindevs,
const PaDeviceInfo *pdi = Pa_GetDeviceInfo(i);
if (pdi->maxInputChannels > 0 && nin < maxndev)
{
- strcpy(indevlist + nin * devdescsize, pdi->name);
+ sprintf(indevlist + nin * devdescsize, "(%d)%s",
+ pdi->hostApi,pdi->name);
+ /* strcpy(indevlist + nin * devdescsize, pdi->name); */
nin++;
}
if (pdi->maxOutputChannels > 0 && nout < maxndev)
{
- strcpy(outdevlist + nout * devdescsize, pdi->name);
+ sprintf(outdevlist + nout * devdescsize, "(%d)%s",
+ pdi->hostApi,pdi->name);
+ /* strcpy(outdevlist + nout * devdescsize, pdi->name); */
nout++;
}
}
diff --git a/pd/src/s_audio_pablio.c b/pd/src/s_audio_pablio.c
index 3bd626ee..a7d1a4fe 100644
--- a/pd/src/s_audio_pablio.c
+++ b/pd/src/s_audio_pablio.c
@@ -69,8 +69,8 @@ static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
PaTimestamp outTime, void *userData );
#endif
-static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );
-static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
+static PaError PABLIO_InitFIFO( sys_ringbuf *rbuf, long numFrames, long bytesPerFrame );
+static PaError PABLIO_TermFIFO( sys_ringbuf *rbuf );
/************************************************************************/
/******** Functions *****************************************************/
@@ -97,14 +97,14 @@ static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
/* This may get called with NULL inputBuffer during initial setup. */
if( inputBuffer != NULL )
{
- RingBuffer_Write( &data->inFIFO, inputBuffer,
+ sys_ringbuf_Write( &data->inFIFO, inputBuffer,
data->inbytesPerFrame * framesPerBuffer );
}
if( outputBuffer != NULL )
{
int i;
int numBytes = data->outbytesPerFrame * framesPerBuffer;
- int numRead = RingBuffer_Read( &data->outFIFO, outputBuffer,
+ int numRead = sys_ringbuf_Read( &data->outFIFO, outputBuffer,
numBytes);
/* Zero out remainder of buffer if we run out of data. */
for( i=numRead; i<numBytes; i++ )
@@ -117,17 +117,17 @@ static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
}
/* Allocate buffer. */
-static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )
+static PaError PABLIO_InitFIFO( sys_ringbuf *rbuf, long numFrames, long bytesPerFrame )
{
long numBytes = numFrames * bytesPerFrame;
char *buffer = (char *) malloc( numBytes );
if( buffer == NULL ) return paInsufficientMemory;
memset( buffer, 0, numBytes );
- return (PaError) RingBuffer_Init( rbuf, numBytes, buffer );
+ return (PaError) sys_ringbuf_Init( rbuf, numBytes, buffer );
}
/* Free buffer. */
-static PaError PABLIO_TermFIFO( RingBuffer *rbuf )
+static PaError PABLIO_TermFIFO( sys_ringbuf *rbuf )
{
if( rbuf->buffer ) free( rbuf->buffer );
rbuf->buffer = NULL;
@@ -145,7 +145,7 @@ long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
long numBytes = aStream->outbytesPerFrame * numFrames;
while( numBytes > 0)
{
- bytesWritten = RingBuffer_Write( &aStream->outFIFO, p, numBytes );
+ bytesWritten = sys_ringbuf_Write( &aStream->outFIFO, p, numBytes );
numBytes -= bytesWritten;
p += bytesWritten;
if( numBytes > 0) NPa_Sleep(10); /* MSP */
@@ -164,7 +164,7 @@ long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
long numBytes = aStream->inbytesPerFrame * numFrames;
while( numBytes > 0)
{
- bytesRead = RingBuffer_Read( &aStream->inFIFO, p, numBytes );
+ bytesRead = sys_ringbuf_Read( &aStream->inFIFO, p, numBytes );
numBytes -= bytesRead;
p += bytesRead;
if( numBytes > 0) NPa_Sleep(10); /* MSP */
@@ -178,7 +178,7 @@ long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
*/
long GetAudioStreamWriteable( PABLIO_Stream *aStream )
{
- int bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ int bytesEmpty = sys_ringbuf_GetWriteAvailable( &aStream->outFIFO );
return bytesEmpty / aStream->outbytesPerFrame;
}
@@ -188,7 +188,7 @@ long GetAudioStreamWriteable( PABLIO_Stream *aStream )
*/
long GetAudioStreamReadable( PABLIO_Stream *aStream )
{
- int bytesFull = RingBuffer_GetReadAvailable( &aStream->inFIFO );
+ int bytesFull = sys_ringbuf_GetReadAvailable( &aStream->inFIFO );
return bytesFull / aStream->inbytesPerFrame;
}
@@ -320,8 +320,8 @@ PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
aStream->outbytesPerFrame );
if( err != paNoError ) goto error;
/* Make Write FIFO appear full initially. */
- numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
- RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes );
+ numBytes = sys_ringbuf_GetWriteAvailable( &aStream->outFIFO );
+ sys_ringbuf_AdvanceWriteIndex( &aStream->outFIFO, numBytes );
}
/* Open a PortAudio stream that we will use to communicate with the underlying
@@ -382,11 +382,11 @@ PaError CloseAudioStream( PABLIO_Stream *aStream )
/* If we are writing data, make sure we play everything written. */
if( byteSize > 0 )
{
- bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ bytesEmpty = sys_ringbuf_GetWriteAvailable( &aStream->outFIFO );
while( bytesEmpty < byteSize )
{
NPa_Sleep( 10 ); /* MSP */
- bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ bytesEmpty = sys_ringbuf_GetWriteAvailable( &aStream->outFIFO );
}
}
diff --git a/pd/src/s_audio_pablio.h b/pd/src/s_audio_pablio.h
index 052ffedb..43e9a4b9 100644
--- a/pd/src/s_audio_pablio.h
+++ b/pd/src/s_audio_pablio.h
@@ -7,7 +7,7 @@ extern "C"
#endif /* __cplusplus */
/*
- * $Id: s_audio_pablio.h,v 1.1 2004-09-06 20:20:35 millerpuckette Exp $
+ * $Id: s_audio_pablio.h,v 1.2 2006-06-03 19:13:07 millerpuckette Exp $
* PABLIO.h
* Portable Audio Blocking read/write utility.
*
@@ -46,13 +46,13 @@ extern "C"
#include <stdlib.h>
#include <math.h>
#include "portaudio.h"
-#include "ringbuffer.h"
+#include "s_audio_paring.h"
#include <string.h>
typedef struct
{
- RingBuffer inFIFO;
- RingBuffer outFIFO;
+ sys_ringbuf inFIFO;
+ sys_ringbuf outFIFO;
PaStream *stream;
int inbytesPerFrame;
int insamplesPerFrame;
diff --git a/pd/src/s_audio_paring.c b/pd/src/s_audio_paring.c
index cbb999e8..ca1a60a5 100644
--- a/pd/src/s_audio_paring.c
+++ b/pd/src/s_audio_paring.c
@@ -1,5 +1,5 @@
/*
- * $Id: s_audio_paring.c,v 1.1 2004-09-06 20:20:35 millerpuckette Exp $
+ * $Id: s_audio_paring.c,v 1.2 2006-06-03 19:13:07 millerpuckette Exp $
* ringbuffer.c
* Ring Buffer utility..
*
@@ -47,35 +47,35 @@
/***************************************************************************
* Initialize FIFO.
*/
-long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )
+long sys_ringbuf_Init( sys_ringbuf *rbuf, long numBytes, void *dataPtr )
{
rbuf->bufferSize = numBytes;
rbuf->buffer = (char *)dataPtr;
- RingBuffer_Flush( rbuf );
+ sys_ringbuf_Flush( rbuf );
return 0;
}
/***************************************************************************
** Return number of bytes available for reading. */
-long RingBuffer_GetReadAvailable( RingBuffer *rbuf )
+long sys_ringbuf_GetReadAvailable( sys_ringbuf *rbuf )
{
long ret = rbuf->writeIndex - rbuf->readIndex;
if (ret < 0)
ret += 2 * rbuf->bufferSize;
if (ret < 0 || ret > rbuf->bufferSize)
fprintf(stderr,
- "consistency check failed: RingBuffer_GetReadAvailable\n");
+ "consistency check failed: sys_ringbuf_GetReadAvailable\n");
return ( ret );
}
/***************************************************************************
** Return number of bytes available for writing. */
-long RingBuffer_GetWriteAvailable( RingBuffer *rbuf )
+long sys_ringbuf_GetWriteAvailable( sys_ringbuf *rbuf )
{
- return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));
+ return ( rbuf->bufferSize - sys_ringbuf_GetReadAvailable(rbuf));
}
/***************************************************************************
** Clear buffer. Should only be called when buffer is NOT being read. */
-void RingBuffer_Flush( RingBuffer *rbuf )
+void sys_ringbuf_Flush( sys_ringbuf *rbuf )
{
rbuf->writeIndex = rbuf->readIndex = 0;
}
@@ -86,12 +86,12 @@ void RingBuffer_Flush( RingBuffer *rbuf )
** If non-contiguous, size2 will be the size of second region.
** Returns room available to be written or numBytes, whichever is smaller.
*/
-long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
+long sys_ringbuf_GetWriteRegions( sys_ringbuf *rbuf, long numBytes,
void **dataPtr1, long *sizePtr1,
void **dataPtr2, long *sizePtr2 )
{
long index;
- long available = RingBuffer_GetWriteAvailable( rbuf );
+ long available = sys_ringbuf_GetWriteAvailable( rbuf );
if( numBytes > available ) numBytes = available;
/* Check to see if write is not contiguous. */
index = rbuf->writeIndex;
@@ -119,7 +119,7 @@ long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
/***************************************************************************
*/
-long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )
+long sys_ringbuf_AdvanceWriteIndex( sys_ringbuf *rbuf, long numBytes )
{
long ret = (rbuf->writeIndex + numBytes);
if ( ret >= 2 * rbuf->bufferSize)
@@ -133,12 +133,12 @@ long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )
** If non-contiguous, size2 will be the size of second region.
** Returns room available to be written or numBytes, whichever is smaller.
*/
-long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+long sys_ringbuf_GetReadRegions( sys_ringbuf *rbuf, long numBytes,
void **dataPtr1, long *sizePtr1,
void **dataPtr2, long *sizePtr2 )
{
long index;
- long available = RingBuffer_GetReadAvailable( rbuf );
+ long available = sys_ringbuf_GetReadAvailable( rbuf );
if( numBytes > available ) numBytes = available;
/* Check to see if read is not contiguous. */
index = rbuf->readIndex;
@@ -165,7 +165,7 @@ long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
}
/***************************************************************************
*/
-long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )
+long sys_ringbuf_AdvanceReadIndex( sys_ringbuf *rbuf, long numBytes )
{
long ret = (rbuf->readIndex + numBytes);
if( ret >= 2 * rbuf->bufferSize)
@@ -175,11 +175,11 @@ long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )
/***************************************************************************
** Return bytes written. */
-long RingBuffer_Write( RingBuffer *rbuf, const void *data, long numBytes )
+long sys_ringbuf_Write( sys_ringbuf *rbuf, const void *data, long numBytes )
{
long size1, size2, numWritten;
void *data1, *data2;
- numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+ numWritten = sys_ringbuf_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
if( size2 > 0 )
{
@@ -191,17 +191,17 @@ long RingBuffer_Write( RingBuffer *rbuf, const void *data, long numBytes )
{
memcpy( data1, data, size1 );
}
- RingBuffer_AdvanceWriteIndex( rbuf, numWritten );
+ sys_ringbuf_AdvanceWriteIndex( rbuf, numWritten );
return numWritten;
}
/***************************************************************************
** Return bytes read. */
-long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )
+long sys_ringbuf_Read( sys_ringbuf *rbuf, void *data, long numBytes )
{
long size1, size2, numRead;
void *data1, *data2;
- numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+ numRead = sys_ringbuf_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
if( size2 > 0 )
{
memcpy( data, data1, size1 );
@@ -212,6 +212,6 @@ long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )
{
memcpy( data, data1, size1 );
}
- RingBuffer_AdvanceReadIndex( rbuf, numRead );
+ sys_ringbuf_AdvanceReadIndex( rbuf, numRead );
return numRead;
}
diff --git a/pd/src/s_audio_paring.h b/pd/src/s_audio_paring.h
index 9eca10b1..27edb01f 100644
--- a/pd/src/s_audio_paring.h
+++ b/pd/src/s_audio_paring.h
@@ -6,7 +6,7 @@ extern "C"
#endif /* __cplusplus */
/*
- * $Id: s_audio_paring.h,v 1.1 2004-09-06 20:20:35 millerpuckette Exp $
+ * $Id: s_audio_paring.h,v 1.2 2006-06-03 19:13:07 millerpuckette Exp $
* ringbuffer.h
* Ring Buffer utility..
*
@@ -43,58 +43,58 @@ extern "C"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
-#include "ringbuffer.h"
+#include "s_audio_paring.h"
#include <string.h>
typedef struct
{
- long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */
+ long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by sys_ringbuf_Init. */
/* These are declared volatile because they are written by a different thread than the reader. */
- volatile long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */
- volatile long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */
+ volatile long writeIndex; /* Index of next writable byte. Set by sys_ringbuf_AdvanceWriteIndex. */
+ volatile long readIndex; /* Index of next readable byte. Set by sys_ringbuf_AdvanceReadIndex. */
long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */
long smallMask; /* Used for fitting indices to buffer. */
char *buffer;
}
-RingBuffer;
+sys_ringbuf;
/*
* Initialize Ring Buffer.
* numBytes must be power of 2, returns -1 if not.
*/
-long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
+long sys_ringbuf_Init( sys_ringbuf *rbuf, long numBytes, void *dataPtr );
/* Clear buffer. Should only be called when buffer is NOT being read. */
-void RingBuffer_Flush( RingBuffer *rbuf );
+void sys_ringbuf_Flush( sys_ringbuf *rbuf );
/* Return number of bytes available for writing. */
-long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
+long sys_ringbuf_GetWriteAvailable( sys_ringbuf *rbuf );
/* Return number of bytes available for read. */
-long RingBuffer_GetReadAvailable( RingBuffer *rbuf );
+long sys_ringbuf_GetReadAvailable( sys_ringbuf *rbuf );
/* Return bytes written. */
-long RingBuffer_Write( RingBuffer *rbuf, const void *data, long numBytes );
+long sys_ringbuf_Write( sys_ringbuf *rbuf, const void *data, long numBytes );
/* Return bytes read. */
-long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );
+long sys_ringbuf_Read( sys_ringbuf *rbuf, void *data, long numBytes );
/* Get address of region(s) to which we can write data.
** If the region is contiguous, size2 will be zero.
** If non-contiguous, size2 will be the size of second region.
** Returns room available to be written or numBytes, whichever is smaller.
*/
-long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
+long sys_ringbuf_GetWriteRegions( sys_ringbuf *rbuf, long numBytes,
void **dataPtr1, long *sizePtr1,
void **dataPtr2, long *sizePtr2 );
-long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );
+long sys_ringbuf_AdvanceWriteIndex( sys_ringbuf *rbuf, long numBytes );
/* Get address of region(s) from which we can read data.
** If the region is contiguous, size2 will be zero.
** If non-contiguous, size2 will be the size of second region.
** Returns room available to be read or numBytes, whichever is smaller.
*/
-long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+long sys_ringbuf_GetReadRegions( sys_ringbuf *rbuf, long numBytes,
void **dataPtr1, long *sizePtr1,
void **dataPtr2, long *sizePtr2 );
-long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
+long sys_ringbuf_AdvanceReadIndex( sys_ringbuf *rbuf, long numBytes );
#ifdef __cplusplus
}
diff --git a/pd/src/s_inter.c b/pd/src/s_inter.c
index 90623df6..520ae882 100644
--- a/pd/src/s_inter.c
+++ b/pd/src/s_inter.c
@@ -788,6 +788,8 @@ void sys_queuegui(void *client, t_glist *glist, t_guicallbackfn f)
for (gq = sys_guiqueuehead; gq->gq_next; gq = gq->gq_next)
if (gq->gq_client == client)
return;
+ if (gq->gq_client == client)
+ return;
gqnextptr = &gq->gq_next;
}
gq = t_getbytes(sizeof(*gq));
diff --git a/pd/src/s_loader.c b/pd/src/s_loader.c
index 89646a48..d985af05 100644
--- a/pd/src/s_loader.c
+++ b/pd/src/s_loader.c
@@ -38,8 +38,12 @@ static char sys_dllextent[] =
".pd_linux";
#endif
#ifdef MACOSX
+#ifdef __i386
+ ".pd_imac";
+#else
".pd_darwin";
#endif
+#endif
#ifdef MSW
".dll";
#endif
@@ -73,30 +77,30 @@ static int sys_load_lib_alt(char *dirname, char *classname, char *altname)
if ((fd = open_via_path(dirname, classname2, sys_dllextent,
dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
{
- /* next try (alternative_classname).(sys_dllextent) */
- if(altname)
+ /* next try (alternative_classname).(sys_dllextent) */
+ if (altname)
{
- if ((fd = open_via_path(dirname, altname, sys_dllextent,
- dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
-
- /* next try (alternative_classname)/(alternative_classname).(sys_dllextent) ... */
- strncpy(classname2, altname, MAXPDSTRING);
- filename[MAXPDSTRING-2] = 0;
- strcat(classname2, "/");
- strncat(classname2, altname, MAXPDSTRING-strlen(classname2));
- filename[MAXPDSTRING-1] = 0;
- if ((fd = open_via_path(dirname, classname2, sys_dllextent,
- dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
+ if ((fd = open_via_path(dirname, altname, sys_dllextent,
+ dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
{
- return 0;
- }
+ /* next try
+ (alt_classname)/(alt_classname).(sys_dllextent) */
+ strncpy(classname2, altname, MAXPDSTRING);
+ filename[MAXPDSTRING-2] = 0;
+ strcat(classname2, "/");
+ strncat(classname2, altname,
+ MAXPDSTRING-strlen(classname2));
+ filename[MAXPDSTRING-1] = 0;
+ if ((fd = open_via_path(dirname, classname2,
+ sys_dllextent, dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
+ {
+ return 0;
+ }
+ }
}
- else
- return (0);
+ else return (0);
}
}
-
-
close(fd);
class_set_extern_dir(gensym(dirbuf));
@@ -110,7 +114,7 @@ static int sys_load_lib_alt(char *dirname, char *classname, char *altname)
if (lastdot = strrchr(nameptr, '.'))
*lastdot = 0;
-#ifdef MACOSX
+#ifdef DIDFORMACOSX /* no longer correct on macosx??? */
strcpy(symname, "_");
strcat(symname, nameptr);
if(altname)
@@ -134,6 +138,7 @@ static int sys_load_lib_alt(char *dirname, char *classname, char *altname)
strcat(symname, "_setup");
#ifdef DL_OPEN
dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
+ post("opened %x", dlobj);
if (!dlobj)
{
post("%s: %s", filename, dlerror());
diff --git a/pd/src/s_main.c b/pd/src/s_main.c
index 98301ac8..a8baa8c4 100644
--- a/pd/src/s_main.c
+++ b/pd/src/s_main.c
@@ -103,7 +103,7 @@ typedef struct _fontinfo
in the six fonts. */
static t_fontinfo sys_fontlist[] = {
- {8, 5, 9, 0, 0, 0}, {10, 7, 13, 0, 0, 0}, {12, 9, 16, 0, 0, 0},
+ {8, 6, 10, 0, 0, 0}, {10, 7, 13, 0, 0, 0}, {12, 9, 16, 0, 0, 0},
{16, 10, 20, 0, 0, 0}, {24, 15, 25, 0, 0, 0}, {36, 25, 45, 0, 0, 0}};
#define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))
@@ -175,8 +175,6 @@ static void openit(const char *dirname, const char *filename)
error("%s: can't open", filename);
}
-#define NHOSTFONT 7
-
/* this is called from the gui process. The first argument is the cwd, and
succeeding args give the widths and heights of known fonts. We wait until
these are known to open files and send messages specified on the command line.
@@ -189,25 +187,33 @@ void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
{
char *cwd = atom_getsymbolarg(0, argc, argv)->s_name;
t_namelist *nl;
- unsigned int i, j;
- if (argc != 2 + 3 * NHOSTFONT) bug("glob_initfromgui");
+ unsigned int i;
+ int j;
+ int nhostfont = (argc-2)/3;
+ sys_oldtclversion = atom_getfloatarg(1, argc, argv);
+ if (argc != 2 + 3 * nhostfont) bug("glob_initfromgui");
for (i = 0; i < NFONT; i++)
{
+ int best = 0;
int wantheight = sys_fontlist[i].fi_maxheight;
- for (j = 0; j < NHOSTFONT-1; j++)
- {
- if (atom_getintarg(3 * (j + 1) + 3, argc, argv) > wantheight)
- break;
- }
- /* j is now the "real" font index for the desired font index i. */
- sys_fontlist[i].fi_hostfontsize = atom_getintarg(3 * j + 1, argc, argv);
- sys_fontlist[i].fi_width = atom_getintarg(3 * j + 2, argc, argv);
- sys_fontlist[i].fi_height = atom_getintarg(3 * j + 3, argc, argv);
+ int wantwidth = sys_fontlist[i].fi_maxwidth;
+ for (j = 1; j < nhostfont; j++)
+ {
+ if (atom_getintarg(3 * j + 4, argc, argv) <= wantheight &&
+ atom_getintarg(3 * j + 3, argc, argv) <= wantwidth)
+ best = j;
+ }
+ /* best is now the host font index for the desired font index i. */
+ sys_fontlist[i].fi_hostfontsize =
+ atom_getintarg(3 * best + 2, argc, argv);
+ sys_fontlist[i].fi_width = atom_getintarg(3 * best + 3, argc, argv);
+ sys_fontlist[i].fi_height = atom_getintarg(3 * best + 4, argc, argv);
}
#if 0
for (i = 0; i < 6; i++)
- fprintf(stderr, "font %d %d %d %d %d\n",
+ fprintf(stderr, "font (%d %d %d) -> (%d %d %d)\n",
sys_fontlist[i].fi_fontsize,
+ sys_fontlist[i].fi_maxwidth,
sys_fontlist[i].fi_maxheight,
sys_fontlist[i].fi_hostfontsize,
sys_fontlist[i].fi_width,
@@ -232,7 +238,6 @@ void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
}
namelist_free(sys_messagelist);
sys_messagelist = 0;
- sys_oldtclversion = atom_getfloatarg(1 + 3 * NHOSTFONT, argc, argv);
}
static void sys_afterargparse(void);
@@ -517,7 +522,7 @@ int sys_argparse(int argc, char **argv)
argc -= 2;
argv += 2;
}
- else if (!strcmp(*argv, "-inchannels"))
+ else if (!strcmp(*argv, "-inchannels") && (argc > 1))
{
sys_parsedevlist(&sys_nchin,
sys_chinlist, MAXAUDIOINDEV, argv[1]);
@@ -527,7 +532,7 @@ int sys_argparse(int argc, char **argv)
argc -= 2; argv += 2;
}
- else if (!strcmp(*argv, "-outchannels"))
+ else if (!strcmp(*argv, "-outchannels") && (argc > 1))
{
sys_parsedevlist(&sys_nchout, sys_choutlist,
MAXAUDIOOUTDEV, argv[1]);
@@ -537,7 +542,7 @@ int sys_argparse(int argc, char **argv)
argc -= 2; argv += 2;
}
- else if (!strcmp(*argv, "-channels"))
+ else if (!strcmp(*argv, "-channels") && (argc > 1))
{
sys_parsedevlist(&sys_nchin, sys_chinlist,MAXAUDIOINDEV,
argv[1]);
@@ -549,7 +554,7 @@ int sys_argparse(int argc, char **argv)
argc -= 2; argv += 2;
}
- else if (!strcmp(*argv, "-soundbuf") || !strcmp(*argv, "-audiobuf"))
+ else if (!strcmp(*argv, "-soundbuf") || !strcmp(*argv, "-audiobuf") && (argc > 1))
{
sys_main_advance = atoi(argv[1]);
argc -= 2; argv += 2;
@@ -559,7 +564,7 @@ int sys_argparse(int argc, char **argv)
sys_setblocksize(atoi(argv[1]));
argc -= 2; argv += 2;
}
- else if (!strcmp(*argv, "-sleepgrain"))
+ else if (!strcmp(*argv, "-sleepgrain") && (argc > 1))
{
sys_sleepgrain = 1000 * atoi(argv[1]);
argc -= 2; argv += 2;
@@ -601,7 +606,7 @@ int sys_argparse(int argc, char **argv)
sys_set_audio_api(API_ALSA);
argc--; argv++;
}
- else if (!strcmp(*argv, "-alsaadd"))
+ else if (!strcmp(*argv, "-alsaadd") && (argc > 1))
{
if (argc > 1)
alsa_adddev(argv[1]);
@@ -664,7 +669,7 @@ int sys_argparse(int argc, char **argv)
goto usage;
argc -= 2; argv += 2;
}
- else if (!strcmp(*argv, "-midioutdev"))
+ else if (!strcmp(*argv, "-midioutdev") && (argc > 1))
{
sys_parsedevlist(&sys_nmidiout, sys_midioutdevlist, MAXMIDIOUTDEV,
argv[1]);
@@ -672,7 +677,7 @@ int sys_argparse(int argc, char **argv)
goto usage;
argc -= 2; argv += 2;
}
- else if (!strcmp(*argv, "-mididev"))
+ else if (!strcmp(*argv, "-mididev") && (argc > 1))
{
sys_parsedevlist(&sys_nmidiin, sys_midiindevlist, MAXMIDIINDEV,
argv[1]);
@@ -682,7 +687,7 @@ int sys_argparse(int argc, char **argv)
goto usage;
argc -= 2; argv += 2;
}
- else if (!strcmp(*argv, "-path"))
+ else if (!strcmp(*argv, "-path") && (argc > 1))
{
sys_searchpath = namelist_append_files(sys_searchpath, argv[1]);
argc -= 2; argv += 2;
@@ -822,7 +827,8 @@ int sys_argparse(int argc, char **argv)
goto usage;
argc -= 2; argv += 2;
}
- else if (!strcmp(*argv, "-sounddev") || !strcmp(*argv, "-audiodev"))
+ else if ((!strcmp(*argv, "-sounddev") || !strcmp(*argv, "-audiodev"))
+ && (argc > 1))
{
sys_parsedevlist(&sys_nsoundin, sys_soundindevlist,
MAXAUDIOINDEV, argv[1]);
diff --git a/pd/src/u_main.tk b/pd/src/u_main.tk
index 82544ac4..62ddf836 100644
--- a/pd/src/u_main.tk
+++ b/pd/src/u_main.tk
@@ -89,6 +89,8 @@ if {$pd_nt == 0} {
}
}
+set pd_deffont {courier 12 bold}
+
set help_top_directory $pd_guidir/doc
# it's unfortunate but we seem to have to turn off global bindings
@@ -354,7 +356,6 @@ proc menu_opentext {filename} {
global doc_number
global pd_guidir
global pd_myversion
-# global pd_font3
set name [format ".help%d" $doc_number]
toplevel $name
text $name.text -relief raised -bd 2 -font -*-times-regular--normal--14-* \
@@ -573,7 +574,7 @@ proc menu_print {name} {
-filetypes { {{postscript} {.ps}} }]
if {$filename != ""} {
- $name.c postscript -file $filename
+ $name.c postscript -file $filename
}
}
@@ -1229,10 +1230,15 @@ proc pdtk_array_listview_fillpage {arrayName} {
global pd_array_listview_page
global pd_array_listview_id
set windowName [format ".%sArrayWindow" $arrayName]
+ set topItem [expr [lindex [$windowName.lb yview] 0] * \
+ [$windowName.lb size]]
+
if {[winfo exists $windowName]} {
set cmd "$pd_array_listview_id($arrayName) \
arrayviewlistfillpage \
- $pd_array_listview_page($arrayName)"
+ $pd_array_listview_page($arrayName) \
+ $topItem"
+
pd [concat $cmd \;]
}
}
@@ -1260,7 +1266,7 @@ proc pdtk_array_listview_new {id arrayName page} {
set $windowName.lb.sb [scrollbar $windowName.lb.sb \
-command "$windowName.lb yview" -orient vertical]
place configure $windowName.lb.sb -relheight 1 -relx 0.9 -relwidth 0.1
- pack $windowName.lb
+ pack $windowName.lb -expand 1 -fill both
bind $windowName.lb <Double-ButtonPress-1> \
"pdtk_array_listview_edit $arrayName $page $font"
# handle copy/paste
@@ -1277,8 +1283,8 @@ proc pdtk_array_listview_new {id arrayName page} {
-command "pdtk_array_listview_changepage $arrayName -1"]
set $windowName.nextBtn [button $windowName.nextBtn -text "->" \
-command "pdtk_array_listview_changepage $arrayName 1"]
- pack $windowName.prevBtn -side left -ipadx 20 -pady 10
- pack $windowName.nextBtn -side right -ipadx 20 -pady 10
+ pack $windowName.prevBtn -side left -ipadx 20 -pady 10 -anchor s
+ pack $windowName.nextBtn -side right -ipadx 20 -pady 10 -anchor s
focus $windowName
}
@@ -3144,7 +3150,7 @@ proc dodata_ok {name} {
}
proc pdtk_data_dialog {name stuff} {
- global pd_font3
+ global pd_deffont
toplevel $name
wm title $name {Atom}
wm protocol $name WM_DELETE_WINDOW [concat dodata_cancel $name]
@@ -3159,7 +3165,7 @@ proc pdtk_data_dialog {name stuff} {
pack $name.buttonframe.ok -side left -expand 1
text $name.text -relief raised -bd 2 -height 40 -width 60 \
- -yscrollcommand "$name.scroll set" -font $pd_font3
+ -yscrollcommand "$name.scroll set" -font $pd_deffont
scrollbar $name.scroll -command "$name.text yview"
pack $name.scroll -side right -fill y
pack $name.text -side left -fill both -expand 1
@@ -3185,15 +3191,18 @@ proc pdtk_text_new {canvasname myname x y text font color} {
# if {$font < 13} {set fontname [format -*-courier-bold----%d-* $font]}
# if {$font >= 13} {set fontname [format -*-courier-----%d-* $font]}
- global pd_font1 pd_font2 pd_font3 pd_font4 pd_font5 pd_font6 pd_font7
+ global pd_fontlist
switch -- $font {
- 8 { set typeface $pd_font1 }
- 10 { set typeface $pd_font2 }
- 12 { set typeface $pd_font3 }
- 14 { set typeface $pd_font4 }
- 16 { set typeface $pd_font5 }
- 24 { set typeface $pd_font6 }
- 36 { set typeface $pd_font7 }
+ 8 { set typeface [lindex $pd_fontlist 0] }
+ 9 { set typeface [lindex $pd_fontlist 1] }
+ 10 { set typeface [lindex $pd_fontlist 2] }
+ 12 { set typeface [lindex $pd_fontlist 3] }
+ 14 { set typeface [lindex $pd_fontlist 4] }
+ 16 { set typeface [lindex $pd_fontlist 5] }
+ 18 { set typeface [lindex $pd_fontlist 6] }
+ 24 { set typeface [lindex $pd_fontlist 7] }
+ 30 { set typeface [lindex $pd_fontlist 8] }
+ 36 { set typeface [lindex $pd_fontlist 9] }
}
$canvasname create text $x $y \
@@ -3226,7 +3235,7 @@ proc pdtk_pd_ctrlkey {name key shift} {
######### startup function. ##############
# Tell pd the current directory; this is used in case the command line
# asked pd to open something. Also, get character width and height for
-# font sizes 8, 10, 12, 14, 16, and 24.
+# seven "useful" font sizes.
# tb: user defined typefaces
proc pdtk_pd_startup {version apilist midiapilist fontname} {
@@ -3235,49 +3244,29 @@ proc pdtk_pd_startup {version apilist midiapilist fontname} {
set pd_myversion $version
set pd_apilist $apilist
set pd_midiapilist $midiapilist
- global pd_font1 pd_font2 pd_font3 pd_font4 pd_font5 pd_font6 pd_font7
-
- set pd_font1 [format -*-%s-bold--normal--8-* $fontname]
- set pd_font2 [format -*-%s-bold--normal--10-* $fontname]
- set pd_font3 [format -*-%s-bold--normal--12-* $fontname]
- set pd_font4 [format -*-%s-bold--normal--14-* $fontname]
- set pd_font5 [format -*-%s-bold--normal--16-* $fontname]
- set pd_font6 [format -*-%s-bold--normal--24-* $fontname]
- set pd_font7 [format -*-%s-bold--normal--36-* $fontname]
-
- set width1 [font measure $pd_font1 x]
- set height1 [lindex [font metrics $pd_font1] 5]
- set width2 [font measure $pd_font2 x]
- set height2 [lindex [font metrics $pd_font2] 5]
- set width3 [font measure $pd_font3 x]
- set height3 [lindex [font metrics $pd_font3] 5]
- set width4 [font measure $pd_font4 x]
- set height4 [lindex [font metrics $pd_font4] 5]
- set width5 [font measure $pd_font5 x]
- set height5 [lindex [font metrics $pd_font5] 5]
- set width6 [font measure $pd_font6 x]
- set height6 [lindex [font metrics $pd_font6] 5]
- set width7 [font measure $pd_font7 x]
- set height7 [lindex [font metrics $pd_font7] 5]
+ global pd_fontlist
+ set pd_fontlist {}
+
+ set fontlist ""
+ foreach i {8 9 10 12 14 16 18 24 30 36} {
+ set font [concat $fontname -$i bold]
+ set pd_fontlist [linsert $pd_fontlist 100000 $font]
+ set width0 [font measure $font x]
+ set height0 [lindex [font metrics $font] 5]
+ set fontlist [concat $fontlist $i [font measure $font x] \
+ [lindex [font metrics $font] 5]]
+ }
set tclpatch [info patchlevel]
if {$tclpatch == "8.3.0" || \
- $tclpatch == "8.3.1" || \
- $tclpatch == "8.3.2" || \
- $tclpatch == "8.3.3" } {
- set oldtclversion 1
+ $tclpatch == "8.3.1" || \
+ $tclpatch == "8.3.2" || \
+ $tclpatch == "8.3.3" } {
+ set oldtclversion 1
} else {
- set oldtclversion 0
+ set oldtclversion 0
}
- pd [concat pd init [pdtk_enquote [pwd]] \
- 8 $width1 $height1 \
- 10 $width2 $height2 \
- 12 $width3 $height3 \
- 14 $width4 $height4 \
- 16 $width5 $height5 \
- 24 $width6 $height6 \
- 36 $width7 $height7 \
- $oldtclversion \;];
+ pd [concat pd init [pdtk_enquote [pwd]] $oldtclversion $fontlist \;];
# add the audio and help menus to the Pd window. We delayed this
# so that we'd know the value of "apilist".
@@ -3352,7 +3341,7 @@ proc texteditor_ok {name} {
proc pdtk_pd_texteditor {stuff} {
- global edit_number pd_font3
+ global edit_number pd_deffont
set name [format ".text%d" $edit_number]
set edit_number [expr $edit_number + 1]
@@ -3369,7 +3358,7 @@ proc pdtk_pd_texteditor {stuff} {
pack $name.buttons.ok -side left -expand 1
text $name.text -relief raised -bd 2 -height 12 -width 60 \
- -yscrollcommand "$name.scroll set" -font $pd_font3
+ -yscrollcommand "$name.scroll set" -font $pd_deffont
scrollbar $name.scroll -command "$name.text yview"
pack $name.scroll -side right -fill y
pack $name.text -side left -fill both -expand 1
@@ -3394,23 +3383,26 @@ proc pdtk_pastetext {} {
############# open and save dialogs for objects in Pd ##########
-proc pdtk_openpanel {target} {
+proc pdtk_openpanel {target localdir} {
global pd_opendir
+ if {$localdir == ""} {
+ set localdir $pd_opendir
+ }
set filename [tk_getOpenFile \
- -initialdir $pd_opendir]
+ -initialdir $localdir]
if {$filename != ""} {
set directory [string range $filename 0 \
[expr [string last / $filename ] - 1]]
set pd_opendir $directory
- pd [concat $target symbol [pdtk_enquote $filename] \;]
+ pd [concat $target callback [pdtk_enquote $filename] \;]
}
}
-proc pdtk_savepanel {target} {
- set filename [tk_getSaveFile]
+proc pdtk_savepanel {target localdir} {
+ set filename [tk_getSaveFile -initialdir $localdir]
if {$filename != ""} {
- pd [concat $target symbol [pdtk_enquote $filename] \;]
+ pd [concat $target callback [pdtk_enquote $filename] \;]
}
}
diff --git a/pd/src/x_gui.c b/pd/src/x_gui.c
index d2d47ae1..bcc6ec8b 100644
--- a/pd/src/x_gui.c
+++ b/pd/src/x_gui.c
@@ -182,7 +182,7 @@ typedef struct _openpanel
t_symbol *x_s;
} t_openpanel;
-static void *openpanel_new(void)
+static void *openpanel_new( void)
{
char buf[50];
t_openpanel *x = (t_openpanel *)pd_new(openpanel_class);
@@ -193,16 +193,23 @@ static void *openpanel_new(void)
return (x);
}
+static void openpanel_symbol(t_openpanel *x, t_symbol *s)
+{
+ char *path = (s && s->s_name) ? s->s_name : "\"\"";
+ sys_vgui("pdtk_openpanel {%s} {%s}\n", x->x_s->s_name, path);
+}
+
static void openpanel_bang(t_openpanel *x)
{
- sys_vgui("pdtk_openpanel %s\n", x->x_s->s_name);
+ openpanel_symbol(x, &s_);
}
-static void openpanel_symbol(t_openpanel *x, t_symbol *s)
+static void openpanel_callback(t_openpanel *x, t_symbol *s)
{
outlet_symbol(x->x_obj.ob_outlet, s);
}
+
static void openpanel_free(t_openpanel *x)
{
pd_unbind(&x->x_obj.ob_pd, x->x_s);
@@ -212,9 +219,11 @@ static void openpanel_setup(void)
{
openpanel_class = class_new(gensym("openpanel"),
(t_newmethod)openpanel_new, (t_method)openpanel_free,
- sizeof(t_openpanel), 0, A_DEFFLOAT, 0);
+ sizeof(t_openpanel), 0, 0);
class_addbang(openpanel_class, openpanel_bang);
class_addsymbol(openpanel_class, openpanel_symbol);
+ class_addmethod(openpanel_class, (t_method)openpanel_callback,
+ gensym("callback"), A_SYMBOL, 0);
}
/* -------------------------- savepanel ------------------------------ */
@@ -227,7 +236,7 @@ typedef struct _savepanel
t_symbol *x_s;
} t_savepanel;
-static void *savepanel_new(void)
+static void *savepanel_new( void)
{
char buf[50];
t_savepanel *x = (t_savepanel *)pd_new(savepanel_class);
@@ -238,12 +247,18 @@ static void *savepanel_new(void)
return (x);
}
+static void savepanel_symbol(t_savepanel *x, t_symbol *s)
+{
+ char *path = (s && s->s_name) ? s->s_name : "\"\"";
+ sys_vgui("pdtk_savepanel {%s} {%s}\n", x->x_s->s_name, path);
+}
+
static void savepanel_bang(t_savepanel *x)
{
- sys_vgui("pdtk_savepanel %s\n", x->x_s->s_name);
+ savepanel_symbol(x, &s_);
}
-static void savepanel_symbol(t_savepanel *x, t_symbol *s)
+static void savepanel_callback(t_savepanel *x, t_symbol *s)
{
outlet_symbol(x->x_obj.ob_outlet, s);
}
@@ -257,9 +272,11 @@ static void savepanel_setup(void)
{
savepanel_class = class_new(gensym("savepanel"),
(t_newmethod)savepanel_new, (t_method)savepanel_free,
- sizeof(t_savepanel), 0, A_DEFFLOAT, 0);
+ sizeof(t_savepanel), 0, 0);
class_addbang(savepanel_class, savepanel_bang);
class_addsymbol(savepanel_class, savepanel_symbol);
+ class_addmethod(savepanel_class, (t_method)savepanel_callback,
+ gensym("callback"), A_SYMBOL, 0);
}
/* ---------------------- key and its relatives ------------------ */