aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pd/README.txt14
-rw-r--r--pd/doc/1.manual/x3.htm193
-rw-r--r--pd/doc/1.manual/x5.htm49
-rw-r--r--pd/doc/3.audio.examples/00.INTRO.txt4
-rw-r--r--pd/doc/3.audio.examples/A01.sinewave.pd32
-rw-r--r--pd/doc/3.audio.examples/A02.amplitude.pd37
-rw-r--r--pd/doc/3.audio.examples/A03.line.pd55
-rw-r--r--pd/doc/3.audio.examples/A04.line2.pd59
-rw-r--r--pd/doc/3.audio.examples/A05.output.subpatch.pd30
-rw-r--r--pd/doc/3.audio.examples/A06.frequency.pd60
-rw-r--r--pd/doc/3.audio.examples/A07.frequency.mod.pd105
-rw-r--r--pd/doc/3.audio.examples/A08.phase.mod.pd246
-rw-r--r--pd/doc/3.audio.examples/A09.review.pd41
-rw-r--r--pd/doc/3.audio.examples/B01.wavetables.pd50
-rw-r--r--pd/doc/3.audio.examples/B02.two-wavetables.pd147
-rw-r--r--pd/doc/3.audio.examples/B03.tabread4.pd130
-rw-r--r--pd/doc/3.audio.examples/B04.tabread4.interpolation.pd44
-rw-r--r--pd/doc/3.audio.examples/B05.tabread.FM.pd107
-rw-r--r--pd/doc/3.audio.examples/B06.table.switching.pd127
-rw-r--r--pd/doc/3.audio.examples/B07.sampler.pd52
-rw-r--r--pd/doc/3.audio.examples/B08.sampler.loop.pd64
-rw-r--r--pd/doc/3.audio.examples/B09.sampler.loop.smooth.pd72
-rw-r--r--pd/doc/3.audio.examples/B10.sampler.scratch.pd83
-rw-r--r--pd/doc/3.audio.examples/B11.sampler.nodoppler.pd85
-rw-r--r--pd/doc/3.audio.examples/B12.sampler.transpose.pd109
-rw-r--r--pd/doc/3.audio.examples/B13.sampler.overlap.pd158
-rw-r--r--pd/doc/3.audio.examples/B14.sampler.rockafella.pd166
-rw-r--r--pd/doc/3.audio.examples/C01.nyquist.pd102
-rw-r--r--pd/doc/3.audio.examples/C02.sawtooth-foldover.pd39
-rw-r--r--pd/doc/3.audio.examples/C03.zipper.noise.pd55
-rw-r--r--pd/doc/3.audio.examples/C04.control.to.signal.pd48
-rw-r--r--pd/doc/3.audio.examples/C05.sampler.oneshot.pd84
-rw-r--r--pd/doc/3.audio.examples/C06.signal.to.control.pd25
-rw-r--r--pd/doc/3.audio.examples/C07.envelope.follower.pd113
-rw-r--r--pd/doc/3.audio.examples/C08.analog.sequencer.pd156
-rw-r--r--pd/doc/3.audio.examples/C09.sample.hold.pd104
-rw-r--r--pd/doc/3.audio.examples/C10.monophonic.synth.pd107
-rw-r--r--pd/doc/3.audio.examples/D01.envelope.gen.pd90
-rw-r--r--pd/doc/3.audio.examples/D02.adsr.pd34
-rw-r--r--pd/doc/3.audio.examples/D03.envelope.dB.pd158
-rw-r--r--pd/doc/3.audio.examples/D04.envelope.pitch.pd209
-rw-r--r--pd/doc/3.audio.examples/D05.envelope.portamento.pd148
-rw-r--r--pd/doc/3.audio.examples/D06.additive.pd92
-rw-r--r--pd/doc/3.audio.examples/D07.sampler.notes.pd321
-rw-r--r--pd/doc/3.audio.examples/D08.sampler.poly.pd229
-rw-r--r--pd/doc/3.audio.examples/D09.table.spectrum.pd143
-rw-r--r--pd/doc/3.audio.examples/D10.risset.bell.pd109
-rw-r--r--pd/doc/3.audio.examples/D11.shepard.tone.pd110
-rw-r--r--pd/doc/3.audio.examples/E01.pulse.pd126
-rw-r--r--pd/doc/3.audio.examples/E02.just.say.pd152
-rw-r--r--pd/doc/3.audio.examples/E03.pulse.spectrum.pd136
-rw-r--r--pd/doc/3.audio.examples/E04.more.pulses.pd138
-rw-r--r--pd/doc/3.audio.examples/E05.pulse.width.mod.pd98
-rw-r--r--pd/doc/3.audio.examples/E06.stereo.pd87
-rw-r--r--pd/doc/3.audio.examples/E07.envelope.mod.pd148
-rw-r--r--pd/doc/3.audio.examples/E08.even.odd.pd116
-rw-r--r--pd/doc/3.audio.examples/E09.bandlimited.pd166
-rw-r--r--pd/doc/3.audio.examples/F01.PART7.filters.pd72
-rw-r--r--pd/doc/3.audio.examples/F02.bandpass.pd146
-rw-r--r--pd/doc/3.audio.examples/F03.filter.sweep.pd173
-rw-r--r--pd/doc/3.audio.examples/F04.filter.floyd.pd193
-rw-r--r--pd/doc/3.audio.examples/F05.filter.noise.pd196
-rw-r--r--pd/doc/3.audio.examples/F06.ring.modulation.pd153
-rw-r--r--pd/doc/3.audio.examples/F07.ssb.modulation.pd150
-rw-r--r--pd/doc/3.audio.examples/G01.delays.pd225
-rw-r--r--pd/doc/3.audio.examples/G02.delay.loop.pd213
-rw-r--r--pd/doc/3.audio.examples/G03.delay.variable.pd129
-rw-r--r--pd/doc/3.audio.examples/G04.delay.pitchshift.pd226
-rw-r--r--pd/doc/3.audio.examples/G05.delay.reverb.pd316
-rw-r--r--pd/doc/3.audio.examples/H01.more.FM.pd132
-rw-r--r--pd/doc/3.audio.examples/H02.packets.pd161
-rw-r--r--pd/doc/3.audio.examples/H03.packet.spectrum.pd147
-rw-r--r--pd/doc/3.audio.examples/H04.two.cosines.pd124
-rw-r--r--pd/doc/3.audio.examples/H05.declickit.pd132
-rw-r--r--pd/doc/3.audio.examples/H06.sweepable.FM.pd161
-rw-r--r--pd/doc/3.audio.examples/H07.paf.pd234
-rw-r--r--pd/doc/3.audio.examples/H08.paf.control.pd219
-rw-r--r--pd/doc/3.audio.examples/J01.quartic.pd140
-rw-r--r--pd/doc/3.audio.examples/J02.more.quartic.pd147
-rw-r--r--pd/doc/3.audio.examples/J03.qlist.pd102
-rw-r--r--pd/doc/3.audio.examples/J04.more.adsr.pd117
-rw-r--r--pd/doc/3.audio.examples/J05.vibrato.pd158
-rw-r--r--pd/doc/3.audio.examples/J06.adsr.sequenced.pd217
-rw-r--r--pd/doc/3.audio.examples/J07.execution.order.pd127
-rw-r--r--pd/doc/3.audio.examples/J08.control.blocksize.pd111
-rw-r--r--pd/doc/3.audio.examples/J09.up.downsampling.pd191
-rw-r--r--pd/doc/3.audio.examples/J10.waveshaping.pd133
-rw-r--r--pd/doc/3.audio.examples/adsr.pd126
-rw-r--r--pd/doc/3.audio.examples/output~.pd16
-rw-r--r--pd/doc/3.audio.examples/qlist-sampler.txt147
-rw-r--r--pd/doc/3.audio.examples/qlist.txt2
-rw-r--r--pd/doc/3.audio.examples/shepvoice.pd37
-rw-r--r--pd/doc/3.audio.examples/sinevoice.pd67
-rw-r--r--pd/doc/5.reference/acoustics-help.pd40
-rw-r--r--pd/doc/5.reference/acoustics~-help.pd81
-rw-r--r--pd/doc/5.reference/adc~_dac~-help.pd11
-rw-r--r--pd/doc/5.reference/append-help.pd44
-rw-r--r--pd/doc/5.reference/bag-help.pd27
-rw-r--r--pd/doc/5.reference/bang-help.pd13
-rw-r--r--pd/doc/5.reference/bang~-help.pd18
-rw-r--r--pd/doc/5.reference/biquad~-help.pd36
-rw-r--r--pd/doc/5.reference/bng-help.pd265
-rw-r--r--pd/doc/5.reference/bp~-help.pd40
-rw-r--r--pd/doc/5.reference/canvas-help.pd19
-rw-r--r--pd/doc/5.reference/change-help.pd23
-rw-r--r--pd/doc/5.reference/clip~-help.pd30
-rw-r--r--pd/doc/5.reference/cos~-help.pd32
-rw-r--r--pd/doc/5.reference/cputime-help.pd15
-rw-r--r--pd/doc/5.reference/delay-help.pd30
-rw-r--r--pd/doc/5.reference/delread~-help.pd33
-rw-r--r--pd/doc/5.reference/delwrite~-help.pd15
-rw-r--r--pd/doc/5.reference/drawnumber-help.pd35
-rw-r--r--pd/doc/5.reference/drawpolygon-help.pd41
-rw-r--r--pd/doc/5.reference/element-help.pd51
-rw-r--r--pd/doc/5.reference/env~-help.pd28
-rw-r--r--pd/doc/5.reference/fft~-help.pd64
-rw-r--r--pd/doc/5.reference/float-help.pd18
-rw-r--r--pd/doc/5.reference/framp~-help.pd40
-rw-r--r--pd/doc/5.reference/gatom-help.pd32
-rw-r--r--pd/doc/5.reference/get-help.pd46
-rw-r--r--pd/doc/5.reference/getsize-help.pd41
-rw-r--r--pd/doc/5.reference/graph-help.pd13
-rw-r--r--pd/doc/5.reference/hdial-help.pd282
-rw-r--r--pd/doc/5.reference/help-metro.pd29
-rw-r--r--pd/doc/5.reference/help-x_all_guis.pd20
-rw-r--r--pd/doc/5.reference/hip~-help.pd31
-rw-r--r--pd/doc/5.reference/hslider-help.pd303
-rw-r--r--pd/doc/5.reference/int-help.pd24
-rw-r--r--pd/doc/5.reference/key-help.pd24
-rw-r--r--pd/doc/5.reference/line-help.pd32
-rw-r--r--pd/doc/5.reference/line~-help.pd33
-rw-r--r--pd/doc/5.reference/lop~-help.pd31
-rw-r--r--pd/doc/5.reference/makefilename-help.pd17
-rw-r--r--pd/doc/5.reference/makenote-help.pd26
-rw-r--r--pd/doc/5.reference/math-help.pd60
-rw-r--r--pd/doc/5.reference/message-help.pd46
-rw-r--r--pd/doc/5.reference/midi-help.pd129
-rw-r--r--pd/doc/5.reference/moses-help.pd17
-rw-r--r--pd/doc/5.reference/my_canvas-help.pd243
-rw-r--r--pd/doc/5.reference/namecanvas-help.pd8
-rw-r--r--pd/doc/5.reference/netreceive-help.pd23
-rw-r--r--pd/doc/5.reference/netsend-help.pd55
-rw-r--r--pd/doc/5.reference/noise~-help.pd18
-rw-r--r--pd/doc/5.reference/numbox2-help.pd302
-rw-r--r--pd/doc/5.reference/openpanel-help.pd11
-rw-r--r--pd/doc/5.reference/operators-help.pd31
-rw-r--r--pd/doc/5.reference/osc~-help.pd58
-rw-r--r--pd/doc/5.reference/otherbinops-help.pd90
-rw-r--r--pd/doc/5.reference/pack-help.pd37
-rw-r--r--pd/doc/5.reference/pd-help.pd52
-rw-r--r--pd/doc/5.reference/phasor~-help.pd36
-rw-r--r--pd/doc/5.reference/pipe-help.pd41
-rw-r--r--pd/doc/5.reference/plot-help.pd58
-rw-r--r--pd/doc/5.reference/pointer-help.pd79
-rw-r--r--pd/doc/5.reference/poly-help.pd30
-rw-r--r--pd/doc/5.reference/print-help.pd13
-rw-r--r--pd/doc/5.reference/print~-help.pd18
-rw-r--r--pd/doc/5.reference/qlist-help.pd76
-rw-r--r--pd/doc/5.reference/random-help.pd19
-rw-r--r--pd/doc/5.reference/readsf~-help.pd63
-rw-r--r--pd/doc/5.reference/realtime-help.pd15
-rw-r--r--pd/doc/5.reference/receive-help.pd26
-rw-r--r--pd/doc/5.reference/route-help.pd80
-rw-r--r--pd/doc/5.reference/rsqrt~-help.pd32
-rw-r--r--pd/doc/5.reference/samphold~-help.pd34
-rw-r--r--pd/doc/5.reference/savepanel-help.pd12
-rw-r--r--pd/doc/5.reference/select-help.pd73
-rw-r--r--pd/doc/5.reference/send-help.pd26
-rw-r--r--pd/doc/5.reference/send~-help.pd32
-rw-r--r--pd/doc/5.reference/set-help.pd45
-rw-r--r--pd/doc/5.reference/setsize-help.pd54
-rw-r--r--pd/doc/5.reference/sigbinops-help.pd60
-rw-r--r--pd/doc/5.reference/sig~-help.pd20
-rw-r--r--pd/doc/5.reference/snapshot~-help.pd33
-rw-r--r--pd/doc/5.reference/soundfiler-help.pd67
-rw-r--r--pd/doc/5.reference/spigot-help.pd21
-rw-r--r--pd/doc/5.reference/sqrt~-help.pd32
-rw-r--r--pd/doc/5.reference/stripnote-help.pd16
-rw-r--r--pd/doc/5.reference/struct-help.pd26
-rw-r--r--pd/doc/5.reference/sublist-help.pd10
-rw-r--r--pd/doc/5.reference/swap-help.pd20
-rw-r--r--pd/doc/5.reference/switch~-help.pd45
-rw-r--r--pd/doc/5.reference/tabosc4~-help.pd86
-rw-r--r--pd/doc/5.reference/tabplay~-help.pd66
-rw-r--r--pd/doc/5.reference/tabread-help.pd21
-rw-r--r--pd/doc/5.reference/tabread4~-help.pd43
-rw-r--r--pd/doc/5.reference/tabreceive~-help.pd6
-rw-r--r--pd/doc/5.reference/tabsend~-help.pd6
-rw-r--r--pd/doc/5.reference/tabwrite-help.pd21
-rw-r--r--pd/doc/5.reference/tabwrite~-help.pd30
-rw-r--r--pd/doc/5.reference/text-help.pd4
-rw-r--r--pd/doc/5.reference/textfile-help.pd59
-rw-r--r--pd/doc/5.reference/threshold~-help.pd31
-rw-r--r--pd/doc/5.reference/throw~-help.pd34
-rw-r--r--pd/doc/5.reference/timer-help.pd15
-rw-r--r--pd/doc/5.reference/toggle-help.pd273
-rw-r--r--pd/doc/5.reference/trigger-help.pd37
-rw-r--r--pd/doc/5.reference/unpack-help.pd28
-rw-r--r--pd/doc/5.reference/until-help.pd25
-rw-r--r--pd/doc/5.reference/value-help.pd30
-rw-r--r--pd/doc/5.reference/vcf~-help.pd35
-rw-r--r--pd/doc/5.reference/vdial-help.pd282
-rw-r--r--pd/doc/5.reference/vd~-help.pd19
-rw-r--r--pd/doc/5.reference/vslider-help.pd302
-rw-r--r--pd/doc/5.reference/vu-help.pd247
-rw-r--r--pd/doc/5.reference/wrap~-help.pd26
-rw-r--r--pd/doc/5.reference/writesf~-help.pd41
-rw-r--r--pd/doc/6.externs/makefile49
-rw-r--r--pd/doc/6.externs/obj1.c47
-rw-r--r--pd/doc/6.externs/obj2.c45
-rw-r--r--pd/doc/6.externs/obj3.c39
-rw-r--r--pd/doc/6.externs/obj4.c47
-rw-r--r--pd/doc/6.externs/obj5.c54
-rw-r--r--pd/doc/6.externs/test-obj1.pd6
-rw-r--r--pd/doc/6.externs/test-obj2.pd8
-rw-r--r--pd/doc/6.externs/test-obj3.pd8
-rw-r--r--pd/doc/6.externs/test-obj4.pd6
-rw-r--r--pd/doc/6.externs/test-obj5.pd4
-rw-r--r--pd/doc/7.stuff/synth/1.poly.synth.pd48
-rw-r--r--pd/doc/7.stuff/synth/preset4.txt1
-rw-r--r--pd/doc/sound/voice.wavbin126092 -> 124204 bytes
-rw-r--r--pd/extra/README.txt8
-rw-r--r--pd/extra/bonk~/help-bonk~.pd162
-rw-r--r--pd/extra/choice/help-choice.pd41
-rw-r--r--pd/extra/choice/makefile8
-rw-r--r--pd/extra/fiddle~/help-fiddle~.pd107
-rw-r--r--pd/extra/help-expr.pd497
-rw-r--r--pd/extra/help-rev1~.pd119
-rw-r--r--pd/extra/help-rev2~.pd130
-rw-r--r--pd/extra/loop~/help-loop~.pd66
-rw-r--r--pd/extra/lrshift~/help-rlshift~.pd29
-rw-r--r--pd/extra/paf~/help-paf~.pd166
-rw-r--r--pd/extra/pique/help-pique.pd33
-rw-r--r--pd/extra/pique/makefile8
-rw-r--r--pd/extra/pique/pique.c.old148
-rw-r--r--pd/extra/rev2~.pd240
-rw-r--r--pd/portaudio/MSP-README.txt7
-rw-r--r--pd/portaudio/Makefile.in132
-rw-r--r--pd/portaudio/Makefile.linux59
-rw-r--r--pd/portaudio/Makefile.mingw57
-rw-r--r--pd/portaudio/README.txt2
-rw-r--r--pd/portaudio/V19-devel-readme.txt230
-rw-r--r--pd/portaudio/aclocal.m457
-rw-r--r--pd/portaudio/config.doxy185
-rwxr-xr-xpd/portaudio/config.guess1308
-rwxr-xr-xpd/portaudio/configure2903
-rw-r--r--pd/portaudio/configure.in123
-rw-r--r--pd/portaudio/docs/index.html60
-rw-r--r--pd/portaudio/docs/latency.html192
-rw-r--r--pd/portaudio/docs/pa_impl_guide.html197
-rw-r--r--pd/portaudio/docs/pa_impl_startstop.html190
-rw-r--r--pd/portaudio/docs/pa_tut_asio.html55
-rw-r--r--pd/portaudio/docs/pa_tut_callback.html91
-rw-r--r--pd/portaudio/docs/pa_tut_devs.html65
-rw-r--r--pd/portaudio/docs/pa_tut_explore.html42
-rw-r--r--pd/portaudio/docs/pa_tut_init.html43
-rw-r--r--pd/portaudio/docs/pa_tut_mac.html41
-rw-r--r--pd/portaudio/docs/pa_tut_mac_osx.html46
-rw-r--r--pd/portaudio/docs/pa_tut_open.html52
-rw-r--r--pd/portaudio/docs/pa_tut_oss.html46
-rw-r--r--pd/portaudio/docs/pa_tut_over.html92
-rw-r--r--pd/portaudio/docs/pa_tut_pc.html78
-rw-r--r--pd/portaudio/docs/pa_tut_run.html56
-rw-r--r--pd/portaudio/docs/pa_tut_rw.html79
-rw-r--r--pd/portaudio/docs/pa_tut_term.html47
-rw-r--r--pd/portaudio/docs/pa_tut_util.html55
-rw-r--r--pd/portaudio/docs/pa_tutorial.html46
-rw-r--r--pd/portaudio/docs/portaudio_h.txt425
-rw-r--r--pd/portaudio/docs/portaudio_icmc2001.pdfbin0 -> 50968 bytes
-rw-r--r--pd/portaudio/docs/proposals.html36
-rw-r--r--pd/portaudio/docs/releases.html339
-rwxr-xr-xpd/portaudio/fixdir.bat19
-rwxr-xr-xpd/portaudio/fixfile.bat7
-rw-r--r--pd/portaudio/index.html89
-rwxr-xr-xpd/portaudio/install-sh251
-rw-r--r--pd/portaudio/pa_asio/Callback_adaptation_.pdfbin0 -> 50527 bytes
-rw-r--r--pd/portaudio/pa_asio/Pa_ASIO.pdfbin0 -> 50778 bytes
-rw-r--r--pd/portaudio/pa_asio/borland_asio_readme.txt6
-rw-r--r--pd/portaudio/pa_asio/pa_asio.cpp4403
-rw-r--r--pd/portaudio/pa_asio/pa_asio.h68
-rwxr-xr-xpd/portaudio/pa_asio/readme_asio_sdk_patch.txt25
-rw-r--r--pd/portaudio/pa_beos/PlaybackNode.cc538
-rw-r--r--pd/portaudio/pa_beos/PlaybackNode.h108
-rw-r--r--pd/portaudio/pa_beos/pa_beos_mk.cc441
-rw-r--r--pd/portaudio/pa_common/pa_allocation.c217
-rw-r--r--pd/portaudio/pa_common/pa_allocation.h92
-rw-r--r--pd/portaudio/pa_common/pa_allocation.obin0 -> 1744 bytes
-rw-r--r--pd/portaudio/pa_common/pa_converters.c1653
-rw-r--r--pd/portaudio/pa_common/pa_converters.h197
-rw-r--r--pd/portaudio/pa_common/pa_converters.obin0 -> 20384 bytes
-rw-r--r--pd/portaudio/pa_common/pa_cpuload.c79
-rw-r--r--pd/portaudio/pa_common/pa_cpuload.h56
-rw-r--r--pd/portaudio/pa_common/pa_cpuload.obin0 -> 1452 bytes
-rw-r--r--pd/portaudio/pa_common/pa_dither.c91
-rw-r--r--pd/portaudio/pa_common/pa_dither.h189
-rw-r--r--pd/portaudio/pa_common/pa_dither.obin0 -> 1136 bytes
-rw-r--r--pd/portaudio/pa_common/pa_endianness.h108
-rw-r--r--pd/portaudio/pa_common/pa_front.c1884
-rw-r--r--pd/portaudio/pa_common/pa_front.obin0 -> 12576 bytes
-rw-r--r--pd/portaudio/pa_common/pa_hostapi.h238
-rw-r--r--pd/portaudio/pa_common/pa_process.c1355
-rw-r--r--pd/portaudio/pa_common/pa_process.h203
-rw-r--r--pd/portaudio/pa_common/pa_process.obin0 -> 10192 bytes
-rw-r--r--pd/portaudio/pa_common/pa_skeleton.c724
-rw-r--r--pd/portaudio/pa_common/pa_skeleton.obin0 -> 3468 bytes
-rw-r--r--pd/portaudio/pa_common/pa_stream.c114
-rw-r--r--pd/portaudio/pa_common/pa_stream.h128
-rw-r--r--pd/portaudio/pa_common/pa_stream.obin0 -> 1059 bytes
-rw-r--r--pd/portaudio/pa_common/pa_trace.c22
-rw-r--r--pd/portaudio/pa_common/pa_trace.h31
-rw-r--r--pd/portaudio/pa_common/pa_trace.obin0 -> 584 bytes
-rw-r--r--pd/portaudio/pa_common/pa_util.h143
-rw-r--r--pd/portaudio/pa_common/portaudio.h1189
-rw-r--r--pd/portaudio/pa_dll_switch/PaDllEntry.h184
-rw-r--r--pd/portaudio/pa_dll_switch/letter_from_tim_010817.txtbin0 -> 1176 bytes
-rw-r--r--pd/portaudio/pa_dll_switch/loadPA_DLL.cpp203
-rw-r--r--pd/portaudio/pa_dll_switch/pa_lib.c827
-rw-r--r--pd/portaudio/pa_dll_switch/portaudio.h439
-rw-r--r--pd/portaudio/pa_jack/pa_jack.c864
-rw-r--r--pd/portaudio/pa_linux_alsa/blocking_calls.c61
-rw-r--r--pd/portaudio/pa_linux_alsa/blocking_calls.obin0 -> 1180 bytes
-rw-r--r--pd/portaudio/pa_linux_alsa/callback_thread.c374
-rw-r--r--pd/portaudio/pa_linux_alsa/callback_thread.obin0 -> 4180 bytes
-rw-r--r--pd/portaudio/pa_linux_alsa/pa_linux_alsa.c989
-rw-r--r--pd/portaudio/pa_linux_alsa/pa_linux_alsa.h45
-rw-r--r--pd/portaudio/pa_linux_alsa/pa_linux_alsa.obin0 -> 10728 bytes
-rw-r--r--pd/portaudio/pa_mac_core/notes.txt14
-rw-r--r--pd/portaudio/pa_mac_core/pa_mac_core.c1512
-rw-r--r--pd/portaudio/pa_mac_sm/pa_mac_sm.c1656
-rw-r--r--pd/portaudio/pa_sgi/Makefile51
-rw-r--r--pd/portaudio/pa_sgi/pa_sgi.c999
-rw-r--r--pd/portaudio/pa_sgi/pthread-Makefile52
-rw-r--r--pd/portaudio/pa_sgi/pthread-pa_sgi.c908
-rw-r--r--pd/portaudio/pa_tests/debug_convert.c131
-rw-r--r--pd/portaudio/pa_tests/debug_dither_calc.c55
-rw-r--r--pd/portaudio/pa_tests/debug_dual.c183
-rw-r--r--pd/portaudio/pa_tests/debug_multi_in.c179
-rw-r--r--pd/portaudio/pa_tests/debug_multi_out.c144
-rw-r--r--pd/portaudio/pa_tests/debug_record.c339
-rw-r--r--pd/portaudio/pa_tests/debug_record_reuse.c351
-rw-r--r--pd/portaudio/pa_tests/debug_sine.c192
-rw-r--r--pd/portaudio/pa_tests/debug_sine_amp.c157
-rw-r--r--pd/portaudio/pa_tests/debug_sine_formats.c202
-rw-r--r--pd/portaudio/pa_tests/debug_srate.c265
-rw-r--r--pd/portaudio/pa_tests/debug_test1.c114
-rw-r--r--pd/portaudio/pa_tests/pa_devs.c199
-rw-r--r--pd/portaudio/pa_tests/pa_fuzz.c168
-rw-r--r--pd/portaudio/pa_tests/pa_minlat.c176
-rw-r--r--pd/portaudio/pa_tests/paqa_devs.c317
-rw-r--r--pd/portaudio/pa_tests/paqa_errs.c330
-rw-r--r--pd/portaudio/pa_tests/patest1.c119
-rw-r--r--pd/portaudio/pa_tests/patest_buffer.c181
-rw-r--r--pd/portaudio/pa_tests/patest_clip.c156
-rw-r--r--pd/portaudio/pa_tests/patest_dither.c152
-rw-r--r--pd/portaudio/pa_tests/patest_hang.c151
-rw-r--r--pd/portaudio/pa_tests/patest_latency.c176
-rw-r--r--pd/portaudio/pa_tests/patest_leftright.c168
-rw-r--r--pd/portaudio/pa_tests/patest_longsine.c137
-rw-r--r--pd/portaudio/pa_tests/patest_many.c194
-rw-r--r--pd/portaudio/pa_tests/patest_maxsines.c197
-rw-r--r--pd/portaudio/pa_tests/patest_multi_sine.c175
-rw-r--r--pd/portaudio/pa_tests/patest_pink.c245
-rw-r--r--pd/portaudio/pa_tests/patest_record.c327
-rw-r--r--pd/portaudio/pa_tests/patest_ringmix.c41
-rw-r--r--pd/portaudio/pa_tests/patest_saw.c118
-rw-r--r--pd/portaudio/pa_tests/patest_sine.c152
-rw-r--r--pd/portaudio/pa_tests/patest_sine8.c184
-rw-r--r--pd/portaudio/pa_tests/patest_sine_formats.c196
-rw-r--r--pd/portaudio/pa_tests/patest_sine_time.c194
-rw-r--r--pd/portaudio/pa_tests/patest_start_stop.c160
-rw-r--r--pd/portaudio/pa_tests/patest_stop.c288
-rw-r--r--pd/portaudio/pa_tests/patest_sync.c257
-rw-r--r--pd/portaudio/pa_tests/patest_toomanysines.c172
-rw-r--r--pd/portaudio/pa_tests/patest_underflow.c151
-rw-r--r--pd/portaudio/pa_tests/patest_wire.c277
-rw-r--r--pd/portaudio/pa_unix/pa_unix_hostapis.c60
-rw-r--r--pd/portaudio/pa_unix/pa_unix_hostapis.obin0 -> 768 bytes
-rw-r--r--pd/portaudio/pa_unix/pa_unix_util.c102
-rw-r--r--pd/portaudio/pa_unix/pa_unix_util.obin0 -> 1096 bytes
-rw-r--r--pd/portaudio/pa_unix_oss/Makefile43
-rw-r--r--pd/portaudio/pa_unix_oss/Makefile_freebsd36
-rw-r--r--pd/portaudio/pa_unix_oss/low_latency_tip.txtbin0 -> 3111 bytes
-rw-r--r--pd/portaudio/pa_unix_oss/pa_unix_oss.c1187
-rw-r--r--pd/portaudio/pa_unix_oss/pa_unix_oss.obin0 -> 8548 bytes
-rw-r--r--pd/portaudio/pa_unix_oss/recplay.c114
-rw-r--r--pd/portaudio/pa_win/pa_win_hostapis.c63
-rw-r--r--pd/portaudio/pa_win/pa_win_util.c128
-rw-r--r--pd/portaudio/pa_win/pa_x86_plain_converters.c1167
-rw-r--r--pd/portaudio/pa_win/pa_x86_plain_converters.h19
-rw-r--r--pd/portaudio/pa_win_ds/dsound_wrapper.c604
-rw-r--r--pd/portaudio/pa_win_ds/dsound_wrapper.h129
-rw-r--r--pd/portaudio/pa_win_ds/pa_dsound.c1021
-rw-r--r--pd/portaudio/pa_win_ds/pa_win_ds.c1441
-rw-r--r--pd/portaudio/pa_win_ds/portaudio.def28
-rw-r--r--pd/portaudio/pa_win_wmme/Makefile.cygwin34
-rw-r--r--pd/portaudio/pa_win_wmme/pa_win_wmme.c2672
-rw-r--r--pd/portaudio/pa_win_wmme/pa_win_wmme.h105
-rw-r--r--pd/portaudio/pablio/pablio.h5
-rw-r--r--pd/portaudio/pablio/pablio_pd.c51
-rw-r--r--pd/portaudio/pablio/pablio_pd.h4
-rw-r--r--pd/portaudio/pablio/pablio_pd.obin0 -> 3500 bytes
-rw-r--r--pd/portaudio/pablio/ringbuffer_pd.obin0 -> 1824 bytes
-rw-r--r--pd/portaudio/testcvs/changeme.txt8
-rw-r--r--pd/portaudio_v18/LICENSE.txt65
-rw-r--r--pd/portaudio_v18/MSP-README.txt6
-rw-r--r--pd/portaudio_v18/README.txt81
-rw-r--r--pd/portaudio_v18/pa_common/pa_convert.c470
-rw-r--r--pd/portaudio_v18/pa_common/pa_host.h189
-rw-r--r--pd/portaudio_v18/pa_common/pa_lib.c806
-rw-r--r--pd/portaudio_v18/pa_common/pa_trace.c83
-rw-r--r--pd/portaudio_v18/pa_common/pa_trace.h67
-rw-r--r--pd/portaudio_v18/pa_common/portaudio.h463
-rw-r--r--pd/portaudio_v18/pa_mac_core/notes.txt34
-rw-r--r--pd/portaudio_v18/pa_mac_core/pa_mac_core.c2116
-rw-r--r--pd/portaudio_v18/pablio/README.txt39
-rw-r--r--pd/portaudio_v18/pablio/pablio.c327
-rw-r--r--pd/portaudio_v18/pablio/pablio.def35
-rw-r--r--pd/portaudio_v18/pablio/pablio.h109
-rw-r--r--pd/portaudio_v18/pablio/pablio_pd.c341
-rw-r--r--pd/portaudio_v18/pablio/pablio_pd.h110
-rw-r--r--pd/portaudio_v18/pablio/ringbuffer.c199
-rw-r--r--pd/portaudio_v18/pablio/ringbuffer.h102
-rw-r--r--pd/portaudio_v18/pablio/ringbuffer_pd.c214
-rw-r--r--pd/portaudio_v18/pablio/test_rw.c99
-rw-r--r--pd/portaudio_v18/pablio/test_rw_echo.c123
-rw-r--r--pd/portaudio_v18/pablio/test_w_saw.c108
-rw-r--r--pd/portaudio_v18/pablio/test_w_saw8.c106
-rw-r--r--pd/portaudio_v18/pablio/test_w_saw_pd.c108
-rw-r--r--pd/portmidi_osx/MSP-README.txt3
-rw-r--r--pd/portmidi_osx/Makefile24
-rw-r--r--pd/portmidi_osx/README12
-rw-r--r--pd/portmidi_osx/pmdarwin.c36
-rw-r--r--pd/portmidi_osx/pminternal.h100
-rw-r--r--pd/portmidi_osx/pmmacosx.c336
-rw-r--r--pd/portmidi_osx/pmmacosx.h4
-rw-r--r--pd/portmidi_osx/pmtestbin0 -> 24685 bytes
-rw-r--r--pd/portmidi_osx/pmtest.c136
-rw-r--r--pd/portmidi_osx/pmutil.c86
-rw-r--r--pd/portmidi_osx/pmutil.h44
-rw-r--r--pd/portmidi_osx/portmidi.c358
-rw-r--r--pd/portmidi_osx/portmidi.h338
-rw-r--r--pd/portmidi_osx/porttime.h30
-rw-r--r--pd/portmidi_osx/ptdarwin.c58
-rwxr-xr-xpd/src/configure6957
-rw-r--r--pd/src/configure.in94
-rw-r--r--pd/src/d_array.c18
-rw-r--r--pd/src/d_ctl.c411
-rw-r--r--pd/src/d_dac.c19
-rw-r--r--pd/src/d_delay.c4
-rw-r--r--pd/src/d_fftroutine.c2
-rw-r--r--pd/src/d_mayer_fft.c2
-rw-r--r--pd/src/d_osc.c4
-rw-r--r--pd/src/d_soundfile.c28
-rw-r--r--pd/src/d_ugen.c5
-rw-r--r--pd/src/g_all_guis.c14
-rw-r--r--pd/src/g_all_guis.h3
-rw-r--r--pd/src/g_array.c9
-rw-r--r--pd/src/g_bang.c4
-rw-r--r--pd/src/g_canvas.c45
-rw-r--r--pd/src/g_canvas.h59
-rw-r--r--pd/src/g_editor.c229
-rw-r--r--pd/src/g_graph.c22
-rw-r--r--pd/src/g_hdial.c13
-rw-r--r--pd/src/g_hslider.c4
-rw-r--r--pd/src/g_mycanvas.c4
-rw-r--r--pd/src/g_numbox.c4
-rw-r--r--pd/src/g_readwrite.c8
-rw-r--r--pd/src/g_rtext.c30
-rw-r--r--pd/src/g_scalar.c21
-rw-r--r--pd/src/g_template.c24
-rw-r--r--pd/src/g_text.c15
-rw-r--r--pd/src/g_toggle.c4
-rw-r--r--pd/src/g_vdial.c11
-rw-r--r--pd/src/g_vslider.c4
-rw-r--r--pd/src/g_vumeter.c4
-rw-r--r--pd/src/m_atom.c2
-rw-r--r--pd/src/m_binbuf.c64
-rw-r--r--pd/src/m_class.c25
-rw-r--r--pd/src/m_conf.c2
-rw-r--r--pd/src/m_glob.c43
-rw-r--r--pd/src/m_imp.h167
-rw-r--r--pd/src/m_memory.c1
-rw-r--r--pd/src/m_obj.c15
-rw-r--r--pd/src/m_pd.c1
-rw-r--r--pd/src/m_pd.h30
-rw-r--r--pd/src/m_sched.c29
-rw-r--r--pd/src/makefile.in33
-rw-r--r--pd/src/makefile.nt112
-rw-r--r--pd/src/notes.txt26
-rw-r--r--pd/src/s_audio.c410
-rw-r--r--pd/src/s_audio_alsa.c630
-rw-r--r--pd/src/s_audio_mmio.c758
-rw-r--r--pd/src/s_audio_oss.c772
-rw-r--r--pd/src/s_audio_pa.c186
-rw-r--r--pd/src/s_entry.c43
-rw-r--r--pd/src/s_file.c7
-rw-r--r--pd/src/s_inter.c136
-rw-r--r--pd/src/s_loader.c139
-rw-r--r--pd/src/s_main.c297
-rw-r--r--pd/src/s_midi.c405
-rw-r--r--pd/src/s_midi_oss.c269
-rw-r--r--pd/src/s_midi_pm.c166
-rw-r--r--pd/src/s_midi_sgi.c188
-rw-r--r--pd/src/s_path.c100
-rw-r--r--pd/src/s_stuff.h179
-rw-r--r--pd/src/t_tkcmd.c16
-rw-r--r--pd/src/u_main.tk424
-rw-r--r--pd/src/u_pdreceive.c10
-rw-r--r--pd/src/u_pdsend.c8
-rw-r--r--pd/src/x_arithmetic.c8
-rw-r--r--pd/src/x_midi.c4
-rw-r--r--pd/src/x_misc.c15
-rw-r--r--pd/src/x_net.c3
-rw-r--r--pd/src/x_qlist.c2
514 files changed, 82182 insertions, 7574 deletions
diff --git a/pd/README.txt b/pd/README.txt
index a348223e..d0075b76 100644
--- a/pd/README.txt
+++ b/pd/README.txt
@@ -35,10 +35,10 @@ For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "LICENSE.txt," included in the Pd distribution.
(Note that tcl/tk, expr, and some other files are copyrighted separately).
-ACKNOWLEDGEMENTS. Thanks to Harry Castle, Mark Danks, Christian Feldbauer,
-Guenter Geiger, Kerry Hagan, Trevor Johnson, Fernando Lopez-Lezcano, Karl
-MacMillan, Thomas Musil, Toshinori Ohkouchi, Winfried Ritsch, Vibeke Sorensen,
-Rand Steiger, Shahrokh Yadegari, David Zicarelli, Iohannes Zmoelnig, and
-probably many others for contributions of code, documentation, ideas, and
-expertise. This work has received generous support from the Intel Research
-Council.
+ACKNOWLEDGEMENTS. Thanks to Harry Castle, Krzysztof Czaja, Mark Danks,
+Christian Feldbauer, Guenter Geiger, Kerry Hagan, Trevor Johnson, Fernando
+Lopez-Lezcano, Adam Lindsay, Karl MacMillan, Thomas Musil, Toshinori Ohkouchi,
+Winfried Ritsch, Vibeke Sorensen, Rand Steiger, Shahrokh Yadegari, David
+Zicarelli, Iohannes Zmoelnig, and probably many others for contributions of
+code, documentation, ideas, and expertise. This work has received generous
+support from the Intel Research Council.
diff --git a/pd/doc/1.manual/x3.htm b/pd/doc/1.manual/x3.htm
index 18d220a6..d34f70e8 100644
--- a/pd/doc/1.manual/x3.htm
+++ b/pd/doc/1.manual/x3.htm
@@ -13,7 +13,7 @@ Pd Documentation chapter 3: Getting Pd to run
<A href=index.htm#s3> back to table of contents </A>
<BR><BR>
-Pd runs under Irix, Windows, and Linux.
+Pd runs under Irix, Microsoft Windows, Linux, and Mac OS 10.2 (Jaguar).
How to get Pd up and running depends on your operating system,
but the overall strategy is the same.
You must first get and install it, and
@@ -61,6 +61,11 @@ operating systems it runs on: IRIX, MS Windows, Linux, and Max OSX.
<H4> <A name=s1.1> 3.1. IRIX (SGI machines) </A> </H4>
+<P> (NOTE: as of release 0.35 I haven't had an IRIX machine to compile
+Pd on. Soeren Bovbjerg has kindly compiled 0.35 and 0.36 for IRIX;
+you can find these at
+<A href=http://www.cvmt.dk/~sb/> http://www.cvmt.dk/~sb/. </A>)
+
<P> Download Pd, which will be a "tar.Z" file. You can unpack this by
typing "zcat [name].tar.Z | tar xf -" to a shell. This creates a directory
named "pd".
@@ -251,8 +256,9 @@ output in W95; see the command line arguments below.
<P> What to do depends on which flavor of Linux you are running (e.g., Debian
or Red Hat). The instructions here should work for Pd 0.33 and up regardless of
-your situation, but if you have any trouble just mail msp@ucsd.edu and I'll try
-to figure out what's wrong and update the instructions accordingly.
+your situation. (If not, you can read the Pd mailing list archives for
+recent problems; if you have found a new problem you're welcome to post it
+to the list.)
<P> Before you start, you might want to check that you have the resources Pd
needs. The main things you need are the C compiler, X windows (including
@@ -316,21 +322,6 @@ to "pd/src" and type
<P> Alternatively, as superuser, you can run "make install" after "make depend"
and then anyone on your system can just type "pd" to run it.
-<H5> TK support trouble </H5>
-
-Some people have reported a problem with Pd findind the shared libraries,
-"libtcl.so" and "libtk.so". I don't know what causes this, but apparently you
-can fix it, as root, by linking /usr/lib/libtcl8.3.so to /usr/lib/libtcl.so and
-similarly for tk:
-
-<PRE>
-
-# cd /usr/lib
-# ln -s libtk8.3.so libtk.so
-# ln -s libtcl8.3.so libtcl.so
-
-</PRE>
-
<H5> Testing audio and MIDI. </H5>
<P>
@@ -366,12 +357,7 @@ audio latency your audio system can handle.
<P>
Be forewarned: installing and testing audio and MIDI drivers in Linux can take
days or weeks. There apears to be no single place where you can get detailed
-information on Linux audio. In addition to the information here, you should
-see what's posted on Guenter's page,
-
- <a href="http://gige.epy.co.at/">
- http://gige.epy.co.at/</A> .
-
+information on Linux audio.
<P>
Depending on your hardware and software, you might or might not be able to
@@ -473,10 +459,8 @@ Alsa comes in a "finished" version (0.5.x) and a
different, redesigned, "beta" version, 0.9. Installing ALSA can be tricky
and/or confusing.
-<P> As of version 0.33 Pd works with either 0.5.x or 0.9.x versions.
-The RPM version of Pd is compiled for 0.9.x. If you're starting from the
-".tar.gz" version, you have to "./configure --enable-alsa" to get it; see
-the "INSTALL.txt" file in the installation.
+<P> As of version 0.37 Pd works only with 0.9.x versions.
+The RPM version of Pd is compiled for 0.9.x.
<P> By default, Pd uses OSS. If you are running ALSA, Pd will use ALSA's OSS
emulation. To make Pd use ALSA "natively", i.e., the way ALSA is designed
@@ -492,47 +476,6 @@ one. You can also specify it the ALSA way: "-alsadev hw:3,0".
Here's a rundown on my experiences with sound cards so far. See
also the Pd mailing list archives.
-<H6> opl3sa </H6>
-
-This is the old ISA "Yamaha" audio system. It comes on many Dell machines and
-seems to offer reasonable consumer quality audio, at least under NT. I
-believe the current version of OSS can get full duplex operation out of an
-OPL3sa audio system.
-This is an ISA ("plug and play" device and you have to deal with I/O
-addresses and all that.
-
-<H6> cs4232 </H6>
-
-The 1999 vintage dual-processor Dell machines have "cs4232" audio, which I
-couldn't get working.
-
-<H6> es1370 (old Creative PCI128s; Ensoniq AudioPCI) </H6>
-
-<P>
-The audio inputs and outputs on my PCI128 aren't clearly labelled and various
-documents give them inconsistent names. On my card there are 4 stereo
-mini jacks and a joystick port, in this order:
-
-<PRE>
-joystick black green red blue
- bidirectional line-out mic-in line-in
-</PRE>
-
-<P> It used to be possilbe to get quadraphonic audio in and out
-of this card, but I haven't tried this in years.
-
-<H6> Creative SBLive </H6>
-
-This seems to work fine either with ALSA or OSS as of Pd version 0.35; earlier
-versions of Pd didn't see MIDI input under OSS (the driver's fault, not Pd's,
-but I figured out a workaround.)
-
-<H6> Sonorus Stud I/O </H6>
-
-This $1000 card is supposed to do multichannel digital I/O
-in Linux, via a beta version of a commercial OSS driver ($40).
-I don't know if anyone has used it with Pd.
-
<H6> RME 9652 (Hammerfall) </H6>
<P> This is the best sound card out there; it costs around $500 and has 3 ADAT
@@ -549,10 +492,6 @@ RedHat 7.1 and up). You have to download and compile it:
<P> You must then run Pd using the "-32bit' flag, because this uses a
non-standard extension of OSS to 32 bit samples.
-<P> There's an older driver by Winfried Ritsch, invoked using the "-rme"
-flag to Pd. This only works on 2.2 kernels, and you probably shouldn't
-try it. It will probably be discontinued after Pd version 0.35.
-
<P> Hammerfalls now have an ALSA driver; from what I hear
it won't work yet with Pd. I was unable to install the ALSA driver on the
two machines I tried ("no such device").
@@ -574,50 +513,60 @@ In RedHat 7.0, motherboards with native i810 audio systems don't work in
full duplex (they crash linux). Either run Pd -noadc or else (better) install
ALSA.
-<H6> Yamaha YMF724 </H6>
-
-The OSS driver for this card appears not to support MIDI. I haven't
-tried with ALSA.
-
-<H6> ES1371 </H6>
+<H4> <A name=s1.4> 3.4. Macintosh OSX </A> </H4>
-In OSS, audio and MIDI seem both to work fine with this chipset.
+Pd version 0.35 and up support Macintosh OSX, although there are still some
+problems. You can always just download
+the sources and compile it yourself, or (easier)
+find a MacOSX-style "package". The first package was put together by Adam
+Lindsay and can be found on
+<A href=http://homepage.mac.com/atl/sw>
+http://homepage.mac.com/atl/sw</A>. The package simply installs itself
+and you needn't follow the directions below.
-<H4> <A name=s1.4> 3.4. Macintosh OSX </A> </H4>
+<H5> To install on OSX from source: </H5>
-Pd version 0.35 supports Macintosh OSX, although there are still various
-problems. You can either download Pd with Mac OSX binaries, or just download
-the sources and compile it yourself.
-<H5> To install the binary OSX release: </H5>
+Whether you've downloaded the source or the "package" you can
+always compile Pd for yourself, whether to make your own improvements, or
+possibly so that you can get the newest version before it shows up compiled for
+Mac OS X.
+<P> To be able to compile Pd, you must have installed Tcl/Tk
+specifically in
+/Applications/Wish Shell.app
+and /Library/Frameworks/Tk.framework and /Library/Frameworks/Tcl.framework.
<P> First download and install TK for OSX
(http://sourceforge.net/projects/tcl/). Get a recent one compiled for
-OSX, by chasing through "Mac OS X Tk Snapshots." I got
-version 8.4a4-2, in a file named "MacOSXTk8.4a4-2.tar.gz ". Unpacking this
-yields three directories: ./Applications/Wish Shell.app,
-./Library/Frameworks/Tcl.framework,
-and ./Library/Frameworks/Tk.framework. These must be moved, either to:
+OSX, by chasing through "latest file releases", and finding a "download"
+link for TCL. Then download "TclTkAqua-8.4.1-Jaguar.dmg" (the version
+number may change). Click on this file and a "folder" will open. Click
+on the "package" icon in that folder and an auto-installer will put Tcl/Tk
+on your system.
+
+<P> For old versions of Tcl/Tk you also had to get the "h" files from XFree86
+and put them in
+/usr/X11R6/include. You can download just the H files from:
<pre>
- ~/Applications/Wish Shell.app
- ~/Library/Frameworks/Tcl.framework
- ~/Library/Frameworks/Tk.framework
+ http://www.crca.ucsd.edu/~msp/x.tgz
</pre>
-or, if you wish to make them available to other users (or make it possible to
-recompile Pd), in /Applications and /Library instead.
+(the individual files seem to have adequate copyright notices so that
+I can just redistribute them.) ((I hope this is no longer necessary but I
+notice people keep downloading these files anyway, so I'll leave them there
+a while longer until I'm sure they're not needed.))
+
+<P> Then, just as for linux, just unload pd-whatever.tar.gz into a directory
+such as ~/pd-0.35-test17 , cd to pd-0.36-0/src, type "./configure"
+and "make". Then type ~/pd-0.36-0/bin/pd to a shell and enjoy!
-<P> Then download and unpack the Pd binary distribution for OS X. This will
-create a directory with a name like ~/Desktop/pd-0.35-test22. You can move
-this elsewhere if you wish (to ~/pd, for example). To a shell window, type
-either "~/Desktop/pd-0.35-test22/bin/pd" or, if you moved it as suggested,
-"~/pd/bin/pd" . If you wish you can put the line,
+<P> If you wish you can put the line,
<pre>
alias pd ~/pd/bin/pd
</pre>
in the file, ~/.tcshrc, so that you can later just type "pd" to a shell. (The
-shell only reads the ~/.tcshrc file onstartup, so this won't take effect in
+shell only reads the ~/.tcshrc file on startup, so this won't take effect in
any existing shells unless you specially type
<pre>
source ~/.tcshrc
@@ -638,47 +587,7 @@ I think you just download the OSX driver and follow directions.
pd -midiindev 1 -midioutdev 2
</pre>
-to get MIDI working. At the moment, using a midiman Midisport 2x2, I'm getting
-several lines of debugging printout for each incoming MIDI message; it seems to
-be the driver printing it out. I don't know how to turn this off.
-
-<P> To get Pd running at high priority, so that you'll get fewer skips in the
-audio input and output, you must "renice" it. The easiest way to do this is
-to make it SETUID and use the "-rt" flag. To do this, become root (you might
-have to add a root account to do this) and type:
-
-<pre>
- chown root ~ferguson/pd/bin/pd
- chmod 4755 ~ferguson/pd/bin/pd
-</pre>
-(assuming your username is "ferguson").
-
-<H5> To compile your own Pd in OSX: </H5>
-
-Whether you've downloaded the source or the OSX binary distribution you can
-always Pd for yourself, whether to make your own improvements, or possibly
-so that you can get the newest version before it shows up compiled
-for Mac OS X.
-
-<P> To be able to compile Pd, you must have installed Tcl/Tk
- specifically in
-/Applications/Wish Shell.app
-and /Library/Frameworks/Tk.framework and /Library/Frameworks/Tcl.framework.
-
-You must also get the "h" files from XFree86 and put them in
-/usr/X11R6/include. You can download just the H files from:
-<pre>
- http://www.crca.ucsd.edu/~msp/x.tgz
-</pre>
-(the individual files seem to have adequate copyright notices so that
-I can just redistribute them.)
-
-Then, just as for linux, just unload pd-whatever.tar.gz into a directory
-such as ~/pd-0.35-test17 , cd to pd-0.35-test17/src, type "./configure"
-and "make".
-
-then type ~/pd-0.35-test17/bin/pd to a shell and enjoy!
-
+to get MIDI working.
<H4> <A name=s3> 3.5. graphics rendering using GEM </A> </H4>
diff --git a/pd/doc/1.manual/x5.htm b/pd/doc/1.manual/x5.htm
index 767ffc3e..0b18cf1a 100644
--- a/pd/doc/1.manual/x5.htm
+++ b/pd/doc/1.manual/x5.htm
@@ -16,6 +16,55 @@ This section tracks changes in Pd's current implementation.
<H4> <A name=s2> 5.1. release notes </A> </H4>
+<P> ------------------ 0.37-test 1 --------------------------
+
+<P> The MacOSX version now prioritizes itself effectively (thanks to
+gert@test.at (v93r)) via Adam Lindsay). Adam has made a proper MacOSX
+"package" for Pd; see <A href=http://homepage.mac.com/atl/sw>
+http://homepage.mac.com/atl/sw</A>.
+
+<P> A bug was fixed in readsf~/writesf~ (things were coming out in the wrong
+number of channels.)
+
+<P> A problem compiling Pd with TK8.4 (the latest version) was fixed.
+
+<P> Large numbers of GUI improvements by Adam Lindsay, especially relevant
+to Mac OSX.
+
+<P> For externs, the binary may now be included in a subdirectory of the
+same name (e.g., "choice/choice.pd_linux" and "choice\choice.dll"). So
+now you can pack multiple binaries for the same extern, along with the
+source, in one convenient place. (Note that
+"expr~" is an exception, since it goes by three different names, so this
+trick fails for that example.)
+
+<P> "Help" files renamed "help-xxx.pd", so that help files are now possible
+for abstractions. The "help path" feature from CVS (I forgot who contributed
+that) is also included but should now not be needed: Pd remembers where it got
+externs and abstractions and looks back in the same directory for a help file.
+See the way "extras" is organized.
+
+<P> Pd refuses to connect signal outlets to non-signal inlets.
+
+<P> When you save any patch, Pd looks for all invocations of that patch
+as an abstraction and reloads them. This unfortunately has the side effect of
+making all the containing windows visible, but it's better than nothing.
+
+
+
+<P> ------------------ 0.36-1 -------------------------------
+
+<P> "print" now queries you for a file to save the postscript to.
+
+<P> "expr" brought up to date (0.4) -- a bug was fixed involving expresions
+like "max($f1, 100)" which had erroneously output an integer.
+
+<P> a bug fix in the 4-point interpolation formula, which affects tabosc4~,
+tabread4~, tabread4, and vd~. These should have significantly lower
+distortion than before.
+
+<P> bug fix: vradio, hradio "send symbol" feature didn't work
+
<P> ------------------ 0.36 -------------------------------
<P> There's now an "undo" for most editing operations. Undoing is only
diff --git a/pd/doc/3.audio.examples/00.INTRO.txt b/pd/doc/3.audio.examples/00.INTRO.txt
index af9e3c96..8792dc1e 100644
--- a/pd/doc/3.audio.examples/00.INTRO.txt
+++ b/pd/doc/3.audio.examples/00.INTRO.txt
@@ -10,14 +10,14 @@ Here is an approximate table of contents...
frequency and pitch
FM
-2. wavetable synthesis
+2. wavetable synthesis and sampling
3. synthetic waveforms, classic and modern
pulses
rectangles and sawtooth waves
additive synthesis
-4. sampling
+4. more sampling
5. envelopes
two flavors of ADSR envelope
diff --git a/pd/doc/3.audio.examples/A01.sinewave.pd b/pd/doc/3.audio.examples/A01.sinewave.pd
new file mode 100644
index 00000000..42b8aed0
--- /dev/null
+++ b/pd/doc/3.audio.examples/A01.sinewave.pd
@@ -0,0 +1,32 @@
+#N canvas 6 2 588 513 12;
+#X obj 108 109 osc~ 440;
+#X obj 108 168 dac~;
+#X text 187 111 <-- 440 Hz. sine wave at full blast;
+#X obj 108 138 *~ 0.05;
+#X text 202 3 MAKING A SINE WAVE;
+#X text 32 195 Audio computation can be turned on and off by sending
+messages to the global "pd" object as follows:;
+#X msg 98 239 \; pd dsp 1;
+#X msg 202 239 \; pd dsp 0;
+#X text 113 276 ON;
+#X text 222 276 OFF;
+#X text 29 297 You should see the Pd window change to reflect whether
+audio is on or off. You can also turn audio on and off using the "audio"
+menu \, but the buttons are provided as a shortcut.;
+#X text 30 368 When DSP is on \, you should hear a tone whose pitch
+is A 440 and whose amplitude is 0.05. If instead you are greeted with
+silence \, you might want to read the HTML documentation on setting
+up audio.;
+#X text 28 434 In general when you start a work session with Pd \,
+you will want to choose "test audio and MIDI" from the help window
+\, which opens a more comprehensive test patch than this one.;
+#X text 296 247 <-- click these;
+#X text 187 139 <-- reduce amplitude to 0.05;
+#X text 160 168 <----- send to the audio output device;
+#X text 32 23 Audio computation in Pd is done using "tilde objects"
+such as the three below. They use continuous audio streams to intercommunicate
+\, as well as communicating with other ("control") Pd objects using
+messages.;
+#X text 342 490 updated for Pd version 0.36;
+#X connect 0 0 3 0;
+#X connect 3 0 1 0;
diff --git a/pd/doc/3.audio.examples/A02.amplitude.pd b/pd/doc/3.audio.examples/A02.amplitude.pd
new file mode 100644
index 00000000..d24be18d
--- /dev/null
+++ b/pd/doc/3.audio.examples/A02.amplitude.pd
@@ -0,0 +1,37 @@
+#N canvas 73 190 702 512 12;
+#X obj 64 65 osc~ 440;
+#X obj 64 283 dac~;
+#X text 145 66 <-- 440 Hz. sine wave at full blast;
+#X msg 431 7 \; pd dsp 1;
+#X msg 514 7 \; pd dsp 0;
+#X text 456 45 ON;
+#X text 534 43 OFF;
+#X text 164 18 CONTROLLING AMPLITUDE;
+#X text 35 327 Amplitudes of audio signals can have any reasonable
+range \, but when you output a signal via the dac~ object \, the samples
+should range between -1 and +1. Values out of that range will be "clipped."
+;
+#X obj 64 202 *~ 0;
+#X floatatom 107 165 0 0 0 0 - - -;
+#X obj 95 132 dbtorms;
+#X floatatom 95 100 0 0 80 0 - - -;
+#X text 141 100 <-- set amplitude here in dB;
+#X text 211 133 <-- this converts dB to linear units;
+#X text 210 164 <-- this shows the linear gain;
+#X text 116 204 <-- multiply the sine wave by the gain \, reducing
+its amplitude. You can also use the "*~" object to multiply two signals.
+The "0" argument here instructs it that we'll just send it messages
+to set the multiplier.;
+#X text 35 396 Here we calculate a gain for the multiplier (*~) using
+a "dbtorms" object (acronym for "dB to RMS"). 100 dB is normalized
+to one \, and zero dB artificially outputs a true 0;
+#X text 34 452 Pd assumes you have a two channel audio system unless
+you tell it otherwise.;
+#X text 440 486 updated for Pd version 0.33;
+#X text 114 282 <-- and out. We're sending to both channels now.;
+#X connect 0 0 9 0;
+#X connect 9 0 1 0;
+#X connect 9 0 1 1;
+#X connect 11 0 9 1;
+#X connect 11 0 10 0;
+#X connect 12 0 11 0;
diff --git a/pd/doc/3.audio.examples/A03.line.pd b/pd/doc/3.audio.examples/A03.line.pd
new file mode 100644
index 00000000..392df533
--- /dev/null
+++ b/pd/doc/3.audio.examples/A03.line.pd
@@ -0,0 +1,55 @@
+#N canvas 369 106 647 598 12;
+#X obj 56 79 osc~ 440;
+#X obj 56 309 dac~;
+#X msg 446 79 \; pd dsp 1;
+#X msg 538 79 \; pd dsp 0;
+#X text 467 112 ON;
+#X text 555 112 OFF;
+#X obj 56 269 *~;
+#X obj 72 243 line~;
+#X text 129 243 <--- ramp generator;
+#X text 132 78 <-- sine wave;
+#X msg 72 103 0.1 2000;
+#X msg 72 177 0 2000;
+#X msg 72 125 0.1 50;
+#X msg 72 199 0 50;
+#X msg 72 147 0.1;
+#X msg 72 221 0;
+#X text 274 124 ON;
+#X text 154 105 <-- slow;
+#X text 144 126 <-- fast;
+#X text 111 146 <-- instantly;
+#X text 271 197 OFF;
+#X text 136 178 <-- slow;
+#X text 129 199 <-- fast;
+#X text 109 219 <-- instantly;
+#X text 112 161 ----------------------;
+#X text 97 308 <-- out;
+#X text 103 7 CONTROLLING AMPLITUDE USING LINE~;
+#X text 38 342 Line~'s left inlet is a target value \; it reaches that
+target in the time specified (in milliseconds) to its right inlet.
+;
+#X text 34 495 The line~ object (and its control brother \, line) treat
+their right inlet specially. The inlets don't retain values the way
+other inlets do but revert to zero whenever a target is received.;
+#X text 14 27 In this patch \, the multiplier is configured to multiply
+two signals. The amplitude is now a signal computed by the line~ object.
+;
+#X text 37 395 (In this example \, message boxes with two numbers each
+are connected to line~'s left inlet. Except in some special cases \,
+Pd objects with more than one inlet will automatically distribute lists
+of numbers across their inlets. In this case \, "0 50" becomes \, "50
+at right and 0 at left.");
+#X text 386 557 updated for Pd version 0.36;
+#X text 93 268 <-- multiply the sine wave by the ramp. There's no longer
+a "0" argument-- this tells Pd to expect a signal here.;
+#X connect 0 0 6 0;
+#X connect 6 0 1 0;
+#X connect 6 0 1 1;
+#X connect 7 0 6 1;
+#X connect 10 0 7 0;
+#X connect 11 0 7 0;
+#X connect 12 0 7 0;
+#X connect 13 0 7 0;
+#X connect 14 0 7 0;
+#X connect 15 0 7 0;
diff --git a/pd/doc/3.audio.examples/A04.line2.pd b/pd/doc/3.audio.examples/A04.line2.pd
new file mode 100644
index 00000000..c6dd1679
--- /dev/null
+++ b/pd/doc/3.audio.examples/A04.line2.pd
@@ -0,0 +1,59 @@
+#N canvas 30 68 949 754 12;
+#X obj 67 77 osc~ 440;
+#X obj 67 329 dac~;
+#X obj 67 242 *~;
+#X obj 86 180 line~;
+#X text 116 330 <-- out;
+#X text 124 9 LINES GRAPHED;
+#X text 24 33 Here again is a line~ controlling the amplitude of an
+osc~ \, but with the outputs graphed:;
+#X obj 149 89 r graphit;
+#X obj 151 179 r graphit;
+#X obj 151 246 r graphit;
+#X obj 86 149 r to-line;
+#X graph graph1 0 -1.02 44100 1.02 631 480 831 350;
+#X array product 44100 float 0;
+#X pop;
+#X graph graph1 0 -1.02 44100 1.02 631 150 831 20;
+#X array osc-output 44100 float 0;
+#X pop;
+#X graph graph1 0 -1.02 44100 1.02 631 315 831 185;
+#X array line-output 44100 float 0;
+#X pop;
+#X obj 149 119 tabwrite~ osc-output;
+#X obj 67 299 *~ 0.1;
+#X msg 38 401 \; pd dsp 1 \; to-line 0 \, 1 500 \; graphit bang;
+#X msg 210 401 \; pd dsp 1 \; to-line 1 \, 0 500 \; graphit bang;
+#X obj 151 209 tabwrite~ line-output;
+#X obj 151 276 tabwrite~ product;
+#X text 70 379 ramp up;
+#X text 235 378 ramp down;
+#X text 406 376 to 1/2;
+#X msg 375 400 \; pd dsp 1 \; to-line 0.5 1000 \; graphit bang;
+#X text 634 491 ------ 1 second ------;
+#X text 38 485 Click the message boxes above to try it. Note that in
+the first two boxes \, the line~ objects get two messages. The first
+one \, with no time value \, causes the line~ to jump immediately to
+the value. The third box takes line~'s previous value as a point of
+departure. What you see will depend on which box you last clicked and
+how long you waited between the two.;
+#X text 662 727 updated for Pd version 0.33;
+#X text 41 600 On most machines \, you will hear an interruption in
+the sound one second after you click on the first or third box. This
+is because the graphical updates are likely to eat more CPU time than
+your audio buffer has pre-buffered for. You can avoid this if you keep
+your graphs in sub-windows and open them only when you need them. In
+some future version of Pd this behavior will be improved. Until then
+\, you'll have to avoid having arrays getting re-drawn during music
+performances.;
+#X connect 0 0 2 0;
+#X connect 0 0 14 0;
+#X connect 2 0 15 0;
+#X connect 2 0 19 0;
+#X connect 3 0 2 1;
+#X connect 3 0 18 0;
+#X connect 7 0 14 0;
+#X connect 8 0 18 0;
+#X connect 9 0 19 0;
+#X connect 10 0 3 0;
+#X connect 15 0 1 0;
diff --git a/pd/doc/3.audio.examples/A05.output.subpatch.pd b/pd/doc/3.audio.examples/A05.output.subpatch.pd
new file mode 100644
index 00000000..d24fdba2
--- /dev/null
+++ b/pd/doc/3.audio.examples/A05.output.subpatch.pd
@@ -0,0 +1,30 @@
+#N canvas 300 159 635 486 12;
+#X text 261 20 CONTROLLING OUTPUT AMPLITUDE;
+#X obj 32 27 osc~ 440;
+#X obj 54 55 osc~ 550;
+#X obj 54 116 osc~ 660;
+#X obj 32 88 +~;
+#X obj 32 142 +~;
+#X text 108 177 <-- this is a subwindow--right click on it;
+#X text 149 197 and select "open" to see inside.;
+#X text 30 401 The output control automatically starts DSP whenever
+you touch the level control. Hitting "mute" toggles between the current
+level and zero.;
+#X obj 32 173 output~;
+#X text 383 463 updated for Pd version 0.36;
+#X text 143 115 <-- Here we make an A major triad as a test signal.
+;
+#X text 31 250 In this and subsequent patches \, we'll use a subwindow
+\, "output" \, to control overall amplitude. The amplitudes are in
+decibels \, with 100 being full blast. In this example \, you can't
+actually push the output amplitude past 90 or so without clipping.
+You'll know you're clipping if \, instead of an A major chord \, you
+hear a single \, distorted tone two octaves down. The clipping happens
+at Pd's last stage of audio output. Audio signals internal to Pd have
+essentially no level limit.;
+#X connect 1 0 4 0;
+#X connect 2 0 4 1;
+#X connect 3 0 5 1;
+#X connect 4 0 5 0;
+#X connect 5 0 9 0;
+#X connect 5 0 9 1;
diff --git a/pd/doc/3.audio.examples/A06.frequency.pd b/pd/doc/3.audio.examples/A06.frequency.pd
new file mode 100644
index 00000000..50cff7c0
--- /dev/null
+++ b/pd/doc/3.audio.examples/A06.frequency.pd
@@ -0,0 +1,60 @@
+#N canvas 8 17 693 642 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array osc-output 4410 float 0;
+#X coords 0 1.02 4410 -1.02 200 130 1;
+#X restore 473 167 graph;
+#X obj 98 261 tabwrite~ osc-output;
+#X msg 98 232 bang;
+#X floatatom 280 66 0 0 0 0 - - -;
+#X text 147 231 <-- click to graph;
+#X obj 15 206 r frequency;
+#X msg 280 37 set \$1;
+#X floatatom 6 66 0 0 0 0 - - -;
+#X obj 6 8 r frequency;
+#X msg 6 37 set \$1;
+#X obj 19 90 s frequency;
+#X obj 280 8 r pitch;
+#X obj 289 90 s pitch;
+#X obj 280 116 mtof;
+#X obj 280 145 s frequency;
+#X obj 6 145 s pitch;
+#X obj 6 116 ftom;
+#X text 105 66 <-- set frequency;
+#X text 372 65 <-- set MIDI pitch;
+#X text 15 429 Frequency and pitch are converted using the "ftom" and
+"mtof" objects. Frequency refers to the number of cycles per second.
+Pitch is "60" for Middle C \, 61 for C sharp \, 72 for the next C up
+\, and so on.;
+#X text 476 308 ---- 0.1 seconds ----;
+#X text 447 6 FREQUENCY AND PITCH;
+#X text 16 363 The osc~ object \, if you give it an argument \, expects
+floating-point messages to set its frequency. Without arguments \,
+its frequency is controlled by connecting an audio signal to its input.
+;
+#X text 14 496 Mtof and ftom work fine for microtones (non-integral
+"MIDI pitch" ) and don't have MIDI's range restriction-- for example
+\, MIDI -36 is about 1 Hz.;
+#X text 15 553 Note also the "set" messages going to the number boxes
+so that they can each update the other without bringing on an infinite
+loop. (get help on number boxes for details.);
+#X text 87 291 <-- output level;
+#X text 51 116 <-- convert frequency;
+#X text 106 134 to "MIDI" pitch;
+#X text 327 117 <-- convert "MIDI" pitch to frequency;
+#X obj 15 273 output~;
+#X text 437 619 updated for Pd version 0.36;
+#X obj 15 232 osc~;
+#X connect 2 0 1 0;
+#X connect 3 0 12 0;
+#X connect 3 0 13 0;
+#X connect 5 0 31 0;
+#X connect 6 0 3 0;
+#X connect 7 0 10 0;
+#X connect 7 0 16 0;
+#X connect 8 0 9 0;
+#X connect 9 0 7 0;
+#X connect 11 0 6 0;
+#X connect 13 0 14 0;
+#X connect 16 0 15 0;
+#X connect 31 0 1 0;
+#X connect 31 0 29 0;
diff --git a/pd/doc/3.audio.examples/A07.frequency.mod.pd b/pd/doc/3.audio.examples/A07.frequency.mod.pd
new file mode 100644
index 00000000..a7bab032
--- /dev/null
+++ b/pd/doc/3.audio.examples/A07.frequency.mod.pd
@@ -0,0 +1,105 @@
+#N canvas 52 144 760 640 12;
+#X obj 256 180 *~;
+#X floatatom 256 95 0 0 0;
+#X floatatom 166 130 0 0 0;
+#X obj 166 200 +~;
+#X graph graph1 0 -1.02 440 1.02 527 170 727 40;
+#X array fm-output 441 float 0;
+#X pop;
+#X floatatom 204 300 0 0 100;
+#N canvas 159 26 516 274 output 1;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 396 182 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 391 110 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 391 85 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 20 182 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 104 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 90 outlet;
+#X msg 214 65 \; pd dsp 1;
+#X obj 83 198 line~;
+#X obj 20 207 *~;
+#X obj 20 232 dac~;
+#X obj 83 173 pack 0 50;
+#X text 20 159 audio;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 21 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X restore 166 328 pd output;
+#X msg 242 301 MUTE;
+#X text 283 301 <-- output amplitude;
+#X msg 242 248 bang;
+#X text 284 248 <-- click to graph;
+#X obj 242 272 tabwrite~ fm-output;
+#X floatatom 278 150 0 0 0;
+#X text 163 87 carrier;
+#X text 162 105 frequency;
+#X text 241 71 frequency;
+#X text 242 54 modulation;
+#X text 33 8 FREQUENCY MODULATION ("FM") USING TWO OSCILLATORS;
+#X obj 166 252 osc~;
+#X text 50 234 "carrier";
+#X text 32 252 oscillator -->;
+#X text 40 161 add modulator;
+#X text 39 179 to carrier;
+#X text 37 198 frequency -->;
+#X text 317 162 index;
+#X text 319 143 modulation;
+#X text 477 601 updated for Pd version 0.34;
+#X obj 256 120 osc~;
+#X text 52 363 This shows the classical FM synthesis technique developed
+by John Chowning. It's nothing but an oscillator with vibrato controlled
+by another "modulation" oscillator. First \, to understand the patch
+\, set carrier frequency to 400 or so \, modulation frequency between
+5 and 10 \, and try modulation index values between 0 and 400 \, say.
+You'll hear a sine wave with vibrato.;
+#X text 531 172 --- 0.01 seconds ----;
+#X text 51 478 To get the FM sound \, set all three of carrier frequency
+\, modulation frequency \, and modulation index in the hundreds. Note
+that you get a timbral change as you sweep modulation index \, because
+this changes the amplitudes of the components of the output sound but
+not their frequencies.;
+#X text 48 564 The component frequencies are equal to the carrier frequency
+\, plus or minus multiples of the modulator frequency.;
+#X connect 0 0 3 1;
+#X connect 1 0 27 0;
+#X connect 2 0 3 0;
+#X connect 3 0 18 0;
+#X connect 5 0 6 1;
+#X connect 6 0 5 0;
+#X connect 7 0 6 2;
+#X connect 9 0 11 0;
+#X connect 12 0 0 1;
+#X connect 18 0 11 0;
+#X connect 18 0 6 0;
+#X connect 27 0 0 0;
diff --git a/pd/doc/3.audio.examples/A08.phase.mod.pd b/pd/doc/3.audio.examples/A08.phase.mod.pd
new file mode 100644
index 00000000..716ba6ab
--- /dev/null
+++ b/pd/doc/3.audio.examples/A08.phase.mod.pd
@@ -0,0 +1,246 @@
+#N canvas 36 68 722 738 12;
+#X obj 216 145 *~;
+#X floatatom 216 88 0 0 0;
+#X obj 297 125 line~;
+#X floatatom 128 108 0 0 0;
+#X obj 128 222 cos~;
+#X obj 128 178 +~;
+#X floatatom 166 299 0 0 100;
+#N canvas 159 26 495 270 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 182 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 159 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 128 326 pd output;
+#X msg 204 299 MUTE;
+#X obj 216 113 osc~ 0;
+#X obj 297 99 pack 0 50;
+#X floatatom 297 46 0 0 0;
+#X obj 297 73 / 100;
+#X text 271 8 modulation index;
+#X text 271 23 in hundredths;
+#X text 125 65 carrier;
+#X text 124 83 frequency;
+#X text 201 64 frequency;
+#X text 202 47 modulation;
+#X text 33 119 carrier;
+#X text 33 134 phase -->;
+#X text 6 162 phase;
+#X text 5 177 modulation-->;
+#X text 12 204 output;
+#X text 11 221 waveform -->;
+#X text 527 6 PHASE MODULATION;
+#X text 417 703 updated for Pd version 0.34;
+#X text 13 377 Most implementations of "FM" actually use phase \, not
+frequency \, modulation \, because it extends in a more natural way
+to "multi-operator FM" with three or more oscillators.;
+#X text 15 437 To do phase modulation \, we split the "carrier oscillator"
+into its phase calculation (phasor~) and its waveform lookup (cos~).
+These together would be equivalent to an osc~ object \, but the "+~"
+between them adds the modulating oscillator's output to the phase.
+;
+#X text 18 587 The units of the "modulation" index change--it is now
+dimensionless and relative to the modulation frequency \, and "good"
+values tend to be between 0 and 1 In this patch it's in hundredths.
+;
+#X text 19 658 We also have to use a line~ to smooth changes in the
+modulation index \, which wasn't necessary in the previous patch.;
+#X obj 128 135 phasor~;
+#X obj 117 557 cos~;
+#X obj 117 529 phasor~;
+#X text 60 539 this:;
+#X text 219 532 is the same;
+#X text 220 551 as this:;
+#X obj 335 544 osc~;
+#X graph graph2 0 -1 440 1 509 330 709 190;
+#X array phase-out 441 float 1;
+#A 0 0.43245 0.433463 0.434452 0.435418 0.43636 0.43728 0.438178 0.439056
+0.439912 0.440749 0.441567 0.442366 0.443148 0.443912 0.444659 0.445391
+0.446107 0.446809 0.447497 0.448172 0.448834 0.449484 0.450122 0.450751
+0.451369 0.451978 0.452579 0.453172 0.453758 0.454338 0.454911 0.45548
+0.456045 0.456606 0.457164 0.457719 0.458274 0.458827 0.45938 0.459934
+0.460489 0.461046 0.461605 0.462168 0.462735 0.463306 0.463883 0.464466
+0.465056 0.465654 0.466259 0.466873 0.467497 0.468131 0.468776 0.469433
+0.470102 0.470783 0.471479 0.472188 0.472913 0.473653 0.474409 0.475182
+0.475973 0.476782 0.477611 0.478459 0.479327 0.480216 0.481127 0.48206
+0.483015 0.483994 0.484997 0.486024 0.487077 0.488156 0.48926 0.490392
+0.491552 0.49274 0.493957 0.495203 0.496479 0.497785 0.499123 0.500493
+0.501896 0.503332 0.504801 0.506304 0.507842 0.509415 0.511023 0.512667
+0.514348 0.516066 0.517821 0.519615 0.521447 0.523318 0.525228 0.527179
+0.52917 0.531202 0.533275 0.53539 0.537547 0.539747 0.541992 0.54428
+0.546613 0.548989 0.551411 0.553877 0.556389 0.558947 0.561551 0.564202
+0.5669 0.569645 0.572437 0.575278 0.578166 0.581104 0.58409 0.587125
+0.59021 0.593345 0.596529 0.599764 0.603051 0.606389 0.609778 0.613219
+0.61671 0.620254 0.62385 0.627497 0.631197 0.634949 0.638754 0.642612
+0.646522 0.650486 0.654503 0.658573 0.662696 0.666873 0.671104 -0.324611
+-0.320273 -0.315881 -0.311434 -0.306931 -0.302375 -0.297764 -0.2931
+-0.288381 -0.283608 -0.278781 -0.2739 -0.268964 -0.263975 -0.258931
+-0.253833 -0.248682 -0.243476 -0.238217 -0.232904 -0.227537 -0.222116
+-0.216642 -0.211115 -0.205534 -0.1999 -0.194211 -0.18847 -0.182675
+-0.176829 -0.170929 -0.164978 -0.158975 -0.152919 -0.146813 -0.140655
+-0.134446 -0.128186 -0.121875 -0.115514 -0.109103 -0.102642 -0.0961313
+-0.0895714 -0.0829625 -0.0763049 -0.0695988 -0.0628447 -0.056041 -0.0491896
+-0.0422913 -0.0353461 -0.0283546 -0.0213171 -0.0142339 -0.00710538
+6.80089e-05 0.00728586 0.0145478 0.0218535 0.0292025 0.0365944 0.0440286
+0.0515049 0.0590228 0.0665818 0.0741815 0.0818213 0.0895009 0.0972198
+0.104978 0.112776 0.120611 0.128484 0.136393 0.144339 0.15232 0.160337
+0.168388 0.176473 0.184592 0.192744 0.200929 0.209146 0.217393 0.225672
+0.233981 0.24232 0.250688 0.259084 0.267509 0.27596 0.284439 0.292944
+0.301475 0.310031 0.318611 0.327215 0.335842 0.344491 0.353162 0.361854
+0.370566 0.379298 0.38805 0.39682 0.405608 0.414413 0.423234 0.432072
+0.440924 0.449792 0.458673 0.467567 0.476474 0.485394 0.494324 0.503265
+0.512216 0.521176 0.530145 0.539121 0.548104 0.557094 0.566089 0.575089
+0.584094 0.593102 0.602113 0.611126 0.620141 0.629157 0.638173 0.647189
+0.656203 0.665215 0.674225 0.683232 0.692234 0.701231 0.710224 0.71921
+0.728189 0.737161 0.746124 0.755079 0.764024 0.772959 0.781884 0.790796
+0.799697 0.808584 0.817458 0.826318 0.835162 0.843992 0.852804 0.861601
+0.870379 0.879139 0.887879 0.8966 0.905301 0.913981 0.92264 0.931276
+0.93989 0.94848 0.957046 0.965588 0.974105 0.982595 0.99106 0.999497
+1.00791 1.01629 1.02464 1.03296 1.04126 1.04952 1.05775 1.06595 1.07412
+1.08225 1.09035 1.09841 1.10645 1.11444 1.1224 1.13033 1.13822 1.14607
+1.15388 1.16166 1.1694 1.17709 1.18475 1.19237 1.19995 1.20749 1.21498
+1.22244 1.22985 1.23722 1.24454 1.25182 1.25906 1.26625 1.2734 0.280502
+0.287559 0.29457 0.301536 0.308454 0.315325 0.32215 0.328926 0.335655
+0.342335 0.348967 0.35555 0.362084 0.368568 0.375003 0.381388 0.387722
+0.394004 0.400235 0.406415 0.412544 0.418621 0.424647 0.430621 0.436542
+0.442412 0.448228 0.453993 0.459704 0.465363 0.470969 0.476521 0.48202
+0.487466 0.492858 0.498196 0.503481 0.508712 0.513889 0.519011 0.524077
+0.52909 0.534049 0.538953 0.543804 0.5486 0.553342 0.55803 0.562664
+0.567243 0.571769 0.57624 0.580658 0.585021 0.589331 0.593587 0.597789
+0.601938 0.606033 0.610075 0.614064 0.617999 0.621879 0.625706 0.629481
+0.633203 0.636873 0.640491 0.644057 0.647571 0.651033 0.654445 0.657805
+0.661114 0.664372 0.66758 0.670739 0.673847 0.676905 0.679914 0.682875
+;
+#X array cos-out 441 float 1;
+#A 0 -0.911256 -0.913872 -0.916365 -0.918789 -0.921097 -0.923342 -0.925486
+-0.927564 -0.92956 -0.931483 -0.93335 -0.935129 -0.936867 -0.938528
+-0.940137 -0.941707 -0.943197 -0.944657 -0.946072 -0.947426 -0.948755
+-0.95004 -0.951276 -0.952491 -0.953672 -0.954806 -0.955924 -0.957024
+-0.958071 -0.959106 -0.960132 -0.961119 -0.962086 -0.963047 -0.963993
+-0.964903 -0.965811 -0.966718 -0.967595 -0.968461 -0.969329 -0.970192
+-0.971025 -0.971863 -0.972707 -0.973527 -0.974343 -0.975168 -0.975986
+-0.976786 -0.977597 -0.978414 -0.979202 -0.980003 -0.980816 -0.981596
+-0.982391 -0.983194 -0.983968 -0.984757 -0.985543 -0.98631 -0.987093
+-0.987851 -0.98861 -0.98937 -0.990102 -0.990852 -0.991557 -0.992275
+-0.99296 -0.993642 -0.994295 -0.994935 -0.995544 -0.996137 -0.996687
+-0.997227 -0.997705 -0.998173 -0.998575 -0.998944 -0.999273 -0.999527
+-0.999743 -0.999894 -0.999966 -0.999981 -0.999927 -0.999765 -0.999526
+-0.999202 -0.998785 -0.99824 -0.997586 -0.996816 -0.995923 -0.994897
+-0.99373 -0.992413 -0.990934 -0.989283 -0.987458 -0.985449 -0.983247
+-0.980843 -0.978222 -0.975372 -0.972288 -0.968961 -0.965377 -0.96153
+-0.95741 -0.952995 -0.948265 -0.943231 -0.937881 -0.932182 -0.926128
+-0.919728 -0.912938 -0.905762 -0.898197 -0.890198 -0.881799 -0.87293
+-0.863637 -0.853855 -0.843612 -0.832873 -0.821629 -0.809886 -0.797593
+-0.784764 -0.771394 -0.757466 -0.742953 -0.727864 -0.712189 -0.695918
+-0.679041 -0.661549 -0.643437 -0.624697 -0.605324 -0.585314 -0.564664
+-0.543374 -0.521441 -0.498869 -0.475658 -0.451811 -0.427334 -0.402219
+-0.376482 -0.350131 -0.323174 -0.295626 -0.267508 -0.238824 -0.2096
+-0.179853 -0.149603 -0.118875 -0.0876953 -0.0560885 -0.0240874 0.00827867
+0.040974 0.0739643 0.107208 0.140666 0.174297 0.208056 0.241893 0.275757
+0.309603 0.343385 0.377036 0.410498 0.443712 0.476616 0.509148 0.541242
+0.572835 0.603858 0.634244 0.66391 0.692797 0.720837 0.747961 0.774084
+0.799131 0.823051 0.845758 0.867169 0.887248 0.90588 0.923037 0.938628
+0.952605 0.964885 0.975433 0.984153 0.991037 0.995988 0.998986 0.999997
+0.998938 0.995807 0.990576 0.983211 0.973668 0.961961 0.948075 0.932007
+0.913757 0.893328 0.87073 0.845995 0.81915 0.790227 0.759268 0.726324
+0.691452 0.654714 0.616181 0.57593 0.534037 0.490599 0.445716 0.399491
+0.352033 0.303459 0.253886 0.203441 0.152259 0.100478 0.0482368 -0.00432081
+-0.057045 -0.109786 -0.162386 -0.214696 -0.266564 -0.317814 -0.368301
+-0.417864 -0.466337 -0.513584 -0.559424 -0.603732 -0.646344 -0.687125
+-0.725934 -0.762631 -0.797101 -0.829205 -0.858847 -0.8859 -0.91028
+-0.931885 -0.950636 -0.966466 -0.97929 -0.989092 -0.995773 -0.999358
+-0.999773 -0.997042 -0.991152 -0.982099 -0.969941 -0.954655 -0.936332
+-0.915008 -0.890737 -0.863625 -0.833713 -0.801132 -0.765979 -0.728348
+-0.688394 -0.646219 -0.601975 -0.555817 -0.507869 -0.45832 -0.407319
+-0.355036 -0.301652 -0.247328 -0.192258 -0.136617 -0.0805873 -0.0243537
+0.0319027 0.0879985 0.143752 0.198986 0.253526 0.307194 0.359834 0.411262
+0.461345 0.509907 0.556823 0.601935 0.645131 0.686266 0.725245 0.761935
+0.796272 0.828125 0.857461 0.884158 0.9082 0.929508 0.948044 0.9638
+0.976698 0.986778 0.99402 0.998404 0.999981 0.998763 0.994751 0.988022
+0.978621 0.966582 0.95197 0.93487 0.915357 0.893512 0.869405 0.843139
+0.814817 0.784538 0.752408 0.718535 0.68303 0.646007 0.607581 0.567872
+0.526996 0.485074 0.442227 0.398573 0.354231 0.30932 0.263957 0.218256
+0.172326 0.126282 0.0802317 0.0342922 -0.0114471 -0.0568861 -0.101931
+-0.146492 -0.190474 -0.233802 -0.276394 -0.318171 -0.359072 -0.399015
+-0.437958 -0.475821 -0.512573 -0.548149 -0.582512 -0.615632 -0.647446
+-0.677951 -0.707119 -0.734897 -0.761296 -0.786293 -0.80988 -0.83204
+-0.852773 -0.872085 -0.88998 -0.906462 -0.921542 -0.935229 -0.94754
+-0.95849 -0.968102 -0.976397 -0.9834 -0.989136 -0.993613 -0.996882
+-0.998976 -0.99993 -0.999748 -0.998484 -0.996188 -0.99286 -0.988563
+-0.983336 -0.977186 -0.970195 -0.962347 -0.953732 -0.944344 -0.934249
+-0.923482 -0.912051 -0.900028 -0.887441 -0.874296 -0.860659 -0.846562
+-0.832035 -0.817101 -0.801792 -0.786149 -0.770201 -0.753977 -0.737507
+-0.720826 -0.703952 -0.686912 -0.669731 -0.652436 -0.635043 -0.617572
+-0.600055 -0.582513 -0.564966 -0.547418 -0.529898 -0.512429 -0.495016
+-0.477676 -0.460438 -0.443287 -0.426265 -0.409364;
+#X pop;
+#X obj 251 241 tabwrite~ phase-out;
+#X obj 251 268 tabwrite~ cos-out;
+#X msg 251 216 bang;
+#X text 298 215 <-- graph them;
+#X text 386 99 <-- change smoothly to avoid clicks;
+#X connect 0 0 5 1;
+#X connect 1 0 9 0;
+#X connect 2 0 0 1;
+#X connect 3 0 31 0;
+#X connect 4 0 7 0;
+#X connect 4 0 40 0;
+#X connect 5 0 4 0;
+#X connect 5 0 39 0;
+#X connect 6 0 7 1;
+#X connect 7 0 6 0;
+#X connect 8 0 7 2;
+#X connect 9 0 0 0;
+#X connect 10 0 2 0;
+#X connect 11 0 12 0;
+#X connect 12 0 10 0;
+#X connect 31 0 5 0;
+#X connect 33 0 32 0;
+#X connect 41 0 39 0;
+#X connect 41 0 40 0;
diff --git a/pd/doc/3.audio.examples/A09.review.pd b/pd/doc/3.audio.examples/A09.review.pd
new file mode 100644
index 00000000..9b190a19
--- /dev/null
+++ b/pd/doc/3.audio.examples/A09.review.pd
@@ -0,0 +1,41 @@
+#N canvas 36 68 701 588 12;
+#X text 444 542 updated for Pd version 0.34;
+#X text 39 14 PART 1 REVIEW;
+#X obj 66 131 tabwrite~;
+#X obj 66 105 line~;
+#X obj 54 298 +;
+#X obj 66 79 +~;
+#X obj 66 209 cos~;
+#X obj 66 157 osc~;
+#X obj 66 183 phasor~;
+#X obj 54 324 pack;
+#X obj 52 511 r;
+#X obj 53 487 s;
+#X obj 54 408 inlet;
+#X obj 53 462 f;
+#X obj 53 436 t;
+#X obj 54 378 dbtorms;
+#X obj 97 351 mtof;
+#X obj 54 350 ftom;
+#X obj 105 408 outlet;
+#X obj 66 235 dac~;
+#X text 26 52 So far we've seen these audio ("tilde") objects:;
+#X text 123 104 -- ramp generator;
+#X text 157 131 -- sampler (which we've only used for graphing so far)
+;
+#X text 111 157 -- a cosine wave oscillator;
+#X text 139 183 -- phase generator for making your own oscillator;
+#X text 112 209 -- cosine waveshape lookup;
+#X text 112 236 -- audio output ("digital/analog converter" -- a misnomer)
+;
+#X text 31 266 ... and these "control" objects:;
+#X text 145 349 -- frequency to pitch conversion;
+#X text 126 378 -- decibel to amplitude conversion;
+#X text 167 409 -- input and output to a subpatch;
+#X text 90 437 ("trigger") -- message ordering and conversion;
+#X text 93 462 ("float") -- store a (floating point) number;
+#X text 90 488 ("send") -- wireless message sending;
+#X text 91 513 ("receive") ... and receiving;
+#X text 106 78 (etc.) -- arithmetic on audio signals;
+#X text 92 296 (etc.) -- arithmetic;
+#X text 99 323 -- combine two or more values in a single message;
diff --git a/pd/doc/3.audio.examples/B01.wavetables.pd b/pd/doc/3.audio.examples/B01.wavetables.pd
new file mode 100644
index 00000000..66549d3e
--- /dev/null
+++ b/pd/doc/3.audio.examples/B01.wavetables.pd
@@ -0,0 +1,50 @@
+#N canvas 19 22 722 608 12;
+#X floatatom 164 43 0 0 0 0 - - -;
+#N canvas 0 0 450 300 graph1 0;
+#X array table10 259 float 1;
+#A 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0.612 0.612 0.612 0.612 0.612 0.627692 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 -0.470769 -0.470769 -0.470769 -0.470769 -0.470769
+-0.470769 -0.470769 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0.627692 0.627692 0.627692 0.643385 0.643385 0.643385
+0.659077 0 -0.502154 -0.502154 -0.502154 -0.486462 -0.486462 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0.580615 0.596308 0.596308 0.596308 0.596308
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
+#X coords 0 1.02 258 -1.02 258 130 1;
+#X restore 445 47 graph;
+#X text 30 123 oscillator -->;
+#X text 456 587 updated for Pd version 0.34;
+#X text 33 8 WAVETABLE OSCILLATORS;
+#X text 36 106 wavetable;
+#X obj 164 70 mtof;
+#X floatatom 164 97 0 0 0 0 - - -;
+#X obj 164 123 tabosc4~ table10;
+#X text 94 42 pitch->;
+#X text 35 309 Note that I selected "save contents" in the properties
+dialog for table10 (right click on the table to see.) If this isn't
+set \, the waveform won't be remembered as part of the patch but will
+be reinitialized to zero when the patch is reopened.;
+#X msg 35 549 \; table10 cosinesum 256 0.2 -0.2 0.2 -0.2 0.2 -0.2 0.2
+;
+#X msg 578 240 \; table10 const 0;
+#X text 597 217 CLEAR TABLE;
+#X text 35 395 For efficiency's sake tabosc4~ requires that the table
+have a power of two plus three points (64+3=67 \, 128+3=131 \, 256+3=259
+\, etc.) If you want wraparound to work smoothly \, you should make
+the last three points copies of the first three. This is done because
+tabread4~ does 4-point interpolation.;
+#X text 38 494 If you want a specific sinusoidal composition \, you
+can send table10 a message \, as below (see 11.arrays in the control
+examples):;
+#X text 36 240 Here \, in place of the "osc~" cosine wave oscillator
+\, we introduce the tabosc4~ oscillator which produces an arbitrary
+waveform. You can draw in the waveform with the mouse.;
+#X obj 164 151 output~;
+#X connect 0 0 6 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 17 0;
+#X connect 8 0 17 1;
diff --git a/pd/doc/3.audio.examples/B02.two-wavetables.pd b/pd/doc/3.audio.examples/B02.two-wavetables.pd
new file mode 100644
index 00000000..c4cc6d60
--- /dev/null
+++ b/pd/doc/3.audio.examples/B02.two-wavetables.pd
@@ -0,0 +1,147 @@
+#N canvas 74 98 749 466 12;
+#X graph graph1 0 -1.02 258 1.02 475 298 733 168;
+#X array waveform11 259 float 1;
+#A 0 -0.0896033 0 0.0896033 0.178356 0.265425 0.350007 0.431348 0.508756
+0.58161 0.649372 0.711597 0.767935 0.818137 0.862053 0.89963 0.930912
+0.956028 0.975187 0.988669 0.996811 1 0.998655 0.993223 0.984158 0.971919
+0.956953 0.939691 0.920538 0.899867 0.878018 0.85529 0.831945 0.808204
+0.784252 0.760239 0.736284 0.712477 0.688888 0.665568 0.642553 0.619872
+0.59755 0.575607 0.554066 0.532953 0.512296 0.49213 0.472491 0.453419
+0.434957 0.417147 0.400027 0.383632 0.367992 0.353126 0.339046 0.32575
+0.313227 0.301453 0.290394 0.280002 0.270224 0.260995 0.252248 0.24391
+0.235908 0.22817 0.220628 0.213219 0.205888 0.198586 0.191278 0.183936
+0.176545 0.169098 0.1616 0.154063 0.146505 0.138954 0.131437 0.123987
+0.116636 0.109415 0.102354 0.0954784 0.0888083 0.08236 0.0761442 0.0701659
+0.0644253 0.0589178 0.0536354 0.0485669 0.0436994 0.0390194 0.0345135
+0.0301695 0.0259776 0.0219306 0.0180245 0.0142591 0.0106377 0.00716724
+0.00385775 0.000722025 -0.00222511 -0.0049675 -0.00748845 -0.00977153
+-0.0118014 -0.0135644 -0.0150493 -0.0162479 -0.0171551 -0.0177693 -0.0180928
+-0.0181312 -0.0178936 -0.017392 -0.0166417 -0.0156601 -0.0144666 -0.0130822
+-0.0115294 -0.00983114 -0.0080113 -0.00609396 -0.0041034 -0.00206402
+-2.23572e-07 0.00206358 0.00410297 0.00609353 0.00801089 0.00983075
+0.011529 0.0130819 0.0144663 0.0156599 0.0166416 0.0173919 0.0178935
+0.0181312 0.0180929 0.0177695 0.0171552 0.0162481 0.0150496 0.0135647
+0.0118018 0.009772 0.00748897 0.00496807 0.00222573 -0.000721367 -0.00385706
+-0.00716651 -0.010637 -0.0142583 -0.0180237 -0.0219297 -0.0259767 -0.0301686
+-0.0345125 -0.0390184 -0.0436984 -0.0485658 -0.0536343 -0.0589167 -0.0644241
+-0.0701647 -0.0761429 -0.0823587 -0.0888069 -0.0954769 -0.102353 -0.109414
+-0.116634 -0.123985 -0.131435 -0.138952 -0.146504 -0.154061 -0.161598
+-0.169097 -0.176543 -0.183935 -0.191276 -0.198584 -0.205886 -0.213218
+-0.220627 -0.228169 -0.235906 -0.243908 -0.252246 -0.260993 -0.270222
+-0.28 -0.290392 -0.301451 -0.313224 -0.325747 -0.339043 -0.353123 -0.367989
+-0.383629 -0.400023 -0.417143 -0.434954 -0.453415 -0.472486 -0.492125
+-0.512292 -0.532948 -0.554062 -0.575602 -0.597545 -0.619868 -0.642548
+-0.665563 -0.688883 -0.712472 -0.736279 -0.760234 -0.784247 -0.808199
+-0.83194 -0.855285 -0.878013 -0.899863 -0.920533 -0.939687 -0.956949
+-0.971916 -0.984156 -0.993221 -0.998655 -1 -0.996813 -0.988671 -0.975191
+-0.956033 -0.930918 -0.899638 -0.862061 -0.818147 -0.767947 -0.71161
+-0.649386 -0.581625 -0.508772 -0.431366 -0.350025 -0.265443 -0.178375
+-0.0896226 -1.94061e-05 0.089584;
+#X pop;
+#X floatatom 202 171 0 0 100;
+#N canvas 159 26 532 285 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 426 180 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 397 110 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 85 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 20 155 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 105 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 90 outlet;
+#X msg 214 65 \; pd dsp 1;
+#X obj 83 198 line~;
+#X obj 20 207 *~;
+#X obj 20 232 dac~;
+#X obj 83 173 pack 0 50;
+#X text 20 132 audio;
+#X text 96 114 show level;
+#X obj 426 155 t b;
+#X obj 20 181 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 26 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 27 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 5 0;
+#X connect 27 0 21 0;
+#X restore 164 199 pd output;
+#X msg 240 172 MUTE;
+#X text 30 123 oscillator -->;
+#X text 485 445 updated for Pd version 0.34;
+#X text 33 8 WAVETABLE OSCILLATORS;
+#X text 36 106 wavetable;
+#X text 88 54 pitch->;
+#X graph graph2 0 0 258 1000 475 155 734 15;
+#X array pitch11 259 float 1;
+#A 0 757.143 757.143 735.714 700 671.429 650 621.429 600 571.429 550
+521.429 507.143 485.714 464.286 442.857 428.571 414.286 400 378.571
+364.286 342.857 328.571 928.571 921.429 921.429 914.286 907.143 892.857
+885.714 878.571 864.286 850 828.571 807.143 792.857 785.714 775 764.286
+753.571 742.857 735.714 728.571 721.429 714.286 703.571 692.857 682.143
+671.429 650 628.571 617.857 607.143 596.429 585.714 575 564.286 553.571
+542.857 532.143 521.429 510.714 500 485.714 478.571 464.286 450 435.714
+428.571 400 392.857 385.714 378.571 357.143 350 342.857 335.714 328.571
+314.286 292.857 285.714 271.429 264.286 571.429 571.429 571.429 571.429
+571.429 564.286 564.286 278.571 271.429 271.429 278.571 278.571 278.571
+278.571 571.429 571.429 571.429 575 578.571 578.571 278.571 278.571
+285.714 285.714 278.571 278.571 278.571 878.571 878.571 878.571 878.571
+878.571 321.429 325 328.571 328.571 328.571 328.571 885.714 885.714
+885.714 885.714 207.143 207.143 207.143 200 207.143 207.143 207.143
+214.286 214.286 221.429 228.571 228.571 242.857 250 257.143 264.286
+278.571 292.857 307.143 321.429 335.714 350 371.429 392.857 421.429
+435.714 471.429 500 542.857 571.429 628.571 664.286 700 728.571 757.143
+792.857 828.571 885.714 928.571 978.571 1000 1007.14 1007.14 1000 1000
+992.857 985.714 885.714 914.286 671.429 671.429 671.429 671.429 671.429
+671.429 671.429 671.429 671.429 671.429 678.571 635.714 635.714 678.571
+714.286 714.286 678.571 635.714 635.714 635.714 742.857 742.857 685.714
+685.714 635.714 621.429 685.714 792.857 792.857 678.571 521.429 521.429
+521.429 864.286 857.143 857.143 471.429 471.429 471.429 471.429 921.429
+921.429 385.714 385.714 385.714 964.286 964.286 964.286 328.571 328.571
+328.571 328.571 885.714 885.714 885.714 685.714 214.286 214.286 207.143
+207.143 921.429 921.429 921.429 921.429 207.143 207.143 200 200 957.143
+957.143 950 214.286 214.286 207.143 207.143 957.143 957.143 950 200
+207.143 207.143 942.857 942.857 942.857 950 950;
+#X pop;
+#X obj 164 87 tabosc4~ pitch11;
+#X obj 164 123 tabosc4~ waveform11;
+#X obj 164 55 sig~ 0.5;
+#X text 13 319 Here's a tabosc4~ controlling the frequency of another
+one. If you get properties on the two arrays \, you'll see that the
+top graph has a vertical scale from 0 to 1000 \; we're looping through
+that at a frequency of 0.5 Hz. and the output is used as the frequency
+input of the second tabosc4~. I've detected Klingons \, Captain Kirk...
+;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 10 0 11 0;
+#X connect 11 0 2 0;
+#X connect 12 0 10 0;
diff --git a/pd/doc/3.audio.examples/B03.tabread4.pd b/pd/doc/3.audio.examples/B03.tabread4.pd
new file mode 100644
index 00000000..15fa6652
--- /dev/null
+++ b/pd/doc/3.audio.examples/B03.tabread4.pd
@@ -0,0 +1,130 @@
+#N canvas 55 137 820 651 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array waveform12 131 float 1;
+#A 0 -0.172615 -0.172615 -0.172615 -0.172615 -0.172615 -0.141231 -0.109846
+-0.0941538 -0.0627692 -0.0470769 0.0156923 0.0784615 0.125538 0.188308
+0.235385 0.298154 0.360923 0.392308 0.470769 0.533538 0.596308 0.643385
+0.674769 0.721846 0.753231 0.784615 0.816 0.831692 0.847385 0.878769
+0.894462 0.910154 0.910154 0.910154 0.910154 0.910154 0.894462 0.894462
+0.894462 0.894462 0.878769 0.863077 0.816 0.800308 0.768923 0.737538
+0.706154 0.674769 0.643385 0.596308 0.564923 0.533538 0.470769 0.423692
+0.376615 0.313846 0.266769 0.204 0.172615 0.109846 0.0627692 0.0156923
+0 -0.0313846 -0.0627692 -0.0784615 -0.0941538 -0.109846 -0.141231 -0.156923
+-0.172615 -0.204 -0.219692 -0.219692 -0.235385 -0.235385 -0.235385
+-0.219692 -0.219692 -0.219692 -0.204 -0.156923 -0.125538 -0.0784615
+0 0.172615 0.313846 0.470769 0.564923 0.627692 0.690462 0.721846 0.737538
+0.753231 0.768923 0.768923 0.753231 0.737538 0.706154 0.674769 0.612
+0.580615 0.549231 0.517846 0.486462 0.423692 0.392308 0.360923 0.282462
+0.219692 0.109846 -0.0156923 -0.0941538 -0.109846 -0.141231 -0.156923
+-0.172615 -0.188308 -0.204 -0.204 -0.219692 -0.204 -0.204 -0.219692
+-0.219692 -0.204 -0.204 -0.204 -0.204 -0.204 -0.188308;
+#X coords 0 1.02 130 -1.02 258 130 1;
+#X restore 462 30 graph;
+#X floatatom 194 299 0 0 100 0 - - -;
+#N canvas 159 26 532 285 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 426 180 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 397 110 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 85 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 20 155 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 105 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 90 outlet;
+#X msg 214 65 \; pd dsp 1;
+#X obj 83 198 line~;
+#X obj 20 207 *~;
+#X obj 20 232 dac~;
+#X obj 83 173 pack 0 50;
+#X text 20 132 audio;
+#X text 96 114 show level;
+#X obj 426 155 t b;
+#X obj 20 181 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 26 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 27 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 5 0;
+#X connect 27 0 21 0;
+#X restore 156 327 pd output;
+#X msg 232 300 MUTE;
+#X text 33 8 WAVETABLE OSCILLATORS;
+#X obj 156 95 phasor~;
+#X obj 156 184 tabread4~ waveform12;
+#X obj 156 157 +~ 1;
+#X floatatom 156 66 4 0 0 0 - - -;
+#X floatatom 250 59 4 0 1000 0 - - -;
+#X obj 250 80 pack 0 50;
+#X obj 250 104 line~;
+#X obj 156 131 *~;
+#X text 21 81 phase;
+#X text 20 96 generation -->;
+#X text 25 117 range;
+#X text 24 132 adjustment -->;
+#X text 250 38 squeeze;
+#X text 133 40 frequency;
+#N canvas 0 0 450 300 graph3 0;
+#X array wave-out12 441 float 0;
+#X coords 0 1 440 -1 300 140 1;
+#X restore 481 190 graph;
+#X obj 177 247 tabwrite~ wave-out12;
+#X msg 177 216 bang;
+#X text 223 217 <--click to graph;
+#X text 25 360 The tabread4~ module is available for situations requiring
+more control than tabosc4~ offers. The relationship between the two
+is the same as between cos~ and osc~ \, although the units are different
+between cos~ and tabread4~. Cos~ assumes input is normalized from 0
+to 1 (and will wrap around as needed.) Tabread4~ takes values from
+1 to n-2 where n is the number of points in the table-- for a 259-point
+table such as we have here \, it's 1 to 129 (so the "good" segment
+is 128 samples long.);
+#X text 30 508 You would use tabread4~ (as opposed to tabosc4~) if
+you need direct control of the phase \, for instance if you to advance
+nonlinearly through the table. In the case shown here \, the "squeeze"
+factor makes the phase grow to a value at least \, and possibly much
+graeater than \, 129 (to which tabread4~ then limits it). So the resulting
+waveform is compressed in time.;
+#X obj 250 128 +~ 128;
+#X text 554 624 updated for Pd version 0.37;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 5 0 12 0;
+#X connect 6 0 2 0;
+#X connect 6 0 20 0;
+#X connect 7 0 6 0;
+#X connect 8 0 5 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 0;
+#X connect 11 0 25 0;
+#X connect 12 0 7 0;
+#X connect 21 0 20 0;
+#X connect 25 0 12 1;
diff --git a/pd/doc/3.audio.examples/B04.tabread4.interpolation.pd b/pd/doc/3.audio.examples/B04.tabread4.interpolation.pd
new file mode 100644
index 00000000..18aef089
--- /dev/null
+++ b/pd/doc/3.audio.examples/B04.tabread4.interpolation.pd
@@ -0,0 +1,44 @@
+#N canvas 137 102 781 520 12;
+#X graph graph1 0 -1.02 10 1.02 468 159 648 29;
+#X array waveform13 11 float 1;
+#A 0 1 1 1 1 1 1 1 -1 -1 -1 -1;
+#X pop;
+#X text 533 502 updated for Pd version 0.34;
+#X obj 156 157 +~ 1;
+#X text 21 81 phase;
+#X text 20 96 generation -->;
+#X text 25 117 range;
+#X text 24 132 adjustment -->;
+#X graph graph3 0 -1.02 440 1.02 469 362 769 222;
+#X array wave-out13 441 float 0;
+#X pop;
+#X msg 177 216 bang;
+#X text 223 217 <--click to graph;
+#N canvas 11 418 523 216 other-stuff 0;
+#X obj 41 49 loadbang;
+#X msg 39 81 \; waveform13 0 1 1 1 1 1 1 1 -1 -1 -1 -1 \; waveform13
+xlabel -1.2 0 1 2 3 4 5 6 7 8 9 10 \; pd dsp 1;
+#X connect 0 0 1 0;
+#X restore 626 426 pd other-stuff;
+#X obj 156 247 tabwrite~ wave-out13;
+#X obj 156 184 tabread4~ waveform13;
+#X obj 156 131 *~ 8;
+#X obj 156 95 phasor~ 220;
+#X text 36 22 4-POINT INTERPOLATION IN DETAIL;
+#X obj 216 316 sig~ 220;
+#X obj 216 346 tabosc4~ waveform13;
+#X text 35 293 (this would be;
+#X text 36 313 equivalent to the;
+#X text 110 333 above) -->;
+#X text 18 409 This patch demonstrates 4-point interpolation in tabread4~.
+The 11-point table \, waveform13 \, contains a transition from from
+1 to -1 \, which is "smoothed" as seen in wave-out13. There's no such
+transition at the wraparoind point--the interpolation always happens
+between 4 consccutive samples of the table \, disregarding wraparound.
+;
+#X connect 2 0 12 0;
+#X connect 8 0 11 0;
+#X connect 12 0 11 0;
+#X connect 13 0 2 0;
+#X connect 14 0 13 0;
+#X connect 16 0 17 0;
diff --git a/pd/doc/3.audio.examples/B05.tabread.FM.pd b/pd/doc/3.audio.examples/B05.tabread.FM.pd
new file mode 100644
index 00000000..ac2d9507
--- /dev/null
+++ b/pd/doc/3.audio.examples/B05.tabread.FM.pd
@@ -0,0 +1,107 @@
+#N canvas 55 137 777 467 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array pitchmod14 131 float 1;
+#A 0 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385
+0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.863077
+0.863077 0.863077 0.863077 0.863077 0.863077 0.863077 0.863077 0.863077
+0.863077 0.863077 0.863077 0.863077 0.863077 0.863077 0.863077 0.863077
+0.863077 0.863077 0.863077 0.863077 0.863077 0.831692 0.847385 0.847385
+0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385
+0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385
+0.847385 0.863077 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385
+-0.800308 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.768923 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.768923 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.800308 -0.800308
+-0.800308 -0.800308 -0.800308 -0.800308 -0.800308;
+#X coords 0 1.02 130 -1.02 258 130 1;
+#X restore 462 30 graph;
+#X floatatom 191 277 0 0 100 0 - - -;
+#N canvas 159 26 532 285 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 426 180 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 397 110 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 85 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 20 155 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 105 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 90 outlet;
+#X msg 214 65 \; pd dsp 1;
+#X obj 83 198 line~;
+#X obj 20 207 *~;
+#X obj 20 232 dac~;
+#X obj 83 173 pack 0 50;
+#X text 20 132 audio;
+#X text 96 114 show level;
+#X obj 426 155 t b;
+#X obj 20 181 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 26 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 27 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 5 0;
+#X connect 27 0 21 0;
+#X restore 153 305 pd output;
+#X msg 229 278 MUTE;
+#X text 521 439 updated for Pd version 0.34;
+#X floatatom 153 95 4 0 0 0 - - -;
+#X text 153 69 frequency;
+#X text 33 8 MORE ON FREQUENCY MODULATION;
+#X floatatom 195 206 4 0 0 0 - - -;
+#X text 155 50 modulation;
+#X obj 152 157 *~;
+#X text 255 150 modulation;
+#X text 253 169 depth;
+#X floatatom 201 157 4 0 0 0 - - -;
+#X obj 152 205 +~;
+#X text 250 212 frequency;
+#X obj 152 237 osc~;
+#X obj 153 122 tabosc4~ pitchmod14;
+#X text 254 194 carrier;
+#X text 47 356 This patch is like the original FM patch except in having
+a settable wavetable for the modulation oscillator. Try changing the
+waveform as well as the three familiar parameters.;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 5 0 17 0;
+#X connect 8 0 14 1;
+#X connect 10 0 14 0;
+#X connect 13 0 10 1;
+#X connect 14 0 16 0;
+#X connect 16 0 2 0;
+#X connect 17 0 10 0;
diff --git a/pd/doc/3.audio.examples/B06.table.switching.pd b/pd/doc/3.audio.examples/B06.table.switching.pd
new file mode 100644
index 00000000..558f91c4
--- /dev/null
+++ b/pd/doc/3.audio.examples/B06.table.switching.pd
@@ -0,0 +1,127 @@
+#N canvas 55 137 835 504 12;
+#X graph graph1 0 -1.02 130 1.02 565 153 823 23;
+#X array waveshape15a 131 float 1;
+#A 0 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385
+0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.863077
+0.863077 0.863077 0.863077 0.863077 0.863077 0.863077 0.863077 0.863077
+0.863077 0.863077 0.863077 0.863077 0.863077 0.863077 0.863077 0.863077
+0.863077 0.863077 0.863077 0.863077 0.863077 0.831692 0.847385 0.847385
+0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385
+0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385
+0.847385 0.863077 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385
+-0.800308 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.768923 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.768923 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.800308 -0.800308
+-0.800308 -0.800308 -0.800308 -0.800308 -0.800308;
+#X pop;
+#X floatatom 194 299 0 0 100;
+#N canvas 159 26 532 285 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 426 180 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 397 110 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 85 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 20 155 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 105 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 90 outlet;
+#X msg 214 65 \; pd dsp 1;
+#X obj 83 198 line~;
+#X obj 20 207 *~;
+#X obj 20 232 dac~;
+#X obj 83 173 pack 0 50;
+#X text 20 132 audio;
+#X text 96 114 show level;
+#X obj 426 155 t b;
+#X obj 20 181 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 26 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 27 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 5 0;
+#X connect 27 0 21 0;
+#X restore 156 327 pd output;
+#X msg 232 300 MUTE;
+#X text 581 481 updated for Pd version 0.34;
+#X text 33 8 SWITCHING BETWEEN TABLES;
+#X graph graph1 0 -1.02 130 1.02 565 308 823 178;
+#X array waveshape15b 131 float 1;
+#A 0 -0.659077 -0.643385 -0.643385 -0.627692 -0.612 -0.612 -0.596308
+-0.596308 -0.580615 -0.580615 -0.580615 -0.580615 -0.580615 -0.580615
+-0.580615 -0.596308 -0.596308 -0.596308 -0.596308 -0.596308 -0.596308
+-0.596308 -0.596308 -0.580615 -0.580615 -0.580615 -0.580615 -0.580615
+-0.580615 -0.580615 -0.580615 -0.564923 -0.549231 -0.549231 -0.533538
+-0.517846 -0.517846 -0.517846 -0.517846 -0.517846 -0.517846 -0.517846
+-0.517846 -0.533538 -0.549231 -0.580615 -0.580615 0.847385 0.847385
+0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 0.863077
+0.847385 0.847385 0.847385 0.847385 0.847385 0.847385 -0.800308 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.768923 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.768923 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615 -0.784615
+-0.784615 -0.784615 -0.784615 -0.800308 -0.800308 -0.800308 -0.800308
+-0.800308 -0.800308 -0.800308;
+#X pop;
+#X obj 156 274 tabosc4~ waveshape15a;
+#X obj 156 186 sig~ 110;
+#X msg 181 215 set waveshape15a;
+#X msg 182 244 set waveshape15b;
+#X text 20 51 During a performance you're unlikely to want to draw
+or recalculate wavetables on the fly \, because you don't want to give
+Pd computationally intensive atomic tasks that could make Pd miss a
+DAC deadline. Instead \, use "set" mesages to switch tabosc~ or tabread4~
+between pre-prepared tables. Indeed \, you will eventually want to
+save screen space by throwing all your wavetables in a subpatch somewhere.
+;
+#X obj 161 401 table waveshape15c 131;
+#X text 41 362 There's also a "text object" hook so that you can have
+arrays with parametrizable names and sizes:;
+#X text 31 431 You would use this if you want to include one or more
+arrays in an abstraction. In this invocation you can't save the state
+of the array--instead \, juts read it in from a file or calculate it
+at startup.;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 7 0 2 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 0;
+#X connect 10 0 7 0;
diff --git a/pd/doc/3.audio.examples/B07.sampler.pd b/pd/doc/3.audio.examples/B07.sampler.pd
new file mode 100644
index 00000000..632c1d03
--- /dev/null
+++ b/pd/doc/3.audio.examples/B07.sampler.pd
@@ -0,0 +1,52 @@
+#N canvas 11 3 915 618 12;
+#X obj 37 217 hip~ 5;
+#X text 96 219 high pass filter to cut DC;
+#N canvas 0 0 450 300 graph1 0;
+#X array sample-table 44104 float 0;
+#X coords 0 1.02 44103 -1.02 200 130 1;
+#X restore 585 20 graph;
+#X obj 37 185 tabread4~ sample-table;
+#X obj 37 150 line~;
+#X obj 37 101 * 441;
+#X floatatom 37 47 0 0 100 0 - - -;
+#X obj 37 125 pack 0 100;
+#X text 102 13 SCRATCH MACHINE;
+#X text 72 48 <-- read point in 100ths of a second;
+#X text 94 101 convert to SAMPLES (441 samples in 0.01 sec);
+#X obj 405 235 loadbang;
+#X text 246 174 read from the table;
+#X text 237 192 (the input is the index in samples);
+#X text 16 482 For more on reading and writing soundfiles to tables
+\, setting their lengths \, etc \, see "arrays" in the "control examples"
+series.;
+#X text 14 355 This patch introduces the "tabread4~" object \, which
+reads audio samples out of a floating-point array \, often called a
+"sample table." The input is the index of the sample to read \, counting
+from zero. The output is calculated using 4-point cubic interpolation
+\, which is adequate for most purposes. Because of the interpolation
+scheme \, tabread4~'s input cannot be less than one or greater than
+the table length minus two.;
+#X text 17 539 Fanatics take note: if you want really high-fidelity
+sampling \, use a high-quality resampling program to up-sample your
+soundfile to 88200 to drastically reduce interpolation error.;
+#X text 591 173 (one second plus three extra;
+#X text 593 192 for 4-point interpolation);
+#X text 385 304 message to read a soundfile into the table (automatically
+sent when you load this patch by the "loadbang" object.);
+#X text 84 150 convert smoothly to audio signal;
+#X text 84 62 (range is 0-100.) YOU ONLY HEAR OUTPUT;
+#X text 85 78 WHEN THIS IS 0-100 AND ACTIVELY CHANGING.;
+#X text 596 589 updated for Pd version 0.33;
+#X text 584 151 --- 44103 samples ---;
+#X msg 405 259 read ../sound/voice.wav sample-table;
+#X obj 405 284 soundfiler;
+#X obj 36 249 output~;
+#X connect 0 0 27 0;
+#X connect 0 0 27 1;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 5 0 7 0;
+#X connect 6 0 5 0;
+#X connect 7 0 4 0;
+#X connect 11 0 25 0;
+#X connect 25 0 26 0;
diff --git a/pd/doc/3.audio.examples/B08.sampler.loop.pd b/pd/doc/3.audio.examples/B08.sampler.loop.pd
new file mode 100644
index 00000000..db2362e8
--- /dev/null
+++ b/pd/doc/3.audio.examples/B08.sampler.loop.pd
@@ -0,0 +1,64 @@
+#N canvas 143 17 992 621 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array tabread4-out 44100 float 0;
+#X coords 0 1.02 44100 -1.02 200 130 1;
+#X restore 632 200 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array table17 44103 float 0;
+#X coords 0 1.02 44103 -1.02 200 130 1;
+#X restore 631 14 graph;
+#X obj 568 496 loadbang;
+#X obj 65 277 tabwrite~ tabread4-out;
+#X obj 34 308 hip~ 5;
+#X floatatom 34 54 0 0 0 0 - - -;
+#X text 241 215 read from the table;
+#X text 49 11 LOOPING SAMPLER;
+#X text 83 54 <-- frequency (Hz.);
+#X floatatom 65 107 0 0 0 0 - - -;
+#X obj 65 133 * 441;
+#X obj 34 160 *~ 0;
+#X obj 34 187 +~ 1;
+#X text 110 248 <-- click to display output;
+#X obj 34 80 phasor~ 0;
+#X msg 65 245 bang;
+#X text 110 108 <-- chunk size (100ths of a second);
+#X obj 561 395 adc~ 1;
+#X msg 575 422 bang;
+#X text 615 423 <-- click here to record your own sample;
+#X text 678 501 v-- re-read the original sample;
+#X text 14 540 In this patch you will frequently hear discontinuities
+at the looping point. If you're working in a studio \, you can sometimes
+find "good" loop points for samples. Another approach \, better for
+live situations \, is shown in the next patch.;
+#X text 80 159 <-- readjust phase for range 0 - (chunk size);
+#X text 79 187 <-- add one to avoid beginning of table;
+#X obj 568 549 soundfiler;
+#X text 629 153 ---- 44103 samples ----;
+#X text 643 336 ---- 1 second ------;
+#X obj 34 335 output~;
+#X text 742 591 updated for Pd version 0.37;
+#X obj 34 216 tabread4~ table17;
+#X obj 562 455 tabwrite~ table17;
+#X msg 568 524 read ../sound/voice.wav table17;
+#X text 16 409 This is a looping sampler in which you specify the number
+of loops per second (the frequency) and the size of the chunk to loop.
+If the frequency is less than about 20 \, you will hear repetition
+and the chunk size will sound like transposition. For frequencies above
+50 or so \, you hear a tone whose timbre is controlled by the chunk
+size (best kept below 10 or so.) Remember you can use the "shift" key
+on number boxes to make fine adjustments.;
+#X connect 2 0 31 0;
+#X connect 4 0 27 0;
+#X connect 4 0 27 1;
+#X connect 5 0 14 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 1;
+#X connect 11 0 12 0;
+#X connect 12 0 29 0;
+#X connect 14 0 11 0;
+#X connect 15 0 3 0;
+#X connect 17 0 30 0;
+#X connect 18 0 30 0;
+#X connect 29 0 4 0;
+#X connect 29 0 3 0;
+#X connect 31 0 24 0;
diff --git a/pd/doc/3.audio.examples/B09.sampler.loop.smooth.pd b/pd/doc/3.audio.examples/B09.sampler.loop.smooth.pd
new file mode 100644
index 00000000..818d9206
--- /dev/null
+++ b/pd/doc/3.audio.examples/B09.sampler.loop.smooth.pd
@@ -0,0 +1,72 @@
+#N canvas 75 15 973 599 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array cos-output 44100 float 0;
+#X coords 0 1.02 44100 -1.02 200 130 1;
+#X restore 724 191 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array table18 44103 float 0;
+#X coords 0 1.02 44103 -1.02 200 130 1;
+#X restore 721 16 graph;
+#X obj 584 491 loadbang;
+#X obj 45 249 hip~ 5;
+#X floatatom 46 50 0 0 0 0 - - -;
+#X text 85 49 <-- frequency (Hz.);
+#X floatatom 132 87 0 0 0 0 - - -;
+#X obj 132 114 * 441;
+#X obj 110 163 +~ 1;
+#X text 171 86 <-- chunk size (100ths of a second);
+#X obj 584 404 adc~ 1;
+#X msg 599 429 bang;
+#X text 40 9 ENVELOPING YOUR LOOPING SAMPLER;
+#X obj 45 139 -~ 0.5;
+#X obj 45 189 cos~;
+#X obj 45 222 *~;
+#X obj 584 545 soundfiler;
+#X text 736 148 -- 44103 samples ---;
+#X text 727 322 ----- 1 second ------;
+#X obj 46 77 phasor~;
+#X obj 45 164 *~ 0.5;
+#X obj 44 281 output~;
+#X obj 110 138 *~;
+#X text 28 362 Here we apply an amplitude envelope to protect against
+discontinuities at the loop point. The envelope is just a cosine wave
+from -90 degrees to +90 degrees \, (-pi/2 to pi/2 radians) \, i.e.
+\, the part that is zero or positive in sign. The "cos~" object's input
+is in cycles (units of 2pi radians) so -1/4 to +1/4 addresses the desired
+part of the waveform.;
+#X obj 167 247 tabwrite~ cos-output;
+#X obj 167 223 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 188 220 <-- click to graph envelope;
+#X text 28 476 To see the envelope \, put the phasor on 2 Hz or so
+\, click the "graph" button \, and look at "cos-output." This is multiplied
+by the tabread4~ output so that it doesn't click when the phase wraps
+around.;
+#X text 26 545 It is possible to get much more control over the shape
+of the envelope \, but this will be taken up later.;
+#X obj 110 189 tabread4~ table18;
+#X obj 584 456 tabwrite~ table18;
+#X msg 584 520 read ../sound/voice.wav table18;
+#X text 641 430 <-- click here to record to table;
+#X text 675 499 v-- re-read the original sound;
+#X text 708 565 updated for Pd version 0.37;
+#X connect 2 0 31 0;
+#X connect 3 0 21 0;
+#X connect 3 0 21 1;
+#X connect 4 0 19 0;
+#X connect 6 0 7 0;
+#X connect 7 0 22 1;
+#X connect 8 0 29 0;
+#X connect 10 0 30 0;
+#X connect 11 0 30 0;
+#X connect 13 0 20 0;
+#X connect 14 0 15 0;
+#X connect 14 0 24 0;
+#X connect 15 0 3 0;
+#X connect 19 0 13 0;
+#X connect 19 0 22 0;
+#X connect 20 0 14 0;
+#X connect 22 0 8 0;
+#X connect 25 0 24 0;
+#X connect 29 0 15 1;
+#X connect 31 0 16 0;
diff --git a/pd/doc/3.audio.examples/B10.sampler.scratch.pd b/pd/doc/3.audio.examples/B10.sampler.scratch.pd
new file mode 100644
index 00000000..38c67b76
--- /dev/null
+++ b/pd/doc/3.audio.examples/B10.sampler.scratch.pd
@@ -0,0 +1,83 @@
+#N canvas 53 232 936 654 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array table19 44103 float 0;
+#X coords 0 1.02 44100 -1.02 200 130 1;
+#X restore 680 8 graph;
+#X obj 40 382 hip~ 5;
+#X floatatom 99 51 0 0 0 0 - - -;
+#X text 146 50 <-- frequency (Hz.);
+#X floatatom 129 106 0 0 0 0 - - -;
+#X obj 129 135 * 441;
+#X obj 100 158 *~ 0;
+#X obj 100 181 +~ 1;
+#X msg 194 281 bang;
+#X text 164 106 <-- chunk size (100ths of a second);
+#X obj 591 369 adc~ 1;
+#X obj 591 395 hip~ 5;
+#X msg 609 423 bang;
+#N canvas 0 0 450 300 graph2 0;
+#X array graph19 44100 float 0;
+#X coords 0 44100 44100 0 200 130 1;
+#X restore 681 196 graph;
+#X obj 40 356 *~;
+#X obj 123 276 line~;
+#X obj 123 228 * 441;
+#X floatatom 123 205 0 0 0 0 - - -;
+#X obj 123 252 pack 0 100;
+#X obj 101 310 +~;
+#X text 34 474 In this patch we can loop in any "window" of the input
+sample. The "read point" (0-100) gives the starting point of the window
+and "chunk" is its size (both in 100ths of a second.) Try \, for example
+\, frequency 4 \, sharpness 10 \, chunk size 25 \, and vary the read
+point from -25 to 100 \, listening to the result.;
+#X text 242 281 <-- graph table index;
+#X text 684 337 ----- 1 second ------;
+#X obj 595 490 loadbang;
+#X text 631 514 v-- re-read the original sample;
+#X obj 605 559 soundfiler;
+#X text 678 147 ---- 44103 samples ---;
+#X obj 591 455 tabwrite~ table19;
+#X msg 605 535 read ../sound/voice.wav table19;
+#X text 688 628 updated for Pd version 0.37;
+#X msg 595 585 \; graph19 ylabel 48000 0 44100;
+#X obj 39 103 -~ 0.5;
+#X obj 99 76 phasor~;
+#X obj 39 127 *~ 0.5;
+#X obj 39 150 cos~;
+#X text 157 206 <-- read point (100ths of a second);
+#X obj 41 406 output~;
+#X text 651 422 <-- record;
+#X text 36 13 ENVELOPING THE LOOPING SAMPLER;
+#X text 37 574 You should hear some doppler shift as you change the
+read point. To see why \, click on "graph table index" and quickly
+start changing the read point--- you should see entertaining pictures
+in "table-index". The next patch shows how to prevent this if you wish
+to.;
+#X obj 100 336 tabread4~ table19;
+#X obj 194 307 tabwrite~ graph19;
+#X connect 1 0 36 0;
+#X connect 2 0 32 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 1;
+#X connect 6 0 7 0;
+#X connect 7 0 19 0;
+#X connect 8 0 41 0;
+#X connect 10 0 11 0;
+#X connect 11 0 27 0;
+#X connect 12 0 27 0;
+#X connect 14 0 1 0;
+#X connect 15 0 19 1;
+#X connect 16 0 18 0;
+#X connect 17 0 16 0;
+#X connect 18 0 15 0;
+#X connect 19 0 40 0;
+#X connect 19 0 41 0;
+#X connect 23 0 30 0;
+#X connect 23 0 28 0;
+#X connect 28 0 25 0;
+#X connect 31 0 33 0;
+#X connect 32 0 6 0;
+#X connect 32 0 31 0;
+#X connect 33 0 34 0;
+#X connect 34 0 14 0;
+#X connect 40 0 14 1;
diff --git a/pd/doc/3.audio.examples/B11.sampler.nodoppler.pd b/pd/doc/3.audio.examples/B11.sampler.nodoppler.pd
new file mode 100644
index 00000000..1ec362ac
--- /dev/null
+++ b/pd/doc/3.audio.examples/B11.sampler.nodoppler.pd
@@ -0,0 +1,85 @@
+#N canvas 177 116 924 622 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array table20 44103 float 0;
+#X coords 0 1.02 44100 -1.02 200 130 1;
+#X restore 631 10 graph;
+#X obj 582 447 loadbang;
+#X obj 13 425 hip~ 5;
+#X floatatom 87 49 0 0 0 0 - - -;
+#X text 126 48 <-- frequency (Hz.);
+#X floatatom 150 108 0 0 0 0 - - -;
+#X obj 150 133 * 441;
+#X obj 50 220 +~ 1;
+#X obj 87 73 phasor~ 0;
+#X msg 175 273 bang;
+#X text 189 107 <-- chunk size (100ths of a second);
+#X obj 576 343 adc~ 1;
+#X obj 576 367 hip~ 5;
+#X msg 591 390 bang;
+#X text 630 464 v-- re-read the original sample;
+#N canvas 0 0 450 300 graph2 0;
+#X array graph20 44100 float 0;
+#X coords 0 44100 44100 0 200 130 1;
+#X restore 633 179 graph;
+#X obj 13 401 *~;
+#X obj 72 308 line~;
+#X obj 149 242 * 441;
+#X floatatom 149 218 0 0 0 0 - - -;
+#X obj 72 284 pack 0 100;
+#X text 184 217 <-- read point in 100ths of a second;
+#X obj 51 356 +~;
+#X text 218 272 <-- graph table index;
+#X obj 72 332 samphold~;
+#X obj 74 170 samphold~;
+#X obj 51 196 *~;
+#X text 643 315 ----- 1 second ------;
+#X text 631 144 ---- 44103 samples ---;
+#X obj 591 508 soundfiler;
+#X text 21 8 SLIDING STABLE LOOPS WITHOUT DOPPLER SHIFT;
+#X msg 582 534 \; graph20 ylabel 48000 0 44100;
+#X text 631 390 <-- record;
+#X obj 13 451 output~;
+#X obj 12 103 -~ 0.5;
+#X obj 12 127 *~ 0.5;
+#X obj 12 150 cos~;
+#X obj 175 353 tabwrite~ graph20;
+#X obj 51 381 tabread4~ table20;
+#X obj 576 417 tabwrite~ table20;
+#X msg 591 484 read ../sound/voice.wav table20;
+#X text 11 518 This example differs from the previous one in having
+samphold~ objects which allow the chunk size and especially the read
+point to change only at points where the phase wraps around. This removes
+signal discontinuities (when the chunk size changes) and doppler shift
+when the read point is changing.;
+#X text 652 592 updated for Pd version 0.37;
+#X connect 1 0 31 0;
+#X connect 1 0 40 0;
+#X connect 2 0 33 0;
+#X connect 2 0 33 1;
+#X connect 3 0 8 0;
+#X connect 5 0 6 0;
+#X connect 6 0 25 0;
+#X connect 7 0 22 0;
+#X connect 8 0 24 1;
+#X connect 8 0 25 1;
+#X connect 8 0 26 0;
+#X connect 8 0 34 0;
+#X connect 9 0 37 0;
+#X connect 11 0 12 0;
+#X connect 12 0 39 0;
+#X connect 13 0 39 0;
+#X connect 16 0 2 0;
+#X connect 17 0 24 0;
+#X connect 18 0 20 0;
+#X connect 19 0 18 0;
+#X connect 20 0 17 0;
+#X connect 22 0 37 0;
+#X connect 22 0 38 0;
+#X connect 24 0 22 1;
+#X connect 25 0 26 1;
+#X connect 26 0 7 0;
+#X connect 34 0 35 0;
+#X connect 35 0 36 0;
+#X connect 36 0 16 0;
+#X connect 38 0 16 1;
+#X connect 40 0 29 0;
diff --git a/pd/doc/3.audio.examples/B12.sampler.transpose.pd b/pd/doc/3.audio.examples/B12.sampler.transpose.pd
new file mode 100644
index 00000000..fc7a7d14
--- /dev/null
+++ b/pd/doc/3.audio.examples/B12.sampler.transpose.pd
@@ -0,0 +1,109 @@
+#N canvas 107 88 930 596 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array table21 44103 float 0;
+#X coords 0 1.02 44100 -1.02 200 130 1;
+#X restore 645 291 graph;
+#X obj 467 506 loadbang;
+#X obj 19 508 hip~ 5;
+#X floatatom 10 254 0 0 0 0 - - -;
+#X obj 10 279 * 441;
+#X obj 10 401 +~ 1;
+#X text 47 253 <-- chunk size (100ths of a second);
+#X obj 471 402 adc~ 1;
+#X obj 471 427 hip~ 5;
+#X msg 486 449 bang;
+#X obj 44 482 *~;
+#X obj 106 404 line~;
+#X obj 106 354 * 441;
+#X floatatom 106 329 0 0 0 0 - - -;
+#X obj 106 379 pack 0 100;
+#X text 152 331 <-- read point in 100ths of a second;
+#X obj 44 433 +~;
+#X obj 106 429 samphold~;
+#X obj 10 329 samphold~;
+#X obj 10 304 sig~;
+#X obj 10 376 *~;
+#X text 18 5 CALCULATING LOOP FREQUENCY AS FUNCTION OF TRANSPOSITION
+;
+#X obj 124 485 r~ phase;
+#X obj 10 204 s~ phase;
+#X obj 68 304 r~ phase;
+#X obj 26 351 r~ phase;
+#X obj 164 405 r~ phase;
+#X obj 151 299 s chunk-size;
+#X floatatom 10 50 0 0 0 0 - - -;
+#X text 48 51 <-- transposition (10ths of a halftone);
+#X obj 151 274 * 0.01;
+#X text 264 287 chunk size;
+#X text 264 309 in seconds;
+#X obj 21 105 r chunk-size;
+#X obj 21 130 t b f;
+#X obj 10 154 /;
+#X text 80 131 divide speed change by chunk;
+#X text 78 152 size to get loop frequency;
+#X text 382 75 The transposition is frequency in Hz. divided by chunk
+size in seconds. This patch calculates the loop frequency as a function
+of desired transposition;
+#X text 384 126 Notice now that we get Doppler effects when the chunk
+size changes. You can suppress that if you don't want it \, by converting
+the chunk size to an audio signal \, sampling and holding it. But then
+there would be more work to deal with very low frequencies never triggering
+the sample and hold...;
+#X obj 467 560 soundfiler;
+#X obj 10 27 loadbang;
+#X obj 124 509 -~ 0.5;
+#X obj 124 533 *~ 0.5;
+#X obj 124 556 cos~;
+#X obj 19 533 output~;
+#X obj 44 458 tabread4~ table21;
+#X text 527 449 <-- record;
+#X text 560 513 v-- re-read original table;
+#X text 682 572 updated for Pd version 0.37;
+#X text 647 425 --- 44103 samples ---;
+#X obj 10 75 expr pow(2 \, $f1/120);
+#X text 199 75 speed change;
+#X text 387 208 You might also want to have a way to retrigger the
+loop to sync it with some other process. By the time we had all this
+built the patch would be fairly involved. For now \, we'll move on
+to the next topic...;
+#X obj 10 178 phasor~;
+#X obj 471 476 tabwrite~ table21;
+#X msg 467 533 read ../sound/voice.wav table21;
+#X connect 1 0 56 0;
+#X connect 2 0 45 0;
+#X connect 2 0 45 1;
+#X connect 3 0 4 0;
+#X connect 3 0 30 0;
+#X connect 4 0 19 0;
+#X connect 5 0 16 0;
+#X connect 7 0 8 0;
+#X connect 8 0 55 0;
+#X connect 9 0 55 0;
+#X connect 10 0 2 0;
+#X connect 11 0 17 0;
+#X connect 12 0 14 0;
+#X connect 13 0 12 0;
+#X connect 14 0 11 0;
+#X connect 16 0 46 0;
+#X connect 17 0 16 1;
+#X connect 18 0 20 0;
+#X connect 19 0 18 0;
+#X connect 20 0 5 0;
+#X connect 22 0 42 0;
+#X connect 24 0 18 1;
+#X connect 25 0 20 1;
+#X connect 26 0 17 1;
+#X connect 28 0 51 0;
+#X connect 30 0 27 0;
+#X connect 33 0 34 0;
+#X connect 34 0 35 0;
+#X connect 34 1 35 1;
+#X connect 35 0 54 0;
+#X connect 41 0 28 0;
+#X connect 42 0 43 0;
+#X connect 43 0 44 0;
+#X connect 44 0 10 1;
+#X connect 46 0 10 0;
+#X connect 51 0 35 0;
+#X connect 54 0 23 0;
+#X connect 56 0 40 0;
diff --git a/pd/doc/3.audio.examples/B13.sampler.overlap.pd b/pd/doc/3.audio.examples/B13.sampler.overlap.pd
new file mode 100644
index 00000000..35acc48b
--- /dev/null
+++ b/pd/doc/3.audio.examples/B13.sampler.overlap.pd
@@ -0,0 +1,158 @@
+#N canvas 28 47 748 713 12;
+#X obj 19 511 hip~ 5;
+#X floatatom 25 38 0 0 100 0 - - -;
+#X obj 25 63 * 441;
+#X obj 20 380 +~ 1;
+#X text 69 35 <-- chunk size (100ths of a second);
+#X obj 20 458 *~;
+#X obj 26 211 line~;
+#X obj 26 161 * 441;
+#X floatatom 26 136 0 0 100 0 - - -;
+#X obj 26 186 pack 0 100;
+#X text 60 137 <-- read point in 100ths of a second;
+#X obj 20 409 +~;
+#X obj 76 408 samphold~;
+#X obj 20 308 samphold~;
+#X obj 20 355 *~;
+#X obj 185 369 r~ phase;
+#X obj 418 210 s~ phase;
+#X obj 108 308 r~ phase;
+#X obj 42 332 r~ phase;
+#X obj 96 383 r~ phase;
+#X obj 77 82 s chunk-size;
+#X floatatom 418 56 0 0 0 0 - - -;
+#X obj 77 57 * 0.01;
+#X text 189 58 chunk size;
+#X text 189 80 in seconds;
+#X obj 429 111 r chunk-size;
+#X obj 429 136 t b f;
+#X obj 418 160 /;
+#X obj 418 33 loadbang;
+#X obj 185 393 -~ 0.5;
+#X obj 185 417 *~ 0.5;
+#X obj 185 440 cos~;
+#X obj 19 536 output~;
+#X text 486 684 updated for Pd version 0.37;
+#X obj 418 81 expr pow(2 \, $f1/120);
+#X text 607 81 speed change;
+#X obj 418 184 phasor~;
+#X text 18 5 TWO OVERLAPPING SAMPLE READ ELEMENTS;
+#N canvas 30 567 660 275 table 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array table22 44103 float 0;
+#X coords 0 1.02 44100 -1.02 200 130 1;
+#X restore 442 61 graph;
+#X text 444 195 --- 44103 samples ---;
+#X obj 41 148 loadbang;
+#X obj 45 44 adc~ 1;
+#X obj 45 69 hip~ 5;
+#X msg 60 91 bang;
+#X obj 41 202 soundfiler;
+#X text 101 91 <-- record;
+#X text 134 155 v-- re-read original table;
+#X obj 45 118 tabwrite~ table22;
+#X msg 41 175 read ../sound/voice.wav table22;
+#X connect 2 0 10 0;
+#X connect 3 0 4 0;
+#X connect 4 0 9 0;
+#X connect 5 0 9 0;
+#X connect 10 0 6 0;
+#X restore 567 327 pd table;
+#X obj 25 110 s chunk-size-samples;
+#X text 211 112 ... and in samples;
+#X obj 26 234 s~ read-pt;
+#X obj 77 360 r~ read-pt;
+#X obj 505 203 +~ 0.5;
+#X obj 506 229 wrap~;
+#X obj 506 254 s~ phase2;
+#X obj 20 283 r chunk-size-samples;
+#X obj 274 391 +~ 1;
+#X obj 274 469 *~;
+#X obj 274 420 +~;
+#X obj 329 419 samphold~;
+#X obj 274 319 samphold~;
+#X obj 274 366 *~;
+#X obj 439 404 -~ 0.5;
+#X obj 439 428 *~ 0.5;
+#X obj 439 451 cos~;
+#X obj 330 371 r~ read-pt;
+#X obj 274 294 r chunk-size-samples;
+#X obj 363 320 r~ phase2;
+#X obj 296 343 r~ phase2;
+#X obj 439 380 r~ phase2;
+#X obj 339 394 r~ phase2;
+#X obj 19 487 +~;
+#X text 453 56 <-- transposition \, halftones/10;
+#X text 456 159 loop frequency;
+#X text 566 190 second phase signal;
+#X text 566 210 out of phase from;
+#X text 565 231 first one;
+#X text 70 265 copy 1;
+#X text 327 274 copy 2;
+#X text 118 503 Here is the previous patch modified to use two copies
+of the sample reader \, 180 degrees out of phase. The second sawtooth
+signal is derived from the first one by adding a constant (0.5) and
+wrapping the result to fit again between zero and one. The result is
+the "phase2" signal.;
+#X text 119 584 The computation of "chunk-size-samples" (as a message)
+and "read-pt" (an audio signal) is the same for both copies and is
+separated out at top left. At top right is the same loop frequency
+calculation as before.;
+#X text 120 654 Finally \, the two copies' outputs are added and the
+result sent to the audio output.;
+#X obj 20 434 tabread4~ table22;
+#X obj 274 445 tabread4~ table22;
+#X connect 0 0 32 0;
+#X connect 0 0 32 1;
+#X connect 1 0 2 0;
+#X connect 1 0 22 0;
+#X connect 2 0 39 0;
+#X connect 3 0 11 0;
+#X connect 5 0 62 0;
+#X connect 6 0 41 0;
+#X connect 7 0 9 0;
+#X connect 8 0 7 0;
+#X connect 9 0 6 0;
+#X connect 11 0 73 0;
+#X connect 12 0 11 1;
+#X connect 13 0 14 0;
+#X connect 14 0 3 0;
+#X connect 15 0 29 0;
+#X connect 17 0 13 1;
+#X connect 18 0 14 1;
+#X connect 19 0 12 1;
+#X connect 21 0 34 0;
+#X connect 22 0 20 0;
+#X connect 25 0 26 0;
+#X connect 26 0 27 0;
+#X connect 26 1 27 1;
+#X connect 27 0 36 0;
+#X connect 28 0 21 0;
+#X connect 29 0 30 0;
+#X connect 30 0 31 0;
+#X connect 31 0 5 1;
+#X connect 34 0 27 0;
+#X connect 36 0 16 0;
+#X connect 36 0 43 0;
+#X connect 42 0 12 0;
+#X connect 43 0 44 0;
+#X connect 44 0 45 0;
+#X connect 46 0 13 0;
+#X connect 47 0 49 0;
+#X connect 48 0 62 1;
+#X connect 49 0 74 0;
+#X connect 50 0 49 1;
+#X connect 51 0 52 0;
+#X connect 52 0 47 0;
+#X connect 53 0 54 0;
+#X connect 54 0 55 0;
+#X connect 55 0 48 1;
+#X connect 56 0 50 0;
+#X connect 57 0 51 0;
+#X connect 58 0 51 1;
+#X connect 59 0 52 1;
+#X connect 60 0 53 0;
+#X connect 61 0 50 1;
+#X connect 62 0 0 0;
+#X connect 73 0 5 0;
+#X connect 74 0 48 0;
diff --git a/pd/doc/3.audio.examples/B14.sampler.rockafella.pd b/pd/doc/3.audio.examples/B14.sampler.rockafella.pd
new file mode 100644
index 00000000..20416b6b
--- /dev/null
+++ b/pd/doc/3.audio.examples/B14.sampler.rockafella.pd
@@ -0,0 +1,166 @@
+#N canvas 123 36 683 718 12;
+#X obj 6 529 hip~ 5;
+#X floatatom 8 47 4 0 100 0 - - -;
+#X obj 7 476 *~;
+#X floatatom 7 123 0 0 200 0 - - -;
+#X obj 7 378 +~;
+#X obj 6 330 samphold~;
+#X obj 7 354 *~;
+#X obj 172 385 r~ phase;
+#X obj 357 210 s~ phase;
+#X obj 94 331 r~ phase;
+#X obj 42 355 r~ phase;
+#X obj 8 90 s chunk-size;
+#X floatatom 357 42 0 0 0 0 - - -;
+#X text 124 82 chunk size;
+#X text 121 96 in seconds;
+#X obj 369 79 r chunk-size;
+#X obj 369 104 t b f;
+#X obj 172 409 -~ 0.5;
+#X obj 172 433 *~ 0.5;
+#X obj 172 456 cos~;
+#X obj 7 560 output~;
+#X text 417 698 updated for Pd version 0.37;
+#X obj 357 184 phasor~;
+#N canvas 30 567 660 275 table 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array table23 44103 float 0;
+#X coords 0 1.02 44100 -1.02 200 130 1;
+#X restore 442 61 graph;
+#X text 444 195 --- 44103 samples ---;
+#X obj 41 148 loadbang;
+#X obj 45 44 adc~ 1;
+#X obj 45 69 hip~ 5;
+#X msg 60 91 bang;
+#X obj 41 202 soundfiler;
+#X text 101 91 <-- record;
+#X text 134 155 v-- re-read original table;
+#X obj 45 118 tabwrite~ table23;
+#X msg 41 175 read ../sound/voice.wav table23;
+#X connect 2 0 10 0;
+#X connect 3 0 4 0;
+#X connect 4 0 9 0;
+#X connect 5 0 9 0;
+#X connect 10 0 6 0;
+#X restore 558 460 pd table;
+#X obj 7 263 s~ read-pt;
+#X obj 45 378 r~ read-pt;
+#X obj 444 203 +~ 0.5;
+#X obj 445 229 wrap~;
+#X obj 445 254 s~ phase2;
+#X obj 6 505 +~;
+#X text 391 43 <-- transposition \, halftones/10;
+#X obj 8 67 * 0.001;
+#X obj 7 215 phasor~;
+#X obj 7 402 *~ 44100;
+#X obj 7 452 tabread4~ table23;
+#X obj 6 305 r chunk-size;
+#X obj 6 428 +~ 1;
+#X floatatom 365 161 5 0 0 0 - - -;
+#X obj 15 169 s precession;
+#X obj 482 103 t b f;
+#X obj 482 78 r precession;
+#X obj 7 146 * 0.01;
+#X obj 258 485 *~;
+#X obj 258 387 +~;
+#X obj 257 339 samphold~;
+#X obj 258 363 *~;
+#X obj 423 418 -~ 0.5;
+#X obj 423 442 *~ 0.5;
+#X obj 423 465 cos~;
+#X obj 296 387 r~ read-pt;
+#X obj 258 411 *~ 44100;
+#X obj 258 461 tabread4~ table23;
+#X obj 257 314 r chunk-size;
+#X obj 257 437 +~ 1;
+#X obj 345 340 r~ phase2;
+#X obj 293 364 r~ phase2;
+#X obj 423 394 r~ phase2;
+#X text 37 123 <-- precession \, percent;
+#X obj 8 3 loadbang;
+#X text 158 3 TIME COMPRESSION/EXPANSION BY LOOPED SAMPLING;
+#X text 111 529 Here \, rather than ask you to push the read pointer
+back and forth in the sample \, we use a phasor~. This makes it possible
+to avoid the samphold~ on the read pointer (r~ read-pt) \, since \,
+knowing the precession \, we can correct for it in computing the frequency
+of the original phasor~ at right.;
+#X text 111 626 We've changed the control for "chunk size" to milliseconds
+for added convenience \, and delayed multiplying sample location by
+the sample rate (44100) until the last moment \, so that calculations
+using "read-pt" and "chunk size" can be in the same units (seconds.)
+;
+#X msg 8 25 25;
+#X floatatom 139 192 4 0 900 0 - - -;
+#X obj 139 212 * 0.001;
+#X msg 139 170 900;
+#X text 48 47 <-- chunk size (msec);
+#X obj 357 136 expr (pow(2 \, $f1/120)-$f3)/$f2;
+#X obj 139 237 t b f;
+#X obj 139 146 loadbang;
+#X text 182 188 <-- loop length;
+#X text 223 203 (msec);
+#X obj 7 239 *~;
+#X obj 7 191 /;
+#X connect 0 0 20 0;
+#X connect 0 0 20 1;
+#X connect 1 0 31 0;
+#X connect 2 0 29 0;
+#X connect 3 0 41 0;
+#X connect 4 0 33 0;
+#X connect 5 0 6 0;
+#X connect 6 0 4 0;
+#X connect 7 0 17 0;
+#X connect 9 0 5 1;
+#X connect 10 0 6 1;
+#X connect 12 0 67 0;
+#X connect 15 0 16 0;
+#X connect 16 0 67 0;
+#X connect 16 1 67 1;
+#X connect 17 0 18 0;
+#X connect 18 0 19 0;
+#X connect 19 0 2 1;
+#X connect 22 0 8 0;
+#X connect 22 0 26 0;
+#X connect 25 0 4 1;
+#X connect 26 0 27 0;
+#X connect 27 0 28 0;
+#X connect 29 0 0 0;
+#X connect 31 0 11 0;
+#X connect 32 0 72 0;
+#X connect 33 0 36 0;
+#X connect 34 0 2 0;
+#X connect 35 0 5 0;
+#X connect 36 0 34 0;
+#X connect 39 0 67 0;
+#X connect 39 1 67 2;
+#X connect 40 0 39 0;
+#X connect 41 0 38 0;
+#X connect 41 0 73 0;
+#X connect 42 0 29 1;
+#X connect 43 0 50 0;
+#X connect 44 0 45 0;
+#X connect 45 0 43 0;
+#X connect 46 0 47 0;
+#X connect 47 0 48 0;
+#X connect 48 0 42 1;
+#X connect 49 0 43 1;
+#X connect 50 0 53 0;
+#X connect 51 0 42 0;
+#X connect 52 0 44 0;
+#X connect 53 0 51 0;
+#X connect 54 0 44 1;
+#X connect 55 0 45 1;
+#X connect 56 0 46 0;
+#X connect 58 0 62 0;
+#X connect 62 0 1 0;
+#X connect 63 0 64 0;
+#X connect 64 0 68 0;
+#X connect 64 0 72 1;
+#X connect 65 0 63 0;
+#X connect 67 0 22 0;
+#X connect 67 0 37 0;
+#X connect 68 0 73 0;
+#X connect 68 1 73 1;
+#X connect 69 0 65 0;
+#X connect 72 0 24 0;
+#X connect 73 0 32 0;
diff --git a/pd/doc/3.audio.examples/C01.nyquist.pd b/pd/doc/3.audio.examples/C01.nyquist.pd
new file mode 100644
index 00000000..256da0e3
--- /dev/null
+++ b/pd/doc/3.audio.examples/C01.nyquist.pd
@@ -0,0 +1,102 @@
+#N canvas 601 188 580 659 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array table24 259 float 1;
+#A 0 -0.294693 0 0.294693 0.4 0.28948 0.10749 0.022875 0.0789655 0.181673
+0.218249 0.171348 0.115564 0.119192 0.169863 0.201356 0.178657 0.137857
+0.138353 0.188891 0.23571 0.22487 0.164534 0.115848 0.125265 0.176634
+0.214361 0.205655 0.169043 0.14204 0.134157 0.124033 0.0997798 0.0859507
+0.118173 0.195202 0.270956 0.301868 0.293569 0.285908 0.289835 0.256276
+0.128881 -0.0684912 -0.215994 -0.195335 -0.0145421 0.174701 0.203986
+0.0451069 -0.159794 -0.231026 -0.119011 0.0575033 0.135323 0.0628509
+-0.0665307 -0.124779 -0.0776696 0.000279083 0.0247376 -0.00546273 -0.0222151
+0.017933 0.0755681 0.0749102 4.97367e-06 -0.0729564 -0.0490464 0.0834901
+0.232853 0.286943 0.213202 0.0759584 -0.0357248 -0.0863297 -0.101697
+-0.115455 -0.125625 -0.107127 -0.0530433 0.012152 0.0608637 0.0902219
+0.111597 0.119683 0.0910146 0.0236817 -0.0326555 -0.0100379 0.100844
+0.216022 0.223032 0.094995 -0.0649958 -0.110291 0.00678482 0.180334
+0.247439 0.144699 -0.0319975 -0.124321 -0.0648335 0.0680811 0.141409
+0.100343 0.00354248 -0.0636733 -0.0891566 -0.131987 -0.227286 -0.316392
+-0.293048 -0.12222 0.100475 0.222686 0.173879 0.0281889 -0.0714016
+-0.0482686 0.0482418 0.108884 0.0773858 -0.00559103 -0.0590099 -0.0454391
+0.00509731 0.0411467 0.0421476 0.0225557 2.40108e-06 -0.0225508 -0.0421448
+-0.0411506 -0.00510821 0.0454302 0.0590142 0.0056084 -0.0773706 -0.108887
+-0.0482625 0.048252 0.0714103 -0.0281575 -0.173853 -0.222693 -0.100517
+0.122172 0.293026 0.316402 0.22731 0.132002 0.0891614 0.063682 -0.00352253
+-0.100324 -0.141412 -0.0681076 0.0648079 0.124324 0.0320316 -0.144663
+-0.247435 -0.180365 -0.00682225 0.110282 0.0650224 -0.0949583 -0.223017
+-0.216038 -0.100873 0.010022 0.0326611 -0.0236657 -0.0910033 -0.119682
+-0.111601 -0.0902271 -0.0608718 -0.0121649 0.0530291 0.107119 0.125625
+0.115458 0.101699 0.0863353 0.0357423 -0.0759289 -0.213176 -0.28694
+-0.232878 -0.0835252 0.0490278 0.0729642 1.4921e-05 -0.0749008 -0.0755765
+-0.0179463 0.0222127 0.00547055 -0.0247352 -0.000292052 0.0776522 0.12478
+0.0665546 -0.062824 -0.135322 -0.0575355 0.118973 0.23102 0.159828
+-0.0450604 -0.203969 -0.174729 0.014495 0.195309 0.21601 0.0685338
+-0.128843 -0.25626 -0.289835 -0.285909 -0.293565 -0.30187 -0.270969
+-0.195221 -0.118186 -0.0859518 -0.0997742 -0.124029 -0.134156 -0.142036
+-0.169035 -0.205649 -0.214364 -0.176646 -0.125273 -0.115843 -0.16452
+-0.22486 -0.235715 -0.188904 -0.13836 -0.137851 -0.178647 -0.201357
+-0.169874 -0.1192 -0.115557 -0.171333 -0.218246 -0.181691 -0.0789875
+-0.0228734 -0.107456 -0.289441 -0.399997 -0.294741 -7.20325e-05 0.294645
+;
+#X coords 0 1.02 258 -1.02 258 130 1;
+#X restore 93 408 graph;
+#X obj 33 288 line~;
+#X msg 33 237 500 \, 1423 4000;
+#X floatatom 41 262 5 0 0 0 - - -;
+#X text 24 556 Synthesis techniques vary in their tendency to make
+foldover. For higher pitched sounds you'll want to try out relatively
+folvover-resistant ones.;
+#X obj 33 342 output~;
+#X obj 201 281 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#N canvas 0 0 618 384 make-tab 0;
+#X obj 13 28 inlet;
+#X obj 99 28 inlet;
+#X obj 183 28 inlet;
+#X obj 255 29 inlet;
+#X msg 38 176 \; table24 sinesum 256 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0
+1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 1 \, normalize
+0.4;
+#X msg 14 277 \; table24 sinesum 256 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 \, normalize
+0.2;
+#X msg 183 101 \; table24 const 0 \, 0 1 1 1 1 1;
+#X msg 255 58 \; table24 const 0;
+#X connect 0 0 5 0;
+#X connect 1 0 4 0;
+#X connect 2 0 6 0;
+#X connect 3 0 7 0;
+#X restore 201 355 pd make-tab;
+#X obj 232 300 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 263 317 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 295 334 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 222 276 sine;
+#X text 252 297 complex;
+#X text 284 314 rectangle;
+#X text 313 332 clear;
+#X obj 33 315 tabosc4~ table24;
+#X text 56 2 THE NYQUIST THEOREM AND FOLDOVER;
+#X text 30 33 WARNING: PLAY THIS QUIETLY TO AVOID UNPLEASANTNESS AND
+POSSIBLE EAR DAMAGE.;
+#X text 29 77 Foldover occurs when you synthesize frequencies greater
+than the Nyquist frequency (half the sample rate). In this example
+\, the fundamental only reaches 1423 \, but the tables contain high
+partials. As the partials sweep upward you hear them reflect off the
+Nyquist frequency. Also \, partials can come into contact with each
+other causing beating. The value of 1423 was chosen to make the beating
+effect especially strong if you're running at a sample rate of 44100
+(the usual one.);
+#X text 330 616 updated for Pd version 0.37;
+#X text 219 245 waveforms:;
+#X connect 1 0 15 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 0;
+#X connect 6 0 7 0;
+#X connect 8 0 7 1;
+#X connect 9 0 7 2;
+#X connect 10 0 7 3;
+#X connect 15 0 5 0;
+#X connect 15 0 5 1;
diff --git a/pd/doc/3.audio.examples/C02.sawtooth-foldover.pd b/pd/doc/3.audio.examples/C02.sawtooth-foldover.pd
new file mode 100644
index 00000000..f52fc548
--- /dev/null
+++ b/pd/doc/3.audio.examples/C02.sawtooth-foldover.pd
@@ -0,0 +1,39 @@
+#N canvas 180 71 562 473 12;
+#X obj 155 348 output~;
+#X text 310 443 updated for Pd version 0.37;
+#X text 56 2 FOLDOVER IN SAWTOOTH WAVES;
+#X obj 154 320 clip~ 0 1;
+#X obj 155 153 mtof;
+#X floatatom 155 131 3 0 0 0 - - -;
+#X obj 155 269 *~ 20;
+#X obj 155 295 -~ 19;
+#X obj 155 177 phasor~;
+#N canvas 0 0 560 183 /SUBPATCH/ 0;
+#X obj 25 74 loadbang;
+#X msg 25 99 61;
+#X obj 25 124 outlet;
+#X text 7 6 This sets the pitch initially to 61 when the patch is first
+opened.;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X restore 155 105 pd;
+#X text 190 130 <--pitch;
+#X obj 164 206 output~;
+#X text 237 205 <--sawtooth amplitude;
+#X text 233 373 <--pulse train amplitude;
+#X text 28 406 We'll explain more about making pulses later on... this
+example is mostly intended as ear training.;
+#X text 19 23 In more ordinary kinds of waveforms \, foldover comes
+across as a "cheap synth" sound. You can hear the foldover clearly
+in the pulse train here \, and less clearly (but still audibly) in
+the straight sawtooth \, especially at high pitches.;
+#X connect 3 0 0 0;
+#X connect 3 0 0 1;
+#X connect 4 0 8 0;
+#X connect 5 0 4 0;
+#X connect 6 0 7 0;
+#X connect 7 0 3 0;
+#X connect 8 0 6 0;
+#X connect 8 0 11 0;
+#X connect 8 0 11 1;
+#X connect 9 0 5 0;
diff --git a/pd/doc/3.audio.examples/C03.zipper.noise.pd b/pd/doc/3.audio.examples/C03.zipper.noise.pd
new file mode 100644
index 00000000..a49f51ad
--- /dev/null
+++ b/pd/doc/3.audio.examples/C03.zipper.noise.pd
@@ -0,0 +1,55 @@
+#N canvas 298 115 555 414 12;
+#X obj 42 349 output~;
+#X text 302 376 updated for Pd version 0.37;
+#X text 56 2 ZIPPER NOISE;
+#X obj 43 321 *~;
+#X obj 125 350 output~;
+#X obj 126 322 *~;
+#X obj 65 262 line;
+#X obj 149 262 line~;
+#N canvas 0 0 450 300 metro 0;
+#X obj 88 39 loadbang;
+#X msg 87 65 1;
+#X obj 87 96 metro 500;
+#X obj 87 131 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 1 1
+;
+#X obj 87 153 sel 0 1;
+#X obj 87 190 outlet;
+#X obj 151 192 outlet;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 4 1 6 0;
+#X restore 65 170 pd metro;
+#X obj 65 198 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X obj 132 199 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X msg 65 219 1 300;
+#X msg 132 221 0 300;
+#X obj 72 290 osc~ 880;
+#X text 30 28 Here is a related issue: if we use a (control) line object
+to change an amplitude \, it sends ramping control messages \, once
+every 20 msec by default. At left we use this to control the amplitude
+of a sinusoid. In effect we're multiplying the sinusoid by a staircase
+signal (50 increments per second.) Using the signal version \, line~
+\, fixes the problem. Line~ outputs a ramp that is incremented every
+sample.;
+#X connect 3 0 0 0;
+#X connect 3 0 0 1;
+#X connect 5 0 4 0;
+#X connect 5 0 4 1;
+#X connect 6 0 3 1;
+#X connect 7 0 5 1;
+#X connect 8 0 9 0;
+#X connect 8 1 10 0;
+#X connect 9 0 11 0;
+#X connect 10 0 12 0;
+#X connect 11 0 6 0;
+#X connect 11 0 7 0;
+#X connect 12 0 6 0;
+#X connect 12 0 7 0;
+#X connect 13 0 3 0;
+#X connect 13 0 5 0;
diff --git a/pd/doc/3.audio.examples/C04.control.to.signal.pd b/pd/doc/3.audio.examples/C04.control.to.signal.pd
new file mode 100644
index 00000000..eed326dd
--- /dev/null
+++ b/pd/doc/3.audio.examples/C04.control.to.signal.pd
@@ -0,0 +1,48 @@
+#N canvas 215 77 561 455 12;
+#X text 14 7 CONVERTING CONTROL TO SIGNALS;
+#X obj 29 350 output~;
+#X obj 107 352 output~;
+#N canvas 0 0 450 300 metro 0;
+#X obj 88 39 loadbang;
+#X msg 87 65 1;
+#X obj 87 131 tgl 15 0 empty empty empty 0 -6 0 8 -262144 -1 -1 0 1
+;
+#X obj 87 153 sel 0 1;
+#X obj 87 190 outlet;
+#X obj 151 192 outlet;
+#X obj 87 96 metro 2;
+#X connect 0 0 1 0;
+#X connect 1 0 6 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 3 1 5 0;
+#X connect 6 0 2 0;
+#X restore 30 242 pd metro;
+#X msg 30 268 1 2;
+#X msg 97 270 0 2;
+#X obj 30 305 line~;
+#X obj 108 306 vline~;
+#X text 13 107 Here we try out line~ and vline~ as triangle wave generators.
+The subpatch is still sending alternating bangs as in the last patch
+\, but now at an audible frequency \, every 2 msec.;
+#X text 17 172 The effect of line~ rounding breakpoints to the nearest
+block (on the order of a millisecond) is that each 4-millisecond-long
+cycle has a different shape. Using vline~ resolves the problem.;
+#X text 385 437 Updated for Pd 0.37;
+#X text 16 411 Sometimes you will want to use vline~ in place of sig~
+for the same reason.;
+#X text 15 27 For controlling amplitudes \, line~ \, with its block-aligned
+breakpoints \, is accurate enough for most purposes. But certain usages
+\, such as this patch \, demand more accuracy. The vline~ object \,
+somewhat more expensive than line~ \, can handle breakpoints to sub-sample
+accuracy.;
+#X connect 3 0 4 0;
+#X connect 3 1 5 0;
+#X connect 4 0 6 0;
+#X connect 4 0 7 0;
+#X connect 5 0 6 0;
+#X connect 5 0 7 0;
+#X connect 6 0 1 0;
+#X connect 6 0 1 1;
+#X connect 7 0 2 0;
+#X connect 7 0 2 1;
diff --git a/pd/doc/3.audio.examples/C05.sampler.oneshot.pd b/pd/doc/3.audio.examples/C05.sampler.oneshot.pd
new file mode 100644
index 00000000..f75d5517
--- /dev/null
+++ b/pd/doc/3.audio.examples/C05.sampler.oneshot.pd
@@ -0,0 +1,84 @@
+#N canvas 34 0 985 746 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array tab28 176403 float 0;
+#X coords 0 1.02 176403 -1.02 200 130 1;
+#X restore 740 126 graph;
+#X obj 577 486 loadbang;
+#X obj 31 340 hip~ 5;
+#X obj 587 345 adc~ 1;
+#X obj 587 375 hip~ 5;
+#X msg 558 306 bang;
+#X text 681 492 v-- re-read the original sample;
+#X text 20 6 ONE-SHOT SAMPLER USING LINE~ AS PHASE;
+#X obj 31 306 *~;
+#X obj 71 279 r cutoff;
+#X obj 31 194 r phase;
+#X msg 24 37 bang;
+#X obj 124 92 delay 5;
+#X text 77 37 <-- play the sample;
+#X msg 24 128 \; cutoff 0 5;
+#X text 34 85 cut the;
+#X text 34 104 sound off;
+#X text 204 77 Wait for the;
+#X text 202 97 cutoff to finish;
+#X text 349 121 set the upper line~ to start;
+#X text 349 140 at the first sample and go;
+#X text 348 161 forever (until the next trigger);
+#X text 18 486 To start a note \, first we have to mute the output
+in case ther's already something playing---otherwise we'll get a click.
+The "cutoff" line~ then takes 5 msec to get to zero. After that amount
+of delay \, we reset the phase to sample number 1 and set it in motion.
+We want the line~ output to increase by 1 each sample of output \,
+so we ask for it to do 4.41e+08 samples in 1e+07 milliseconds.;
+#X text 18 602 The cutoff mechanism is still safe if we happen to ask
+for two notes in under 5 msec. The second request would reset the delay
+\, so that there's no way the delay can possibly fire without the cutoff
+line~ at zero.;
+#X text 596 305 <-- record;
+#X obj 622 405 line~;
+#X obj 587 410 *~;
+#X text 738 267 ------ 4 seconds ------;
+#X obj 655 342 del 3990;
+#X msg 655 370 0 10;
+#X text 706 371 <--stop recording;
+#X text 19 672 We avoid clicking at the end of the table by getting
+the table's own contents to go smoothly to zero. To do this we added
+a level control to the recording patch that cuts off just before the
+recording reaches the end of the table.;
+#X text 576 599 this is.;
+#X text 578 575 My apologies to Jonathan Harvey whose bell;
+#X obj 577 545 soundfiler;
+#X text 19 443 Here's how to make a sampler with a line~ object \,
+instead of a phasor~ \, to generate the read location signal.;
+#X obj 71 306 vline~;
+#X obj 30 369 output~;
+#X obj 31 224 vline~;
+#X obj 558 439 tabwrite~ tab28;
+#X msg 577 516 read ../sound/bell.aiff tab28;
+#X obj 31 254 tabread4~ tab28;
+#X msg 124 127 \; phase 1 \, 4.41e+08 1e+07 \; cutoff 1;
+#X msg 497 386 0 \, 1 5;
+#X text 719 717 updated for Pd version 0.37;
+#X connect 1 0 40 0;
+#X connect 2 0 37 0;
+#X connect 2 0 37 1;
+#X connect 3 0 4 0;
+#X connect 4 0 26 0;
+#X connect 5 0 28 0;
+#X connect 5 0 43 0;
+#X connect 5 0 39 0;
+#X connect 8 0 2 0;
+#X connect 9 0 36 0;
+#X connect 10 0 38 0;
+#X connect 11 0 14 0;
+#X connect 11 0 12 0;
+#X connect 12 0 42 0;
+#X connect 25 0 26 1;
+#X connect 26 0 39 0;
+#X connect 28 0 29 0;
+#X connect 29 0 25 0;
+#X connect 36 0 8 1;
+#X connect 38 0 41 0;
+#X connect 40 0 34 0;
+#X connect 41 0 8 0;
+#X connect 43 0 25 0;
diff --git a/pd/doc/3.audio.examples/C06.signal.to.control.pd b/pd/doc/3.audio.examples/C06.signal.to.control.pd
new file mode 100644
index 00000000..1c3e4bf0
--- /dev/null
+++ b/pd/doc/3.audio.examples/C06.signal.to.control.pd
@@ -0,0 +1,25 @@
+#N canvas 215 77 561 455 12;
+#N canvas 0 0 269 179 metro 0;
+#X obj 88 39 loadbang;
+#X msg 87 65 1;
+#X obj 87 128 outlet;
+#X obj 87 96 metro 100;
+#X msg 178 70 \; pd dsp 1;
+#X connect 0 0 1 0;
+#X connect 0 0 4 0;
+#X connect 1 0 3 0;
+#X connect 3 0 2 0;
+#X restore 41 247 pd metro;
+#X text 374 425 Updated for Pd 0.37;
+#X obj 41 316 snapshot~;
+#X obj 66 286 phasor~ 1;
+#X floatatom 41 347 5 0 0 0 - - -;
+#X text 14 7 CONVERTING SIGNALS TO CONTROLS;
+#X text 15 35 The snapshot~ object allows you to convert from signals
+back to control streams (float messages) -- an opposite of signal~.
+The value output is always the end of the most recently computed audio
+block \, so that even if you bang it metronomically (as here) it need
+not give you samples that are exactly evenly spaced.;
+#X connect 0 0 2 0;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
diff --git a/pd/doc/3.audio.examples/C07.envelope.follower.pd b/pd/doc/3.audio.examples/C07.envelope.follower.pd
new file mode 100644
index 00000000..51f8f56b
--- /dev/null
+++ b/pd/doc/3.audio.examples/C07.envelope.follower.pd
@@ -0,0 +1,113 @@
+#N canvas 66 7 617 909 12;
+#X text 164 5 ENVELOPE FOLLOWERS;
+#X text 10 25 The env~ object reports ths RMS signal level over the
+last 256 samples (by default) or any other power of 2 that's at least
+twice the block size. The analysis is done in an overlapped fashion
+so that results appear every N/2 points if N is the analysis window
+size. So the larger the window \, the stabler the result and the less
+frequently it appears. Computation time doesn't depend heavily on N.
+;
+#X text 11 135 Envelope followers are frequently used to detect attacks
+and periods of silence. (There are fancier attack detectors out there
+\, though.) Here is a simple threshold-based attack and rest detector.
+;
+#X obj 102 297 dbtorms;
+#X obj 23 293 osc~ 440;
+#X obj 23 339 env~;
+#X floatatom 78 329 0 0 0 0 - - -;
+#X floatatom 102 274 0 0 0 0 - - -;
+#X msg 451 320 \; pd dsp 1;
+#X obj 119 380 t b f;
+#X floatatom 119 403 0 0 0 0 - - -;
+#X obj 126 458 pack;
+#X obj 126 481 route 0 1;
+#X obj 126 504 > 55;
+#X obj 176 504 < 45;
+#X obj 126 527 sel 1;
+#X obj 176 527 sel 1;
+#X msg 90 538 1;
+#X msg 90 516 0;
+#X obj 126 564 print attack;
+#X obj 119 435 != 0;
+#X obj 24 612 t b f;
+#X floatatom 15 638 0 0 0 0 - - -;
+#X obj 27 688 pack;
+#X obj 27 711 route 0 1;
+#X obj 27 749 sel 1;
+#X msg 6 856 1;
+#X msg 7 879 0;
+#X obj 20 666 != 0;
+#X obj 58 639 < 45;
+#X obj 31 783 timer;
+#X obj 113 712 sel 0;
+#X obj 95 832 sel 0;
+#X obj 45 832 sel 1;
+#X obj 45 873 print rest;
+#X obj 31 806 > 1000;
+#X text 162 403 state -- 1 if waiting for low threshold \,;
+#X text 199 418 0 if we've attained it and now want the;
+#X text 202 434 high one.;
+#X text 209 480 route the RMS value according to state;
+#X text 239 506 if off \, 55 dB means attack. If on \, 45;
+#X text 240 527 dB or less means state changes to off.;
+#X text 132 359 ATTACK DETECTION;
+#X text 40 594 REST DETECTION;
+#X text 100 637 Here we always will test RMS against a low value;
+#X text 125 654 but as before we route the result according to;
+#X text 147 671 our state \, 1 if "resting" \, 0 if not.;
+#X text 163 709 regardless of state \, when RMS isn't low;
+#X text 185 724 reset the timer;
+#X text 202 846 RMS isn't low enough.;
+#X text 120 744 If we're not in rest \, and the RMS is low \,;
+#X text 143 761 check elapsed time sinse RMS last wasn't low.;
+#X text 122 802 If more than 1 second \, report a rest.;
+#X text 170 828 If we're at rest \, pop out of it when;
+#X text 11 201 Both detectors are state machines with two states \,
+on and off. If on \, a test is run to determine whether to turn off
+\, and vice versa. The tests are run at each output of the rms~ object.
+;
+#X text 355 884 updated for Pd version 0.37;
+#X text 109 320 note 3.01 dB difference between;
+#X text 113 336 peak and RMS amplitudes.;
+#X obj 451 297 loadbang;
+#X obj 23 316 *~;
+#X connect 3 0 59 1;
+#X connect 4 0 59 0;
+#X connect 5 0 6 0;
+#X connect 5 0 9 0;
+#X connect 5 0 21 0;
+#X connect 7 0 3 0;
+#X connect 9 0 10 0;
+#X connect 9 1 11 1;
+#X connect 10 0 20 0;
+#X connect 11 0 12 0;
+#X connect 12 0 13 0;
+#X connect 12 1 14 0;
+#X connect 13 0 15 0;
+#X connect 14 0 16 0;
+#X connect 15 0 17 0;
+#X connect 15 0 19 0;
+#X connect 16 0 18 0;
+#X connect 17 0 10 0;
+#X connect 18 0 10 0;
+#X connect 20 0 11 0;
+#X connect 21 0 22 0;
+#X connect 21 1 29 0;
+#X connect 22 0 28 0;
+#X connect 23 0 24 0;
+#X connect 24 0 25 0;
+#X connect 24 1 32 0;
+#X connect 25 0 30 1;
+#X connect 26 0 22 0;
+#X connect 27 0 22 0;
+#X connect 28 0 23 0;
+#X connect 29 0 23 1;
+#X connect 29 0 31 0;
+#X connect 30 0 35 0;
+#X connect 31 0 30 0;
+#X connect 32 0 27 0;
+#X connect 33 0 26 0;
+#X connect 33 0 34 0;
+#X connect 35 0 33 0;
+#X connect 58 0 8 0;
+#X connect 59 0 5 0;
diff --git a/pd/doc/3.audio.examples/C08.analog.sequencer.pd b/pd/doc/3.audio.examples/C08.analog.sequencer.pd
new file mode 100644
index 00000000..9ee9e6de
--- /dev/null
+++ b/pd/doc/3.audio.examples/C08.analog.sequencer.pd
@@ -0,0 +1,156 @@
+#N canvas 46 22 825 554 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array 29-sequence 9 float 1;
+#A 0 55 550 385 495 165 385 495 275 615;
+#X coords 0 500 8 0 200 100 1;
+#X restore 621 42 graph;
+#X obj 27 426 *~;
+#X obj 27 454 hip~ 5;
+#N canvas 0 0 450 300 graph1 0;
+#X array 29-envelope 103 float 1;
+#A 0 -0.1 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 1.01111 1 0.988889 0.977778
+0.966667 0.955556 0.944444 0.933333 0.922222 0.911111 0.9 0.888889
+0.797778 0.737777 0.677777 0.647777 0.617777 0.557777 0.487777 0.467777
+0.447776 0.417776 0.397776 0.387776 0.377776 0.367776 0.347776 0.327776
+0.317776 0.297776 0.277776 0.267776 0.257776 0.257776 0.277776 0.297776
+0.327776 0.357776 0.377776 0.397776 0.407776 0.427776 0.437776 0.387776
+0.367776 0.347776 0.337776 0.287776 0.277776 0.277776 0.277776 0.267776
+0.267776 0.267776 0.297776 0.317776 0.347776 0.367776 0.367776 0.357776
+0.347776 0.337776 0.307776 0.287776 0.257776 0.227776 0.197776 0.167776
+0.167776 0.167776 0.167776 0.167776 0.157776 0.157776 0.157776 0.157776
+0.147776 0.147776 0.147776 0.137776 0.137776 0.111111 0.1 0.0888889
+0.0777778 0.0666667 0.0555556 0.0444444 0.0333333 0.0222222 0.0111111
+0 -0.0111111;
+#X coords 0 1 102 0 200 100 1;
+#X restore 622 146 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array 29-sample 259 float 1;
+#A 0 0.989177 1 0.989177 0.95694 0.903989 0.83147 0.740952 0.634394
+0.514103 0.382684 0.242981 0.0980184 -0.0490663 -0.195089 -0.336888
+-0.471395 -0.595698 -0.707105 -0.803206 -0.88192 -0.941543 -0.980785
+-0.998795 -0.995185 -0.970032 -0.923881 -0.85773 -0.773013 -0.671561
+-0.555573 -0.427558 -0.290288 -0.146734 -3.98038e-06 0.146726 0.290281
+0.427551 0.555566 0.671556 0.773007 0.857726 0.923878 0.97003 0.995184
+0.998796 0.980786 0.941546 0.881924 0.803211 0.707111 0.595704 0.471402
+0.336896 0.195097 0.0490743 -0.0980105 -0.242974 -0.382677 -0.514097
+-0.634388 -0.740946 -0.831465 -0.903986 -0.956938 -0.989175 -1 -0.989178
+-0.956943 -0.903993 -0.831474 -0.740957 -0.6344 -0.51411 -0.382692
+-0.242989 -0.0980263 0.0490584 0.195081 0.336881 0.471388 0.595691
+0.7071 0.803202 0.881916 0.941541 0.980783 0.998795 0.995186 0.970034
+0.923884 0.857734 0.773018 0.671567 0.55558 0.427566 0.290296 0.146742
+1.19412e-05 -0.146719 -0.290273 -0.427544 -0.55556 -0.67155 -0.773002
+-0.857722 -0.923875 -0.970028 -0.995183 -0.998796 -0.980788 -0.941549
+-0.881928 -0.803216 -0.707117 -0.595711 -0.471409 -0.336903 -0.195104
+-0.0490822 0.0980025 0.242966 0.38267 0.51409 0.634382 0.740941 0.831461
+0.903983 0.956936 0.989174 1 0.989179 0.956945 0.903996 0.831479 0.740962
+0.634406 0.514117 0.382699 0.242997 0.0980342 -0.0490504 -0.195073
+-0.336873 -0.471381 -0.595685 -0.707094 -0.803197 -0.881913 -0.941538
+-0.980782 -0.998795 -0.995187 -0.970036 -0.923887 -0.857738 -0.773023
+-0.671573 -0.555586 -0.427573 -0.290303 -0.14675 -1.99019e-05 0.146711
+0.290265 0.427537 0.555553 0.671544 0.772997 0.857718 0.923872 0.970026
+0.995183 0.998797 0.980789 0.941551 0.881931 0.803221 0.707122 0.595717
+0.471416 0.336911 0.195112 0.0490902 -0.0979946 -0.242958 -0.382662
+-0.514083 -0.634375 -0.740936 -0.831457 -0.903979 -0.956933 -0.989173
+-1 -0.98918 -0.956947 -0.904 -0.831483 -0.740968 -0.634412 -0.514124
+-0.382706 -0.243004 -0.0980421 0.0490425 0.195065 0.336866 0.471374
+0.595679 0.707088 0.803192 0.881909 0.941535 0.98078 0.998794 0.995187
+0.970038 0.92389 0.857742 0.773028 0.671579 0.555593 0.42758 0.290311
+0.146758 2.78627e-05 -0.146703 -0.290258 -0.42753 -0.555547 -0.671538
+-0.772992 -0.857714 -0.923868 -0.970024 -0.995182 -0.998797 -0.980791
+-0.941554 -0.881935 -0.803225 -0.707128 -0.595723 -0.471423 -0.336918
+-0.19512 -0.0490981 0.0979867 0.24295 0.382655 0.514076 0.634369 0.74093
+0.831452 0.903976 0.956931 0.989172 1 0.989181;
+#X coords 0 1 258 -1 200 100 1;
+#X restore 619 281 graph;
+#X text 566 533 updated for Pd version 0.37;
+#X obj 26 218 tabread~ 29-sequence;
+#X obj 106 241 wrap~;
+#X obj 106 265 *~ 100;
+#X obj 106 289 +~ 1;
+#X obj 26 242 phasor~;
+#X obj 26 266 -~ 0.5;
+#X obj 27 377 cos~;
+#X obj 84 336 *~;
+#X obj 28 488 output~;
+#X obj 84 408 tabread4~ 29-sample;
+#X obj 106 313 tabread4~ 29-envelope;
+#X obj 84 360 *~ 128;
+#X obj 84 384 +~ 129;
+#X obj 27 401 +~ 1;
+#X obj 26 194 *~ 9;
+#N canvas 328 85 609 424 make-tables 0;
+#X msg 109 52 bang;
+#X obj 109 77 t b b;
+#X obj 152 134 f;
+#X obj 190 134 + 1;
+#X msg 174 106 0;
+#X obj 109 103 until;
+#X obj 152 162 t f f;
+#X obj 27 190 moses 10;
+#X obj 18 272 tabwrite 29-envelope;
+#X obj 75 159 sel 102;
+#X obj 23 218 expr ($f1-1)/10;
+#X obj 35 243 expr (101-$f1)/90;
+#X msg 120 380 \; 29-sample cosinesum 256 0 0 0 0 0 0 1;
+#X msg 120 338 \; 29-sequence 0 55 550 385 495 165 385 495 275 615
+;
+#X text 30 8 bang to recalculate the envelope table (I did this but
+then went in and changed it with the mouse afterward.);
+#X text 84 299 The sequence is just a list of specified frequencies
+\; the wavetable is a cosine.;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 1 1 4 0;
+#X connect 2 0 3 0;
+#X connect 2 0 6 0;
+#X connect 2 0 9 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 6 1 8 1;
+#X connect 7 0 10 0;
+#X connect 7 1 11 0;
+#X connect 9 0 5 1;
+#X connect 10 0 8 0;
+#X connect 11 0 8 0;
+#X restore 689 401 pd make-tables;
+#X text 46 1 ANALOG-SYNTH-STYLE SEQUENCER;
+#X obj 26 170 phasor~ 0.6;
+#X text 27 27 Some control operations can be carried out entirely by
+tilde objects passing audio signals around. Here is an imitation of
+an analog sequencer and envelope generator. A phasor~ loops through
+the "sequence" table at 0.6 Hz \, generating 9 frequencies. Simultaneously
+\, by multiplying by 9 and wrapping \, we create a sawtooth at 9*0.6=5.4
+Hz \, which reads a second table for an envelope shape. This becomes
+the grain size for a samplerbased on the 18.sampler.looped example
+earlier.;
+#X text 97 194 main loop: sawtooth of amplitude 9;
+#X text 218 219 read frequency sequence;
+#X text 162 241 9x original frequency sawtooth;
+#X text 173 266 adjust for reading;
+#X text 346 266 envelope sample;
+#X text 123 336 multiply envelope by audio-frequency sawtooth;
+#X text 147 361 adjust amplitude and center for wavetable;
+#X text 62 428 multiply by raised-cosine smoothing function;
+#X text 478 401 how to make the tables:;
+#X connect 1 0 2 0;
+#X connect 2 0 14 0;
+#X connect 2 0 14 1;
+#X connect 6 0 10 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 16 0;
+#X connect 10 0 11 0;
+#X connect 11 0 13 0;
+#X connect 11 0 12 0;
+#X connect 12 0 19 0;
+#X connect 13 0 17 0;
+#X connect 15 0 1 1;
+#X connect 16 0 13 1;
+#X connect 17 0 18 0;
+#X connect 18 0 15 0;
+#X connect 19 0 1 0;
+#X connect 20 0 6 0;
+#X connect 20 0 7 0;
+#X connect 23 0 20 0;
diff --git a/pd/doc/3.audio.examples/C09.sample.hold.pd b/pd/doc/3.audio.examples/C09.sample.hold.pd
new file mode 100644
index 00000000..dc41aacd
--- /dev/null
+++ b/pd/doc/3.audio.examples/C09.sample.hold.pd
@@ -0,0 +1,104 @@
+#N canvas 120 85 930 452 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array samphold 44100 float 0;
+#X coords 0 1 44100 0 300 200 1;
+#X restore 606 36 graph;
+#N canvas 0 0 439 429 tables 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array dbtorms 123 float 1;
+#A 0 0 0 1.25893e-05 1.41254e-05 1.58489e-05 1.77828e-05 1.99526e-05
+2.23872e-05 2.51189e-05 2.81838e-05 3.16228e-05 3.54813e-05 3.98107e-05
+4.46684e-05 5.01187e-05 5.62341e-05 6.30957e-05 7.07946e-05 7.94328e-05
+8.91251e-05 1e-04 0.000112202 0.000125893 0.000141254 0.000158489 0.000177828
+0.000199526 0.000223872 0.000251189 0.000281838 0.000316228 0.000354813
+0.000398107 0.000446684 0.000501187 0.000562341 0.000630957 0.000707946
+0.000794328 0.000891251 0.001 0.00112202 0.00125893 0.00141254 0.00158489
+0.00177828 0.00199526 0.00223872 0.00251189 0.00281838 0.00316228 0.00354813
+0.00398107 0.00446684 0.00501187 0.00562341 0.00630957 0.00707946 0.00794328
+0.00891251 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1 1.12202 1.25893 1.41254 1.58489 1.77828 1.99526
+2.23872 2.51189 2.81838 3.16228 3.54813 3.98107 4.46684 5.01187 5.62341
+6.30957 7.07946 7.94328 8.91251 10 11.2202 12.5893;
+#X coords 0 10 123 0 200 100 1;
+#X restore 78 55 graph;
+#X text 280 148 0;
+#X text 282 48 10;
+#X text 97 158 ------ 123 samples ------;
+#N canvas 0 0 450 300 graph2 0;
+#X array mtof 130 float 1;
+#A 0 8.1758 8.66196 9.17702 9.72272 10.3009 10.9134 11.5623 12.2499
+12.9783 13.75 14.5676 15.4339 16.3516 17.3239 18.354 19.4454 20.6017
+21.8268 23.1247 24.4997 25.9565 27.5 29.1352 30.8677 32.7032 34.6478
+36.7081 38.8909 41.2034 43.6535 46.2493 48.9994 51.9131 55 58.2705
+61.7354 65.4064 69.2957 73.4162 77.7817 82.4069 87.3071 92.4986 97.9989
+103.826 110 116.541 123.471 130.813 138.591 146.832 155.563 164.814
+174.614 184.997 195.998 207.652 220 233.082 246.942 261.626 277.183
+293.665 311.127 329.628 349.228 369.994 391.995 415.305 440 466.164
+493.883 523.251 554.365 587.33 622.254 659.255 698.456 739.989 783.991
+830.609 880 932.328 987.767 1046.5 1108.73 1174.66 1244.51 1318.51
+1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32
+2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07
+4186.01 4434.92 4698.64 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88
+7040 7458.62 7902.13 8372.02 8869.84 9397.27 9956.06 10548.1 11175.3
+11839.8 12543.9 13289.8 14080;
+#X coords 0 12000 130 0 200 100 1;
+#X restore 85 232 graph;
+#X text 95 340 ------ 130 samples ------;
+#X text 294 325 0;
+#X text 296 225 12000;
+#X restore 648 280 pd tables;
+#X text 67 8 SAMPLE AND HOLD;
+#X obj 141 266 phasor~ 5;
+#X obj 44 241 phasor~ 7;
+#X obj 44 266 samphold~;
+#X floatatom 44 216 0 0 0 0 - - -;
+#X floatatom 141 211 0 0 0 0 - - -;
+#X obj 216 319 tabwrite~ samphold;
+#X msg 216 294 bang;
+#X obj 44 341 tabread4~ mtof;
+#X obj 44 291 *~ 48;
+#X obj 44 316 +~ 36;
+#X obj 44 366 osc~;
+#X msg 216 236 0;
+#X text 259 293 <--graph output;
+#X obj 44 191 unpack;
+#X text 254 233 <-- reset phase;
+#X msg 311 131 32 96.33;
+#X msg 124 131 5 7;
+#X msg 44 131 1 5;
+#X msg 78 131 2 11;
+#X msg 161 131 3.7 8.8;
+#X msg 235 131 3.4 8.9;
+#X text 16 31 Another analog favorite \, the sample and hold unit freezes
+an audio signal on command. In the Pd version \, the second input of
+samphold~ triggers it \, and the first input becomes the output's new
+value whenever the trigger decreases from one sample to the next. This
+is ideal for updating values when a phasor wraps around.;
+#X text 679 428 updated for Pd version 0.37;
+#X obj 44 392 output~;
+#X connect 3 0 5 1;
+#X connect 4 0 5 0;
+#X connect 5 0 11 0;
+#X connect 5 0 8 0;
+#X connect 6 0 4 0;
+#X connect 7 0 3 0;
+#X connect 9 0 8 0;
+#X connect 10 0 13 0;
+#X connect 11 0 12 0;
+#X connect 12 0 10 0;
+#X connect 13 0 26 0;
+#X connect 13 0 26 1;
+#X connect 14 0 3 1;
+#X connect 14 0 4 1;
+#X connect 16 0 6 0;
+#X connect 16 1 7 0;
+#X connect 18 0 16 0;
+#X connect 19 0 16 0;
+#X connect 20 0 16 0;
+#X connect 21 0 16 0;
+#X connect 22 0 16 0;
+#X connect 23 0 16 0;
diff --git a/pd/doc/3.audio.examples/C10.monophonic.synth.pd b/pd/doc/3.audio.examples/C10.monophonic.synth.pd
new file mode 100644
index 00000000..66b14564
--- /dev/null
+++ b/pd/doc/3.audio.examples/C10.monophonic.synth.pd
@@ -0,0 +1,107 @@
+#N canvas 57 27 578 769 12;
+#X obj 13 514 mtof;
+#X obj 13 463 stripnote;
+#X obj 164 519 select;
+#X obj 155 413 float;
+#X obj 164 381 t b f;
+#X obj 164 487 float;
+#X text 217 367 f - store pitch below;
+#X text 209 415 velocity stored here;
+#X text 128 459 off;
+#X text 216 486 recall pitch;
+#X text 132 2 MONOPHONIC MIDI SYNTH;
+#X obj 13 340 unpack;
+#X obj 13 273 notein;
+#X obj 13 300 pack;
+#X obj 94 570 line~;
+#X msg 94 544 \$1 100;
+#X msg 164 545 0 1000;
+#X text 15 75 First \, at top \, incoming MIDI notes are parsed and
+used to set pitch and trigger an ADSR envelope. Second \, the envelope
+generator itself has been extended to offer controls over the time
+and target values via number boxes.;
+#X text 17 21 This patch shows how to make a monophonic synthesizer
+that could be controlled from a MIDI or voltage-control keyboard--in
+this example we assume MIDI.;
+#X msg 152 290 55 64;
+#X msg 152 316 55 0;
+#X msg 95 291 48 64;
+#X msg 95 317 48 0;
+#X text 14 142 The note-off testing is complicated by the fact that
+we have to test both that the velocity is zero \, and further that
+the note-off pitch matches the pitch that is now playing (the most
+recent note-on pitch.);
+#X text 218 387 b - bang to recall velocity;
+#X obj 155 442 sel 0;
+#X text 177 463 on;
+#X obj 16 712 output~;
+#X obj 15 688 hip~ 5;
+#X obj 14 642 *~;
+#X obj 13 541 phasor~;
+#X obj 13 565 -~ 0.5;
+#X obj 14 593 cos~;
+#X obj 102 617 *~;
+#X obj 14 617 +~ 1;
+#X text 332 741 updated for Pd version 0.37;
+#X obj 102 665 cos~;
+#X msg 95 268 48 128;
+#X text 18 491 pitch;
+#X text 19 443 messages;
+#X text 210 441 test for note on or off;
+#X text 227 520 test against latest;
+#X text 270 535 note-on pitch;
+#X text 18 407 filter;
+#X text 19 425 note-on;
+#X obj 15 664 *~;
+#X obj 94 517 / 127;
+#X text 14 208 The synthesis technique is the same as in the previous
+patch \, done in a simpler (but less general) way with a cos~ object
+replacing the wavetable lookup.;
+#X text 148 571 envelope generator now controls amplitude;
+#X text 317 589 as well as grain size;
+#X obj 102 641 *~ 2;
+#X obj 123 594 +~ 0.5;
+#X text 148 687 The +~ 0.5 and *~ 2 are fudge factors.;
+#X text 148 648 This replaces the tabread4~;
+#X text 146 668 in the previous patch.;
+#X text 211 290 These buttons simulate MIDI input.;
+#X connect 0 0 30 0;
+#X connect 1 0 2 1;
+#X connect 1 0 0 0;
+#X connect 2 0 16 0;
+#X connect 3 0 25 0;
+#X connect 4 0 3 0;
+#X connect 4 1 5 1;
+#X connect 5 0 2 0;
+#X connect 11 0 1 0;
+#X connect 11 0 4 0;
+#X connect 11 1 1 1;
+#X connect 11 1 3 1;
+#X connect 12 0 13 0;
+#X connect 12 1 13 1;
+#X connect 13 0 11 0;
+#X connect 14 0 45 1;
+#X connect 14 0 51 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 0;
+#X connect 19 0 11 0;
+#X connect 20 0 11 0;
+#X connect 21 0 11 0;
+#X connect 22 0 11 0;
+#X connect 25 0 5 0;
+#X connect 25 1 46 0;
+#X connect 28 0 27 0;
+#X connect 28 0 27 1;
+#X connect 29 0 45 0;
+#X connect 30 0 31 0;
+#X connect 31 0 33 0;
+#X connect 31 0 32 0;
+#X connect 32 0 34 0;
+#X connect 33 0 50 0;
+#X connect 34 0 29 0;
+#X connect 36 0 29 1;
+#X connect 37 0 11 0;
+#X connect 45 0 28 0;
+#X connect 46 0 15 0;
+#X connect 50 0 36 0;
+#X connect 51 0 33 1;
diff --git a/pd/doc/3.audio.examples/D01.envelope.gen.pd b/pd/doc/3.audio.examples/D01.envelope.gen.pd
new file mode 100644
index 00000000..61e7a6d7
--- /dev/null
+++ b/pd/doc/3.audio.examples/D01.envelope.gen.pd
@@ -0,0 +1,90 @@
+#N canvas 173 105 609 433 12;
+#X floatatom 96 358 0 0 100;
+#N canvas 448 68 641 420 output 0;
+#X obj 430 203 t b;
+#X obj 430 143 f;
+#X obj 430 83 inlet;
+#X obj 430 233 f;
+#X msg 541 225 0;
+#X msg 430 113 bang;
+#X obj 430 173 moses 1;
+#X obj 496 151 moses 1;
+#X obj 107 174 dbtorms;
+#X obj 496 121 r master-lvl;
+#X obj 107 56 r master-lvl;
+#X obj 430 263 s master-lvl;
+#X obj 36 202 inlet~;
+#X obj 251 229 inlet;
+#X obj 269 257 s master-lvl;
+#X msg 119 85 set \$1;
+#X obj 119 115 outlet;
+#X msg 251 283 \; pd dsp 1;
+#X obj 107 236 line~;
+#X obj 36 258 *~;
+#X obj 36 290 dac~;
+#X obj 107 204 pack 0 50;
+#X text 23 179 audio in;
+#X text 2 313 out both channels;
+#X obj 36 231 hip~ 1;
+#X obj 541 194 t b;
+#X connect 0 0 3 0;
+#X connect 1 0 6 0;
+#X connect 2 0 5 0;
+#X connect 3 0 11 0;
+#X connect 4 0 11 0;
+#X connect 5 0 1 0;
+#X connect 6 0 0 0;
+#X connect 6 1 25 0;
+#X connect 7 1 3 1;
+#X connect 8 0 21 0;
+#X connect 9 0 1 1;
+#X connect 9 0 7 0;
+#X connect 10 0 8 0;
+#X connect 10 0 15 0;
+#X connect 12 0 24 0;
+#X connect 13 0 14 0;
+#X connect 13 0 17 0;
+#X connect 15 0 16 0;
+#X connect 18 0 19 1;
+#X connect 19 0 20 0;
+#X connect 19 0 20 1;
+#X connect 21 0 18 0;
+#X connect 24 0 19 0;
+#X connect 25 0 4 0;
+#X restore 58 391 pd output;
+#X msg 134 359 MUTE;
+#X msg 247 180 bang;
+#X msg 328 180 bang;
+#X text 244 152 attack;
+#X text 325 150 release;
+#X obj 247 281 line~;
+#X msg 328 254 0 500;
+#X text 134 10 ENVELOPE GENERATORS;
+#X obj 58 246 phasor~ 50;
+#X obj 58 301 *~;
+#X obj 58 328 wrap~;
+#X msg 247 248 1 2500;
+#X obj 58 275 -~ 0.5;
+#X msg 179 247 10 200;
+#X obj 247 221 del 200;
+#X text 349 405 updated for Pd version 0.34;
+#X text 39 35 This patch uses an envelope generator to control a sound.
+When you hit "attack" two things happen. First \, the line~ object
+rises to 10 in 200 milliseconds. Then after a "delay" of the same 200
+msec \, the second message sends the line~ back down to 1 over another
+2500 msec. The "release" just ramps us down to zero at the end.;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 3 0 15 0;
+#X connect 3 0 16 0;
+#X connect 4 0 8 0;
+#X connect 7 0 11 1;
+#X connect 8 0 7 0;
+#X connect 10 0 14 0;
+#X connect 11 0 12 0;
+#X connect 12 0 1 0;
+#X connect 13 0 7 0;
+#X connect 14 0 11 0;
+#X connect 15 0 7 0;
+#X connect 16 0 13 0;
diff --git a/pd/doc/3.audio.examples/D02.adsr.pd b/pd/doc/3.audio.examples/D02.adsr.pd
new file mode 100644
index 00000000..06fa21b7
--- /dev/null
+++ b/pd/doc/3.audio.examples/D02.adsr.pd
@@ -0,0 +1,34 @@
+#N canvas 141 83 672 516 12;
+#X text 412 489 updated for Pd version 0.26;
+#X graph graph1 0 -1.02 44100 1.02 395 235 595 105;
+#X array adsr-output 44100 float 0;
+#X pop;
+#X text 394 244 ------ 1 second ------;
+#X obj 32 74 r trigger;
+#X obj 32 148 tabwrite~ adsr-output;
+#X obj 54 123 r graphit;
+#X msg 31 176 bang;
+#X text 75 177 <-- attack and delayed release;
+#X obj 42 200 del 500;
+#X text 146 283 <-- attack only;
+#X msg 31 264 \; pd dsp 1 \; trigger 1 \; graphit bang;
+#X text 147 360 <-- release only;
+#X msg 30 334 \; pd dsp 1 \; trigger 0 \; graphit bang;
+#X msg 42 225 \; trigger 0;
+#X text 598 221 -1;
+#X text 600 96 1;
+#X text 35 24 This patch introduces a simple "adsr" abstraction we'll
+use frequently. You can click on the "adsr" object to see what's inside.
+;
+#X text 30 402 The active ingredient of the ADSR envelope generator
+is a single line~ which gets passed messages to make the attack and
+release behavior. You can retrigger the ADSR envelope generator all
+you wish without having to wait for attacks or releases to finish;
+#X text 104 5 ENVELOPE GENERATOR ABSTRACTION;
+#X obj 32 100 adsr 1 100 200 50 300;
+#X connect 3 0 19 0;
+#X connect 5 0 4 0;
+#X connect 6 0 10 0;
+#X connect 6 0 8 0;
+#X connect 8 0 13 0;
+#X connect 19 0 4 0;
diff --git a/pd/doc/3.audio.examples/D03.envelope.dB.pd b/pd/doc/3.audio.examples/D03.envelope.dB.pd
new file mode 100644
index 00000000..8ec1d1ae
--- /dev/null
+++ b/pd/doc/3.audio.examples/D03.envelope.dB.pd
@@ -0,0 +1,158 @@
+#N canvas 112 44 674 673 12;
+#X obj 32 80 r trigger;
+#X text 85 8 USING ADSR'S OUTPUT AS dB;
+#X text 34 28 For natural sounding amplitude control \, you will want
+to use the ADSR's output as log amplitude. In practice this is best
+done using a lookup table:;
+#X obj 32 131 tabread4~ dbtorms;
+#N canvas 0 0 450 300 graph1 0;
+#X array dbtorms 123 float 1;
+#A 0 0 0 1.25893e-05 1.41254e-05 1.58489e-05 1.77828e-05 1.99526e-05
+2.23872e-05 2.51189e-05 2.81838e-05 3.16228e-05 3.54813e-05 3.98107e-05
+4.46684e-05 5.01187e-05 5.62341e-05 6.30957e-05 7.07946e-05 7.94328e-05
+8.91251e-05 1e-04 0.000112202 0.000125893 0.000141254 0.000158489 0.000177828
+0.000199526 0.000223872 0.000251189 0.000281838 0.000316228 0.000354813
+0.000398107 0.000446684 0.000501187 0.000562341 0.000630957 0.000707946
+0.000794328 0.000891251 0.001 0.00112202 0.00125893 0.00141254 0.00158489
+0.00177828 0.00199526 0.00223872 0.00251189 0.00281838 0.00316228 0.00354813
+0.00398107 0.00446684 0.00501187 0.00562341 0.00630957 0.00707946 0.00794328
+0.00891251 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1 1.12202 1.25893 1.41254 1.58489 1.77828 1.99526
+2.23872 2.51189 2.81838 3.16228 3.54813 3.98107 4.46684 5.01187 5.62341
+6.30957 7.07946 7.94328 8.91251 10 11.2202 12.5893;
+#X coords 0 10 123 0 200 100 1;
+#X restore 387 83 graph;
+#N canvas 461 495 663 358 make-table 0;
+#X obj 97 195 moses 2;
+#X msg 81 44 bang;
+#X obj 81 73 t b b;
+#X obj 152 134 f;
+#X obj 190 134 + 1;
+#X msg 174 106 0;
+#X obj 81 102 until;
+#X obj 73 162 sel 122;
+#X msg 97 226 0;
+#X obj 141 227 dbtorms;
+#X obj 152 162 t f f;
+#X obj 97 259 tabwrite dbtorms;
+#X floatatom 435 103 0 0 0;
+#X floatatom 435 186 0 0 0;
+#X obj 435 157 tabread4 dbtorms;
+#X floatatom 331 183 0 0 0;
+#X obj 331 154 dbtorms;
+#X text 35 12 bang to recalculate the table;
+#X text 268 62 check accuracy of reading table against;
+#X text 268 81 the "real" dbtorms object.;
+#X connect 0 0 8 0;
+#X connect 0 1 9 0;
+#X connect 1 0 2 0;
+#X connect 2 0 6 0;
+#X connect 2 1 5 0;
+#X connect 3 0 4 0;
+#X connect 3 0 7 0;
+#X connect 3 0 10 0;
+#X connect 4 0 3 1;
+#X connect 5 0 3 1;
+#X connect 6 0 3 0;
+#X connect 7 0 6 1;
+#X connect 8 0 11 0;
+#X connect 9 0 11 0;
+#X connect 10 0 0 0;
+#X connect 10 1 11 1;
+#X connect 12 0 14 0;
+#X connect 12 0 16 0;
+#X connect 14 0 13 0;
+#X connect 16 0 15 0;
+#X restore 288 328 pd make-table;
+#X text 258 299 here's the patch I used to make the table:;
+#X obj 48 156 osc~ 440;
+#X text 589 176 0;
+#X text 590 77 10;
+#X text 406 186 ------ 123 samples ------;
+#X floatatom 61 204 0 0 0;
+#N canvas 159 26 532 285 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X obj 425 153 t b;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 26 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 21 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 5 0;
+#X restore 32 232 pd output;
+#X msg 108 205 MUTE;
+#X text 149 204 <-- output amplitude;
+#X text 112 276 <-- attack;
+#X text 113 333 <-- release;
+#X msg 32 319 \; pd dsp 1 \; trigger 0;
+#X obj 32 182 *~;
+#X msg 31 264 \; pd dsp 1 \; trigger 1;
+#X text 29 431 Notice how the attack sounds different when you retrigger
+than when you start from zero. This is because if you go from the steady
+state you only rise 30 dB instead of 100 \, so it sounds slower.;
+#X obj 32 106 adsr 100 100 200 70 300;
+#X text 29 381 The table is indexed from 1 to 120 so that 1 gives a
+true zero out and 120 gives 10 (a 20 dB boost.) The extra 20 dB are
+for headroom.;
+#X text 28 498 If this is a problem you have at least 2 ways of dealing
+with it. The best might be to adjust the attack time inside the abstraction
+using snapshot~ to find out where you're slewing from \, as demonstrated
+in the next patch.;
+#X text 406 631 updated for Pd version 0.35;
+#X text 28 568 There's also a "real" dbtorms~ object... but it's almost
+certainly much more compute-intensive than tabread4~ \, since it has
+to call a library "exp" function.;
+#X connect 0 0 21 0;
+#X connect 3 0 18 0;
+#X connect 7 0 18 1;
+#X connect 11 0 12 1;
+#X connect 12 0 11 0;
+#X connect 13 0 12 2;
+#X connect 18 0 12 0;
+#X connect 21 0 3 0;
diff --git a/pd/doc/3.audio.examples/D04.envelope.pitch.pd b/pd/doc/3.audio.examples/D04.envelope.pitch.pd
new file mode 100644
index 00000000..43fbe5bc
--- /dev/null
+++ b/pd/doc/3.audio.examples/D04.envelope.pitch.pd
@@ -0,0 +1,209 @@
+#N canvas 222 84 686 544 12;
+#X obj 48 106 r trigger;
+#X obj 48 154 tabread4~ dbtorms;
+#X floatatom 86 232 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 48 258 pd output;
+#X msg 124 232 MUTE;
+#X text 166 231 <-- output amplitude;
+#X text 141 298 <-- attack;
+#X text 568 305 <-- release;
+#X obj 48 208 *~;
+#N canvas 151 343 812 522 make-table 0;
+#X msg 82 49 bang;
+#X obj 82 78 t b b;
+#X obj 141 142 f;
+#X obj 179 142 + 1;
+#X msg 150 112 0;
+#X obj 82 107 until;
+#X obj 141 176 t f f;
+#X floatatom 369 67 0 0 0;
+#X floatatom 369 127 0 0 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array dbtorms 123 float 1;
+#A 0 0 0 1.25893e-05 1.41254e-05 1.58489e-05 1.77828e-05 1.99526e-05
+2.23872e-05 2.51189e-05 2.81838e-05 3.16228e-05 3.54813e-05 3.98107e-05
+4.46684e-05 5.01187e-05 5.62341e-05 6.30957e-05 7.07946e-05 7.94328e-05
+8.91251e-05 1e-04 0.000112202 0.000125893 0.000141254 0.000158489 0.000177828
+0.000199526 0.000223872 0.000251189 0.000281838 0.000316228 0.000354813
+0.000398107 0.000446684 0.000501187 0.000562341 0.000630957 0.000707946
+0.000794328 0.000891251 0.001 0.00112202 0.00125893 0.00141254 0.00158489
+0.00177828 0.00199526 0.00223872 0.00251189 0.00281838 0.00316228 0.00354813
+0.00398107 0.00446684 0.00501187 0.00562341 0.00630957 0.00707946 0.00794328
+0.00891251 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1 1.12202 1.25893 1.41254 1.58489 1.77828 1.99526
+2.23872 2.51189 2.81838 3.16228 3.54813 3.98107 4.46684 5.01187 5.62341
+6.30957 7.07946 7.94328 8.91251 10 11.2202 12.5893;
+#X coords 0 10 123 0 200 100 1;
+#X restore 538 298 graph;
+#X text 740 391 0;
+#X text 742 291 10;
+#X text 544 403 ------ 123 samples ------;
+#N canvas 0 0 450 300 graph2 0;
+#X array mtof 130 float 1;
+#A 0 8.1758 8.66196 9.17702 9.72272 10.3009 10.9134 11.5623 12.2499
+12.9783 13.75 14.5676 15.4339 16.3516 17.3239 18.354 19.4454 20.6017
+21.8268 23.1247 24.4997 25.9565 27.5 29.1352 30.8677 32.7032 34.6478
+36.7081 38.8909 41.2034 43.6535 46.2493 48.9994 51.9131 55 58.2705
+61.7354 65.4064 69.2957 73.4162 77.7817 82.4069 87.3071 92.4986 97.9989
+103.826 110 116.541 123.471 130.813 138.591 146.832 155.563 164.814
+174.614 184.997 195.998 207.652 220 233.082 246.942 261.626 277.183
+293.665 311.127 329.628 349.228 369.994 391.995 415.305 440 466.164
+493.883 523.251 554.365 587.33 622.254 659.255 698.456 739.989 783.991
+830.609 880 932.328 987.767 1046.5 1108.73 1174.66 1244.51 1318.51
+1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32
+2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07
+4186.01 4434.92 4698.64 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88
+7040 7458.62 7902.13 8372.02 8869.84 9397.27 9956.06 10548.1 11175.3
+11839.8 12543.9 13289.8 14080;
+#X coords 0 12000 130 0 200 100 1;
+#X restore 537 130 graph;
+#X obj 283 102 mtof;
+#X floatatom 282 127 0 0 0;
+#X text 541 237 ------ 130 samples ------;
+#X text 746 223 0;
+#X text 748 123 12000;
+#X obj 81 203 mtof;
+#X obj 72 167 sel 129;
+#X obj 80 229 tabwrite mtof;
+#X obj 369 99 tabread4 mtof;
+#X obj 71 418 moses 2;
+#X msg 55 267 bang;
+#X obj 55 296 t b b;
+#X obj 126 357 f;
+#X obj 164 357 + 1;
+#X msg 148 329 0;
+#X obj 55 325 until;
+#X obj 47 385 sel 122;
+#X msg 71 449 0;
+#X obj 115 450 dbtorms;
+#X obj 126 385 t f f;
+#X obj 71 482 tabwrite dbtorms;
+#X text 312 40 ... and test accuracy;
+#X text 23 15 patch to recalculate the mtof table;
+#X text 107 267 bang to recalculate dbtorms table;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 1 1 4 0;
+#X connect 2 0 3 0;
+#X connect 2 0 6 0;
+#X connect 2 0 20 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 2 0;
+#X connect 6 0 19 0;
+#X connect 6 1 21 1;
+#X connect 7 0 14 0;
+#X connect 7 0 22 0;
+#X connect 14 0 15 0;
+#X connect 19 0 21 0;
+#X connect 20 0 5 1;
+#X connect 22 0 8 0;
+#X connect 23 0 31 0;
+#X connect 23 1 32 0;
+#X connect 24 0 25 0;
+#X connect 25 0 29 0;
+#X connect 25 1 28 0;
+#X connect 26 0 27 0;
+#X connect 26 0 30 0;
+#X connect 26 0 33 0;
+#X connect 27 0 26 1;
+#X connect 28 0 26 1;
+#X connect 29 0 26 0;
+#X connect 30 0 29 1;
+#X connect 31 0 34 0;
+#X connect 32 0 34 0;
+#X connect 33 0 23 0;
+#X connect 33 1 34 1;
+#X restore 451 222 pd make-table;
+#X text 35 6 PITCH ENVELOPES;
+#X text 125 24 For pitch envelopes \, unlike amplitude envelopes \,
+discontinuities are allowed and sometimes you would rather the envelope
+generator actually jump to zero when it's triggered. The "adsr" object
+does this for you if you send a negative trigger instead of a positive
+one:;
+#X obj 280 106 r trigger2;
+#X obj 280 178 tabread4~ mtof;
+#X obj 280 202 osc~;
+#X msg 46 288 \; pd dsp 1 \; trigger 1 \; trigger2 1;
+#X text 358 297 <-- attack;
+#X msg 249 293 \; pd dsp 1 \; trigger 1 \; trigger2 -1;
+#X msg 472 293 \; pd dsp 1 \; trigger 0 \; trigger2 0;
+#X obj 280 154 +~ 69;
+#X text 358 314 restarting;
+#X text 363 331 pitch env;
+#X text 37 377 We have added a new table \, mtof \, for converting
+audio signals from pitch to frequency. Its range is 1-127 \, so you
+want to add a base pitch in before you start reading from it.;
+#X text 37 443 This is an extreme use of pitch enveloping. In a real
+situation you might want an envelope controlling vibrato depth or the
+like instead of straight pitch.;
+#X obj 48 130 adsr 100 50 200 90 1000;
+#X obj 280 130 adsr 20 200 100 100 1000;
+#X text 413 497 updated for Pd version 0.37;
+#X connect 0 0 24 0;
+#X connect 1 0 8 0;
+#X connect 2 0 3 1;
+#X connect 3 0 2 0;
+#X connect 4 0 3 2;
+#X connect 8 0 3 0;
+#X connect 12 0 25 0;
+#X connect 13 0 14 0;
+#X connect 14 0 8 1;
+#X connect 19 0 13 0;
+#X connect 24 0 1 0;
+#X connect 25 0 19 0;
diff --git a/pd/doc/3.audio.examples/D05.envelope.portamento.pd b/pd/doc/3.audio.examples/D05.envelope.portamento.pd
new file mode 100644
index 00000000..6542e8b5
--- /dev/null
+++ b/pd/doc/3.audio.examples/D05.envelope.portamento.pd
@@ -0,0 +1,148 @@
+#N canvas 222 84 642 346 12;
+#X floatatom 75 227 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 46 255 pd output;
+#X msg 123 227 MUTE;
+#X text 166 225 <-- output amplitude;
+#X obj 46 173 tabread4~ mtof;
+#X obj 46 197 osc~;
+#N canvas 247 30 505 439 tables 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array dbtorms 123 float 1;
+#A 0 0 0 1.25893e-05 1.41254e-05 1.58489e-05 1.77828e-05 1.99526e-05
+2.23872e-05 2.51189e-05 2.81838e-05 3.16228e-05 3.54813e-05 3.98107e-05
+4.46684e-05 5.01187e-05 5.62341e-05 6.30957e-05 7.07946e-05 7.94328e-05
+8.91251e-05 1e-04 0.000112202 0.000125893 0.000141254 0.000158489 0.000177828
+0.000199526 0.000223872 0.000251189 0.000281838 0.000316228 0.000354813
+0.000398107 0.000446684 0.000501187 0.000562341 0.000630957 0.000707946
+0.000794328 0.000891251 0.001 0.00112202 0.00125893 0.00141254 0.00158489
+0.00177828 0.00199526 0.00223872 0.00251189 0.00281838 0.00316228 0.00354813
+0.00398107 0.00446684 0.00501187 0.00562341 0.00630957 0.00707946 0.00794328
+0.00891251 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1 1.12202 1.25893 1.41254 1.58489 1.77828 1.99526
+2.23872 2.51189 2.81838 3.16228 3.54813 3.98107 4.46684 5.01187 5.62341
+6.30957 7.07946 7.94328 8.91251 10 11.2202 12.5893;
+#X coords 0 10 123 0 200 100 1;
+#X restore 129 49 graph;
+#X text 331 142 0;
+#X text 333 42 10;
+#X text 127 157 ------ 123 samples ------;
+#N canvas 0 0 450 300 graph2 0;
+#X array mtof 130 float 1;
+#A 0 8.1758 8.66196 9.17702 9.72272 10.3009 10.9134 11.5623 12.2499
+12.9783 13.75 14.5676 15.4339 16.3516 17.3239 18.354 19.4454 20.6017
+21.8268 23.1247 24.4997 25.9565 27.5 29.1352 30.8677 32.7032 34.6478
+36.7081 38.8909 41.2034 43.6535 46.2493 48.9994 51.9131 55 58.2705
+61.7354 65.4064 69.2957 73.4162 77.7817 82.4069 87.3071 92.4986 97.9989
+103.826 110 116.541 123.471 130.813 138.591 146.832 155.563 164.814
+174.614 184.997 195.998 207.652 220 233.082 246.942 261.626 277.183
+293.665 311.127 329.628 349.228 369.994 391.995 415.305 440 466.164
+493.883 523.251 554.365 587.33 622.254 659.255 698.456 739.989 783.991
+830.609 880 932.328 987.767 1046.5 1108.73 1174.66 1244.51 1318.51
+1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32
+2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07
+4186.01 4434.92 4698.64 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88
+7040 7458.62 7902.13 8372.02 8869.84 9397.27 9956.06 10548.1 11175.3
+11839.8 12543.9 13289.8 14080;
+#X coords 0 12000 130 0 200 100 1;
+#X restore 136 226 graph;
+#X text 128 336 ------ 130 samples ------;
+#X text 340 318 0;
+#X text 342 218 12000;
+#X restore 490 225 pd tables;
+#X text 35 6 PORTAMENTO;
+#X obj 46 149 line~;
+#X obj 46 101 r pitch;
+#X msg 316 101 36;
+#X msg 345 101 48;
+#X msg 372 101 60;
+#X msg 429 101 72;
+#X msg 401 101 67;
+#X msg 483 101 76;
+#X msg 457 101 74;
+#X obj 451 165 s pitch;
+#X msg 514 101 84;
+#X msg 544 101 96;
+#X floatatom 143 125 0 0 0;
+#X text 173 126 <-- change speed;
+#X floatatom 451 139 0 0 0;
+#X obj 46 125 pack 0 100;
+#X obj 388 192 loadbang;
+#X msg 387 214 \; pitch 72;
+#X text 40 37 Portamento can be done using just line~ \, but you still
+might want to sweep in pitch \, not frequency:;
+#X text 363 293 updated for Pd version 0.35;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 4 0 5 0;
+#X connect 5 0 1 0;
+#X connect 8 0 4 0;
+#X connect 9 0 23 0;
+#X connect 10 0 22 0;
+#X connect 11 0 22 0;
+#X connect 12 0 22 0;
+#X connect 13 0 22 0;
+#X connect 14 0 22 0;
+#X connect 15 0 22 0;
+#X connect 16 0 22 0;
+#X connect 18 0 22 0;
+#X connect 19 0 22 0;
+#X connect 20 0 23 1;
+#X connect 22 0 17 0;
+#X connect 23 0 8 0;
+#X connect 24 0 25 0;
diff --git a/pd/doc/3.audio.examples/D06.additive.pd b/pd/doc/3.audio.examples/D06.additive.pd
new file mode 100644
index 00000000..5121e62f
--- /dev/null
+++ b/pd/doc/3.audio.examples/D06.additive.pd
@@ -0,0 +1,92 @@
+#N canvas 179 69 696 468 12;
+#X floatatom 81 408 0 0 0 0 - - -;
+#N canvas 159 26 534 281 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X obj 425 153 t b;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 26 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 21 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 5 0;
+#X restore 43 435 pd output;
+#X msg 119 408 MUTE;
+#X text 153 407 <-- output amplitude;
+#X obj 43 377 catch~ sum;
+#X obj 381 288 s frequency;
+#X floatatom 381 264 0 0 0 0 - - -;
+#X floatatom 495 265 0 0 0 0 - - -;
+#X obj 495 289 s duration;
+#X msg 260 276 \; trigger bang;
+#X obj 45 221 partial 0.67 0.56 0 1;
+#X obj 45 245 partial 1 0.56 1 0.9;
+#X obj 45 269 partial 1 0.92 0 0.65;
+#X obj 45 294 partial 1.8 0.94 0 0.55;
+#X floatatom 495 217 0 0 0 0 - - -;
+#X obj 495 241 * 100;
+#X obj 381 240 mtof;
+#X floatatom 381 216 0 0 0 0 - - -;
+#X text 87 15 ADDITIVE SYNTHESIS;
+#X text 32 73 This patch demonstrates using an abstraction \, "partial"
+\, to make a simple additive synthesis instrument.;
+#X text 28 114 Partial takes as arguments an amplitude \, a relative
+frequency \, a detuning frequency \, and a relative duration. You set
+absolute duration and pitch using the controls below. Hit hte trigger
+to make sound.;
+#X text 460 435 updated for Pd version 0.26;
+#X text 535 207 duration in tenths;
+#X text 535 222 of a second;
+#X text 419 215 pitch;
+#X text 251 253 click to start;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 4 0 1 0;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 14 0 15 0;
+#X connect 15 0 7 0;
+#X connect 16 0 6 0;
+#X connect 17 0 16 0;
diff --git a/pd/doc/3.audio.examples/D07.sampler.notes.pd b/pd/doc/3.audio.examples/D07.sampler.notes.pd
new file mode 100644
index 00000000..9b08a10a
--- /dev/null
+++ b/pd/doc/3.audio.examples/D07.sampler.notes.pd
@@ -0,0 +1,321 @@
+#N canvas 12 0 1074 786 12;
+#X msg 862 17 \; pd dsp 1;
+#X msg 946 17 \; pd dsp 0;
+#X text 887 53 ON;
+#X text 965 53 OFF;
+#X floatatom 64 512 0 0 0;
+#N canvas 159 26 495 262 output 0;
+#X obj 406 192 t b;
+#X obj 406 132 f;
+#X obj 406 72 inlet;
+#X text 413 35 mute;
+#X obj 406 222 f;
+#X msg 510 214 0;
+#X msg 406 102 bang;
+#X obj 406 162 moses 1;
+#X obj 510 184 t b f;
+#X obj 476 140 moses 1;
+#X obj 100 178 dbtorms;
+#X obj 476 110 r master-lvl;
+#X obj 100 50 r master-lvl;
+#X obj 406 252 s master-lvl;
+#X obj 26 217 inlet~;
+#X obj 239 49 inlet;
+#X text 239 22 level;
+#X obj 239 120 s master-lvl;
+#X msg 115 78 set \$1;
+#X obj 115 107 outlet;
+#X msg 257 77 \; pd dsp 1;
+#X obj 100 233 line~;
+#X obj 26 254 *~;
+#X obj 26 289 dac~;
+#X obj 100 205 pack 0 50;
+#X text 24 190 audio;
+#X text 112 132 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 29 546 pd output;
+#X msg 98 512 MUTE;
+#X text 143 511 <-- output amplitude;
+#X msg 253 7 bang;
+#X obj 253 35 delay 5;
+#X text 493 269 end of note;
+#X obj 359 35 r note;
+#N canvas 459 46 678 451 samples 0;
+#X graph graph1 0 -1.02 176403 1.02 262 171 462 41;
+#X array sample1 176403 float 0;
+#X pop;
+#X text 264 376 ------ 4 seconds ------;
+#X graph graph1 0 -1.02 176403 1.02 262 356 462 226;
+#X array sample2 176403 float 0;
+#X pop;
+#X restore 29 277 pd samples;
+#N canvas 21 287 947 410 recorder 0;
+#X obj 318 43 inlet;
+#X obj 272 196 adc~ 1;
+#X obj 272 224 hip~ 5;
+#X obj 341 254 line~;
+#X obj 272 253 *~;
+#X msg 341 226 1;
+#X obj 400 191 del 3990;
+#X msg 377 226 0 10;
+#X obj 272 304 tabwrite~ sample1;
+#X obj 124 110 makefilename sample%1;
+#X msg 124 139 set \$1 \, bang;
+#X msg 446 162 stop;
+#X msg 400 162 bang;
+#X obj 557 182 loadbang;
+#X obj 660 137 openpanel;
+#X msg 660 109 bang;
+#X text 702 108 <-- browse for samples;
+#X text 628 233 v-- re-read original samples;
+#X obj 318 72 route record stop reload browse;
+#X obj 557 319 soundfiler;
+#X msg 557 261 read ../sound/bell.aiff sample1 \, read ../sound/voice2.wav
+sample2;
+#X msg 660 164 read \$1 sample1;
+#X obj 660 191 soundfiler;
+#X connect 0 0 18 0;
+#X connect 1 0 2 0;
+#X connect 2 0 4 0;
+#X connect 3 0 4 1;
+#X connect 4 0 8 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 7 0 3 0;
+#X connect 9 0 10 0;
+#X connect 10 0 8 0;
+#X connect 11 0 6 0;
+#X connect 12 0 6 0;
+#X connect 13 0 20 0;
+#X connect 14 0 21 0;
+#X connect 15 0 14 0;
+#X connect 18 0 9 0;
+#X connect 18 0 12 0;
+#X connect 18 0 5 0;
+#X connect 18 1 7 0;
+#X connect 18 1 11 0;
+#X connect 18 2 20 0;
+#X connect 18 3 15 0;
+#X connect 20 0 19 0;
+#X connect 21 0 22 0;
+#X restore 29 443 pd recorder;
+#X msg 29 305 record 1;
+#X msg 29 360 stop;
+#N canvas 700 402 671 621 playback 0;
+#X obj 37 79 line~;
+#X obj 56 271 line~;
+#X obj 37 302 *~;
+#X obj 56 242 r cutoff;
+#X obj 37 50 r phase;
+#X obj 37 626 outlet~;
+#X obj 37 598 hip~ 5;
+#X obj 49 113 r sample-number;
+#X obj 49 142 makefilename sample%d;
+#X msg 49 170 set \$1;
+#X obj 37 211 tabread4~ sample1;
+#X obj 55 338 r envelope;
+#X obj 55 396 dbtorms;
+#X obj 55 367 unpack;
+#X obj 55 425 sqrt;
+#X obj 55 454 sqrt;
+#X obj 55 482 line~;
+#X obj 37 569 *~;
+#X obj 55 511 *~;
+#X obj 55 540 *~;
+#X text 107 51 messages to the phase generating line~;
+#X text 188 114 setting the sample number.;
+#X text 238 143 compute the name;
+#X text 110 171 and send a "set" message to the tabread4~.;
+#X text 116 270 line~ for de-clicking;
+#X text 156 341 The envelope generator. Rather than sending our message
+straight to the line~ we unpack it in order to fool with the amplitude
+field.;
+#X text 126 397 convert amplitude to linear units.;
+#X text 121 426 take the fourth root. This because we want to raies
+the line~'s output to the 4th power afterward. This is an inexpensive
+way to give the rise and decay a more natural sounding evolution than
+just a straight line.;
+#X text 94 514 square the output twice to get the fourth power.;
+#X connect 0 0 10 0;
+#X connect 1 0 2 1;
+#X connect 2 0 17 0;
+#X connect 3 0 1 0;
+#X connect 4 0 0 0;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 10 0;
+#X connect 10 0 2 0;
+#X connect 11 0 13 0;
+#X connect 12 0 14 0;
+#X connect 13 0 12 0;
+#X connect 13 1 16 1;
+#X connect 14 0 15 0;
+#X connect 15 0 16 0;
+#X connect 16 0 18 0;
+#X connect 16 0 18 1;
+#X connect 17 0 6 0;
+#X connect 18 0 19 0;
+#X connect 18 0 19 1;
+#X connect 19 0 17 1;
+#X restore 29 480 pd playback;
+#X msg 29 332 record 2;
+#X text 641 25 ARGUMENTS FOR NOTES:;
+#X text 662 53 pitch in halftones;
+#X text 662 77 amplitude (dB);
+#X text 662 125 sample number;
+#X text 662 101 duration (msec);
+#X text 662 149 start location (msec);
+#X text 662 173 rise time (msec);
+#X text 662 197 decay time (msec);
+#X obj 359 62 unpack 0 0 0 0 0 0 0;
+#X text 46 6 CHOCOLATE SAMPLER;
+#X obj 517 168 f;
+#X obj 452 142 f;
+#X obj 383 142 f;
+#X obj 346 142 f;
+#X obj 314 142 f;
+#X obj 220 142 f;
+#X obj 220 169 mtof;
+#X obj 220 197 / 261.62;
+#X obj 220 224 * 4.41e+08;
+#X obj 220 252 +;
+#X obj 485 142 delay;
+#X obj 314 312 pack 0 0 0 0 0;
+#X obj 253 62 t b b b;
+#X text 494 346 This starts the note \, sending to "receives" in the
+playback subptach. The new receive "envelope" is an amplitude control
+in parallel with the cutoff control. The "sample-number" switches the
+tabread4~ between tables.;
+#X msg 152 44 \; pd dsp 1 \; cutoff 0 5;
+#X obj 383 197 + 1;
+#X msg 552 467 60 100 10000 1 0 0 0;
+#X obj 552 737 s note;
+#X msg 517 196 \; envelope 0 \$1;
+#X msg 671 691 62;
+#X msg 706 691 64;
+#X msg 637 691 60;
+#X msg 608 691 55;
+#X msg 739 691 72;
+#X msg 576 691 48;
+#X msg 638 734 60.5;
+#X msg 552 494 60 90 10000 1 0 0 0;
+#X msg 552 522 60 100 10000 2 0 0 0;
+#X msg 552 550 60 100 10000 1 3000 0 0;
+#X obj 383 169 * 44.1;
+#X msg 552 605 60 100 100 1 0 0 0;
+#X msg 552 632 60 100 100 1 0 0 1000;
+#X msg 552 577 60 100 10000 1 0 1000 0;
+#X msg 314 340 \; envelope 0 \, \$1 \$2 \; phase \$3 \, \$4 1e+07 \;
+sample-number \$5 \; cutoff 1 5 \;;
+#X text 108 315 <-- record;
+#X msg 29 388 reload;
+#X msg 29 415 browse;
+#X text 6 109 transposition works;
+#X text 6 133 by altering the phase;
+#X text 6 181 The mtof and / 261;
+#X text 6 205 calculate speed change;
+#X text 6 229 considering 60 as unity.;
+#X text 20 43 as before we;
+#X text 11 64 mute and wait;
+#X text 6 157 target ($4 below right.);
+#X text 446 303 combine amplitude \, rise time \, start phase \, end
+phase \, and sample number in one message;
+#X text 16 594 This patch take the same principle as the previous one
+\, but allows you to parametrize sample playback. Since we must wait
+5 msec before starting the playback \, we store all the parameters
+in "f" objects \, and recall them to construct the new note. Transposition
+is done by altering the amount to play back in the (artificial) ten
+thousand seconds (1e+07). The playback segment can be altered to start
+in the middle of the sample instead of the beginning \, and you can
+change the duration and rise and decay times.;
+#X text 744 468 straight playback;
+#X text 749 495 change amplitude;
+#X text 752 523 change sample number;
+#X text 755 550 change start location;
+#X text 754 576 change rise time;
+#X text 754 609 change duration;
+#X text 755 633 ... and decay time;
+#X text 688 736 microtones OK too.;
+#X text 576 667 If you omit values they stay unchanged;
+#X text 799 759 updated for Pd version 0.33;
+#X text 548 426 Here are buttons to demonstrate the effect of varying
+the parameters one by one.;
+#X connect 4 0 5 1;
+#X connect 5 0 4 0;
+#X connect 6 0 5 2;
+#X connect 8 0 9 0;
+#X connect 8 0 42 0;
+#X connect 9 0 40 0;
+#X connect 11 0 26 0;
+#X connect 14 0 13 0;
+#X connect 15 0 13 0;
+#X connect 16 0 5 0;
+#X connect 17 0 13 0;
+#X connect 26 0 33 1;
+#X connect 26 0 8 0;
+#X connect 26 1 32 1;
+#X connect 26 2 38 1;
+#X connect 26 3 31 1;
+#X connect 26 4 30 1;
+#X connect 26 5 29 1;
+#X connect 26 6 28 1;
+#X connect 28 0 46 0;
+#X connect 29 0 39 1;
+#X connect 30 0 57 0;
+#X connect 31 0 39 4;
+#X connect 32 0 39 0;
+#X connect 33 0 34 0;
+#X connect 34 0 35 0;
+#X connect 35 0 36 0;
+#X connect 36 0 37 0;
+#X connect 37 0 39 3;
+#X connect 38 0 28 0;
+#X connect 39 0 61 0;
+#X connect 40 0 32 0;
+#X connect 40 1 33 0;
+#X connect 40 2 29 0;
+#X connect 40 2 30 0;
+#X connect 40 2 31 0;
+#X connect 40 2 38 0;
+#X connect 43 0 39 2;
+#X connect 43 0 37 1;
+#X connect 44 0 45 0;
+#X connect 47 0 45 0;
+#X connect 48 0 45 0;
+#X connect 49 0 45 0;
+#X connect 50 0 45 0;
+#X connect 51 0 45 0;
+#X connect 52 0 45 0;
+#X connect 53 0 45 0;
+#X connect 54 0 45 0;
+#X connect 55 0 45 0;
+#X connect 56 0 45 0;
+#X connect 57 0 43 0;
+#X connect 58 0 45 0;
+#X connect 59 0 45 0;
+#X connect 60 0 45 0;
+#X connect 63 0 13 0;
+#X connect 64 0 13 0;
diff --git a/pd/doc/3.audio.examples/D08.sampler.poly.pd b/pd/doc/3.audio.examples/D08.sampler.poly.pd
new file mode 100644
index 00000000..3e6cdba9
--- /dev/null
+++ b/pd/doc/3.audio.examples/D08.sampler.poly.pd
@@ -0,0 +1,229 @@
+#N canvas 66 253 1119 674 12;
+#X floatatom 582 562 0 0 0 0 - - -;
+#N canvas 159 26 495 262 output 0;
+#X obj 406 192 t b;
+#X obj 406 132 f;
+#X obj 406 72 inlet;
+#X text 413 35 mute;
+#X obj 406 222 f;
+#X msg 510 214 0;
+#X msg 406 102 bang;
+#X obj 406 162 moses 1;
+#X obj 510 184 t b f;
+#X obj 476 140 moses 1;
+#X obj 100 178 dbtorms;
+#X obj 476 110 r master-lvl;
+#X obj 100 50 r master-lvl;
+#X obj 406 252 s master-lvl;
+#X obj 26 217 inlet~;
+#X obj 239 49 inlet;
+#X text 239 22 level;
+#X obj 239 120 s master-lvl;
+#X msg 115 78 set \$1;
+#X obj 115 107 outlet;
+#X msg 257 77 \; pd dsp 1;
+#X obj 100 233 line~;
+#X obj 26 254 *~;
+#X obj 26 289 dac~;
+#X obj 100 205 pack 0 50;
+#X text 24 190 audio;
+#X text 112 132 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 547 595 pd output;
+#X msg 617 562 MUTE;
+#X text 660 561 <-- output amplitude;
+#N canvas 0 0 600 392 samples 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array sample1 176403 float 0;
+#X coords 0 1.02 176403 -1.02 200 130 1;
+#X restore 262 41 graph;
+#X text 282 385 ------ 4 seconds ------;
+#N canvas 0 0 450 300 graph1 0;
+#X array sample2 176403 float 0;
+#X coords 0 1.02 176403 -1.02 200 130 1;
+#X restore 262 226 graph;
+#X restore 931 97 pd samples;
+#N canvas 52 219 967 340 recorder 0;
+#X obj 220 21 inlet;
+#X obj 174 174 adc~ 1;
+#X obj 174 202 hip~ 5;
+#X obj 243 232 line~;
+#X obj 174 231 *~;
+#X msg 243 204 1;
+#X obj 302 169 del 3990;
+#X msg 279 204 0 10;
+#X obj 174 282 tabwrite~ sample1;
+#X obj 26 88 makefilename sample%1;
+#X msg 26 117 set \$1 \, bang;
+#X msg 348 140 stop;
+#X msg 302 140 bang;
+#X obj 220 50 route record stop reload browse;
+#X obj 411 158 loadbang;
+#X obj 514 113 openpanel;
+#X msg 514 85 bang;
+#X text 556 84 <-- browse for samples;
+#X text 482 209 v-- re-read original samples;
+#X obj 411 295 soundfiler;
+#X msg 411 237 read ../sound/bell.aiff sample1 \, read ../sound/voice2.wav
+sample2;
+#X msg 514 140 read \$1 sample1;
+#X obj 514 167 soundfiler;
+#X connect 0 0 13 0;
+#X connect 1 0 2 0;
+#X connect 2 0 4 0;
+#X connect 3 0 4 1;
+#X connect 4 0 8 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 7 0 3 0;
+#X connect 9 0 10 0;
+#X connect 10 0 8 0;
+#X connect 11 0 6 0;
+#X connect 12 0 6 0;
+#X connect 13 0 9 0;
+#X connect 13 0 12 0;
+#X connect 13 0 5 0;
+#X connect 13 1 7 0;
+#X connect 13 1 11 0;
+#X connect 13 2 20 0;
+#X connect 13 3 16 0;
+#X connect 14 0 20 0;
+#X connect 15 0 21 0;
+#X connect 16 0 15 0;
+#X connect 20 0 19 0;
+#X connect 21 0 22 0;
+#X restore 931 284 pd recorder;
+#X msg 931 146 record 1;
+#X msg 931 202 stop;
+#X msg 931 174 record 2;
+#X text 19 49 ARGUMENTS FOR NOTES:;
+#X text 19 71 pitch in halftones;
+#X text 19 95 amplitude (dB);
+#X text 19 143 sample number;
+#X text 19 119 duration (msec);
+#X text 19 167 start location (msec);
+#X text 19 191 rise time (msec);
+#X text 19 215 decay time (msec);
+#X msg 931 229 reload;
+#X msg 931 257 browse;
+#X text 47 10 POLYPHONIC SAMPLER;
+#X obj 547 522 sampvoice;
+#X obj 547 494 sampvoice;
+#X obj 547 467 sampvoice;
+#X obj 547 439 sampvoice;
+#X obj 547 412 sampvoice;
+#X obj 547 384 sampvoice;
+#X obj 547 356 sampvoice;
+#X obj 547 329 sampvoice;
+#X obj 631 17 r note;
+#X obj 631 44 unpack 0 0 0 0 0 0 0;
+#X obj 604 76 t b f;
+#X obj 544 109 f;
+#X obj 580 109 + 1;
+#X obj 552 146 mod 1e+06;
+#X obj 544 175 makenote 64;
+#X obj 544 203 poly 8 1;
+#X obj 544 230 stripnote;
+#X obj 617 272 pack 0 0 0 0 0 0 0 0;
+#X obj 617 300 route 1 2 3 4 5 6 7 8;
+#X text 929 124 record \, etc.;
+#X text 206 142 increment mod 1e+06 to make fake pitch;
+#X text 326 177 supply note-off message;
+#X text 336 207 allocate sampler voice;
+#X text 359 232 drop note off again;
+#X obj 704 516 qlist;
+#X obj 870 520 r comment;
+#X text 732 445 sailors to untie him...;
+#X text 735 395 Lashed to the mast of his boat \, Ulysses;
+#X text 735 420 hears beautiful singing. He begs his;
+#X text 19 271 Here we take the previous patch and make it polyphonic
+\, with 8 voices. The single voice which we had before has been made
+into an abstraction \, "sampvoice.pd" \, which we instantiate in 8
+copies. Earlier we used sends and receives to pass messages to "cutoff"
+\, etc \, but here if we did that the copies of sampvoice would be
+sending messages to each other \, so we combine the control and the
+audio computation in the sampvoice abstraction without using send and
+receive. Click on one to see how.;
+#X text 20 421 The "poly" object essentially repeats pitch and velocity
+pairs to its output \, but also sending a voice number from its left
+outlet. To use it \, we unpack the 7 parameters \, calculate the voice
+number \, repack the message as 8 parameters with voice number first
+\, and use "route" to send it to one of the 8 voices.;
+#X text 20 523 There's some bother because poly expects to track note
+on and note off messages separately as they would come from a MIDI
+keyboard. So we assign each note a unique fake "pitch" \, use makenote
+to generate the note-off messages \, and run poly on the resulting
+stream. We then discard both pitch and velocity (using the velocity
+only to strip note-offs) and rebuild the original message adding the
+voice number we just scored.;
+#X text 854 639 updated for Pd version 0.33;
+#X msg 704 486 read qlist-sampler.txt \, rewind \, tempo 1 \, bang
+;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 8 0 5 0;
+#X connect 17 0 5 0;
+#X connect 18 0 5 0;
+#X connect 20 0 1 0;
+#X connect 21 0 20 0;
+#X connect 22 0 21 0;
+#X connect 23 0 22 0;
+#X connect 24 0 23 0;
+#X connect 25 0 24 0;
+#X connect 26 0 25 0;
+#X connect 27 0 26 0;
+#X connect 28 0 29 0;
+#X connect 29 0 30 0;
+#X connect 29 1 37 2;
+#X connect 29 2 34 2;
+#X connect 29 2 37 3;
+#X connect 29 3 37 4;
+#X connect 29 4 37 5;
+#X connect 29 5 37 6;
+#X connect 29 6 37 7;
+#X connect 30 0 31 0;
+#X connect 30 1 37 1;
+#X connect 31 0 32 0;
+#X connect 31 0 34 0;
+#X connect 32 0 33 0;
+#X connect 33 0 31 1;
+#X connect 34 0 35 0;
+#X connect 34 1 35 1;
+#X connect 35 0 36 0;
+#X connect 35 2 36 1;
+#X connect 36 0 37 0;
+#X connect 37 0 38 0;
+#X connect 38 0 27 1;
+#X connect 38 1 26 1;
+#X connect 38 2 25 1;
+#X connect 38 3 24 1;
+#X connect 38 4 23 1;
+#X connect 38 5 22 1;
+#X connect 38 6 21 1;
+#X connect 38 7 20 1;
+#X connect 53 0 44 0;
diff --git a/pd/doc/3.audio.examples/D09.table.spectrum.pd b/pd/doc/3.audio.examples/D09.table.spectrum.pd
new file mode 100644
index 00000000..65ccccde
--- /dev/null
+++ b/pd/doc/3.audio.examples/D09.table.spectrum.pd
@@ -0,0 +1,143 @@
+#N canvas 227 120 801 403 12;
+#X graph graph3 0 0 126 50 496 276 796 136;
+#X array spectrum-tab 127 float 1;
+#A 0 42.8571 42.5 43.2143 43.2143 43.2143 43.2143 43.2143 42.8571 42.8571
+42.8571 42.8571 42.8571 42.8571 42.5 42.5 42.5 42.5 42.5 42.5 42.5
+42.5 42.5 42.5 42.5 42.5 42.5 42.5 42.5 42.5 42.5 42.5 42.5 42.5 42.5
+42.5 42.5 42.1429 42.1429 41.7857 41.0714 40.3571 39.6429 39.2857 38.2143
+37.5 37.1429 36.0714 35.3571 33.9286 33.2143 32.8571 31.4286 31.0714
+30.3571 28.9286 28.2143 27.5 26.4286 25.7143 23.9286 23.2143 21.7857
+21.0714 20.7143 20 19.6429 19.6429 23.2143 28.2143 31.4286 33.5714
+36.4286 37.8571 38.9286 43.9286 45.7143 47.8571 47.8571 47.8571 47.8571
+47.5 47.1429 43.2143 40.3571 36.4286 33.9286 32.1429 29.2857 18.2143
+16.7857 16.7857 17.5 19.6429 22.1429 28.2143 33.9286 33.9286 33.9286
+33.5714 22.5 18.5714 16.7857 4.64286 4.64286 18.2143 17.1429 8.92857
+4.28571 11.4286 10 7.5 6.42857 5.71429 5.35714 5 4.64286 4.28571 3.92857
+3.92857 3.57143 3.57143 2.85714 2.5 2.14286 1.78571 0.714286 0.357143
+;
+#X pop;
+#X floatatom 57 351 0 0 0;
+#N canvas 159 26 526 286 output 0;
+#X obj 345 163 t b;
+#X obj 345 112 f;
+#X obj 345 61 inlet;
+#X text 351 30 mute;
+#X obj 345 189 f;
+#X msg 434 182 0;
+#X msg 345 87 bang;
+#X obj 345 138 moses 1;
+#X obj 405 119 moses 1;
+#X obj 85 151 dbtorms;
+#X obj 405 94 r master-lvl;
+#X obj 85 43 r master-lvl;
+#X obj 345 214 s master-lvl;
+#X obj 22 185 inlet~;
+#X obj 203 42 inlet;
+#X text 203 18 level;
+#X obj 203 102 s master-lvl;
+#X msg 98 67 set \$1;
+#X obj 98 91 outlet;
+#X msg 218 65 \; pd dsp 1;
+#X obj 85 198 line~;
+#X obj 22 216 *~;
+#X obj 22 246 dac~;
+#X obj 85 175 pack 0 50;
+#X text 20 162 audio;
+#X obj 434 155 t b;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 25 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 21 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 25 0 5 0;
+#X restore 19 376 pd output;
+#X msg 95 350 MUTE;
+#N canvas 98 16 694 474 oscbank 0;
+#X obj 36 53 spectrum-partial 1;
+#X obj 36 79 spectrum-partial 2;
+#X obj 36 105 spectrum-partial 3;
+#X obj 36 131 spectrum-partial 4;
+#X obj 36 157 spectrum-partial 5;
+#X obj 36 183 spectrum-partial 6;
+#X obj 36 209 spectrum-partial 7;
+#X obj 36 235 spectrum-partial 8;
+#X obj 36 261 spectrum-partial 9;
+#X obj 36 287 spectrum-partial 10;
+#X obj 216 53 spectrum-partial 11;
+#X obj 122 382 loadbang;
+#X obj 122 407 metro 30;
+#X obj 122 433 s poll-table;
+#X text 107 21 This is the bank of oscillators--open one to see:;
+#X text 72 345 And here we send bangs to "poll-table" needed by the
+abstraction.;
+#X obj 216 79 spectrum-partial 12;
+#X obj 216 105 spectrum-partial 13;
+#X obj 216 131 spectrum-partial 14;
+#X obj 216 157 spectrum-partial 15;
+#X obj 216 183 spectrum-partial 16;
+#X obj 216 209 spectrum-partial 17;
+#X obj 216 235 spectrum-partial 18;
+#X obj 215 261 spectrum-partial 19;
+#X obj 215 287 spectrum-partial 20;
+#X obj 395 53 spectrum-partial 21;
+#X obj 395 78 spectrum-partial 22;
+#X obj 395 104 spectrum-partial 23;
+#X obj 395 130 spectrum-partial 24;
+#X obj 395 156 spectrum-partial 25;
+#X obj 395 182 spectrum-partial 26;
+#X obj 395 207 spectrum-partial 27;
+#X obj 396 234 spectrum-partial 28;
+#X obj 395 260 spectrum-partial 29;
+#X obj 395 287 spectrum-partial 30;
+#X connect 11 0 12 0;
+#X connect 12 0 13 0;
+#X restore 17 251 pd oscbank;
+#X obj 19 321 catch~ sum-bus;
+#X obj 16 153 s pitch;
+#X floatatom 16 125 4 0 0;
+#X text 43 18 DRAWABLE SPECTRA;
+#X floatatom 14 183 4 0 0;
+#X obj 14 211 s whammybar;
+#N canvas 0 0 650 341 table-setup 0;
+#X obj 39 227 loadbang;
+#X msg 39 261 \; spectrum-tab xlabel -5 0 12 24 36 48 60 72 84 96 108
+120;
+#X text 82 60 comment;
+#X connect 0 0 1 0;
+#X restore 17 283 pd table-setup;
+#X msg 596 65 \; spectrum-tab const 0;
+#X text 555 381 Updated for Pd version 0.34;
+#X text 26 42 In this array \, you can draw a spectral envelope that
+will be synthesized by an oscillator bank. Each oscillator in the bank
+computes its own frequency and uses it to look up amplitude from the
+array.;
+#X text 113 254 <-- the oscillator bank;
+#X text 71 128 <-- pitch;
+#X text 61 185 <-- left or right shift (normally 0);
+#X text 157 318 <-- here we just collect the sum of all the partials
+which are computed in "oscbank".;
+#X text 662 44 CLEAR;
+#X text 148 283 <-- make the number labels;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 5 0 2 0;
+#X connect 7 0 6 0;
+#X connect 9 0 10 0;
diff --git a/pd/doc/3.audio.examples/D10.risset.bell.pd b/pd/doc/3.audio.examples/D10.risset.bell.pd
new file mode 100644
index 00000000..8e329eaa
--- /dev/null
+++ b/pd/doc/3.audio.examples/D10.risset.bell.pd
@@ -0,0 +1,109 @@
+#N canvas 375 37 484 454 12;
+#X floatatom 129 403 0 0 0 0 - - -;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 182 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 159 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 105 428 pd output;
+#X msg 154 403 MUTE;
+#X text 195 402 <-- output amplitude;
+#X obj 97 167 sinevoice 1 0.56 0 1;
+#X obj 243 42 unpack 0 0 0;
+#X floatatom 242 84 0 0 0 0 - - -;
+#X obj 217 62 t b f;
+#X floatatom 276 84 0 0 0 0 - - -;
+#X floatatom 310 84 0 0 0 0 - - -;
+#X obj 217 105 f;
+#X msg 170 84 bang;
+#X obj 217 127 pack 0 0 0;
+#X msg 243 20 80 72 5000;
+#X obj 97 189 sinevoice 0.67 0.56 1 0.9;
+#X obj 97 211 sinevoice 1 0.92 0 0.65;
+#X obj 97 233 sinevoice 1.8 0.92 1.7 0.55;
+#X obj 97 255 sinevoice 2.67 1.19 0 0.325;
+#X obj 97 277 sinevoice 1.67 1.7 0 0.35;
+#X obj 97 299 sinevoice 1.46 2 0 0.25;
+#X obj 97 321 sinevoice 1.33 2.74 0 0.2;
+#X obj 97 343 sinevoice 1 3 0 0.15;
+#X obj 97 365 sinevoice 1.33 4.07 0 0.075;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 4 0 14 0;
+#X connect 4 1 14 1;
+#X connect 5 0 7 0;
+#X connect 5 1 8 0;
+#X connect 5 2 9 0;
+#X connect 6 0 10 1;
+#X connect 7 0 10 0;
+#X connect 7 1 6 0;
+#X connect 8 0 12 1;
+#X connect 9 0 12 2;
+#X connect 10 0 12 0;
+#X connect 11 0 10 0;
+#X connect 12 0 4 1;
+#X connect 13 0 5 0;
+#X connect 14 0 15 0;
+#X connect 14 1 15 1;
+#X connect 15 0 16 0;
+#X connect 15 1 16 1;
+#X connect 16 0 17 0;
+#X connect 16 1 17 1;
+#X connect 17 0 18 0;
+#X connect 17 1 18 1;
+#X connect 18 0 19 0;
+#X connect 18 1 19 1;
+#X connect 19 0 20 0;
+#X connect 19 1 20 1;
+#X connect 20 0 21 0;
+#X connect 20 1 21 1;
+#X connect 21 0 22 0;
+#X connect 21 1 22 1;
+#X connect 22 0 1 0;
diff --git a/pd/doc/3.audio.examples/D11.shepard.tone.pd b/pd/doc/3.audio.examples/D11.shepard.tone.pd
new file mode 100644
index 00000000..8be283ab
--- /dev/null
+++ b/pd/doc/3.audio.examples/D11.shepard.tone.pd
@@ -0,0 +1,110 @@
+#N canvas 19 0 594 599 12;
+#X floatatom 107 202 0 0 0 0 - - -;
+#X floatatom 11 202 0 0 0 0 - - -;
+#X text 140 17 STOP;
+#X text 20 3 START;
+#X floatatom 78 358 0 0 0 0 - - -;
+#X obj 78 337 r incr;
+#X obj 65 310 metro 50;
+#X floatatom 64 426 0 0 0 0 - - -;
+#X obj 62 494 s phase;
+#X obj 62 474 + 10000;
+#X obj 64 406 +;
+#X obj 11 222 s dropoff+;
+#X obj 186 221 s interval+;
+#X floatatom 186 201 0 0 0 0 - - -;
+#X obj 107 222 s pitch+;
+#X obj 11 182 r dropoff;
+#X obj 107 182 r pitch;
+#X obj 186 181 r interval;
+#X floatatom 65 289 0 0 0 0 - - -;
+#X obj 65 269 r metro;
+#X obj 124 406 f;
+#X obj 295 467 *~;
+#X obj 295 15 shepvoice 0;
+#X obj 315 441 line~;
+#X obj 471 408 pack 0 100;
+#X floatatom 471 367 0 0 0 0 - - -;
+#X obj 471 347 r amp;
+#X obj 295 519 dac~;
+#X obj 471 387 dbtorms;
+#X floatatom 372 464 0 0 0 0 - - -;
+#X obj 372 444 r rev;
+#X obj 420 440 r revtime;
+#X floatatom 420 461 0 0 0 0 - - -;
+#X obj 313 497 rev4~;
+#X obj 124 426 mod 10000;
+#X obj 295 36 shepvoice 500;
+#X obj 295 56 shepvoice 1000;
+#X obj 295 77 shepvoice 1500;
+#X obj 295 97 shepvoice 2000;
+#X obj 295 117 shepvoice 2500;
+#X obj 295 138 shepvoice 3000;
+#X obj 295 158 shepvoice 3500;
+#X obj 295 179 shepvoice 4000;
+#X obj 295 199 shepvoice 4500;
+#X obj 295 219 shepvoice 5000;
+#X obj 295 240 shepvoice 5500;
+#X obj 295 260 shepvoice 6000;
+#X obj 295 281 shepvoice 6500;
+#X obj 295 301 shepvoice 7000;
+#X obj 295 321 shepvoice 7500;
+#X obj 295 342 shepvoice 8000;
+#X obj 295 362 shepvoice 8500;
+#X obj 295 385 shepvoice 9000;
+#X obj 295 405 shepvoice 9500;
+#X obj 65 380 f;
+#X msg 140 35 \; amp 0 \;;
+#X msg 6 18 \; dropoff 10 \; pitch 60 \; interval 120 \; metro 1 \;
+rev 74 \; revtime 87 \; incr -2 \; pd dsp 1;
+#X connect 0 0 14 0;
+#X connect 1 0 11 0;
+#X connect 4 0 54 1;
+#X connect 5 0 4 0;
+#X connect 6 0 54 0;
+#X connect 7 0 9 0;
+#X connect 9 0 8 0;
+#X connect 10 0 20 0;
+#X connect 10 0 7 0;
+#X connect 13 0 12 0;
+#X connect 15 0 1 0;
+#X connect 16 0 0 0;
+#X connect 17 0 13 0;
+#X connect 18 0 6 0;
+#X connect 19 0 18 0;
+#X connect 20 0 34 0;
+#X connect 21 0 27 0;
+#X connect 21 0 33 0;
+#X connect 22 0 35 0;
+#X connect 23 0 21 1;
+#X connect 24 0 23 0;
+#X connect 25 0 28 0;
+#X connect 26 0 25 0;
+#X connect 28 0 24 0;
+#X connect 29 0 33 1;
+#X connect 30 0 29 0;
+#X connect 31 0 32 0;
+#X connect 32 0 33 2;
+#X connect 33 0 27 0;
+#X connect 33 1 27 1;
+#X connect 34 0 10 1;
+#X connect 35 0 36 0;
+#X connect 36 0 37 0;
+#X connect 37 0 38 0;
+#X connect 38 0 39 0;
+#X connect 39 0 40 0;
+#X connect 40 0 41 0;
+#X connect 41 0 42 0;
+#X connect 42 0 43 0;
+#X connect 43 0 44 0;
+#X connect 44 0 45 0;
+#X connect 45 0 46 0;
+#X connect 46 0 47 0;
+#X connect 47 0 48 0;
+#X connect 48 0 49 0;
+#X connect 49 0 50 0;
+#X connect 50 0 51 0;
+#X connect 51 0 52 0;
+#X connect 52 0 53 0;
+#X connect 53 0 21 0;
+#X connect 54 0 10 0;
diff --git a/pd/doc/3.audio.examples/E01.pulse.pd b/pd/doc/3.audio.examples/E01.pulse.pd
new file mode 100644
index 00000000..8efe6390
--- /dev/null
+++ b/pd/doc/3.audio.examples/E01.pulse.pd
@@ -0,0 +1,126 @@
+#N canvas 15 126 821 582 12;
+#X obj 285 163 line~;
+#X floatatom 66 64 0 0 0;
+#X obj 43 315 cos~;
+#X graph graph1 0 -1.02 882 1.02 599 472 799 342;
+#X array pulse-output 882 float 0;
+#X pop;
+#X floatatom 72 407 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 43 435 pd output;
+#X msg 111 405 MUTE;
+#X text 158 406 <-- output amplitude;
+#X obj 66 91 phasor~ 0;
+#X obj 285 139 pack 0 50;
+#X floatatom 285 54 0 0 0;
+#X text 63 43 frequency;
+#X obj 66 115 -~ 0.5;
+#X obj 66 207 *~;
+#X obj 285 78 / 10;
+#X obj 43 265 clip~ -0.5 0.5;
+#X obj 43 371 hip~ 5;
+#X graph graph1 0 -1.02 882 1.02 599 168 799 108;
+#X array phase-output 882 float 0;
+#X pop;
+#X graph graph1 0 -1.02 882 1.02 599 335 799 205;
+#X array clip-output 882 float 0;
+#X pop;
+#X text 280 34 bandwidth;
+#X text 130 114 phase -1/2 to 1/2;
+#X text 152 91 phase 0 to 1;
+#X text 132 5 PULSE GENERATOR;
+#X obj 32 234 tabwrite~ phase-output;
+#X obj 32 346 tabwrite~ pulse-output;
+#X text 116 372 high pass filter to cut DC;
+#X msg 32 147 bang;
+#X text 332 79 fix range;
+#X text 337 100 force;
+#X text 337 117 nonnegative;
+#X text 339 164 smooth it;
+#X text 327 187 add 1;
+#X text 78 148 <-- click to graph;
+#X text 96 209 increase amplitude;
+#X text 177 264 clip back to range -1/2 to 1/2;
+#X text 103 316 cosine wave lookup (-1/2 and 1/2 give -1);
+#X text 24 470 This patch computes a pulse train \, with a "bandwidth"
+control that essentually squeezes the pulses. If "bandwidth" is zero
+you get a pure cosine wave \, and for larger values of the bandwidth
+\, the cosine wave is squeezed to fill smaller portions of the waveform.
+;
+#X obj 285 188 +~ 1;
+#X obj 32 292 tabwrite~ clip-output;
+#X text 601 478 ---- 0.02 seconds ----;
+#X obj 285 102 max 0;
+#X text 544 551 updated for Pd version 0.34;
+#X connect 0 0 37 0;
+#X connect 1 0 8 0;
+#X connect 2 0 16 0;
+#X connect 2 0 24 0;
+#X connect 4 0 5 1;
+#X connect 5 0 4 0;
+#X connect 6 0 5 2;
+#X connect 8 0 12 0;
+#X connect 9 0 0 0;
+#X connect 10 0 14 0;
+#X connect 12 0 13 0;
+#X connect 13 0 15 0;
+#X connect 13 0 23 0;
+#X connect 14 0 40 0;
+#X connect 15 0 2 0;
+#X connect 15 0 38 0;
+#X connect 16 0 5 0;
+#X connect 26 0 23 0;
+#X connect 26 0 24 0;
+#X connect 26 0 38 0;
+#X connect 37 0 13 1;
+#X connect 40 0 9 0;
diff --git a/pd/doc/3.audio.examples/E02.just.say.pd b/pd/doc/3.audio.examples/E02.just.say.pd
new file mode 100644
index 00000000..b82b4953
--- /dev/null
+++ b/pd/doc/3.audio.examples/E02.just.say.pd
@@ -0,0 +1,152 @@
+#N canvas 32 67 900 421 12;
+#X obj 39 247 cos~;
+#X graph graph1 0 -1.02 44100 1.02 452 206 652 76;
+#X array env-output 44100 float 0;
+#X pop;
+#X floatatom 71 305 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 39 333 pd output;
+#X msg 115 306 MUTE;
+#X msg 162 93 bang;
+#X text 203 93 <-- click to graph;
+#X obj 39 168 -~ 0.5;
+#X obj 39 192 *~;
+#X obj 39 219 clip~ -0.5 0.5;
+#X obj 39 274 hip~ 5;
+#X obj 126 60 *~;
+#X floatatom 205 142 0 0 0;
+#X floatatom 205 168 0 0 0;
+#X obj 126 27 phasor~ -4;
+#X obj 126 191 +~ 0.5;
+#X obj 162 117 tabwrite~ env-output;
+#X text 451 211 --------- 1 second ---------;
+#X floatatom 205 194 0 0 0;
+#X obj 126 142 lop~ 130;
+#N canvas 168 232 351 420 freq 0;
+#X obj 180 176 t f f;
+#X obj 181 202 *;
+#X obj 60 320 line 0 30;
+#X obj 90 132 t b b;
+#X obj 90 107 metro 100;
+#X obj 61 287 pack;
+#X obj 60 376 outlet;
+#X floatatom 89 82 0 0 0;
+#X floatatom 54 243 0 0 0;
+#X floatatom 94 248 0 0 0;
+#X obj 60 348 pack 0 30;
+#X obj 55 202 + 150;
+#X obj 88 34 loadbang;
+#X msg 89 58 1;
+#X obj 56 175 random 300;
+#X obj 181 226 + 100;
+#X obj 179 152 random 35;
+#X connect 0 0 1 0;
+#X connect 0 1 1 1;
+#X connect 1 0 15 0;
+#X connect 2 0 10 0;
+#X connect 3 0 14 0;
+#X connect 3 1 16 0;
+#X connect 4 0 3 0;
+#X connect 5 0 2 0;
+#X connect 7 0 4 0;
+#X connect 8 0 5 0;
+#X connect 9 0 5 1;
+#X connect 10 0 6 0;
+#X connect 11 0 8 0;
+#X connect 12 0 13 0;
+#X connect 13 0 7 0;
+#X connect 14 0 11 0;
+#X connect 15 0 4 1;
+#X connect 15 0 9 0;
+#X connect 16 0 0 0;
+#X restore 38 94 pd freq;
+#X obj 39 119 line~;
+#X obj 39 144 phasor~;
+#X text 225 19 negative frequency;
+#X text 226 35 makes falling sawtooth;
+#X text 155 59 square it to make a curve;
+#X text 245 152 you can;
+#X text 243 170 adjust these;
+#X text 247 189 values;
+#X text 334 250 We interrupt this series of patches to bring you an
+important message from Nancy Reagan. If \, anywhere \, at any time
+\, someone offers you an illicit drug \, just say one word in reply...
+;
+#X text 334 313 Now that I'm sure you've heard this important message
+\, we can return to the essentially frivolous occupation of making
+turn-of-the-millenium western art music.;
+#X obj 126 165 *~ 6;
+#X text 561 384 updated for Pd version 0.34;
+#X text 156 305 <-- output;
+#X connect 0 0 10 0;
+#X connect 2 0 3 1;
+#X connect 3 0 2 0;
+#X connect 4 0 3 2;
+#X connect 5 0 16 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 0 0;
+#X connect 10 0 3 0;
+#X connect 11 0 16 0;
+#X connect 11 0 19 0;
+#X connect 12 0 19 1;
+#X connect 13 0 31 1;
+#X connect 14 0 11 0;
+#X connect 14 0 11 1;
+#X connect 15 0 8 1;
+#X connect 18 0 15 1;
+#X connect 19 0 31 0;
+#X connect 20 0 21 0;
+#X connect 21 0 22 0;
+#X connect 22 0 7 0;
+#X connect 31 0 15 0;
diff --git a/pd/doc/3.audio.examples/E03.pulse.spectrum.pd b/pd/doc/3.audio.examples/E03.pulse.spectrum.pd
new file mode 100644
index 00000000..49d21cbd
--- /dev/null
+++ b/pd/doc/3.audio.examples/E03.pulse.spectrum.pd
@@ -0,0 +1,136 @@
+#N canvas 15 126 887 588 12;
+#X obj 189 166 line~;
+#X obj 42 187 cos~;
+#X graph graph1 0 -1.02 882 1.02 633 508 833 378;
+#X array pulse-output 882 float 0;
+#X pop;
+#X floatatom 71 317 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 42 345 pd output;
+#X msg 118 319 MUTE;
+#X obj 189 142 pack 0 50;
+#X floatatom 189 41 0 0 0;
+#X text 598 545 updated for Pd version 0.26;
+#X obj 43 114 -~ 0.5;
+#X obj 43 140 *~;
+#X obj 189 67 / 10;
+#X obj 189 91 moses 0;
+#X msg 189 115 0;
+#X obj 42 163 clip~ -0.5 0.5;
+#X obj 42 289 hip~ 5;
+#X graph graph1 0 0 128 500 503 285 759 155;
+#X array spectrum 128 float 0;
+#X pop;
+#X text 184 23 bandwidth;
+#X obj 115 267 tabwrite~ pulse-output;
+#X msg 105 229 bang;
+#X text 143 226 <-- click to graph;
+#X obj 189 191 +~ 1;
+#N canvas 204 17 358 238 fft 0;
+#X obj 46 48 inlet~;
+#X obj 159 181 tabwrite~ spectrum;
+#X obj 159 145 inlet;
+#X obj 46 78 rfft~;
+#X obj 46 111 *~;
+#X obj 77 111 *~;
+#X obj 46 141 sqrt~;
+#X obj 191 45 block~ 1024 1;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 3 0 4 1;
+#X connect 3 1 5 0;
+#X connect 3 1 5 1;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X restore 53 267 pd fft;
+#X obj 43 90 phasor~ 172.266;
+#X obj 42 211 +~ 1;
+#X text 63 1 PULSE SPECTRUM MEASUREMENT;
+#X text 16 377 Here is a measured amplitude spectrum for the pulse
+train. Nutice that \, other than a smallish spillover \, the energy
+sits in one "lobe" whose changing width justifies our calling the squeeze
+factor the "bandwidth.";
+#X text 16 442 The spectrum is in units of amplitude. THe sidelobes
+\, although they look small \, are actually only about 34 dB down.
+You can design more complicated pulse trains \, little Blackman window
+functions \, which control the sidelobes much better.;
+#X text 17 518 The spectrum measurement is done in the "pd fft" subwindow
+\, but see the "FFT examples" for information about that.;
+#X text 501 291 0;
+#X text 749 288 5512;
+#X text 633 511 ---- 0.02 seconds ----;
+#X text 160 319 <-- output;
+#X connect 0 0 21 0;
+#X connect 1 0 24 0;
+#X connect 3 0 4 1;
+#X connect 4 0 3 0;
+#X connect 5 0 4 2;
+#X connect 6 0 0 0;
+#X connect 7 0 11 0;
+#X connect 9 0 10 0;
+#X connect 10 0 14 0;
+#X connect 11 0 12 0;
+#X connect 12 0 13 0;
+#X connect 12 1 6 0;
+#X connect 13 0 6 0;
+#X connect 14 0 1 0;
+#X connect 15 0 4 0;
+#X connect 19 0 18 0;
+#X connect 19 0 22 1;
+#X connect 21 0 10 1;
+#X connect 23 0 9 0;
+#X connect 24 0 22 0;
+#X connect 24 0 15 0;
+#X connect 24 0 18 0;
diff --git a/pd/doc/3.audio.examples/E04.more.pulses.pd b/pd/doc/3.audio.examples/E04.more.pulses.pd
new file mode 100644
index 00000000..1aa97555
--- /dev/null
+++ b/pd/doc/3.audio.examples/E04.more.pulses.pd
@@ -0,0 +1,138 @@
+#N canvas 15 126 902 581 12;
+#X obj 220 171 line~;
+#X msg 350 15 \; pd dsp 1;
+#X msg 434 16 \; pd dsp 0;
+#X text 371 46 ON;
+#X text 451 47 OFF;
+#X floatatom 68 303 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 39 331 pd output;
+#X msg 106 303 MUTE;
+#X text 150 302 <-- output amplitude;
+#X obj 220 147 pack 0 50;
+#X floatatom 220 46 0 0 0;
+#X text 640 544 updated for Pd version 0.26;
+#X obj 70 108 *~;
+#X obj 220 72 / 10;
+#X obj 220 96 moses 0;
+#X msg 220 120 0;
+#X obj 39 275 hip~ 5;
+#X graph graph1 0 0 128 300 620 491 876 361;
+#X array spectrum 128 float 0;
+#X pop;
+#X text 215 28 bandwidth;
+#X msg 135 235 bang;
+#X text 177 234 <-- click to graph;
+#N canvas 204 17 358 238 fft 0;
+#X obj 46 48 inlet~;
+#X obj 159 181 tabwrite~ spectrum;
+#X obj 159 145 inlet;
+#X obj 46 78 rfft~;
+#X obj 46 111 *~;
+#X obj 77 111 *~;
+#X obj 46 141 sqrt~;
+#X obj 191 45 block~ 1024 1;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 3 0 4 1;
+#X connect 3 1 5 0;
+#X connect 3 1 5 1;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X restore 68 237 pd fft;
+#X text 618 497 0;
+#X text 851 492 5512;
+#X obj 78 141 *~;
+#X obj 18 141 sig~ 1;
+#X obj 39 194 /~;
+#X obj 54 168 +~;
+#X obj 70 79 osc~ 86.1328;
+#X text 103 107 call this X;
+#X text 111 141 X^2;
+#X text 84 171 1+X^2;
+#X text 71 196 1/(1+X^2);
+#X text 10 357 This is the form of pulse train used in the Phase Aligned
+Formant (PAF) algorithm. It has the neat property that its amplitude
+spectrum drops off as a perfectly exponential function of frequency.
+This algorithm is protected by French and US patents. contact Vincent
+Puig to learn what restrictions may apply.;
+#X text 11 457 On the other hand \, there are rumors that exp(-X*X)
+actually sounds better than 1/(1+X*X). To compute exp(-X*X) efficiently
+you will want to employ tabread4~ with a stored bell curve. I don't
+want to know you're doing this. However \, the first Pd user who e-mails
+me the correct formula for the output spectrum wins a free CO2 fire
+extinguisher.;
+#X text 28 4 ANOTHER PULSE WIDTH MOD ALGORITHM;
+#X connect 0 0 12 1;
+#X connect 5 0 6 1;
+#X connect 6 0 5 0;
+#X connect 7 0 6 2;
+#X connect 9 0 0 0;
+#X connect 10 0 13 0;
+#X connect 12 0 24 0;
+#X connect 12 0 24 1;
+#X connect 13 0 14 0;
+#X connect 14 0 15 0;
+#X connect 14 1 9 0;
+#X connect 15 0 9 0;
+#X connect 16 0 6 0;
+#X connect 19 0 21 1;
+#X connect 24 0 27 1;
+#X connect 25 0 26 0;
+#X connect 25 0 27 0;
+#X connect 26 0 16 0;
+#X connect 26 0 21 0;
+#X connect 27 0 26 1;
+#X connect 28 0 12 0;
diff --git a/pd/doc/3.audio.examples/E05.pulse.width.mod.pd b/pd/doc/3.audio.examples/E05.pulse.width.mod.pd
new file mode 100644
index 00000000..214d250a
--- /dev/null
+++ b/pd/doc/3.audio.examples/E05.pulse.width.mod.pd
@@ -0,0 +1,98 @@
+#N canvas 27 355 931 532 12;
+#X floatatom 86 104 0 0 0;
+#X graph graph1 0 -1.02 882 1.02 669 456 869 326;
+#X array difference-output 882 float 0;
+#X pop;
+#X floatatom 123 324 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 86 351 pd output;
+#X msg 162 324 MUTE;
+#X obj 86 137 phasor~ 0;
+#X text 83 86 frequency;
+#X graph graph1 0 -1.02 882 1.02 668 179 868 49;
+#X array phasor1-output 882 float 0;
+#X pop;
+#X msg 191 77 bang;
+#X text 231 76 <-- click to graph;
+#X text 57 9 CLASSICAL PULSE WIDTH MODULATION;
+#X obj 102 196 phasor~ 0;
+#X obj 102 172 + 0.2;
+#X obj 86 246 -~;
+#X graph graph1 0 -1.02 882 1.02 668 316 868 186;
+#X array phasor2-output 882 float 0;
+#X pop;
+#X obj 191 164 tabwrite~ phasor1-output;
+#X obj 191 222 tabwrite~ phasor2-output;
+#X obj 191 276 tabwrite~ difference-output;
+#X text 12 386 This patch demonstrates pulse width modulation \, which
+is accomplished simply by subtracting two sawtooth waves at a varying
+phase difference. Here their frequencies are set to differ by 1/5 Hz.
+so that the relative phase wanders continuously.;
+#X text 669 459 ---- 0.02 seconds ----;
+#X text 665 498 updated for Pd version 0.34;
+#X text 203 325 <-- output;
+#X connect 0 0 5 0;
+#X connect 0 0 12 0;
+#X connect 2 0 3 1;
+#X connect 3 0 2 0;
+#X connect 4 0 3 2;
+#X connect 5 0 13 0;
+#X connect 5 0 15 0;
+#X connect 8 0 15 0;
+#X connect 8 0 16 0;
+#X connect 8 0 17 0;
+#X connect 11 0 13 1;
+#X connect 11 0 16 0;
+#X connect 12 0 11 0;
+#X connect 13 0 17 0;
+#X connect 13 0 3 0;
diff --git a/pd/doc/3.audio.examples/E06.stereo.pd b/pd/doc/3.audio.examples/E06.stereo.pd
new file mode 100644
index 00000000..1c417df5
--- /dev/null
+++ b/pd/doc/3.audio.examples/E06.stereo.pd
@@ -0,0 +1,87 @@
+#N canvas 27 355 553 341 12;
+#X floatatom 59 63;
+#X msg 340 12 \; pd dsp 1;
+#X msg 407 12 \; pd dsp 0;
+#X text 361 45 ON;
+#X text 424 43 OFF;
+#X floatatom 123 196;
+#N canvas 159 26 618 383 output 0;
+#X obj 393 156 t b;
+#X obj 393 106 f;
+#X obj 393 56 inlet;
+#X text 399 25 mute;
+#X obj 393 181 f;
+#X msg 480 174 0;
+#X msg 393 81 bang;
+#X obj 393 131 moses 1;
+#X obj 480 149 t b f;
+#X obj 452 113 moses 1;
+#X obj 138 144 dbtorms;
+#X obj 452 88 r master-lvl;
+#X obj 138 38 r master-lvl;
+#X obj 393 206 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 254 37 inlet;
+#X text 254 14 level;
+#X obj 254 96 s master-lvl;
+#X msg 151 61 set \$1;
+#X obj 151 85 outlet;
+#X msg 269 60 \; pd dsp 1;
+#X obj 138 190 line~;
+#X obj 22 212 *~;
+#X obj 138 167 pack 0 50;
+#X text 34 159 audio;
+#X text 148 106 show level;
+#X obj 73 182 inlet~;
+#X obj 73 213 *~;
+#X obj 22 241 dac~ 1;
+#X obj 73 241 dac~ 2;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 23 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 21 0 27 1;
+#X connect 22 0 28 0;
+#X connect 23 0 21 0;
+#X connect 26 0 27 0;
+#X connect 27 0 29 0;
+#X restore 61 224 pd output;
+#X msg 152 196 MUTE;
+#X text 186 195 <-- output amplitude;
+#X obj 59 111 phasor~ 0;
+#X text 56 45 frequency;
+#X text 331 323 updated for Pd version 0.26;
+#X text 57 9 CLASSICAL PULSE WIDTH MODULATION;
+#X obj 131 110 phasor~ 0;
+#X obj 59 134 -~ 0.5;
+#X obj 131 85 + 0.5;
+#X obj 131 135 -~ 0.5;
+#X obj 131 160 *~ -1;
+#X text 34 262 Here's what happens if you take the previous patch but \, instead of subtracting the two sawtooth waves \, we put them in two speakers with opposite phase.;
+#X connect 0 0 9 0;
+#X connect 0 0 15 0;
+#X connect 5 0 6 2;
+#X connect 6 0 5 0;
+#X connect 7 0 6 3;
+#X connect 9 0 14 0;
+#X connect 13 0 16 0;
+#X connect 14 0 6 0;
+#X connect 15 0 13 0;
+#X connect 16 0 17 0;
+#X connect 17 0 6 1;
diff --git a/pd/doc/3.audio.examples/E07.envelope.mod.pd b/pd/doc/3.audio.examples/E07.envelope.mod.pd
new file mode 100644
index 00000000..52551163
--- /dev/null
+++ b/pd/doc/3.audio.examples/E07.envelope.mod.pd
@@ -0,0 +1,148 @@
+#N canvas 75 15 1014 733 12;
+#X graph graph1 0 -1.02 44100 1.02 764 446 964 316;
+#X array cos-output 44100 float 0;
+#X pop;
+#X graph graph1 0 -1.02 44103 1.02 761 148 961 18;
+#X array sample-table 44103 float 0;
+#X pop;
+#X obj 593 579 loadbang;
+#X floatatom 96 489 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 67 517 pd output;
+#X msg 133 490 MUTE;
+#X text 176 490 <-- output amplitude;
+#X obj 67 460 hip~ 5;
+#X obj 47 408 tabread4~ sample-table;
+#X floatatom 46 50 0 0 0;
+#X text 85 49 <-- frequency (Hz.);
+#X floatatom 97 358 0 0 0;
+#X obj 97 385 * 441;
+#X obj 47 358 *~ 0;
+#X obj 47 383 +~ 1;
+#X text 271 274 <-- click to display output;
+#X msg 229 275 bang;
+#X text 136 357 <-- chunk size (100ths of a second);
+#X obj 588 471 adc~ 1;
+#X obj 588 495 hip~ 5;
+#X obj 588 545 tabwrite~ sample-table;
+#X msg 603 518 bang;
+#X text 635 518 <-- click here to record your own sample;
+#X text 704 583 v-- re-read the original sample;
+#X text 40 9 ENVELOPING YOUR LOOPING SAMPLER;
+#X obj 88 101 -~ 0.5;
+#X obj 88 259 clip~ -0.5 0.5;
+#X obj 88 237 *~ 1;
+#X graph graph1 0 -1.02 44100 1.02 763 311 963 181;
+#X array cos-input 44100 float 0;
+#X pop;
+#X obj 229 303 tabwrite~ cos-input;
+#X obj 88 284 cos~;
+#X obj 88 126 wrap~;
+#X obj 88 155 -~ 0.5;
+#X obj 88 332 *~ -0.5;
+#X obj 88 307 -~ 1;
+#X obj 229 329 tabwrite~ cos-output;
+#X floatatom 119 187 0 0 0;
+#X obj 67 433 *~;
+#X text 157 98 subtracting 0.5 and wrapping produces a sawtooth wave
+180 degrees out of phase from the original.;
+#X text 153 150 as before we subtract 1/2 again to center the sawtooth
+from -1/2 to 1/2.;
+#X text 153 188 <-- sharpness (at least 1);
+#X msg 593 608 read ../sound/voice.wav sample-table;
+#X obj 593 633 soundfiler;
+#X text 776 150 -- 44103 samples ---;
+#X text 767 447 ----- 1 second ------;
+#X obj 119 211 max 1;
+#X obj 46 77 phasor~;
+#X text 24 560 Here we apply an amplitude envelope to protect against
+discontinuities at the loop point. The envelope is based on the pulse
+width modulation example \, except that the widening is applied to
+the "1" part of the pulse \, not the "0" part.;
+#X text 23 647 To see the envelope \, put the phasor on 2 Hz \, select
+"sharpness" values between 1 and 3 \, and look at "cos-input" and "cos-output."
+You should both see and hear the effect of the "sharpness" parameter.
+;
+#X text 734 688 updated for Pd version 0.34;
+#X connect 2 0 41 0;
+#X connect 3 0 4 1;
+#X connect 4 0 3 0;
+#X connect 5 0 4 2;
+#X connect 7 0 4 0;
+#X connect 8 0 37 0;
+#X connect 9 0 46 0;
+#X connect 11 0 12 0;
+#X connect 12 0 13 1;
+#X connect 13 0 14 0;
+#X connect 14 0 8 0;
+#X connect 16 0 29 0;
+#X connect 16 0 35 0;
+#X connect 18 0 19 0;
+#X connect 19 0 20 0;
+#X connect 21 0 20 0;
+#X connect 25 0 31 0;
+#X connect 26 0 30 0;
+#X connect 26 0 29 0;
+#X connect 27 0 26 0;
+#X connect 30 0 34 0;
+#X connect 31 0 32 0;
+#X connect 32 0 27 0;
+#X connect 33 0 35 0;
+#X connect 33 0 37 1;
+#X connect 34 0 33 0;
+#X connect 36 0 45 0;
+#X connect 37 0 7 0;
+#X connect 41 0 42 0;
+#X connect 45 0 27 1;
+#X connect 46 0 13 0;
+#X connect 46 0 25 0;
diff --git a/pd/doc/3.audio.examples/E08.even.odd.pd b/pd/doc/3.audio.examples/E08.even.odd.pd
new file mode 100644
index 00000000..bfa950a9
--- /dev/null
+++ b/pd/doc/3.audio.examples/E08.even.odd.pd
@@ -0,0 +1,116 @@
+#N canvas 213 27 840 639 12;
+#X floatatom 45 74 0 0 0;
+#X obj 99 164 wrap~;
+#X graph graph1 0 -1.02 882 1.02 624 153 824 23;
+#X array phasor-output 882 float 0;
+#X pop;
+#X obj 45 102 phasor~ 0;
+#X text 81 73 frequency;
+#X obj 45 130 -~ 0.5;
+#X obj 99 192 -~ 0.5;
+#X obj 36 244 -~;
+#X obj 98 244 +~;
+#X graph graph1 0 -1.02 882 1.02 625 288 825 158;
+#X array wrap-output 882 float 0;
+#X pop;
+#X graph graph1 0 -1.02 882 1.02 626 423 826 293;
+#X array sum 882 float 0;
+#X pop;
+#X graph graph1 0 -1.02 882 1.02 626 563 826 433;
+#X array difference 882 float 0;
+#X pop;
+#X obj 172 166 tabwrite~ phasor-output;
+#X obj 172 218 tabwrite~ wrap-output;
+#X obj 172 282 tabwrite~ sum;
+#X obj 172 327 tabwrite~ difference;
+#X msg 172 120 bang;
+#X text 106 13 BUCHLA'S METHOD;
+#X floatatom 119 369 0 0 0;
+#N canvas 159 26 618 383 output 0;
+#X obj 393 156 t b;
+#X obj 393 106 f;
+#X obj 393 56 inlet;
+#X text 399 25 mute;
+#X obj 393 181 f;
+#X msg 480 174 0;
+#X msg 393 81 bang;
+#X obj 393 131 moses 1;
+#X obj 480 149 t b f;
+#X obj 452 113 moses 1;
+#X obj 138 144 dbtorms;
+#X obj 452 88 r master-lvl;
+#X obj 138 38 r master-lvl;
+#X obj 393 206 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 254 37 inlet;
+#X text 254 14 level;
+#X obj 254 96 s master-lvl;
+#X msg 151 61 set \$1;
+#X obj 151 85 outlet;
+#X msg 269 60 \; pd dsp 1;
+#X obj 138 190 line~;
+#X obj 22 212 *~;
+#X obj 138 167 pack 0 50;
+#X text 34 159 audio;
+#X text 148 106 show level;
+#X obj 73 182 inlet~;
+#X obj 73 213 *~;
+#X obj 22 241 dac~ 1;
+#X obj 73 241 dac~ 2;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 23 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 21 0 27 1;
+#X connect 22 0 28 0;
+#X connect 23 0 21 0;
+#X connect 26 0 27 0;
+#X connect 27 0 29 0;
+#X restore 81 392 pd output;
+#X msg 156 369 MUTE;
+#X text 13 430 A patch to split a sawtooth into even and odd harmonics
+ala Buchla. The wrap~ object folds its input into the interval [0 \,
+1) so taht \, for instance \, subtracting 1/5 from a phasor and wrapping
+it gives another phasor a half cycle out of phase frmo the original.
+Adding and subtracting the two give the results shown and heard. (Listen
+to the two outputs separately \, then together.);
+#X text 631 567 ---- 0.02 seconds ----;
+#X text 577 613 updated for Pd version 0.34;
+#X text 193 369 <-- output;
+#X connect 0 0 3 0;
+#X connect 1 0 6 0;
+#X connect 3 0 5 0;
+#X connect 5 0 1 0;
+#X connect 5 0 12 0;
+#X connect 5 0 8 0;
+#X connect 5 0 7 0;
+#X connect 6 0 13 0;
+#X connect 6 0 8 1;
+#X connect 6 0 7 1;
+#X connect 7 0 15 0;
+#X connect 7 0 19 0;
+#X connect 8 0 14 0;
+#X connect 8 0 19 1;
+#X connect 16 0 13 0;
+#X connect 16 0 14 0;
+#X connect 16 0 15 0;
+#X connect 16 0 12 0;
+#X connect 18 0 19 2;
+#X connect 19 0 18 0;
+#X connect 20 0 19 3;
diff --git a/pd/doc/3.audio.examples/E09.bandlimited.pd b/pd/doc/3.audio.examples/E09.bandlimited.pd
new file mode 100644
index 00000000..f49bcb68
--- /dev/null
+++ b/pd/doc/3.audio.examples/E09.bandlimited.pd
@@ -0,0 +1,166 @@
+#N canvas 21 90 540 752 12;
+#X floatatom 183 91;
+#X obj 183 115 mtof;
+#X floatatom 340 183;
+#X obj 164 431 -~;
+#N canvas 391 51 561 806 tables 1;
+#X graph graph1 0 -1 1002 1 99 322 499 22;
+#X array array1 1002 float;
+#X pop;
+#X graph graph1 0 -1 882 1 96 684 496 384;
+#X array array2 882 float;
+#X pop;
+#X text 138 326 ---------------- 1002 samples ---------------;
+#X text 150 693 ---------------- 0.02 sec ---------------;
+#X restore 33 201 pd tables;
+#N canvas 104 390 728 408 make-table 0;
+#X obj 469 146 cos~;
+#X obj 303 146 cos~;
+#X obj 255 141 cos~;
+#X msg 199 210 bang;
+#X obj 255 229 tabwrite~ array1;
+#X text 366 79 period is 2000 samples \, twice the table length;
+#X msg 94 94 \; pd dsp 1;
+#X text 118 286 this network puts a half cycle of a band-limited square wave into the table "array1.";
+#X text 114 335 logically the half-cycle is in samples 1 through 1000 \; samples 0 and 1001 are provided so that the 4-point interpolation will work everywhere.;
+#X text 401 57 back the phase up one sample;
+#X msg 336 56 -0.0005;
+#X obj 171 16 loadbang;
+#X obj 303 120 *~ 3;
+#X obj 468 122 *~ 5;
+#X obj 303 171 *~ 0.33333;
+#X obj 468 172 *~ -0.2;
+#X obj 255 169 *~ -1;
+#X msg 171 38 bang;
+#X obj 254 80 phasor~ 22.05;
+#X obj 255 202 *~ 0.57692;
+#X connect 0 0 15 0;
+#X connect 1 0 14 0;
+#X connect 2 0 16 0;
+#X connect 3 0 4 0;
+#X connect 10 0 18 1;
+#X connect 11 0 17 0;
+#X connect 12 0 1 0;
+#X connect 13 0 0 0;
+#X connect 14 0 19 0;
+#X connect 15 0 19 0;
+#X connect 16 0 19 0;
+#X connect 17 0 10 0;
+#X connect 17 0 6 0;
+#X connect 17 0 3 0;
+#X connect 18 0 2 0;
+#X connect 18 0 12 0;
+#X connect 18 0 13 0;
+#X connect 19 0 4 0;
+#X restore 34 224 pd make-table;
+#X obj 183 163 sig~;
+#X obj 341 283 /~;
+#X obj 357 256 clip~ 1 999999;
+#X obj 183 218 phasor~;
+#X obj 196 301 *~;
+#X obj 196 325 clip~ -0.5 0.5;
+#X floatatom 183 139;
+#X obj 196 397 tabread4~ array1;
+#X floatatom 340 135;
+#X obj 340 206 * 0.33333;
+#X obj 340 159 mtof;
+#X text 374 110 band limit (MIDI units);
+#X text 220 78 pitch;
+#X obj 340 87 loadbang;
+#X msg 340 111 130;
+#X obj 340 230 sig~;
+#X text 246 139 frequency;
+#X obj 196 349 *~ 1000;
+#X obj 196 373 +~ 501;
+#X obj 183 242 -~ 0.5;
+#X floatatom 206 441;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 177 469 pd output;
+#X msg 235 441 MUTE;
+#X text 276 440 <-- output amplitude;
+#X text 27 503 Patch to make an approximately band-limited sawtooth. This is useful if you intend to use sawtooth generators above about 200 Hz. \, perhaps to use any of the techniques shown in the previous four patches.;
+#X text 28 562 We generate a perfect square wave at Nyquist/6 \; this will have partials 1 \, 3 \, and 5 \, but the Nyquist frequency at partial 6 will cut off the rest of the partials. This is stored in array1 using the "make-table" subpatch.;
+#X text 64 34 BAND-LIMITED SAWTOOTH GENERATOR;
+#X obj 43 459 tabwrite~ array2;
+#X msg 44 435 bang;
+#X text 28 632 Now any time we wish to make a discontinuity in the output signal \, we make it look exactly like the bandlimited square wave looks. We do this by reading through the table we recorded \, carefully adding a "digital" \, non-band-limited \, sawtooth to "array1" so that the discontinuities in the two cancel out and what you have left is the transition in the table.;
+#X text 338 737 updated for Pd version 0.26;
+#X text 41 409 graph output;
+#X connect 0 0 1 0;
+#X connect 1 0 12 0;
+#X connect 2 0 15 0;
+#X connect 3 0 27 0;
+#X connect 3 0 33 0;
+#X connect 6 0 8 0;
+#X connect 6 0 9 0;
+#X connect 7 0 10 1;
+#X connect 8 0 7 1;
+#X connect 9 0 25 0;
+#X connect 10 0 11 0;
+#X connect 11 0 23 0;
+#X connect 12 0 6 0;
+#X connect 13 0 3 0;
+#X connect 14 0 16 0;
+#X connect 15 0 21 0;
+#X connect 16 0 2 0;
+#X connect 19 0 20 0;
+#X connect 20 0 14 0;
+#X connect 21 0 7 0;
+#X connect 23 0 24 0;
+#X connect 24 0 13 0;
+#X connect 25 0 10 0;
+#X connect 25 0 3 1;
+#X connect 26 0 27 1;
+#X connect 27 0 26 0;
+#X connect 28 0 27 2;
+#X connect 34 0 33 0;
diff --git a/pd/doc/3.audio.examples/F01.PART7.filters.pd b/pd/doc/3.audio.examples/F01.PART7.filters.pd
new file mode 100644
index 00000000..4a64a0b5
--- /dev/null
+++ b/pd/doc/3.audio.examples/F01.PART7.filters.pd
@@ -0,0 +1,72 @@
+#N canvas 124 28 964 549 12;
+#X floatatom 20 391;
+#X floatatom 297 394;
+#X floatatom 210 394;
+#X graph graph1 0 -1 400 1 544 335 944 35;
+#X array orig 400 float;
+#X array lop 400 float;
+#X array hip 400 float;
+#X array bp 400 float;
+#X pop;
+#X obj 334 457 r metro;
+#X obj 180 322 hip~ 100;
+#X obj 105 320 lop~ 100;
+#X obj 273 322 bp~ 100 10;
+#X floatatom 255 245;
+#X floatatom 338 295;
+#X floatatom 118 393;
+#X text 9 11 Filters;
+#X msg 87 130 \; pd dsp 1 \; metro bang;
+#X msg 191 135 \; pd dsp 0;
+#X text 15 417 Original;
+#X text 122 417 Low pass;
+#X text 210 417 High pass;
+#X text 298 416 Band pass;
+#X obj 14 517 tabwrite~ orig;
+#X obj 309 520 tabwrite~ bp;
+#X obj 213 520 tabwrite~ hip;
+#X obj 116 519 tabwrite~ lop;
+#X text 97 110 start;
+#X text 193 111 stop;
+#X floatatom 14 235;
+#X obj 14 261 osc~ 440;
+#X text 51 236 <-- change frequency;
+#X text 294 247 <-- center/rolloff frequency;
+#X text 374 297 <-- Q;
+#X text 548 341 This graph holds 4 arrays for the input and three filter outputs.;
+#X text 375 389 RMS amplitudes of the original signal and the three filter outputs;
+#X text 746 536 updated for Pd version 0.26;
+#X obj 334 482 metro 1000;
+#X text 29 33 Pd provides low \, high \, and band pass filters \, as shown here. By changing the test frequency \, the filter frequency \, and the "Q" value \, you can see how these filters affect the amplitude and phase of incoming signals;
+#X obj 20 366 env~ 4096;
+#X obj 118 368 env~ 4096;
+#X obj 210 369 env~ 4096;
+#X obj 297 369 env~ 4096;
+#X obj 91 213 print~;
+#X text 456 434 Notice how the phase of the graphed sinusoids slips back and forth... this is because graphing always starts on the nearest 64-sample boundary to the time the metronome fires. If you run at 48K the slippage disappears \, because then the metronome fires every 48K samples \, which is a multiple of 64;
+#X connect 4 0 32 0;
+#X connect 5 0 20 0;
+#X connect 5 0 36 0;
+#X connect 6 0 21 0;
+#X connect 6 0 35 0;
+#X connect 7 0 19 0;
+#X connect 7 0 37 0;
+#X connect 8 0 6 1;
+#X connect 8 0 5 1;
+#X connect 8 0 7 1;
+#X connect 9 0 7 2;
+#X connect 24 0 25 0;
+#X connect 25 0 18 0;
+#X connect 25 0 6 0;
+#X connect 25 0 5 0;
+#X connect 25 0 7 0;
+#X connect 25 0 34 0;
+#X connect 25 0 38 0;
+#X connect 32 0 18 0;
+#X connect 32 0 21 0;
+#X connect 32 0 20 0;
+#X connect 32 0 19 0;
+#X connect 34 0 0 0;
+#X connect 35 0 10 0;
+#X connect 36 0 2 0;
+#X connect 37 0 1 0;
diff --git a/pd/doc/3.audio.examples/F02.bandpass.pd b/pd/doc/3.audio.examples/F02.bandpass.pd
new file mode 100644
index 00000000..0ce9cc47
--- /dev/null
+++ b/pd/doc/3.audio.examples/F02.bandpass.pd
@@ -0,0 +1,146 @@
+#N canvas 58 17 943 765 12;
+#X floatatom 91 731 0 0 0;
+#X graph graph1 0 -1 155947 1 624 401 824 251;
+#X array array1 155948 float 0;
+#X pop;
+#X floatatom 247 705 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 406 192 t b;
+#X obj 406 132 f;
+#X obj 406 72 inlet;
+#X text 413 35 mute;
+#X obj 406 222 f;
+#X msg 510 214 0;
+#X msg 406 102 bang;
+#X obj 406 162 moses 1;
+#X obj 510 184 t b f;
+#X obj 476 140 moses 1;
+#X obj 100 178 dbtorms;
+#X obj 476 110 r master-lvl;
+#X obj 100 50 r master-lvl;
+#X obj 406 252 s master-lvl;
+#X obj 26 217 inlet~;
+#X obj 239 49 inlet;
+#X text 239 22 level;
+#X obj 239 120 s master-lvl;
+#X msg 115 78 set \$1;
+#X obj 115 107 outlet;
+#X msg 257 77 \; pd dsp 1;
+#X obj 100 233 line~;
+#X obj 26 254 *~;
+#X obj 26 289 dac~;
+#X obj 100 205 pack 0 50;
+#X text 24 190 audio;
+#X text 112 132 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 210 740 pd output;
+#X msg 280 707 MUTE;
+#X text 320 706 <-- output amplitude;
+#X obj 206 654 hip~ 5;
+#X obj 31 545 tabread4~ array1;
+#X obj 31 340 r totsamps;
+#X obj 31 430 /;
+#X obj 206 625 bp~;
+#X obj 206 596 bp~;
+#X obj 216 463 mtof;
+#X floatatom 216 491 0 0 0;
+#X floatatom 319 570 0 0 0;
+#X obj 319 541 r q;
+#X floatatom 216 434 0 0 0;
+#X msg 227 550 \; p set \$1;
+#X obj 216 406 r p;
+#X obj 90 647 env~ 4096;
+#X obj 31 487 *~ 0;
+#X obj 31 458 phasor~ 0;
+#X obj 31 516 +~ 1;
+#X obj 227 521 ftom;
+#X msg 826 49 \; pd dsp 0;
+#X obj 90 674 + 0.5;
+#X obj 91 702 int;
+#X msg 31 400 44100;
+#X obj 31 368 t b f;
+#X text 648 14 START;
+#X text 845 19 STOP;
+#X text 88 11 BANDPASS FILTERS;
+#X text 12 41 In this example we use two cascaded bandpass filters
+to troll for partials in Jonathan Harvey's famous bell sample.;
+#X obj 78 487 r totsamps;
+#X text 14 82 Note that filters can give unexpected level changes.
+The bp~ object is designed to have roughly unit gain at teh pass band
+\, so the higher you set "Q" the more amplitude is lost. YOu can correct
+for this by pushing the output amplitude \, but be sure to remember
+to reset the output amplitude before you reduce Q again. I set the
+Q to 100 and the output amplitude to 110 or 120 (with the room gain
+way down.) Then holding the shift key \, slowly drag the center pitch
+upward listening for modes.;
+#X text 16 233 You can hear partials around 48 \, 51.3 \, 55 (faint!)
+\, 57 (fainter!) \, 60 \, two beating partials around 65 \, 67 \, 69
+\, 70.9 \, 71.75 \, 72.6 \, 74 \, 74.65 \, 75.6 \, 77 \, 81.2 \, 84.6
+\, 86.5 \, and probably many more. There's also one down at 36 \, but
+it's easier to see it on the meter than hear it.;
+#X text 271 436 <-- center pitch;
+#X text 281 450 (shift-drag to fine tune);
+#X text 292 492 <-- center frequency;
+#X text 359 570 <-- Q (filter selectivity);
+#X obj 683 453 r readfile;
+#X obj 683 530 soundfiler;
+#X msg 683 503 read -resize \$1 array1;
+#X obj 683 478 symbol;
+#X msg 553 48 \; readfile ../sound/bell.aiff \; totsamps 143718 \;
+p 69 \; q 0 \; pd dsp 1;
+#X text 681 739 updated for Pd version 0.33;
+#X connect 2 0 3 1;
+#X connect 3 0 2 0;
+#X connect 4 0 3 2;
+#X connect 6 0 3 0;
+#X connect 7 0 11 0;
+#X connect 8 0 28 0;
+#X connect 9 0 21 0;
+#X connect 10 0 6 0;
+#X connect 10 0 19 0;
+#X connect 11 0 10 0;
+#X connect 12 0 13 0;
+#X connect 13 0 11 1;
+#X connect 13 0 10 1;
+#X connect 13 0 23 0;
+#X connect 14 0 11 2;
+#X connect 14 0 10 2;
+#X connect 15 0 14 0;
+#X connect 16 0 12 0;
+#X connect 18 0 16 0;
+#X connect 19 0 25 0;
+#X connect 20 0 22 0;
+#X connect 21 0 20 0;
+#X connect 22 0 7 0;
+#X connect 23 0 17 0;
+#X connect 25 0 26 0;
+#X connect 26 0 0 0;
+#X connect 27 0 9 0;
+#X connect 28 0 27 0;
+#X connect 28 1 9 1;
+#X connect 33 0 20 1;
+#X connect 40 0 43 0;
+#X connect 42 0 41 0;
+#X connect 43 0 42 0;
diff --git a/pd/doc/3.audio.examples/F03.filter.sweep.pd b/pd/doc/3.audio.examples/F03.filter.sweep.pd
new file mode 100644
index 00000000..0d478275
--- /dev/null
+++ b/pd/doc/3.audio.examples/F03.filter.sweep.pd
@@ -0,0 +1,173 @@
+#N canvas 194 58 693 586 12;
+#X text 437 559 updated for Pd version 0.26;
+#X floatatom 70 539 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 41 567 pd output;
+#X msg 99 539 MUTE;
+#X text 138 538 <-- output amplitude;
+#X obj 41 212 line~;
+#X floatatom 41 164 0 0 0;
+#X obj 41 188 pack 0 100;
+#X obj 528 110 loadbang;
+#X text 35 6 SWEEPING FILTERS;
+#N canvas 0 0 600 392 conversion-tables 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array dbtorms 123 float 1;
+#A 0 0 0 1.25893e-05 1.41254e-05 1.58489e-05 1.77828e-05 1.99526e-05
+2.23872e-05 2.51189e-05 2.81838e-05 3.16228e-05 3.54813e-05 3.98107e-05
+4.46684e-05 5.01187e-05 5.62341e-05 6.30957e-05 7.07946e-05 7.94328e-05
+8.91251e-05 1e-04 0.000112202 0.000125893 0.000141254 0.000158489 0.000177828
+0.000199526 0.000223872 0.000251189 0.000281838 0.000316228 0.000354813
+0.000398107 0.000446684 0.000501187 0.000562341 0.000630957 0.000707946
+0.000794328 0.000891251 0.001 0.00112202 0.00125893 0.00141254 0.00158489
+0.00177828 0.00199526 0.00223872 0.00251189 0.00281838 0.00316228 0.00354813
+0.00398107 0.00446684 0.00501187 0.00562341 0.00630957 0.00707946 0.00794328
+0.00891251 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1 1.12202 1.25893 1.41254 1.58489 1.77828 1.99526
+2.23872 2.51189 2.81838 3.16228 3.54813 3.98107 4.46684 5.01187 5.62341
+6.30957 7.07946 7.94328 8.91251 10 11.2202 12.5893;
+#X coords 0 10 123 0 200 100 1;
+#X restore 302 48 graph;
+#X text 504 141 0;
+#X text 506 41 10;
+#X text 321 151 ------ 123 samples ------;
+#N canvas 0 0 450 300 graph2 0;
+#X array mtof 130 float 1;
+#A 0 8.1758 8.66196 9.17702 9.72272 10.3009 10.9134 11.5623 12.2499
+12.9783 13.75 14.5676 15.4339 16.3516 17.3239 18.354 19.4454 20.6017
+21.8268 23.1247 24.4997 25.9565 27.5 29.1352 30.8677 32.7032 34.6478
+36.7081 38.8909 41.2034 43.6535 46.2493 48.9994 51.9131 55 58.2705
+61.7354 65.4064 69.2957 73.4162 77.7817 82.4069 87.3071 92.4986 97.9989
+103.826 110 116.541 123.471 130.813 138.591 146.832 155.563 164.814
+174.614 184.997 195.998 207.652 220 233.082 246.942 261.626 277.183
+293.665 311.127 329.628 349.228 369.994 391.995 415.305 440 466.164
+493.883 523.251 554.365 587.33 622.254 659.255 698.456 739.989 783.991
+830.609 880 932.328 987.767 1046.5 1108.73 1174.66 1244.51 1318.51
+1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32
+2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07
+4186.01 4434.92 4698.64 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88
+7040 7458.62 7902.13 8372.02 8869.84 9397.27 9956.06 10548.1 11175.3
+11839.8 12543.9 13289.8 14080;
+#X coords 0 12000 130 0 200 100 1;
+#X restore 309 225 graph;
+#X text 319 333 ------ 130 samples ------;
+#X text 518 318 0;
+#X text 520 218 12000;
+#X restore 461 256 pd conversion-tables;
+#X obj 41 260 phasor~;
+#X obj 41 236 tabread4~ mtof;
+#X obj 174 384 +~;
+#X obj 190 361 line~;
+#X obj 190 337 pack 0 100;
+#X floatatom 190 313 0 0 0;
+#X floatatom 174 164 0 0 0;
+#X floatatom 197 238 0 0 0;
+#X obj 41 140 r pitch;
+#X obj 197 214 r depth;
+#X obj 174 140 r speed;
+#X obj 190 289 r offset;
+#X obj 121 465 r q;
+#X floatatom 121 489 0 0 0;
+#X obj 41 484 vcf~;
+#X obj 41 508 hip~ 5;
+#X obj 174 263 *~ 0;
+#X obj 174 188 phasor~ 0;
+#X obj 174 408 tabread4~ mtof;
+#X msg 528 134 \; pitch 48 \; speed -2 \; depth 27 \; offset 56 \;
+q 2;
+#X text 160 490 <-- Q (selectivity);
+#X text 51 277 sawtooth;
+#X text 50 291 oscillator;
+#X text 228 167 <-- sweep speed;
+#X text 265 189 LFO for sweep;
+#X text 251 241 <-- sweep depth;
+#X text 242 316 <-- base center frequency;
+#X text 218 383 add base to sweep;
+#X text 307 408 convert to Hz.;
+#X text 13 28 If you want actively changing center frequencies \, use
+"vcf~" instead of "bp~". The vcf~ module takes an audio signal to set
+center frequency. (Q is still set by messages though.) Vcf is somewhat
+more expensive than bp~.;
+#X text 78 165 <-- pitch;
+#X text 13 95 Note the effect of negative and positive sweep speed.
+;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 5 0 12 0;
+#X connect 6 0 7 0;
+#X connect 7 0 5 0;
+#X connect 8 0 30 0;
+#X connect 11 0 25 0;
+#X connect 12 0 11 0;
+#X connect 13 0 29 0;
+#X connect 14 0 13 1;
+#X connect 15 0 14 0;
+#X connect 16 0 15 0;
+#X connect 17 0 28 0;
+#X connect 18 0 27 1;
+#X connect 19 0 6 0;
+#X connect 20 0 18 0;
+#X connect 21 0 17 0;
+#X connect 22 0 16 0;
+#X connect 23 0 24 0;
+#X connect 24 0 25 2;
+#X connect 25 0 26 0;
+#X connect 26 0 2 0;
+#X connect 27 0 13 0;
+#X connect 28 0 27 0;
+#X connect 29 0 25 1;
diff --git a/pd/doc/3.audio.examples/F04.filter.floyd.pd b/pd/doc/3.audio.examples/F04.filter.floyd.pd
new file mode 100644
index 00000000..02027117
--- /dev/null
+++ b/pd/doc/3.audio.examples/F04.filter.floyd.pd
@@ -0,0 +1,193 @@
+#N canvas 133 190 795 593 12;
+#X floatatom 44 540 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 15 568 pd output;
+#X msg 90 540 MUTE;
+#X text 151 539 <-- output amplitude;
+#X obj 487 217 loadbang;
+#N canvas 0 0 600 392 conversion-tables 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array dbtorms 123 float 1;
+#A 0 0 0 1.25893e-05 1.41254e-05 1.58489e-05 1.77828e-05 1.99526e-05
+2.23872e-05 2.51189e-05 2.81838e-05 3.16228e-05 3.54813e-05 3.98107e-05
+4.46684e-05 5.01187e-05 5.62341e-05 6.30957e-05 7.07946e-05 7.94328e-05
+8.91251e-05 1e-04 0.000112202 0.000125893 0.000141254 0.000158489 0.000177828
+0.000199526 0.000223872 0.000251189 0.000281838 0.000316228 0.000354813
+0.000398107 0.000446684 0.000501187 0.000562341 0.000630957 0.000707946
+0.000794328 0.000891251 0.001 0.00112202 0.00125893 0.00141254 0.00158489
+0.00177828 0.00199526 0.00223872 0.00251189 0.00281838 0.00316228 0.00354813
+0.00398107 0.00446684 0.00501187 0.00562341 0.00630957 0.00707946 0.00794328
+0.00891251 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1 1.12202 1.25893 1.41254 1.58489 1.77828 1.99526
+2.23872 2.51189 2.81838 3.16228 3.54813 3.98107 4.46684 5.01187 5.62341
+6.30957 7.07946 7.94328 8.91251 10 11.2202 12.5893;
+#X coords 0 10 123 0 200 100 1;
+#X restore 302 48 graph;
+#X text 504 141 0;
+#X text 506 41 10;
+#X text 321 151 ------ 123 samples ------;
+#N canvas 0 0 450 300 graph2 0;
+#X array mtof 130 float 1;
+#A 0 8.1758 8.66196 9.17702 9.72272 10.3009 10.9134 11.5623 12.2499
+12.9783 13.75 14.5676 15.4339 16.3516 17.3239 18.354 19.4454 20.6017
+21.8268 23.1247 24.4997 25.9565 27.5 29.1352 30.8677 32.7032 34.6478
+36.7081 38.8909 41.2034 43.6535 46.2493 48.9994 51.9131 55 58.2705
+61.7354 65.4064 69.2957 73.4162 77.7817 82.4069 87.3071 92.4986 97.9989
+103.826 110 116.541 123.471 130.813 138.591 146.832 155.563 164.814
+174.614 184.997 195.998 207.652 220 233.082 246.942 261.626 277.183
+293.665 311.127 329.628 349.228 369.994 391.995 415.305 440 466.164
+493.883 523.251 554.365 587.33 622.254 659.255 698.456 739.989 783.991
+830.609 880 932.328 987.767 1046.5 1108.73 1174.66 1244.51 1318.51
+1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32
+2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07
+4186.01 4434.92 4698.64 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88
+7040 7458.62 7902.13 8372.02 8869.84 9397.27 9956.06 10548.1 11175.3
+11839.8 12543.9 13289.8 14080;
+#X coords 0 12000 130 0 200 100 1;
+#X restore 309 225 graph;
+#X text 319 333 ------ 130 samples ------;
+#X text 518 318 0;
+#X text 520 218 12000;
+#X restore 490 428 pd conversion-tables;
+#X obj 250 308 line~;
+#X obj 250 284 pack 0 100;
+#X floatatom 251 213 0 0 0;
+#X obj 171 413 r q;
+#X floatatom 171 437 0 0 0;
+#X obj 15 492 vcf~;
+#X obj 15 516 hip~ 5;
+#X obj 250 333 tabread4~ mtof;
+#X text 214 436 <-- Q (selectivity);
+#X text 277 354 convert to Hz.;
+#X text 35 6 ANOTHER SWEEPING FILTER EXAMPLE;
+#X obj 15 286 clip~ 0 0.5;
+#X obj 15 310 *~ 2;
+#X obj 15 334 -~;
+#X text 121 270 trick to;
+#X text 121 291 make symmetric;
+#X text 121 312 triangle wave;
+#X obj 31 161 f;
+#X obj 64 159 + 1;
+#X obj 31 211 tabread array1;
+#X obj 31 235 mtof;
+#X obj 31 113 r metro;
+#X obj 64 183 mod 8;
+#X obj 31 259 phasor~ 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 8 float 0;
+#X coords 0 96 8 36 200 100 1;
+#X restore 464 75 graph;
+#X obj 251 189 r cf;
+#X text 293 210 <-- center frequency;
+#X obj 31 137 metro 85;
+#X obj 15 376 hip~ 5000;
+#X obj 15 399 *~ 100;
+#X obj 252 237 moses 61;
+#X msg 251 260 61;
+#X msg 487 241 \; cf 61 \; q 30 \; metro 1 \; array1 0 45 48 50 48
+55 53 55 57;
+#X text 13 28 Here's an approximate reconstruction of an old riff by
+Pink Floyd (I haven't checked the tempo or transposition against the
+original yet.) Because we're filtering a waveform with odd partials
+\, it's easier to pick out the partials in the filtered sound.;
+#X text 104 352 Here we fudge;
+#X text 100 371 to better imitate;
+#X text 100 390 the EMS3 bandpass;
+#X text 85 403 sound;
+#X text 340 231 protect against;
+#X text 341 252 hitting the;
+#X text 341 271 fundamental;
+#X text 137 139 sequencer for;
+#X text 137 158 8 note loop;
+#X obj 171 459 moses 1;
+#X msg 144 459 1;
+#X text 241 460 speaker protection;
+#X text 437 558 updated for Pd version 0.35;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 4 0 38 0;
+#X connect 6 0 13 0;
+#X connect 7 0 6 0;
+#X connect 8 0 36 0;
+#X connect 9 0 10 0;
+#X connect 10 0 49 0;
+#X connect 11 0 12 0;
+#X connect 12 0 1 0;
+#X connect 13 0 11 1;
+#X connect 17 0 18 0;
+#X connect 18 0 19 0;
+#X connect 19 0 34 0;
+#X connect 23 0 24 0;
+#X connect 23 0 25 0;
+#X connect 24 0 28 0;
+#X connect 25 0 26 0;
+#X connect 26 0 29 0;
+#X connect 27 0 33 0;
+#X connect 28 0 23 1;
+#X connect 29 0 17 0;
+#X connect 29 0 19 1;
+#X connect 31 0 8 0;
+#X connect 33 0 23 0;
+#X connect 34 0 35 0;
+#X connect 35 0 11 0;
+#X connect 36 0 37 0;
+#X connect 36 1 7 0;
+#X connect 37 0 7 0;
+#X connect 49 0 50 0;
+#X connect 49 1 11 2;
+#X connect 50 0 11 2;
diff --git a/pd/doc/3.audio.examples/F05.filter.noise.pd b/pd/doc/3.audio.examples/F05.filter.noise.pd
new file mode 100644
index 00000000..7421c180
--- /dev/null
+++ b/pd/doc/3.audio.examples/F05.filter.noise.pd
@@ -0,0 +1,196 @@
+#N canvas 137 175 735 587 12;
+#X text 437 559 updated for Pd version 0.26;
+#X floatatom 67 397 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 38 425 pd output;
+#X msg 96 397 MUTE;
+#X text 135 396 <-- output amplitude;
+#X obj 515 150 loadbang;
+#N canvas 0 0 600 392 conversion-tables 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array dbtorms 123 float 1;
+#A 0 0 0 1.25893e-05 1.41254e-05 1.58489e-05 1.77828e-05 1.99526e-05
+2.23872e-05 2.51189e-05 2.81838e-05 3.16228e-05 3.54813e-05 3.98107e-05
+4.46684e-05 5.01187e-05 5.62341e-05 6.30957e-05 7.07946e-05 7.94328e-05
+8.91251e-05 1e-04 0.000112202 0.000125893 0.000141254 0.000158489 0.000177828
+0.000199526 0.000223872 0.000251189 0.000281838 0.000316228 0.000354813
+0.000398107 0.000446684 0.000501187 0.000562341 0.000630957 0.000707946
+0.000794328 0.000891251 0.001 0.00112202 0.00125893 0.00141254 0.00158489
+0.00177828 0.00199526 0.00223872 0.00251189 0.00281838 0.00316228 0.00354813
+0.00398107 0.00446684 0.00501187 0.00562341 0.00630957 0.00707946 0.00794328
+0.00891251 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1 1.12202 1.25893 1.41254 1.58489 1.77828 1.99526
+2.23872 2.51189 2.81838 3.16228 3.54813 3.98107 4.46684 5.01187 5.62341
+6.30957 7.07946 7.94328 8.91251 10 11.2202 12.5893;
+#X coords 0 10 123 0 200 100 1;
+#X restore 70 45 graph;
+#X text 272 138 0;
+#X text 274 38 10;
+#X text 89 148 ------ 123 samples ------;
+#N canvas 0 0 450 300 graph2 0;
+#X array mtof 130 float 1;
+#A 0 8.1758 8.66196 9.17702 9.72272 10.3009 10.9134 11.5623 12.2499
+12.9783 13.75 14.5676 15.4339 16.3516 17.3239 18.354 19.4454 20.6017
+21.8268 23.1247 24.4997 25.9565 27.5 29.1352 30.8677 32.7032 34.6478
+36.7081 38.8909 41.2034 43.6535 46.2493 48.9994 51.9131 55 58.2705
+61.7354 65.4064 69.2957 73.4162 77.7817 82.4069 87.3071 92.4986 97.9989
+103.826 110 116.541 123.471 130.813 138.591 146.832 155.563 164.814
+174.614 184.997 195.998 207.652 220 233.082 246.942 261.626 277.183
+293.665 311.127 329.628 349.228 369.994 391.995 415.305 440 466.164
+493.883 523.251 554.365 587.33 622.254 659.255 698.456 739.989 783.991
+830.609 880 932.328 987.767 1046.5 1108.73 1174.66 1244.51 1318.51
+1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32
+2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07
+4186.01 4434.92 4698.64 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88
+7040 7458.62 7902.13 8372.02 8869.84 9397.27 9956.06 10548.1 11175.3
+11839.8 12543.9 13289.8 14080;
+#X coords 0 12000 130 0 200 100 1;
+#X restore 77 222 graph;
+#X text 87 330 ------ 130 samples ------;
+#X text 286 315 0;
+#X text 288 215 12000;
+#N canvas 244 212 672 338 regenerate-tables 0;
+#X msg 415 84 bang;
+#X obj 415 113 t b b;
+#X obj 474 177 f;
+#X obj 512 177 + 1;
+#X msg 483 147 0;
+#X obj 415 142 until;
+#X obj 474 211 t f f;
+#X obj 414 238 mtof;
+#X obj 405 202 sel 129;
+#X obj 413 264 tabwrite mtof;
+#X obj 35 227 moses 2;
+#X msg 19 76 bang;
+#X obj 19 105 t b b;
+#X obj 90 166 f;
+#X obj 128 166 + 1;
+#X msg 112 138 0;
+#X obj 19 134 until;
+#X obj 11 194 sel 122;
+#X msg 35 258 0;
+#X obj 79 259 dbtorms;
+#X obj 90 194 t f f;
+#X obj 35 291 tabwrite dbtorms;
+#X text 18 49 bang to recalculate dbtorms table;
+#X text 356 50 bang to recalculate the mtof table;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 1 1 4 0;
+#X connect 2 0 3 0;
+#X connect 2 0 6 0;
+#X connect 2 0 8 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 6 1 9 1;
+#X connect 7 0 9 0;
+#X connect 8 0 5 1;
+#X connect 10 0 18 0;
+#X connect 10 1 19 0;
+#X connect 11 0 12 0;
+#X connect 12 0 16 0;
+#X connect 12 1 15 0;
+#X connect 13 0 14 0;
+#X connect 13 0 17 0;
+#X connect 13 0 20 0;
+#X connect 14 0 13 1;
+#X connect 15 0 13 1;
+#X connect 16 0 13 0;
+#X connect 17 0 16 1;
+#X connect 18 0 21 0;
+#X connect 19 0 21 0;
+#X connect 20 0 10 0;
+#X connect 20 1 21 1;
+#X restore 375 76 pd regenerate-tables;
+#X restore 449 418 pd conversion-tables;
+#X obj 49 201 line~;
+#X obj 49 177 pack 0 100;
+#X floatatom 49 151 0 0 0;
+#X obj 88 254 r q;
+#X floatatom 88 278 0 0 0;
+#X obj 38 342 vcf~;
+#X obj 38 366 hip~ 5;
+#X obj 49 226 tabread4~ mtof;
+#X text 124 277 <-- Q (selectivity);
+#X obj 49 127 r cf;
+#X text 84 145 <-- center frequency;
+#X text 35 6 FILTERING NOISE;
+#X obj 39 102 noise~;
+#X msg 515 174 \; cf 60 \; q 3 \;;
+#X text 13 28 THe noise~ module puts out unit-amplitude white noise.
+Be careful again here about surging amplitudes if Q hits zero.;
+#X obj 88 305 moses 1;
+#X msg 60 305 1;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 5 0 20 0;
+#X connect 7 0 14 0;
+#X connect 8 0 7 0;
+#X connect 9 0 8 0;
+#X connect 10 0 11 0;
+#X connect 11 0 22 0;
+#X connect 12 0 13 0;
+#X connect 13 0 2 0;
+#X connect 14 0 12 1;
+#X connect 16 0 9 0;
+#X connect 19 0 12 0;
+#X connect 22 0 23 0;
+#X connect 22 1 12 2;
+#X connect 23 0 12 2;
diff --git a/pd/doc/3.audio.examples/F06.ring.modulation.pd b/pd/doc/3.audio.examples/F06.ring.modulation.pd
new file mode 100644
index 00000000..0380a07d
--- /dev/null
+++ b/pd/doc/3.audio.examples/F06.ring.modulation.pd
@@ -0,0 +1,153 @@
+#N canvas 1 23 809 567 12;
+#X graph graph1 0 -1.02 882 1.02 542 471 742 341;
+#X array pulse-output 882 float 0;
+#X pop;
+#X floatatom 101 331 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 63 359 pd output;
+#X msg 139 332 MUTE;
+#X text 179 331 <-- output amplitude;
+#X floatatom 63 48 0 0 0;
+#X obj 63 303 hip~ 5;
+#X graph graph1 0 0 128 1000 490 259 746 129;
+#X array spectrum 128 float 0;
+#X pop;
+#X obj 129 278 tabwrite~ pulse-output;
+#X msg 129 243 bang;
+#X text 170 244 <-- click to graph;
+#N canvas 204 17 358 234 fft 0;
+#X obj 46 48 inlet~;
+#X obj 159 181 tabwrite~ spectrum;
+#X obj 159 145 inlet;
+#X obj 46 78 rfft~;
+#X obj 46 111 *~;
+#X obj 77 111 *~;
+#X obj 46 141 sqrt~;
+#X obj 191 45 block~ 2048 1;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 3 0 4 1;
+#X connect 3 1 5 0;
+#X connect 3 1 5 1;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X restore 74 281 pd fft;
+#X text 488 265 0;
+#X obj 79 194 osc~ 0;
+#N canvas 0 0 600 384 pulse-train 0;
+#X obj 185 162 line~;
+#X obj 39 251 cos~;
+#X obj 185 138 pack 0 50;
+#X obj 40 178 -~ 0.5;
+#X obj 40 204 *~;
+#X obj 185 63 / 10;
+#X obj 185 87 moses 0;
+#X msg 185 111 0;
+#X obj 39 227 clip~ -0.5 0.5;
+#X obj 185 187 +~ 1;
+#X obj 38 274 +~ 1;
+#X obj 184 38 inlet;
+#X obj 38 299 outlet~;
+#X obj 40 154 phasor~ 344.532;
+#X text 51 13 This is the pulse train generator from example 17;
+#X connect 0 0 9 0;
+#X connect 1 0 10 0;
+#X connect 2 0 0 0;
+#X connect 3 0 4 0;
+#X connect 4 0 8 0;
+#X connect 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 6 1 2 0;
+#X connect 7 0 2 0;
+#X connect 8 0 1 0;
+#X connect 9 0 4 1;
+#X connect 10 0 12 0;
+#X connect 11 0 5 0;
+#X connect 13 0 3 0;
+#X restore 63 75 pd pulse-train;
+#X floatatom 79 168 0 0 0;
+#X text 124 167 <-- modulation frequency;
+#X text 102 48 <-- bandwidth;
+#X obj 63 218 *~;
+#X text 736 262 2656 Hz.;
+#X text 196 77 fundamental is 344.5 Hz;
+#X text 157 210 an oscillator...;
+#X text 66 22 RING MODULATION;
+#X text 542 473 ---- 0.02 seconds ----;
+#X text 528 533 updated for Pd version 0.34;
+#X text 156 195 Just multiply by;
+#X text 12 422 Ring modulation is just multiplication by an oscillator.
+This patch shows the effect of ring modulation on a pulse train. When
+bandwidth is high and modulation frequency is moderately low \, you
+see the spectrum reflect off the "y axis".;
+#X obj 79 140 * 344.5;
+#X floatatom 79 114 0 0 0;
+#X text 120 114 <-- modulation frequency as;
+#X text 159 128 multiple of fundamental;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 5 0 14 0;
+#X connect 6 0 2 0;
+#X connect 9 0 8 0;
+#X connect 9 0 11 1;
+#X connect 13 0 18 1;
+#X connect 14 0 18 0;
+#X connect 15 0 13 0;
+#X connect 18 0 11 0;
+#X connect 18 0 6 0;
+#X connect 18 0 8 0;
+#X connect 27 0 15 0;
+#X connect 28 0 27 0;
diff --git a/pd/doc/3.audio.examples/F07.ssb.modulation.pd b/pd/doc/3.audio.examples/F07.ssb.modulation.pd
new file mode 100644
index 00000000..968b3b45
--- /dev/null
+++ b/pd/doc/3.audio.examples/F07.ssb.modulation.pd
@@ -0,0 +1,150 @@
+#N canvas 7 6 923 594 12;
+#X obj 170 349 phasor~ 0;
+#X obj 170 393 cos~;
+#X obj 206 371 +~ -0.25;
+#X obj 206 394 cos~;
+#X obj 23 438 *~;
+#X obj 88 438 *~;
+#X obj 22 462 -~;
+#X floatatom 170 322 0 0 0;
+#X obj 23 238 tabread4~ array1;
+#X obj 23 67 r totsamps;
+#X obj 23 142 /;
+#X obj 23 190 *~ 0;
+#X obj 23 166 phasor~ 0;
+#X obj 23 214 +~ 1;
+#X msg 23 117 44100;
+#X obj 23 91 t b f;
+#X obj 62 190 r totsamps;
+#X msg 636 38 \; pd dsp 0;
+#X text 429 14 START;
+#X text 653 20 STOP;
+#X floatatom 51 499 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 22 527 pd output;
+#X msg 87 500 MUTE;
+#X text 121 499 <-- output amplitude;
+#N canvas 0 0 600 388 hilbert 0;
+#X obj 166 190 biquad~ 0.83774 -0.06338 0.06338 -0.83774 1;
+#X obj 166 164 biquad~ 1.94632 -0.94657 0.94657 -1.94632 1;
+#X obj 99 111 biquad~ -0.02569 0.260502 -0.260502 0.02569 1;
+#X obj 99 137 biquad~ 1.8685 -0.870686 0.870686 -1.8685 1;
+#X obj 98 76 inlet~;
+#X obj 166 213 outlet~;
+#X obj 99 213 outlet~;
+#X text 95 261 This is a pair of all-pass filters whose outputs somehow
+manage to be about 90 degrees out of phase from each other. I don't
+know what phase relation they have with the original signal. I adapted
+this from a 4X patch by Emmanuel Favreau \, circa 1982;
+#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 restore 23 400 pd hilbert;
+#X graph graph1 0 -1 155947 1 441 284 641 134;
+#X array array1 155948 float 0;
+#X pop;
+#X text 36 257 sample loop for;
+#X text 36 271 test signal;
+#X text 35 314 pair of allpass;
+#X text 34 333 filters to make;
+#X text 34 353 90 degree phase;
+#X text 32 373 shifted versions;
+#X text 201 323 <-- shift frequency;
+#X text 122 438 <-- complex multiply;
+#X text 123 452 (calculate real part);
+#X text 161 412 cosine and sine waves;
+#X text 55 7 SINGLE SIDEBAND MODULATION;
+#X text 55 26 (AKA FREQUENCY SHIFTING);
+#X text 394 296 The signal sideband modulator gives you only one sideband
+for each frequency in teh input signal (whereas ring modulation gave
+both a positie and negative sideband.) You can set the shift frequency
+positive to shift all frequencies upward \, or negative to shift them
+downwards.;
+#X obj 484 417 r readfile;
+#X msg 334 34 \; readfile ../sound/bell.aiff \; pd dsp 1;
+#X obj 484 444 symbol;
+#X msg 483 470 read -resize \$1 array1;
+#X obj 483 496 soundfiler;
+#X obj 483 521 s totsamps;
+#X text 671 568 updated for Pd version 0.33;
+#X connect 0 0 2 0;
+#X connect 0 0 1 0;
+#X connect 1 0 4 1;
+#X connect 2 0 3 0;
+#X connect 3 0 5 1;
+#X connect 4 0 6 0;
+#X connect 5 0 6 1;
+#X connect 6 0 21 0;
+#X connect 7 0 0 0;
+#X connect 8 0 24 0;
+#X connect 9 0 15 0;
+#X connect 10 0 12 0;
+#X connect 11 0 13 0;
+#X connect 12 0 11 0;
+#X connect 13 0 8 0;
+#X connect 14 0 10 0;
+#X connect 15 0 14 0;
+#X connect 15 1 10 1;
+#X connect 16 0 11 1;
+#X connect 20 0 21 1;
+#X connect 21 0 20 0;
+#X connect 22 0 21 2;
+#X connect 24 0 4 0;
+#X connect 24 1 5 0;
+#X connect 39 0 41 0;
+#X connect 41 0 42 0;
+#X connect 42 0 43 0;
+#X connect 43 0 44 0;
diff --git a/pd/doc/3.audio.examples/G01.delays.pd b/pd/doc/3.audio.examples/G01.delays.pd
new file mode 100644
index 00000000..5c4f20de
--- /dev/null
+++ b/pd/doc/3.audio.examples/G01.delays.pd
@@ -0,0 +1,225 @@
+#N canvas 22 1 729 584 12;
+#X floatatom 62 506 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 33 534 pd output;
+#X msg 91 506 MUTE;
+#X text 130 505 <-- output amplitude;
+#X obj 33 482 hip~ 5;
+#X text 92 12 DELAYS;
+#X obj 33 341 -~;
+#X obj 30 241 tabread4~ mtof;
+#X obj 33 317 *~ 3;
+#X obj 69 318 *~ 2;
+#X obj 49 266 phasor~;
+#X floatatom 81 215 0 0 0;
+#X obj 33 293 clip~ 0 0.667;
+#X obj 30 190 line~;
+#X obj 30 165 pack 0 1000;
+#X obj 28 64 metro 1000;
+#X obj 28 88 random 200;
+#X obj 29 114 - 100;
+#X obj 30 141 * 0.001;
+#X obj 33 453 +~;
+#X obj 44 374 delwrite~ delay1 2000;
+#X floatatom 49 401 0 0 0;
+#X obj 49 426 delread~ delay1 1000;
+#X obj 27 41 loadbang;
+#X text 210 37 You can delay a signal using the delwrite~ and delread~
+objects. In this example \, the pitch of the oscillator is varying
+slightly so that the delayed signal is different from the straight
+signal.;
+#X text 212 99 delread always delays the signal an integer number of
+samples and does no interpolation.;
+#X text 211 137 The delwrite~ object creates the delay line \; you
+give it a name and a size in milliseconds. Each delwrite~ should have
+a different name.;
+#X text 209 184 Delread~'s arguments are the name of a delwrite (of
+which there should be exactly one) and a delay time in milliseconds
+between 0 and the length of the delay line. Each delwrite~ may have
+as many delread~s as you wish \, which function as multiple delay taps.
+;
+#X obj 30 215 +~ 60;
+#X text 112 215 <-- pitch;
+#X text 83 401 <-- delay time;
+#X text 60 341 asymmetric triangle wave;
+#X text 236 372 write to delay line;
+#X text 232 425 read from delay line;
+#X text 59 454 add the original and the delayed signal;
+#N canvas 0 0 600 392 conversion-tables 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array dbtorms 123 float 1;
+#A 0 0 0 1.25893e-05 1.41254e-05 1.58489e-05 1.77828e-05 1.99526e-05
+2.23872e-05 2.51189e-05 2.81838e-05 3.16228e-05 3.54813e-05 3.98107e-05
+4.46684e-05 5.01187e-05 5.62341e-05 6.30957e-05 7.07946e-05 7.94328e-05
+8.91251e-05 1e-04 0.000112202 0.000125893 0.000141254 0.000158489 0.000177828
+0.000199526 0.000223872 0.000251189 0.000281838 0.000316228 0.000354813
+0.000398107 0.000446684 0.000501187 0.000562341 0.000630957 0.000707946
+0.000794328 0.000891251 0.001 0.00112202 0.00125893 0.00141254 0.00158489
+0.00177828 0.00199526 0.00223872 0.00251189 0.00281838 0.00316228 0.00354813
+0.00398107 0.00446684 0.00501187 0.00562341 0.00630957 0.00707946 0.00794328
+0.00891251 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1 1.12202 1.25893 1.41254 1.58489 1.77828 1.99526
+2.23872 2.51189 2.81838 3.16228 3.54813 3.98107 4.46684 5.01187 5.62341
+6.30957 7.07946 7.94328 8.91251 10 11.2202 12.5893;
+#X coords 0 10 123 0 200 100 1;
+#X restore 70 45 graph;
+#X text 272 138 0;
+#X text 274 38 10;
+#X text 89 148 ------ 123 samples ------;
+#N canvas 0 0 450 300 graph2 0;
+#X array mtof 130 float 1;
+#A 0 8.1758 8.66196 9.17702 9.72272 10.3009 10.9134 11.5623 12.2499
+12.9783 13.75 14.5676 15.4339 16.3516 17.3239 18.354 19.4454 20.6017
+21.8268 23.1247 24.4997 25.9565 27.5 29.1352 30.8677 32.7032 34.6478
+36.7081 38.8909 41.2034 43.6535 46.2493 48.9994 51.9131 55 58.2705
+61.7354 65.4064 69.2957 73.4162 77.7817 82.4069 87.3071 92.4986 97.9989
+103.826 110 116.541 123.471 130.813 138.591 146.832 155.563 164.814
+174.614 184.997 195.998 207.652 220 233.082 246.942 261.626 277.183
+293.665 311.127 329.628 349.228 369.994 391.995 415.305 440 466.164
+493.883 523.251 554.365 587.33 622.254 659.255 698.456 739.989 783.991
+830.609 880 932.328 987.767 1046.5 1108.73 1174.66 1244.51 1318.51
+1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32
+2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07
+4186.01 4434.92 4698.64 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88
+7040 7458.62 7902.13 8372.02 8869.84 9397.27 9956.06 10548.1 11175.3
+11839.8 12543.9 13289.8 14080;
+#X coords 0 12000 130 0 200 100 1;
+#X restore 77 222 graph;
+#X text 87 330 ------ 130 samples ------;
+#X text 286 315 0;
+#X text 288 215 12000;
+#N canvas 244 212 672 338 regenerate-tables 0;
+#X msg 415 84 bang;
+#X obj 415 113 t b b;
+#X obj 474 177 f;
+#X obj 512 177 + 1;
+#X msg 483 147 0;
+#X obj 415 142 until;
+#X obj 474 211 t f f;
+#X obj 414 238 mtof;
+#X obj 405 202 sel 129;
+#X obj 413 264 tabwrite mtof;
+#X obj 35 227 moses 2;
+#X msg 19 76 bang;
+#X obj 19 105 t b b;
+#X obj 90 166 f;
+#X obj 128 166 + 1;
+#X msg 112 138 0;
+#X obj 19 134 until;
+#X obj 11 194 sel 122;
+#X msg 35 258 0;
+#X obj 79 259 dbtorms;
+#X obj 90 194 t f f;
+#X obj 35 291 tabwrite dbtorms;
+#X text 18 49 bang to recalculate dbtorms table;
+#X text 356 50 bang to recalculate the mtof table;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 1 1 4 0;
+#X connect 2 0 3 0;
+#X connect 2 0 6 0;
+#X connect 2 0 8 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 6 1 9 1;
+#X connect 7 0 9 0;
+#X connect 8 0 5 1;
+#X connect 10 0 18 0;
+#X connect 10 1 19 0;
+#X connect 11 0 12 0;
+#X connect 12 0 16 0;
+#X connect 12 1 15 0;
+#X connect 13 0 14 0;
+#X connect 13 0 17 0;
+#X connect 13 0 20 0;
+#X connect 14 0 13 1;
+#X connect 15 0 13 1;
+#X connect 16 0 13 0;
+#X connect 17 0 16 1;
+#X connect 18 0 21 0;
+#X connect 19 0 21 0;
+#X connect 20 0 10 0;
+#X connect 20 1 21 1;
+#X restore 375 76 pd regenerate-tables;
+#X restore 449 418 pd conversion-tables;
+#X text 427 536 updated for Pd version 0.35;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 4 0 1 0;
+#X connect 6 0 19 0;
+#X connect 6 0 20 0;
+#X connect 7 0 10 0;
+#X connect 8 0 6 0;
+#X connect 9 0 6 1;
+#X connect 10 0 9 0;
+#X connect 10 0 12 0;
+#X connect 11 0 28 1;
+#X connect 12 0 8 0;
+#X connect 13 0 28 0;
+#X connect 14 0 13 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 17 0 18 0;
+#X connect 18 0 14 0;
+#X connect 19 0 4 0;
+#X connect 21 0 22 0;
+#X connect 22 0 19 1;
+#X connect 23 0 15 0;
+#X connect 28 0 7 0;
diff --git a/pd/doc/3.audio.examples/G02.delay.loop.pd b/pd/doc/3.audio.examples/G02.delay.loop.pd
new file mode 100644
index 00000000..71b35253
--- /dev/null
+++ b/pd/doc/3.audio.examples/G02.delay.loop.pd
@@ -0,0 +1,213 @@
+#N canvas 22 1 630 601 12;
+#X text 309 531 updated for Pd version 0.26;
+#X floatatom 58 505 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 29 533 pd output;
+#X msg 87 505 MUTE;
+#X text 126 504 <-- output amplitude;
+#X obj 29 476 hip~ 5;
+#X obj 29 297 -~;
+#X obj 29 273 *~ 3;
+#X obj 66 279 *~ 2;
+#X floatatom 29 177 0 0 0;
+#X obj 29 249 clip~ 0 0.667;
+#X obj 39 450 delwrite~ delay1 2000;
+#X floatatom 45 353 0 0 0;
+#X text 79 176 <-- pitch;
+#X text 75 352 <-- delay time;
+#X text 238 450 write to delay line;
+#X text 226 378 read from delay line;
+#X text 64 426 add the original and the delayed signal;
+#X obj 29 201 mtof;
+#X msg 135 238 1;
+#X obj 29 321 *~;
+#X obj 29 225 phasor~ 0;
+#X obj 135 286 tabread4~ dbtorms;
+#X obj 135 262 adsr 100 100 2000 0 2000;
+#X obj 29 427 +~;
+#X obj 45 377 delread~ delay1 160;
+#X obj 45 401 *~ 0.7;
+#X text 103 401 feedback gain;
+#X text 57 9 DELAYS WITH FEEDBACK;
+#X text 33 39 You can feed the result of a delread~ module back into
+its own delwrite~ \, as long as you're careful about stability. For
+delays below 30 msec \, you can frequently hear teh resonant pitch.
+For longer delay times you get the famous old delay loop effect.;
+#X text 32 118 We've added an amplitude control here so that teh test
+oscillator only speaks while you're dragging the pitch up and down.
+Be sure to try the shift key.;
+#N canvas 0 0 600 392 conversion-tables 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array dbtorms 123 float 1;
+#A 0 0 0 1.25893e-05 1.41254e-05 1.58489e-05 1.77828e-05 1.99526e-05
+2.23872e-05 2.51189e-05 2.81838e-05 3.16228e-05 3.54813e-05 3.98107e-05
+4.46684e-05 5.01187e-05 5.62341e-05 6.30957e-05 7.07946e-05 7.94328e-05
+8.91251e-05 1e-04 0.000112202 0.000125893 0.000141254 0.000158489 0.000177828
+0.000199526 0.000223872 0.000251189 0.000281838 0.000316228 0.000354813
+0.000398107 0.000446684 0.000501187 0.000562341 0.000630957 0.000707946
+0.000794328 0.000891251 0.001 0.00112202 0.00125893 0.00141254 0.00158489
+0.00177828 0.00199526 0.00223872 0.00251189 0.00281838 0.00316228 0.00354813
+0.00398107 0.00446684 0.00501187 0.00562341 0.00630957 0.00707946 0.00794328
+0.00891251 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1 1.12202 1.25893 1.41254 1.58489 1.77828 1.99526
+2.23872 2.51189 2.81838 3.16228 3.54813 3.98107 4.46684 5.01187 5.62341
+6.30957 7.07946 7.94328 8.91251 10 11.2202 12.5893;
+#X coords 0 10 123 0 200 100 1;
+#X restore 70 45 graph;
+#X text 272 138 0;
+#X text 274 38 10;
+#X text 89 148 ------ 123 samples ------;
+#N canvas 0 0 450 300 graph2 0;
+#X array mtof 130 float 1;
+#A 0 8.1758 8.66196 9.17702 9.72272 10.3009 10.9134 11.5623 12.2499
+12.9783 13.75 14.5676 15.4339 16.3516 17.3239 18.354 19.4454 20.6017
+21.8268 23.1247 24.4997 25.9565 27.5 29.1352 30.8677 32.7032 34.6478
+36.7081 38.8909 41.2034 43.6535 46.2493 48.9994 51.9131 55 58.2705
+61.7354 65.4064 69.2957 73.4162 77.7817 82.4069 87.3071 92.4986 97.9989
+103.826 110 116.541 123.471 130.813 138.591 146.832 155.563 164.814
+174.614 184.997 195.998 207.652 220 233.082 246.942 261.626 277.183
+293.665 311.127 329.628 349.228 369.994 391.995 415.305 440 466.164
+493.883 523.251 554.365 587.33 622.254 659.255 698.456 739.989 783.991
+830.609 880 932.328 987.767 1046.5 1108.73 1174.66 1244.51 1318.51
+1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32
+2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07
+4186.01 4434.92 4698.64 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88
+7040 7458.62 7902.13 8372.02 8869.84 9397.27 9956.06 10548.1 11175.3
+11839.8 12543.9 13289.8 14080;
+#X coords 0 12000 130 0 200 100 1;
+#X restore 77 222 graph;
+#X text 87 330 ------ 130 samples ------;
+#X text 286 315 0;
+#X text 288 215 12000;
+#N canvas 244 212 672 338 regenerate-tables 0;
+#X msg 415 84 bang;
+#X obj 415 113 t b b;
+#X obj 474 177 f;
+#X obj 512 177 + 1;
+#X msg 483 147 0;
+#X obj 415 142 until;
+#X obj 474 211 t f f;
+#X obj 414 238 mtof;
+#X obj 405 202 sel 129;
+#X obj 413 264 tabwrite mtof;
+#X obj 35 227 moses 2;
+#X msg 19 76 bang;
+#X obj 19 105 t b b;
+#X obj 90 166 f;
+#X obj 128 166 + 1;
+#X msg 112 138 0;
+#X obj 19 134 until;
+#X obj 11 194 sel 122;
+#X msg 35 258 0;
+#X obj 79 259 dbtorms;
+#X obj 90 194 t f f;
+#X obj 35 291 tabwrite dbtorms;
+#X text 18 49 bang to recalculate dbtorms table;
+#X text 356 50 bang to recalculate the mtof table;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 1 1 4 0;
+#X connect 2 0 3 0;
+#X connect 2 0 6 0;
+#X connect 2 0 8 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 6 1 9 1;
+#X connect 7 0 9 0;
+#X connect 8 0 5 1;
+#X connect 10 0 18 0;
+#X connect 10 1 19 0;
+#X connect 11 0 12 0;
+#X connect 12 0 16 0;
+#X connect 12 1 15 0;
+#X connect 13 0 14 0;
+#X connect 13 0 17 0;
+#X connect 13 0 20 0;
+#X connect 14 0 13 1;
+#X connect 15 0 13 1;
+#X connect 16 0 13 0;
+#X connect 17 0 16 1;
+#X connect 18 0 21 0;
+#X connect 19 0 21 0;
+#X connect 20 0 10 0;
+#X connect 20 1 21 1;
+#X restore 375 76 pd regenerate-tables;
+#X restore 334 483 pd conversion-tables;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 5 0 2 0;
+#X connect 6 0 20 0;
+#X connect 7 0 6 0;
+#X connect 8 0 6 1;
+#X connect 9 0 18 0;
+#X connect 9 0 19 0;
+#X connect 10 0 7 0;
+#X connect 12 0 25 0;
+#X connect 18 0 21 0;
+#X connect 19 0 23 0;
+#X connect 20 0 24 0;
+#X connect 21 0 8 0;
+#X connect 21 0 10 0;
+#X connect 22 0 20 1;
+#X connect 23 0 22 0;
+#X connect 24 0 11 0;
+#X connect 24 0 5 0;
+#X connect 25 0 26 0;
+#X connect 26 0 24 1;
diff --git a/pd/doc/3.audio.examples/G03.delay.variable.pd b/pd/doc/3.audio.examples/G03.delay.variable.pd
new file mode 100644
index 00000000..bb16de95
--- /dev/null
+++ b/pd/doc/3.audio.examples/G03.delay.variable.pd
@@ -0,0 +1,129 @@
+#N canvas 100 17 671 522 12;
+#X obj 63 306 hip~ 10;
+#X floatatom 331 222;
+#X obj 331 270 line~;
+#X obj 331 246 pack 0 100;
+#X floatatom 256 192;
+#X floatatom 442 297;
+#X obj 442 369 line~;
+#X obj 442 345 pack 0 100;
+#X obj 442 321 * 0.01;
+#X floatatom 143 167;
+#X obj 143 238 line~;
+#X obj 143 214 pack 0 100;
+#X obj 63 258 *~;
+#X obj 63 282 cos~;
+#X floatatom 63 135;
+#X obj 63 159 mtof;
+#X obj 63 183 * 0.5;
+#X obj 63 330 clip~ -0.2 0.2;
+#X obj 143 190 * 0.01;
+#X obj 426 444 delwrite~ delay1 1000;
+#X obj 63 354 +~;
+#X obj 426 396 *~;
+#X obj 256 336 vd~ delay1;
+#X obj 256 288 *~;
+#X obj 256 216 / 100;
+#X floatatom 93 419;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 64 447 pd output;
+#X msg 122 419 MUTE;
+#X text 161 418 <-- output amplitude;
+#X obj 63 378 hip~ 5;
+#X text 401 505 updated for Pd version 0.26;
+#X obj 256 264 +~ 1;
+#X obj 256 240 osc~ 0;
+#X obj 256 312 +~ 1.46;
+#X obj 426 420 clip~ -5 5;
+#X text 43 35 This is a fuzzed FM generator going into a delay loop \, this time using a variable delay object (vd~). You can get several interesting effects this way. We have taken the precaution if clipping inside the loop to avoid instabilities. You can push the loop gain past 1 if you want \, it will just uscillate.;
+#X text 184 165 <-- timbre;
+#X text 96 136 <-- pitch;
+#X text 300 192 <-- cycle frequency (hundredths);
+#X text 361 222 <-- cycle depth (msec);
+#X text 491 298 <-- feedback (hundredths);
+#X text 86 9 VARIABLE DELAYS;
+#X obj 63 207 osc~ 0;
+#X connect 0 0 17 0;
+#X connect 1 0 3 0;
+#X connect 2 0 23 1;
+#X connect 3 0 2 0;
+#X connect 4 0 24 0;
+#X connect 5 0 8 0;
+#X connect 6 0 21 1;
+#X connect 7 0 6 0;
+#X connect 8 0 7 0;
+#X connect 9 0 18 0;
+#X connect 10 0 12 1;
+#X connect 11 0 10 0;
+#X connect 12 0 13 0;
+#X connect 13 0 0 0;
+#X connect 14 0 15 0;
+#X connect 15 0 16 0;
+#X connect 16 0 42 0;
+#X connect 17 0 20 0;
+#X connect 18 0 11 0;
+#X connect 20 0 29 0;
+#X connect 21 0 34 0;
+#X connect 22 0 20 1;
+#X connect 23 0 33 0;
+#X connect 24 0 32 0;
+#X connect 25 0 26 1;
+#X connect 26 0 25 0;
+#X connect 27 0 26 2;
+#X connect 29 0 26 0;
+#X connect 29 0 21 0;
+#X connect 31 0 23 0;
+#X connect 32 0 31 0;
+#X connect 33 0 22 0;
+#X connect 34 0 19 0;
+#X connect 42 0 12 0;
diff --git a/pd/doc/3.audio.examples/G04.delay.pitchshift.pd b/pd/doc/3.audio.examples/G04.delay.pitchshift.pd
new file mode 100644
index 00000000..feb56e2f
--- /dev/null
+++ b/pd/doc/3.audio.examples/G04.delay.pitchshift.pd
@@ -0,0 +1,226 @@
+#N canvas 93 36 1005 580 12;
+#X obj 19 493 hip~ 5;
+#X floatatom 19 87 0 0 0;
+#X obj 84 359 *~;
+#X obj 192 290 line~;
+#X floatatom 265 114 0 0 0;
+#X text 68 9 PITCH SHIFTER;
+#X obj 192 264 pack 0 200;
+#X obj 266 141 moses 1;
+#X msg 227 141 1;
+#X obj 266 88 r window;
+#X obj 19 61 r transpose;
+#X obj 19 143 exp;
+#X floatatom 19 169 0 0 0;
+#X obj 19 259 /;
+#X obj 146 189 * 0.001;
+#X obj 314 366 line~;
+#X obj 315 338 pack 0 200;
+#X floatatom 315 258 0 0 0;
+#X text 314 202 delay (msec);
+#X obj 315 232 r delay;
+#X obj 84 385 +~;
+#X msg 315 311 1;
+#X obj 315 285 moses 1.5;
+#X obj 84 411 vd~ delay1;
+#X obj 19 410 cos~;
+#X obj 19 437 *~;
+#X obj 19 466 +~;
+#X obj 106 317 wrap~;
+#X obj 251 360 *~;
+#X obj 251 393 +~;
+#X obj 251 422 vd~ delay1;
+#X obj 188 420 cos~;
+#X obj 188 447 *~;
+#X msg 492 56 \; transpose 0 \; window 100 \; delay 0;
+#X obj 492 30 loadbang;
+#X obj 264 42 delwrite~ delay1 5000;
+#X obj 146 216 t b f;
+#X floatatom 19 285 0 0 0;
+#X obj 19 312 phasor~ 0;
+#X floatatom 51 526 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 372 176 t b;
+#X obj 372 121 f;
+#X obj 372 66 inlet;
+#X text 378 32 mute;
+#X obj 372 204 f;
+#X msg 468 196 0;
+#X msg 372 94 bang;
+#X obj 372 149 moses 1;
+#X obj 468 168 t b f;
+#X obj 437 129 moses 1;
+#X obj 91 163 dbtorms;
+#X obj 437 101 r master-lvl;
+#X obj 91 46 r master-lvl;
+#X obj 372 231 s master-lvl;
+#X obj 24 199 inlet~;
+#X obj 219 45 inlet;
+#X text 219 20 level;
+#X obj 219 110 s master-lvl;
+#X msg 106 72 set \$1;
+#X obj 106 98 outlet;
+#X msg 235 70 \; pd dsp 1;
+#X obj 91 213 line~;
+#X obj 24 233 *~;
+#X obj 24 265 dac~;
+#X obj 91 188 pack 0 50;
+#X text 22 174 audio;
+#X text 102 121 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 19 557 pd output;
+#X msg 83 526 MUTE;
+#X text 125 525 <-- output amplitude;
+#X obj 106 290 +~ 0.5;
+#X obj 19 358 -~ 0.5;
+#X obj 19 384 *~ 0.5;
+#X obj 188 359 -~ 0.5;
+#X obj 188 392 *~ 0.5;
+#X floatatom 227 167 0 0 0;
+#X obj 19 196 - 1;
+#X obj 19 117 * 0.05776;
+#X obj 19 222 * -1;
+#X text 53 86 <-- transposition;
+#X text 96 99 (halftones);
+#X text 86 177 speed;
+#X text 85 191 change;
+#X text 310 113 <--window (msec);
+#X text 54 252 tape head;
+#X text 55 265 rotation speed;
+#N canvas 0 0 612 637 test-input 0;
+#X graph graph1 0 -1 155947 1 150 291 350 141;
+#X array array1 155948 float 0;
+#X pop;
+#X obj 139 518 tabread4~ array1;
+#X obj 139 333 r totsamps;
+#X obj 139 413 /;
+#X obj 139 465 *~ 0;
+#X obj 139 439 phasor~ 0;
+#X obj 139 492 +~ 1;
+#X msg 139 386 44100;
+#X obj 139 360 t b f;
+#X obj 182 469 r totsamps;
+#X text 153 538 sample loop for;
+#X text 153 555 test signal;
+#X obj 162 30 loadbang;
+#X obj 139 590 outlet~;
+#X obj 393 169 r readfile;
+#X obj 393 199 symbol;
+#X msg 392 228 read -resize \$1 array1;
+#X obj 392 256 soundfiler;
+#X obj 392 284 s totsamps;
+#X msg 161 64 \; readfile ../sound/bell.aiff;
+#X connect 1 0 13 0;
+#X connect 2 0 8 0;
+#X connect 3 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 4 0;
+#X connect 6 0 1 0;
+#X connect 7 0 3 0;
+#X connect 8 0 7 0;
+#X connect 8 1 3 1;
+#X connect 9 0 4 1;
+#X connect 12 0 19 0;
+#X connect 14 0 15 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 17 0 18 0;
+#X restore 264 11 pd test-input;
+#X text 439 161 This is a classic rotating-tape-head style pitch shifter
+using the vd~ variable delay object. Ther are two moving tape heads
+\, each of which is loudest at the middle of its trajectory \, and
+enveloped out at the moment it has to jump back (or forward) to start
+another scratch. Most of the brain work is in computing how fast the
+tape heads have to move to get the desired transposition.;
+#X text 439 280 The "window size" is the total trajectory of the read
+points in the delay line \, in milliseconds. The delay times are controlled
+by a phasor~ object. The second delay time \, 180 degrees out of phase
+from the first one \, is computed using the "wrap" object.;
+#X text 437 370 The "window size" is the total trajectory of the read
+points in the delay line \, in milliseconds. The delay times are controlled
+by a phasor~ object. The second delay time \, 180 degrees out of phase
+from the first one \, is computed using the "wrap" object.;
+#X text 436 462 The cos~ objects compute the fadein and fadeout of
+the two delay line outputs. They each traverse the positive half of
+the cosine waveform (phase -0.25 to +0.25) over the time the phase
+goes from one end to the other.;
+#X text 757 557 updated for Pd version 0.33;
+#X connect 0 0 40 0;
+#X connect 1 0 50 0;
+#X connect 2 0 20 0;
+#X connect 3 0 2 1;
+#X connect 3 0 28 1;
+#X connect 4 0 7 0;
+#X connect 6 0 3 0;
+#X connect 7 0 8 0;
+#X connect 7 1 48 0;
+#X connect 8 0 48 0;
+#X connect 9 0 4 0;
+#X connect 10 0 1 0;
+#X connect 11 0 12 0;
+#X connect 12 0 49 0;
+#X connect 13 0 37 0;
+#X connect 14 0 36 0;
+#X connect 15 0 20 1;
+#X connect 15 0 29 1;
+#X connect 16 0 15 0;
+#X connect 17 0 22 0;
+#X connect 19 0 17 0;
+#X connect 20 0 23 0;
+#X connect 21 0 16 0;
+#X connect 22 0 21 0;
+#X connect 22 1 16 0;
+#X connect 23 0 25 1;
+#X connect 24 0 25 0;
+#X connect 25 0 26 0;
+#X connect 26 0 0 0;
+#X connect 27 0 28 0;
+#X connect 27 0 46 0;
+#X connect 28 0 29 0;
+#X connect 29 0 30 0;
+#X connect 30 0 32 1;
+#X connect 31 0 32 0;
+#X connect 32 0 26 1;
+#X connect 34 0 33 0;
+#X connect 36 0 13 0;
+#X connect 36 1 13 1;
+#X connect 37 0 38 0;
+#X connect 38 0 2 0;
+#X connect 38 0 44 0;
+#X connect 38 0 43 0;
+#X connect 39 0 40 1;
+#X connect 40 0 39 0;
+#X connect 41 0 40 2;
+#X connect 43 0 27 0;
+#X connect 44 0 45 0;
+#X connect 45 0 24 0;
+#X connect 46 0 47 0;
+#X connect 47 0 31 0;
+#X connect 48 0 6 0;
+#X connect 48 0 14 0;
+#X connect 49 0 51 0;
+#X connect 50 0 11 0;
+#X connect 51 0 13 0;
+#X connect 59 0 35 0;
diff --git a/pd/doc/3.audio.examples/G05.delay.reverb.pd b/pd/doc/3.audio.examples/G05.delay.reverb.pd
new file mode 100644
index 00000000..aad17023
--- /dev/null
+++ b/pd/doc/3.audio.examples/G05.delay.reverb.pd
@@ -0,0 +1,316 @@
+#N canvas 127 171 643 406 12;
+#N canvas 0 0 499 321 test-input 0;
+#X obj 75 253 outlet~;
+#X obj 74 201 -~;
+#X obj 74 177 *~ 3;
+#X obj 111 183 *~ 2;
+#X floatatom 74 81 0 0 0;
+#X obj 74 153 clip~ 0 0.667;
+#X text 124 80 <-- pitch;
+#X obj 74 105 mtof;
+#X msg 195 142 1;
+#X obj 74 225 *~;
+#X obj 74 129 phasor~ 0;
+#X obj 195 190 tabread4~ dbtorms;
+#X obj 195 166 adsr 100 100 2000 0 2000;
+#X obj 73 54 inlet;
+#N canvas 0 0 600 392 conversion-tables 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array dbtorms 123 float 1;
+#A 0 0 0 1.25893e-05 1.41254e-05 1.58489e-05 1.77828e-05 1.99526e-05
+2.23872e-05 2.51189e-05 2.81838e-05 3.16228e-05 3.54813e-05 3.98107e-05
+4.46684e-05 5.01187e-05 5.62341e-05 6.30957e-05 7.07946e-05 7.94328e-05
+8.91251e-05 1e-04 0.000112202 0.000125893 0.000141254 0.000158489 0.000177828
+0.000199526 0.000223872 0.000251189 0.000281838 0.000316228 0.000354813
+0.000398107 0.000446684 0.000501187 0.000562341 0.000630957 0.000707946
+0.000794328 0.000891251 0.001 0.00112202 0.00125893 0.00141254 0.00158489
+0.00177828 0.00199526 0.00223872 0.00251189 0.00281838 0.00316228 0.00354813
+0.00398107 0.00446684 0.00501187 0.00562341 0.00630957 0.00707946 0.00794328
+0.00891251 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1 1.12202 1.25893 1.41254 1.58489 1.77828 1.99526
+2.23872 2.51189 2.81838 3.16228 3.54813 3.98107 4.46684 5.01187 5.62341
+6.30957 7.07946 7.94328 8.91251 10 11.2202 12.5893;
+#X coords 0 10 123 0 200 100 1;
+#X restore 70 45 graph;
+#X text 272 138 0;
+#X text 274 38 10;
+#X text 89 148 ------ 123 samples ------;
+#N canvas 0 0 450 300 graph2 0;
+#X array mtof 130 float 1;
+#A 0 8.1758 8.66196 9.17702 9.72272 10.3009 10.9134 11.5623 12.2499
+12.9783 13.75 14.5676 15.4339 16.3516 17.3239 18.354 19.4454 20.6017
+21.8268 23.1247 24.4997 25.9565 27.5 29.1352 30.8677 32.7032 34.6478
+36.7081 38.8909 41.2034 43.6535 46.2493 48.9994 51.9131 55 58.2705
+61.7354 65.4064 69.2957 73.4162 77.7817 82.4069 87.3071 92.4986 97.9989
+103.826 110 116.541 123.471 130.813 138.591 146.832 155.563 164.814
+174.614 184.997 195.998 207.652 220 233.082 246.942 261.626 277.183
+293.665 311.127 329.628 349.228 369.994 391.995 415.305 440 466.164
+493.883 523.251 554.365 587.33 622.254 659.255 698.456 739.989 783.991
+830.609 880 932.328 987.767 1046.5 1108.73 1174.66 1244.51 1318.51
+1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32
+2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07
+4186.01 4434.92 4698.64 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88
+7040 7458.62 7902.13 8372.02 8869.84 9397.27 9956.06 10548.1 11175.3
+11839.8 12543.9 13289.8 14080;
+#X coords 0 12000 130 0 200 100 1;
+#X restore 77 222 graph;
+#X text 87 330 ------ 130 samples ------;
+#X text 286 315 0;
+#X text 288 215 12000;
+#N canvas 244 212 672 338 regenerate-tables 0;
+#X msg 415 84 bang;
+#X obj 415 113 t b b;
+#X obj 474 177 f;
+#X obj 512 177 + 1;
+#X msg 483 147 0;
+#X obj 415 142 until;
+#X obj 474 211 t f f;
+#X obj 414 238 mtof;
+#X obj 405 202 sel 129;
+#X obj 413 264 tabwrite mtof;
+#X obj 35 227 moses 2;
+#X msg 19 76 bang;
+#X obj 19 105 t b b;
+#X obj 90 166 f;
+#X obj 128 166 + 1;
+#X msg 112 138 0;
+#X obj 19 134 until;
+#X obj 11 194 sel 122;
+#X msg 35 258 0;
+#X obj 79 259 dbtorms;
+#X obj 90 194 t f f;
+#X obj 35 291 tabwrite dbtorms;
+#X text 18 49 bang to recalculate dbtorms table;
+#X text 356 50 bang to recalculate the mtof table;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 1 1 4 0;
+#X connect 2 0 3 0;
+#X connect 2 0 6 0;
+#X connect 2 0 8 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 6 1 9 1;
+#X connect 7 0 9 0;
+#X connect 8 0 5 1;
+#X connect 10 0 18 0;
+#X connect 10 1 19 0;
+#X connect 11 0 12 0;
+#X connect 12 0 16 0;
+#X connect 12 1 15 0;
+#X connect 13 0 14 0;
+#X connect 13 0 17 0;
+#X connect 13 0 20 0;
+#X connect 14 0 13 1;
+#X connect 15 0 13 1;
+#X connect 16 0 13 0;
+#X connect 17 0 16 1;
+#X connect 18 0 21 0;
+#X connect 19 0 21 0;
+#X connect 20 0 10 0;
+#X connect 20 1 21 1;
+#X restore 375 76 pd regenerate-tables;
+#X restore 260 101 pd conversion-tables;
+#X connect 1 0 9 0;
+#X connect 2 0 1 0;
+#X connect 3 0 1 1;
+#X connect 4 0 7 0;
+#X connect 4 0 8 0;
+#X connect 5 0 2 0;
+#X connect 7 0 10 0;
+#X connect 8 0 12 0;
+#X connect 9 0 0 0;
+#X connect 10 0 3 0;
+#X connect 10 0 5 0;
+#X connect 11 0 9 1;
+#X connect 12 0 11 0;
+#X connect 13 0 4 0;
+#X restore 75 129 pd test-input;
+#X text 328 322 updated for Pd version 0.26;
+#X text 62 8 REVERBERATOR;
+#X floatatom 75 100 0 0 0;
+#X text 126 105 <-- pitch;
+#X floatatom 137 219 0 0 0;
+#N canvas 159 26 618 379 output 0;
+#X obj 393 156 t b;
+#X obj 393 106 f;
+#X obj 393 56 inlet;
+#X text 399 25 mute;
+#X obj 393 181 f;
+#X msg 480 174 0;
+#X msg 393 81 bang;
+#X obj 393 131 moses 1;
+#X obj 480 149 t b f;
+#X obj 452 113 moses 1;
+#X obj 138 144 dbtorms;
+#X obj 452 88 r master-lvl;
+#X obj 138 38 r master-lvl;
+#X obj 393 206 s master-lvl;
+#X obj 22 140 inlet~;
+#X obj 254 37 inlet;
+#X text 254 14 level;
+#X obj 254 96 s master-lvl;
+#X msg 151 61 set \$1;
+#X obj 151 85 outlet;
+#X msg 269 60 \; pd dsp 1;
+#X obj 138 190 line~;
+#X obj 22 231 *~;
+#X obj 138 167 pack 0 50;
+#X text 34 118 audio;
+#X text 148 106 show level;
+#X obj 73 140 inlet~;
+#X obj 73 232 *~;
+#X obj 22 260 dac~ 1;
+#X obj 73 260 dac~ 2;
+#X obj 22 182 hip~ 5;
+#X obj 73 181 hip~ 5;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 23 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 30 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 21 0 27 1;
+#X connect 22 0 28 0;
+#X connect 23 0 21 0;
+#X connect 26 0 31 0;
+#X connect 27 0 29 0;
+#X connect 30 0 22 0;
+#X connect 31 0 27 0;
+#X restore 75 247 pd output;
+#X msg 166 219 MUTE;
+#X text 184 217 <-- output amplitude;
+#N canvas 137 269 1056 577 reverb 0;
+#X obj 77 37 inlet~;
+#X obj 77 85 echo echo-del2 8.45346;
+#X obj 77 61 echo echo-del1 5.43216;
+#X obj 77 109 echo echo-del3 13.4367;
+#X obj 77 133 echo echo-del4 21.5463;
+#X obj 77 157 echo echo-del5 34.3876;
+#X obj 77 181 echo echo-del6 55.5437;
+#X obj 253 545 delwrite~ loop-del1 70;
+#X obj 295 157 delread~ loop-del1 70;
+#X obj 466 157 delread~ loop-del2 81.9345;
+#X obj 416 545 delwrite~ loop-del2 81.9345;
+#X obj 665 154 delread~ loop-del3 94.7545;
+#X obj 855 154 delread~ loop-del4 115.945;
+#X obj 622 545 delwrite~ loop-del3 94.7545;
+#X obj 820 545 delwrite~ loop-del4 115.945;
+#X obj 282 215 +~;
+#X obj 443 215 +~;
+#X obj 187 251 outlet~;
+#X obj 364 244 outlet~;
+#X obj 251 337 +~;
+#X obj 619 328 +~;
+#X obj 408 334 -~;
+#X obj 791 327 -~;
+#X obj 251 391 +~;
+#X obj 411 397 +~;
+#X obj 615 407 -~;
+#X obj 785 388 -~;
+#X obj 620 474 *~ 0;
+#X obj 620 511 lop~ 5000;
+#X obj 415 472 *~ 0;
+#X obj 415 510 lop~ 5000;
+#X obj 246 475 *~ 0;
+#X obj 246 513 lop~ 5000;
+#X obj 821 472 *~ 0;
+#X obj 821 506 lop~ 5000;
+#X obj 924 254 inlet;
+#X obj 924 278 moses 100;
+#X obj 926 325 moses -100;
+#X msg 979 303 100;
+#X msg 930 349 -100;
+#X obj 934 386 / 200;
+#X connect 0 0 2 0;
+#X connect 1 0 3 0;
+#X connect 1 1 3 1;
+#X connect 2 0 1 0;
+#X connect 2 1 1 1;
+#X connect 3 0 4 0;
+#X connect 3 1 4 1;
+#X connect 4 0 5 0;
+#X connect 4 1 5 1;
+#X connect 5 0 6 0;
+#X connect 5 1 6 1;
+#X connect 6 0 15 0;
+#X connect 6 1 16 0;
+#X connect 8 0 15 1;
+#X connect 9 0 16 1;
+#X connect 11 0 19 1;
+#X connect 11 0 21 1;
+#X connect 12 0 20 1;
+#X connect 12 0 22 1;
+#X connect 15 0 17 0;
+#X connect 15 0 19 0;
+#X connect 15 0 21 0;
+#X connect 16 0 18 0;
+#X connect 16 0 20 0;
+#X connect 16 0 22 0;
+#X connect 19 0 23 0;
+#X connect 19 0 25 0;
+#X connect 20 0 25 1;
+#X connect 20 0 23 1;
+#X connect 21 0 24 0;
+#X connect 21 0 26 0;
+#X connect 22 0 24 1;
+#X connect 22 0 26 1;
+#X connect 23 0 27 0;
+#X connect 24 0 29 0;
+#X connect 25 0 31 0;
+#X connect 26 0 33 0;
+#X connect 27 0 28 0;
+#X connect 28 0 13 0;
+#X connect 29 0 30 0;
+#X connect 30 0 10 0;
+#X connect 31 0 32 0;
+#X connect 32 0 7 0;
+#X connect 33 0 34 0;
+#X connect 34 0 14 0;
+#X connect 35 0 36 0;
+#X connect 36 0 37 0;
+#X connect 36 1 38 0;
+#X connect 37 0 39 0;
+#X connect 37 1 40 0;
+#X connect 38 0 37 0;
+#X connect 39 0 40 0;
+#X connect 40 0 33 1;
+#X connect 40 0 31 1;
+#X connect 40 0 29 1;
+#X connect 40 0 27 1;
+#X restore 50 193 pd reverb;
+#X floatatom 108 163 0 0 0;
+#X text 143 163 <-- feedback (100 maximum);
+#X text 32 41 Here is a simple recirculating reverberator. "Feedback"
+should be between -100 and 100;
+#X text 37 285 You can spend a lifetime tweaking reverberators... we'll
+just leave it at that for now.;
+#X connect 0 0 9 0;
+#X connect 0 0 6 0;
+#X connect 3 0 0 0;
+#X connect 5 0 6 2;
+#X connect 6 0 5 0;
+#X connect 7 0 6 3;
+#X connect 9 0 6 0;
+#X connect 9 1 6 1;
+#X connect 10 0 9 1;
diff --git a/pd/doc/3.audio.examples/H01.more.FM.pd b/pd/doc/3.audio.examples/H01.more.FM.pd
new file mode 100644
index 00000000..1b0e112b
--- /dev/null
+++ b/pd/doc/3.audio.examples/H01.more.FM.pd
@@ -0,0 +1,132 @@
+#N canvas 25 100 785 694 12;
+#X floatatom 197 602 0 0 0;
+#N canvas 159 26 541 274 output 0;
+#X obj 351 166 t b;
+#X obj 351 114 f;
+#X obj 351 62 inlet;
+#X text 358 30 mute;
+#X obj 351 192 f;
+#X msg 442 186 0;
+#X msg 351 88 bang;
+#X obj 351 140 moses 1;
+#X obj 413 114 moses 1;
+#X obj 86 153 dbtorms;
+#X obj 413 88 r master-lvl;
+#X obj 86 44 r master-lvl;
+#X obj 351 218 s master-lvl;
+#X obj 12 166 inlet~;
+#X obj 207 43 inlet;
+#X text 207 19 level;
+#X obj 207 104 s master-lvl;
+#X msg 100 67 set \$1;
+#X obj 100 93 outlet;
+#X msg 222 67 \; pd dsp 1;
+#X obj 86 205 line~;
+#X obj 12 218 *~;
+#X obj 12 244 dac~;
+#X obj 86 179 pack 0 50;
+#X text 12 142 audio;
+#X text 100 118 show level;
+#X obj 12 192 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 21 0;
+#X restore 158 630 pd output;
+#X msg 234 602 MUTE;
+#X text 528 618 updated for Pd version 0.34;
+#X text 277 601 <-- output;
+#X text 79 4 FM \, PWM \, PAF as formant generators;
+#X text 39 22 The next several patches illustrate "Synthesizing Sounds
+with Specified \, Time-Varying Spectra" presented at ICMC 2001 and
+reprinted on http://www.crca.ucsd.edu/~msp/publications.html.;
+#X obj 146 468 line~;
+#X obj 146 444 pack 0 50;
+#X floatatom 146 389 0 0 0;
+#X obj 124 493 *~;
+#X text 145 367 index;
+#X floatatom 248 398 0 0 0;
+#X text 250 370 carrier freq;
+#X obj 158 547 cos~;
+#X graph graph1 0 0 128 500 499 556 755 426;
+#X array spectrum 128 float 0;
+#X pop;
+#X msg 233 546 bang;
+#X text 271 543 <-- click to graph;
+#N canvas 204 17 358 238 fft 0;
+#X obj 46 48 inlet~;
+#X obj 159 181 tabwrite~ spectrum;
+#X obj 159 145 inlet;
+#X obj 46 78 rfft~;
+#X obj 46 111 *~;
+#X obj 77 111 *~;
+#X obj 46 141 sqrt~;
+#X obj 191 45 block~ 1024 1;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 3 0 4 1;
+#X connect 3 1 5 0;
+#X connect 3 1 5 1;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X restore 187 574 pd fft;
+#X text 490 562 0;
+#X text 738 559 5512;
+#X obj 153 520 +~;
+#X obj 248 448 phasor~;
+#X obj 23 458 osc~ 172.266;
+#X obj 146 417 / 100;
+#X obj 248 422 * 172.266;
+#X text 34 93 First compare this phase modulation example with the
+ring modulation example from the section on processing (patch 51).
+Here we choose a convenient \, fixed modulation frequency and consider
+the effect of changing carrier frequency and modulation index. It's
+exactly as if the carrier frequency were a ring modulation frequency.
+;
+#X text 33 331 Next we'll look at two techniques for sliding a formant
+frequency without losing harmonicity.;
+#X text 33 191 Using either method we can synthesize the hat-shaped
+spectra called "formants." However \, if you try to move the formant
+up or down in frequency \, you'll lose harmonicity \; the partials
+are only integer multiples of the fundamental \, 172.266 \, when the
+carrier is an integer multiple. To hear this \, set index to 20 and
+carrier frequency to zero \, and scroll carrier through integers. Then
+shift-drag on the carrier frequency to change it in hundredths. Presto
+\, inharmonic sounds...;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 7 0 10 1;
+#X connect 8 0 7 0;
+#X connect 9 0 24 0;
+#X connect 10 0 21 0;
+#X connect 12 0 25 0;
+#X connect 14 0 1 0;
+#X connect 14 0 18 0;
+#X connect 16 0 18 1;
+#X connect 21 0 14 0;
+#X connect 22 0 21 1;
+#X connect 23 0 10 0;
+#X connect 24 0 8 0;
+#X connect 25 0 22 0;
diff --git a/pd/doc/3.audio.examples/H02.packets.pd b/pd/doc/3.audio.examples/H02.packets.pd
new file mode 100644
index 00000000..072ae27d
--- /dev/null
+++ b/pd/doc/3.audio.examples/H02.packets.pd
@@ -0,0 +1,161 @@
+#N canvas 83 221 878 705 12;
+#X obj 315 424 line~;
+#X obj 47 517 cos~;
+#X graph graph1 0 -2 882 2 644 469 844 339;
+#X array pulse-output 882 float 0;
+#X pop;
+#X floatatom 84 633 0 0 0;
+#N canvas 176 241 532 273 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 398 111 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 398 86 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 17 148 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 15 125 audio;
+#X text 93 110 show level;
+#X obj 17 177 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 21 0;
+#X restore 48 660 pd output;
+#X msg 124 633 MUTE;
+#X obj 315 400 pack 0 50;
+#X floatatom 315 328 0 0 0;
+#X obj 47 429 -~ 0.5;
+#X obj 47 468 *~;
+#X obj 315 352 / 10;
+#X obj 47 493 clip~ -0.5 0.5;
+#X text 315 306 bandwidth;
+#X msg 165 602 bang;
+#X obj 315 448 +~ 1;
+#X obj 48 540 +~ 1;
+#X obj 197 513 cos~;
+#X obj 48 569 *~;
+#X floatatom 219 342 4 0 0;
+#X obj 219 366 / 10;
+#X text 644 472 --- 0.02 seconds ---;
+#X obj 197 487 *~;
+#N canvas 204 427 939 588 graph 0;
+#X obj 91 345 inlet~;
+#X obj 729 341 inlet;
+#X obj 74 395 tabwrite~ pulse-output;
+#X obj 319 350 inlet~;
+#X obj 493 343 inlet~;
+#X obj 302 400 tabwrite~ window;
+#X obj 484 401 tabwrite~ carrier;
+#X msg 390 53 \; array2 rename window;
+#X connect 0 0 2 0;
+#X connect 1 0 2 0;
+#X connect 1 0 5 0;
+#X connect 1 0 6 0;
+#X connect 3 0 5 0;
+#X connect 4 0 6 0;
+#X restore 76 602 pd graph;
+#X obj 315 376 max 0;
+#X obj 219 438 line~;
+#X obj 219 414 pack 0 50;
+#X obj 219 390 max 0;
+#X graph graph3 0 -2 881 2 644 328 844 188;
+#X array carrier 882 float 0;
+#X pop;
+#X graph graph4 0 -2 881 2 645 175 845 35;
+#X array window 882 float 0;
+#X pop;
+#X text 211 601 <-- graph;
+#X floatatom 47 381 4 0 0;
+#X obj 47 405 phasor~ 100;
+#X text 31 2 WINDOWED PACKETS;
+#X text 169 632 <-- output;
+#X text 43 356 freq.;
+#X text 43 337 fundamental;
+#X text 28 51 The simpler technique is to synthesize enveloped sinusoidal
+wave packets. The packets should repeat at the fundamental frequency
+\, but the frequency of the packet itself controls the center frequency
+of the formant. The length of the packet varies inversely with bandwidth.
+;
+#X text 27 132 In the patch below \, the "clip~" followed by "cos~"
+and "+~ 1" is the enveloping ("windowing" function \, which appears
+in the top graph. This is just the original PWM patch from part 2 The
+carrier \, on the other hand \, is a broken sinusoid made by amplifying
+the phasor~ (the "*~" controlled by "center freq.") and taking the
+cos~ of the result. The "breaks" in the sinusoid only occur when the
+enveloping signal is zero.;
+#X text 197 256 center;
+#X text 195 275 freq. (in;
+#X text 194 294 tenths of;
+#X text 193 314 fundamental);
+#X text 92 535 window;
+#X text 233 487 magnified phase;
+#X text 278 531 desired center frequency;
+#X text 250 514 <--this cosine goes at the;
+#X text 279 550 but its phase is reset each;
+#X text 277 569 fundamental period.;
+#X text 612 666 updated for Pd version 0.34;
+#X connect 0 0 14 0;
+#X connect 1 0 15 0;
+#X connect 3 0 4 1;
+#X connect 4 0 3 0;
+#X connect 5 0 4 2;
+#X connect 6 0 0 0;
+#X connect 7 0 10 0;
+#X connect 8 0 9 0;
+#X connect 8 0 21 0;
+#X connect 9 0 11 0;
+#X connect 10 0 23 0;
+#X connect 11 0 1 0;
+#X connect 13 0 22 3;
+#X connect 14 0 9 1;
+#X connect 15 0 17 0;
+#X connect 15 0 22 1;
+#X connect 16 0 17 1;
+#X connect 16 0 22 2;
+#X connect 17 0 22 0;
+#X connect 17 0 4 0;
+#X connect 18 0 19 0;
+#X connect 19 0 26 0;
+#X connect 21 0 16 0;
+#X connect 23 0 6 0;
+#X connect 24 0 21 1;
+#X connect 25 0 24 0;
+#X connect 26 0 25 0;
+#X connect 30 0 31 0;
+#X connect 31 0 8 0;
diff --git a/pd/doc/3.audio.examples/H03.packet.spectrum.pd b/pd/doc/3.audio.examples/H03.packet.spectrum.pd
new file mode 100644
index 00000000..bef1483b
--- /dev/null
+++ b/pd/doc/3.audio.examples/H03.packet.spectrum.pd
@@ -0,0 +1,147 @@
+#N canvas 83 221 774 628 12;
+#X obj 302 351 line~;
+#X obj 34 444 cos~;
+#X floatatom 71 560 0 0 0;
+#N canvas 176 241 532 273 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 398 111 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 398 86 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 17 148 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 15 125 audio;
+#X text 93 110 show level;
+#X obj 17 177 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 21 0;
+#X restore 35 587 pd output;
+#X msg 111 560 MUTE;
+#X obj 302 327 pack 0 50;
+#X floatatom 302 255 0 0 0;
+#X obj 34 356 -~ 0.5;
+#X obj 34 395 *~;
+#X obj 302 279 / 10;
+#X obj 34 420 clip~ -0.5 0.5;
+#X text 302 233 bandwidth;
+#X obj 302 375 +~ 1;
+#X obj 35 467 +~ 1;
+#X obj 184 440 cos~;
+#X obj 35 496 *~;
+#X floatatom 206 269 4 0 0;
+#X obj 206 293 / 10;
+#X obj 184 414 *~;
+#X text 204 224 center;
+#X text 204 243 freq.;
+#X obj 302 303 max 0;
+#X obj 206 365 line~;
+#X obj 206 341 pack 0 50;
+#X obj 206 317 max 0;
+#X floatatom 34 308 4 0 0;
+#X obj 34 332 phasor~ 100;
+#X text 156 559 <-- output;
+#X text 30 283 freq.;
+#X text 30 264 fundamental;
+#X graph graph1 0 0 128 500 440 492 696 362;
+#X array spectrum 128 float 0;
+#X pop;
+#X msg 108 498 bang;
+#N canvas 204 17 358 238 fft 0;
+#X obj 46 48 inlet~;
+#X obj 159 181 tabwrite~ spectrum;
+#X obj 159 145 inlet;
+#X obj 46 78 rfft~;
+#X obj 46 111 *~;
+#X obj 77 111 *~;
+#X obj 46 141 sqrt~;
+#X obj 191 45 block~ 1024 1;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 3 0 4 1;
+#X connect 3 1 5 0;
+#X connect 3 1 5 1;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X restore 59 524 pd fft;
+#X text 439 502 0;
+#X text 687 499 5512;
+#X text 149 498 <-- graph;
+#X text 31 2 WINDOWED PACKET SPECTRUM;
+#X text 19 34 Here's the spectrum you get. Note that even if you put
+the center frequency right on a partial \, there is significant energy
+in neighboring partials (try fundamental 440 \, "center freq" 30 \,
+bandwidth 0.);
+#X text 18 104 The center frequency is in units of ten per partial
+\, or in other words a value of "30" means "centered on the third partial".
+;
+#X text 505 596 updated for Pd version 0.34;
+#X text 22 155 This technique only works if you're doing Hanning-window
+shaped PWM--you can't combine this naturally with FM or with the waveshaping
+technique we'll see later.;
+#X connect 0 0 12 0;
+#X connect 1 0 13 0;
+#X connect 2 0 3 1;
+#X connect 3 0 2 0;
+#X connect 4 0 3 2;
+#X connect 5 0 0 0;
+#X connect 6 0 9 0;
+#X connect 7 0 8 0;
+#X connect 7 0 18 0;
+#X connect 8 0 10 0;
+#X connect 9 0 21 0;
+#X connect 10 0 1 0;
+#X connect 12 0 8 1;
+#X connect 13 0 15 0;
+#X connect 14 0 15 1;
+#X connect 15 0 3 0;
+#X connect 15 0 32 0;
+#X connect 16 0 17 0;
+#X connect 17 0 24 0;
+#X connect 18 0 14 0;
+#X connect 21 0 5 0;
+#X connect 22 0 18 1;
+#X connect 23 0 22 0;
+#X connect 24 0 23 0;
+#X connect 25 0 26 0;
+#X connect 26 0 7 0;
+#X connect 31 0 32 1;
diff --git a/pd/doc/3.audio.examples/H04.two.cosines.pd b/pd/doc/3.audio.examples/H04.two.cosines.pd
new file mode 100644
index 00000000..0f813164
--- /dev/null
+++ b/pd/doc/3.audio.examples/H04.two.cosines.pd
@@ -0,0 +1,124 @@
+#N canvas 10 49 705 610 12;
+#X floatatom 262 549 0 0 0;
+#N canvas 176 241 532 273 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 398 111 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 398 86 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 17 148 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 15 125 audio;
+#X text 93 110 show level;
+#X obj 17 177 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 21 0;
+#X restore 226 576 pd output;
+#X msg 302 549 MUTE;
+#X msg 59 550 bang;
+#X obj 185 427 cos~;
+#X floatatom 232 217 4 0 0;
+#X obj 232 241 / 10;
+#X text 464 288 --- 0.02 seconds ---;
+#X obj 185 397 *~;
+#X text 236 133 center;
+#X obj 232 313 line~;
+#X obj 232 265 max 0;
+#X graph graph3 0 -2 881 2 450 276 650 136;
+#X array carrier 882 float 0;
+#X pop;
+#X floatatom 33 284 4 0 0;
+#X text 29 240 fundamental;
+#X text 31 2 ADDING TWO COSINES;
+#X text 234 152 freq. (in;
+#X text 233 171 tenths of;
+#X text 232 191 fundamental);
+#X text 29 259 frequency;
+#X obj 227 427 cos~;
+#X obj 268 340 wrap~;
+#X obj 232 367 -~;
+#X obj 227 397 +~;
+#X obj 232 464 -~;
+#X obj 247 494 *~;
+#X obj 225 519 +~;
+#X obj 59 578 tabwrite~ carrier;
+#X obj 33 308 phasor~ 40;
+#X obj 232 289 pack 0 50;
+#X text 27 36 The other \, spiffier way is to make a sum of cosines
+to interpolate between adjacent harmonics. Suppose for example we want
+a center frequency of 5.3 (in units of the fundamental.) We just take
+partial 5 with amplitude 0.7 and partial 6 with amplitude 0.7:;
+#X text 451 581 updated for Pd version 0.34;
+#X text 281 366 subtract to get the integer part "n";
+#X text 277 399 multiply phase by n and n+1;
+#X text 282 427 synthesize the two partials;
+#X text 54 526 graph;
+#X text 347 548 <--output;
+#X text 323 339 the fractional part "b";
+#X text 280 463 p2 - p1;
+#X text 295 492 b * (p2 - p1);
+#X text 264 519 b * p2 + (1-b) * p1;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 3 0 27 0;
+#X connect 4 0 24 1;
+#X connect 4 0 26 0;
+#X connect 5 0 6 0;
+#X connect 6 0 11 0;
+#X connect 8 0 4 0;
+#X connect 8 0 23 0;
+#X connect 10 0 22 0;
+#X connect 10 0 21 0;
+#X connect 11 0 29 0;
+#X connect 13 0 28 0;
+#X connect 20 0 24 0;
+#X connect 21 0 22 1;
+#X connect 21 0 25 1;
+#X connect 22 0 8 1;
+#X connect 23 0 20 0;
+#X connect 24 0 25 0;
+#X connect 25 0 26 1;
+#X connect 26 0 1 0;
+#X connect 26 0 27 0;
+#X connect 28 0 8 0;
+#X connect 28 0 23 1;
+#X connect 29 0 10 0;
diff --git a/pd/doc/3.audio.examples/H05.declickit.pd b/pd/doc/3.audio.examples/H05.declickit.pd
new file mode 100644
index 00000000..eb296e63
--- /dev/null
+++ b/pd/doc/3.audio.examples/H05.declickit.pd
@@ -0,0 +1,132 @@
+#N canvas 10 49 715 680 12;
+#X floatatom 242 612 0 0 0;
+#N canvas 176 241 532 273 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 398 111 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 398 86 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 17 148 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 15 125 audio;
+#X text 93 110 show level;
+#X obj 17 177 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 21 0;
+#X restore 206 639 pd output;
+#X msg 282 612 MUTE;
+#X obj 165 490 cos~;
+#X obj 165 460 *~;
+#X obj 207 490 cos~;
+#X obj 249 406 wrap~;
+#X obj 212 415 -~;
+#X obj 207 460 +~;
+#X obj 207 525 -~;
+#X obj 227 557 *~;
+#X obj 205 582 +~;
+#X text 454 648 updated for Pd version 0.34;
+#X text 327 611 <--output;
+#X obj 191 184 loadbang;
+#X obj 191 210 metro 400;
+#X obj 203 234 del 200;
+#X obj 204 335 samphold~;
+#X obj 259 364 toggle 20 0 empty empty empty 20 8 0 10 -262144 -1 -1
+0 1;
+#X obj 166 290 sig~;
+#X msg 203 263 3.5;
+#X msg 166 263 2;
+#X obj 23 280 phasor~ 169;
+#N canvas 0 0 600 400 switch 0;
+#X obj 85 52 inlet~;
+#X obj 177 58 inlet~;
+#X obj 298 66 inlet;
+#X obj 112 107 -~;
+#X obj 112 131 *~ 0;
+#X obj 90 157 +~;
+#X obj 160 249 outlet~;
+#X connect 0 0 3 1;
+#X connect 0 0 5 0;
+#X connect 1 0 3 0;
+#X connect 2 0 4 1;
+#X connect 3 0 4 0;
+#X connect 4 0 5 1;
+#X connect 5 0 6 0;
+#X restore 166 364 pd switch;
+#X text 31 2 CHANGING THE CENTER FREQUENCY QUICKLY;
+#X text 313 381 off to hear the straight sig~;
+#X text 286 363 <--on to hear the "samphold~" \,;
+#X text 25 27 Since in the previous patch the amplitudes of the two
+cosines depend on "center frequency" we can't change that discontinuously
+without clicking \, as you hear in this patch. The fix is to use a
+samphold~ object to keep the center frequency frozen except at phase
+crossings. At the phase crossings the two weighted cosines add to one
+\, so we can discontinuously change the frequencies and weights there.
+;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 3 0 9 1;
+#X connect 3 0 11 0;
+#X connect 4 0 3 0;
+#X connect 4 0 8 0;
+#X connect 5 0 9 0;
+#X connect 6 0 7 1;
+#X connect 6 0 10 1;
+#X connect 7 0 4 1;
+#X connect 8 0 5 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 1;
+#X connect 11 0 1 0;
+#X connect 14 0 15 0;
+#X connect 15 0 21 0;
+#X connect 15 0 16 0;
+#X connect 16 0 20 0;
+#X connect 17 0 23 1;
+#X connect 18 0 23 2;
+#X connect 19 0 17 0;
+#X connect 19 0 23 0;
+#X connect 20 0 19 0;
+#X connect 21 0 19 0;
+#X connect 22 0 4 0;
+#X connect 22 0 8 1;
+#X connect 22 0 17 1;
+#X connect 23 0 7 0;
+#X connect 23 0 6 0;
diff --git a/pd/doc/3.audio.examples/H06.sweepable.FM.pd b/pd/doc/3.audio.examples/H06.sweepable.FM.pd
new file mode 100644
index 00000000..ff3827ee
--- /dev/null
+++ b/pd/doc/3.audio.examples/H06.sweepable.FM.pd
@@ -0,0 +1,161 @@
+#N canvas 89 117 803 661 12;
+#X floatatom 242 605 0 0 0;
+#N canvas 176 241 532 273 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 398 111 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 398 86 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 17 148 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 15 125 audio;
+#X text 93 110 show level;
+#X obj 17 177 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 21 0;
+#X restore 204 634 pd output;
+#X msg 280 606 MUTE;
+#X obj 165 506 cos~;
+#X obj 165 460 *~;
+#X obj 208 508 cos~;
+#X obj 249 409 wrap~;
+#X obj 212 408 -~;
+#X obj 208 485 +~;
+#X obj 206 543 -~;
+#X obj 226 575 *~;
+#X obj 204 600 +~;
+#X text 520 628 updated for Pd version 0.34;
+#X text 325 605 <--output;
+#X obj 212 378 samphold~;
+#X text 31 2 APPLYING TWO-COSINE CARRIER TO FM;
+#X floatatom 229 238 4 0 0;
+#X obj 229 261 / 10;
+#X text 229 157 center;
+#X obj 229 330 line~;
+#X obj 229 284 max 0;
+#X text 229 177 freq. (in;
+#X text 229 197 tenths of;
+#X text 229 217 fundamental);
+#X obj 229 307 pack 0 50;
+#X obj 118 313 phasor~;
+#X floatatom 118 290 4 0 0;
+#X text 103 237 fundamental;
+#X text 103 257 (= mod freq);
+#X text 432 284 index;
+#X text 432 304 (percent);
+#X floatatom 432 325 4 0 0;
+#X obj 382 391 cos~;
+#X obj 432 394 line~;
+#X obj 382 414 *~;
+#X obj 432 348 / 100;
+#X obj 432 371 pack 0 50;
+#X obj 165 483 +~;
+#X graph graph1 0 0 128 500 515 256 771 126;
+#X array spectrum 128 float 0;
+#X pop;
+#X text 511 261 0;
+#X text 759 258 5512;
+#X msg 117 599 bang;
+#N canvas 204 17 358 238 fft 0;
+#X obj 46 48 inlet~;
+#X obj 159 181 tabwrite~ spectrum;
+#X obj 159 145 inlet;
+#X obj 46 78 rfft~;
+#X obj 46 111 *~;
+#X obj 77 111 *~;
+#X obj 46 141 sqrt~;
+#X obj 191 45 block~ 1024 1;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 3 0 4 1;
+#X connect 3 1 5 0;
+#X connect 3 1 5 1;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X restore 68 630 pd fft;
+#X text 25 33 And now we just treat the cosines like carrier signals
+in an FM instrument. This doesn't work as well as you'd wish \, because
+the phases of the partials of the two FM instruments don't line up
+\, so that \, for indices of modulation above about 20% \, you get
+beating effects as the center frequency goes up and down.;
+#X text 385 440 modulating;
+#X text 385 460 oscillator;
+#X text 37 482 both phases-->;
+#X text 6 465 add modulator to;
+#X text 117 577 graph;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 3 0 9 1;
+#X connect 3 0 11 0;
+#X connect 4 0 37 0;
+#X connect 5 0 9 0;
+#X connect 6 0 7 1;
+#X connect 6 0 10 1;
+#X connect 7 0 4 1;
+#X connect 8 0 5 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 1;
+#X connect 11 0 1 0;
+#X connect 11 0 42 0;
+#X connect 14 0 7 0;
+#X connect 14 0 6 0;
+#X connect 16 0 17 0;
+#X connect 17 0 20 0;
+#X connect 19 0 14 0;
+#X connect 20 0 24 0;
+#X connect 24 0 19 0;
+#X connect 25 0 14 1;
+#X connect 25 0 32 0;
+#X connect 25 0 4 0;
+#X connect 25 0 8 1;
+#X connect 26 0 25 0;
+#X connect 31 0 35 0;
+#X connect 32 0 34 0;
+#X connect 33 0 34 1;
+#X connect 34 0 37 1;
+#X connect 35 0 36 0;
+#X connect 36 0 33 0;
+#X connect 37 0 8 0;
+#X connect 37 0 3 0;
+#X connect 41 0 42 1;
diff --git a/pd/doc/3.audio.examples/H07.paf.pd b/pd/doc/3.audio.examples/H07.paf.pd
new file mode 100644
index 00000000..56c024c0
--- /dev/null
+++ b/pd/doc/3.audio.examples/H07.paf.pd
@@ -0,0 +1,234 @@
+#N canvas 53 0 782 687 12;
+#X floatatom 253 735 0 0 0;
+#N canvas 176 241 532 273 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 398 111 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 398 86 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 17 148 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 15 125 audio;
+#X text 93 110 show level;
+#X obj 17 177 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 21 0;
+#X restore 215 764 pd output;
+#X msg 291 735 MUTE;
+#X obj 158 616 cos~;
+#X obj 158 593 *~;
+#X obj 201 616 cos~;
+#X obj 257 542 wrap~;
+#X obj 221 542 -~;
+#X obj 201 593 +~;
+#X obj 194 646 -~;
+#X obj 214 678 *~;
+#X obj 176 678 +~;
+#X text 515 768 updated for Pd version 0.34;
+#X text 336 734 <--output;
+#X obj 221 510 samphold~;
+#X floatatom 221 369 4 0 0;
+#X obj 221 392 / 10;
+#X text 221 288 center;
+#X obj 221 461 line~;
+#X obj 221 415 max 0;
+#X text 221 308 freq. (in;
+#X text 221 328 tenths of;
+#X text 221 348 fundamental);
+#X obj 221 438 pack 0 50;
+#X obj 104 445 phasor~;
+#X floatatom 104 399 4 0 0;
+#X text 84 372 fundamental;
+#X text 435 441 index;
+#X text 435 461 (percent);
+#X floatatom 435 482 4 0 0;
+#X obj 435 528 line~;
+#X obj 343 550 *~;
+#X obj 435 505 pack 0 50;
+#X graph graph1 0 0 128 500 510 395 766 265;
+#X array spectrum 128 float 0;
+#X pop;
+#X text 501 397 0;
+#X text 745 398 5512;
+#X msg 80 713 bang;
+#N canvas 204 17 358 238 fft 0;
+#X obj 46 48 inlet~;
+#X obj 159 181 tabwrite~ spectrum;
+#X obj 159 145 inlet;
+#X obj 46 78 rfft~;
+#X obj 46 111 *~;
+#X obj 77 111 *~;
+#X obj 46 141 sqrt~;
+#X obj 191 45 block~ 1024 1;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 3 0 4 1;
+#X connect 3 1 5 0;
+#X connect 3 1 5 1;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X restore 31 745 pd fft;
+#X text 82 687 graph;
+#X text 31 2 THE PAF: TWO-COSINE RING MODULATOR FOR WAVESHAPER;
+#X graph graph4 0 0 199 1 563 718 763 578;
+#X array bell-curve 200 float 1;
+#A 0 1.12535e-07 1.54727e-07 2.12059e-07 2.89706e-07 3.94519e-07 5.35535e-07
+7.24633e-07 9.77371e-07 1.31404e-06 1.76105e-06 2.35258e-06 3.13275e-06
+4.15832e-06 5.50199e-06 7.25659e-06 9.54016e-06 1.25023e-05 1.63317e-05
+2.1266e-05 2.76026e-05 3.57128e-05 4.60584e-05 5.92113e-05 7.58768e-05
+9.69224e-05 0.00012341 0.000156634 0.000198167 0.000249912 0.000314163
+0.000393669 0.000491721 0.000612231 0.000759842 0.000940028 0.00115923
+0.00142498 0.00174605 0.00213263 0.00259648 0.00315111 0.00381201 0.00459678
+0.0055254 0.0066204 0.00790705 0.0094136 0.0111714 0.013215 0.0155826
+0.0183156 0.0214592 0.0250621 0.0291763 0.0338573 0.0391639 0.0451575
+0.0519019 0.0594631 0.0679081 0.0773047 0.0877205 0.0992216 0.111872
+0.125732 0.140858 0.1573 0.1751 0.194291 0.214896 0.236928 0.260383
+0.285247 0.311486 0.339053 0.367879 0.397882 0.428956 0.46098 0.493812
+0.527292 0.561244 0.595473 0.62977 0.663916 0.697676 0.730811 0.763074
+0.794216 0.823987 0.852144 0.878447 0.902668 0.924595 0.944027 0.960789
+0.974725 0.985703 0.99362 0.998401 1 0.998401 0.99362 0.985703 0.974725
+0.960789 0.944027 0.924595 0.902668 0.878447 0.852144 0.823987 0.794216
+0.763074 0.730811 0.697676 0.663916 0.62977 0.595473 0.561244 0.527292
+0.493812 0.46098 0.428956 0.397882 0.367879 0.339053 0.311486 0.285247
+0.260383 0.236928 0.214896 0.194291 0.1751 0.1573 0.140858 0.125732
+0.111872 0.0992216 0.0877205 0.0773047 0.0679081 0.0594631 0.0519019
+0.0451575 0.0391639 0.0338573 0.0291763 0.0250621 0.0214592 0.0183156
+0.0155826 0.013215 0.0111714 0.0094136 0.00790705 0.0066204 0.0055254
+0.00459678 0.00381201 0.00315111 0.00259648 0.00213263 0.00174605 0.00142498
+0.00115923 0.000940028 0.000759842 0.000612231 0.000491721 0.000393669
+0.000314163 0.000249912 0.000198167 0.000156634 0.00012341 9.69224e-05
+7.58768e-05 5.92113e-05 4.60584e-05 3.57128e-05 2.76026e-05 2.1266e-05
+1.63317e-05 1.25023e-05 9.54016e-06 7.25659e-06 5.50199e-06 4.15832e-06
+3.13275e-06 2.35258e-06 1.76105e-06 1.31404e-06 9.77371e-07 7.24633e-07
+5.35535e-07 3.94519e-07 2.89706e-07 2.12059e-07 1.54727e-07;
+#X pop;
+#N canvas 94 264 600 388 make-table 0;
+#X msg 81 44 bang;
+#X obj 81 73 t b b;
+#X obj 159 142 f;
+#X obj 197 142 + 1;
+#X msg 175 112 0;
+#X obj 81 102 until;
+#X obj 161 177 t f f;
+#X obj 76 306 tabwrite bell-curve;
+#X obj 52 270 expr exp(-$f1*$f1);
+#X obj 63 168 sel 199;
+#X obj 51 241 expr ($f1-100)/25;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 1 1 4 0;
+#X connect 2 0 3 0;
+#X connect 2 0 6 0;
+#X connect 2 0 9 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 2 0;
+#X connect 6 0 10 0;
+#X connect 6 1 7 1;
+#X connect 8 0 7 0;
+#X connect 9 0 5 1;
+#X connect 10 0 8 0;
+#X restore 627 538 pd make-table;
+#X obj 104 422 * 0.5;
+#X obj 343 527 cos~;
+#X obj 343 504 -~ 0.25;
+#X obj 343 573 +~ 100;
+#X obj 343 596 tabread4~ bell-curve;
+#X obj 104 474 *~ 2;
+#X obj 215 707 *~;
+#X text 25 33 Instead of using the two cosines as FM carrier oscillators
+\, we can use them as ring modulators for a synthetic tone. Here (as
+described in the paper) we use a sinusoid looking up a Gaussian bell
+curve. This has the nice properties that the partials are always positive
+cosines in phase \, and the spectrum spreads out smoothly as the index
+changes.;
+#X text 26 137 We needed the sine wave to have half the fundamental
+frequency \, so we run the phasor~ at half speed but double its output
+to the cosine pair and the samphold~ \, thus giving us the original
+frequency. As to the half-speed signal \, we take its sine (-~ 0.25
+and cos~) \, then center it for lookup in a 200-point table containing
+a bell curve.;
+#X text 251 705 <--ring mod step;
+#X text 375 621 waveshaper;
+#X text 27 239 Then with ~* we do the ring modulation and we're done.
+;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 3 0 9 1;
+#X connect 3 0 11 0;
+#X connect 4 0 8 0;
+#X connect 4 0 3 0;
+#X connect 5 0 9 0;
+#X connect 6 0 7 1;
+#X connect 6 0 10 1;
+#X connect 7 0 4 1;
+#X connect 8 0 5 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 1;
+#X connect 11 0 48 0;
+#X connect 14 0 7 0;
+#X connect 14 0 6 0;
+#X connect 15 0 16 0;
+#X connect 16 0 19 0;
+#X connect 18 0 14 0;
+#X connect 19 0 23 0;
+#X connect 23 0 18 0;
+#X connect 24 0 44 0;
+#X connect 24 0 47 0;
+#X connect 25 0 42 0;
+#X connect 29 0 32 0;
+#X connect 30 0 31 1;
+#X connect 31 0 45 0;
+#X connect 32 0 30 0;
+#X connect 36 0 37 1;
+#X connect 42 0 24 0;
+#X connect 43 0 31 0;
+#X connect 44 0 43 0;
+#X connect 45 0 46 0;
+#X connect 46 0 48 1;
+#X connect 47 0 14 1;
+#X connect 47 0 4 0;
+#X connect 47 0 8 0;
+#X connect 48 0 1 0;
+#X connect 48 0 37 0;
diff --git a/pd/doc/3.audio.examples/H08.paf.control.pd b/pd/doc/3.audio.examples/H08.paf.control.pd
new file mode 100644
index 00000000..7d329357
--- /dev/null
+++ b/pd/doc/3.audio.examples/H08.paf.control.pd
@@ -0,0 +1,219 @@
+#N canvas 89 36 743 752 12;
+#X floatatom 217 684 0 0 0;
+#N canvas 176 241 532 273 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 398 111 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 398 86 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 17 148 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 15 125 audio;
+#X text 93 110 show level;
+#X obj 17 177 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 21 0;
+#X restore 179 713 pd output;
+#X msg 255 684 MUTE;
+#X obj 122 565 cos~;
+#X obj 122 542 *~;
+#X obj 165 565 cos~;
+#X obj 220 510 wrap~;
+#X obj 184 510 -~;
+#X obj 165 542 +~;
+#X obj 158 595 -~;
+#X obj 178 627 *~;
+#X obj 140 627 +~;
+#X text 478 719 updated for Pd version 0.34;
+#X text 299 702 <--output;
+#X obj 184 478 samphold~;
+#X floatatom 183 266 4 0 0;
+#X text 181 218 center;
+#X obj 184 345 line~;
+#X obj 184 322 pack 0 50;
+#X obj 67 413 phasor~;
+#X floatatom 69 305 4 0 0;
+#X text 52 256 fundamental;
+#X floatatom 408 361 4 0 0;
+#X obj 408 438 line~;
+#X obj 306 518 *~;
+#X obj 408 415 pack 0 50;
+#N canvas 94 264 600 388 make-table 0;
+#X msg 81 44 bang;
+#X obj 81 73 t b b;
+#X obj 159 142 f;
+#X obj 197 142 + 1;
+#X msg 175 112 0;
+#X obj 81 102 until;
+#X obj 161 177 t f f;
+#X obj 76 306 tabwrite bell-curve;
+#X obj 52 270 expr exp(-$f1*$f1);
+#X obj 63 168 sel 199;
+#X obj 51 241 expr ($f1-100)/25;
+#X graph graph4 0 0 199 1 342 225 542 85;
+#X array bell-curve 200 float 1;
+#A 0 1.12535e-07 1.54727e-07 2.12059e-07 2.89706e-07 3.94519e-07 5.35535e-07
+7.24633e-07 9.77371e-07 1.31404e-06 1.76105e-06 2.35258e-06 3.13275e-06
+4.15832e-06 5.50199e-06 7.25659e-06 9.54016e-06 1.25023e-05 1.63317e-05
+2.1266e-05 2.76026e-05 3.57128e-05 4.60584e-05 5.92113e-05 7.58768e-05
+9.69224e-05 0.00012341 0.000156634 0.000198167 0.000249912 0.000314163
+0.000393669 0.000491721 0.000612231 0.000759842 0.000940028 0.00115923
+0.00142498 0.00174605 0.00213263 0.00259648 0.00315111 0.00381201 0.00459678
+0.0055254 0.0066204 0.00790705 0.0094136 0.0111714 0.013215 0.0155826
+0.0183156 0.0214592 0.0250621 0.0291763 0.0338573 0.0391639 0.0451575
+0.0519019 0.0594631 0.0679081 0.0773047 0.0877205 0.0992216 0.111872
+0.125732 0.140858 0.1573 0.1751 0.194291 0.214896 0.236928 0.260383
+0.285247 0.311486 0.339053 0.367879 0.397882 0.428956 0.46098 0.493812
+0.527292 0.561244 0.595473 0.62977 0.663916 0.697676 0.730811 0.763074
+0.794216 0.823987 0.852144 0.878447 0.902668 0.924595 0.944027 0.960789
+0.974725 0.985703 0.99362 0.998401 1 0.998401 0.99362 0.985703 0.974725
+0.960789 0.944027 0.924595 0.902668 0.878447 0.852144 0.823987 0.794216
+0.763074 0.730811 0.697676 0.663916 0.62977 0.595473 0.561244 0.527292
+0.493812 0.46098 0.428956 0.397882 0.367879 0.339053 0.311486 0.285247
+0.260383 0.236928 0.214896 0.194291 0.1751 0.1573 0.140858 0.125732
+0.111872 0.0992216 0.0877205 0.0773047 0.0679081 0.0594631 0.0519019
+0.0451575 0.0391639 0.0338573 0.0291763 0.0250621 0.0214592 0.0183156
+0.0155826 0.013215 0.0111714 0.0094136 0.00790705 0.0066204 0.0055254
+0.00459678 0.00381201 0.00315111 0.00259648 0.00213263 0.00174605 0.00142498
+0.00115923 0.000940028 0.000759842 0.000612231 0.000491721 0.000393669
+0.000314163 0.000249912 0.000198167 0.000156634 0.00012341 9.69224e-05
+7.58768e-05 5.92113e-05 4.60584e-05 3.57128e-05 2.76026e-05 2.1266e-05
+1.63317e-05 1.25023e-05 9.54016e-06 7.25659e-06 5.50199e-06 4.15832e-06
+3.13275e-06 2.35258e-06 1.76105e-06 1.31404e-06 9.77371e-07 7.24633e-07
+5.35535e-07 3.94519e-07 2.89706e-07 2.12059e-07 1.54727e-07;
+#X pop;
+#X connect 0 0 1 0;
+#X connect 1 0 5 0;
+#X connect 1 1 4 0;
+#X connect 2 0 3 0;
+#X connect 2 0 6 0;
+#X connect 2 0 9 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 2 0;
+#X connect 6 0 10 0;
+#X connect 6 1 7 1;
+#X connect 8 0 7 0;
+#X connect 9 0 5 1;
+#X connect 10 0 8 0;
+#X restore 573 591 pd make-table;
+#X obj 67 390 * 0.5;
+#X obj 306 495 cos~;
+#X obj 306 472 -~ 0.25;
+#X obj 306 549 +~ 100;
+#X obj 306 572 tabread4~ bell-curve;
+#X obj 67 442 *~ 2;
+#X obj 179 656 *~;
+#X text 338 597 waveshaper;
+#X text 31 2 CHANGING PAF CONTROLS TO NATURAL UNITS;
+#X obj 67 362 mtof;
+#X obj 68 335 max 0;
+#X obj 206 370 expr 1/$f1;
+#X obj 183 296 mtof;
+#X text 181 238 freq.;
+#X obj 184 394 *~;
+#X text 406 340 bandwidth;
+#X obj 408 389 mtof;
+#X obj 408 474 *~;
+#X obj 408 498 *~ 25;
+#X text 25 33 The more "natural" units for describing a formant might
+be center frequency and bandwidth \, so that you can change the fundamental
+without having the formant shift up and down in parallel. Here all
+three frequencies are expressed in MIDI units. The bandwidth and center
+frequency have to be divided by the fundamental (the expr 1/$f1 takes
+its reciprocal and two *~ objects finish the division.);
+#X text 448 473 divide by fundamental;
+#X text 466 497 range for table;
+#X text 372 548 offset to middle of table;
+#X text 191 416 C.F. relative;
+#X text 192 432 to fundamental;
+#X text 48 275 (MIDI units);
+#X text 215 654 ring mod;
+#X text 25 150 And now you essentially have the PAF. Note \, however
+\, that there's a nice paf~ "external" object in the "extras" library
+that does this all more efficiently and takes care of a couple of subtle
+details we don't see here...;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 3 0 9 1;
+#X connect 3 0 11 0;
+#X connect 4 0 8 0;
+#X connect 4 0 3 0;
+#X connect 5 0 9 0;
+#X connect 6 0 7 1;
+#X connect 6 0 10 1;
+#X connect 7 0 4 1;
+#X connect 8 0 5 0;
+#X connect 9 0 10 0;
+#X connect 10 0 11 1;
+#X connect 11 0 33 0;
+#X connect 14 0 7 0;
+#X connect 14 0 6 0;
+#X connect 15 0 39 0;
+#X connect 17 0 41 0;
+#X connect 18 0 17 0;
+#X connect 19 0 29 0;
+#X connect 19 0 32 0;
+#X connect 20 0 37 0;
+#X connect 22 0 43 0;
+#X connect 23 0 44 0;
+#X connect 24 0 30 0;
+#X connect 25 0 23 0;
+#X connect 27 0 19 0;
+#X connect 28 0 24 0;
+#X connect 29 0 28 0;
+#X connect 30 0 31 0;
+#X connect 31 0 33 1;
+#X connect 32 0 14 1;
+#X connect 32 0 4 0;
+#X connect 32 0 8 0;
+#X connect 33 0 1 0;
+#X connect 36 0 27 0;
+#X connect 36 0 38 0;
+#X connect 37 0 36 0;
+#X connect 38 0 41 1;
+#X connect 38 0 44 1;
+#X connect 39 0 18 0;
+#X connect 41 0 14 0;
+#X connect 43 0 25 0;
+#X connect 44 0 45 0;
+#X connect 45 0 24 1;
diff --git a/pd/doc/3.audio.examples/J01.quartic.pd b/pd/doc/3.audio.examples/J01.quartic.pd
new file mode 100644
index 00000000..d71da05a
--- /dev/null
+++ b/pd/doc/3.audio.examples/J01.quartic.pd
@@ -0,0 +1,140 @@
+#N canvas 57 35 614 650 12;
+#X graph graph1 0 0 40 1 151 551 551 301;
+#X array array-ampdb 41 float 1;
+#A 0 0.01 0.0112202 0.0125893 0.0141254 0.0158489 0.0177828 0.0199526
+0.0223872 0.0251189 0.0281838 0.0316228 0.0354813 0.0398107 0.0446684
+0.0501187 0.0562341 0.0630957 0.0707946 0.0794328 0.0891251 0.1 0.112202
+0.125893 0.141254 0.158489 0.177828 0.199526 0.223872 0.251189 0.281838
+0.316228 0.354813 0.398107 0.446684 0.501187 0.562341 0.630957 0.707946
+0.794328 0.891251 1;
+#X array array-dbdb 41 float 1;
+#A 0 0 0.025 0.05 0.075 0.1 0.125 0.15 0.175 0.2 0.225 0.25 0.275 0.3
+0.325 0.35 0.375 0.4 0.425 0.45 0.475 0.5 0.525 0.55 0.575 0.6 0.625
+0.65 0.675 0.7 0.725 0.75 0.775 0.8 0.825 0.85 0.875 0.9 0.925 0.95
+0.975 1;
+#X array array-4thpow 41 float 1;
+#A 0 0 3.90624e-07 6.25001e-06 3.16406e-05 1e-04 0.000244141 0.00050625
+0.000937891 0.0016 0.00256289 0.00390625 0.00571914 0.0081 0.0111566
+0.0150063 0.0197754 0.0256 0.0326254 0.0410062 0.0509067 0.0625 0.0759691
+0.0915063 0.109313 0.1296 0.152588 0.178506 0.207594 0.2401 0.276282
+0.316406 0.36075 0.4096 0.46325 0.522006 0.586182 0.6561 0.732094 0.814506
+0.903688 1;
+#X pop;
+#N canvas 293 37 890 657 otherstuff 0;
+#X obj 42 438 loadbang;
+#X msg 259 94 bang;
+#X obj 259 123 t b b;
+#X obj 337 192 f;
+#X obj 375 192 + 1;
+#X msg 353 162 0;
+#X obj 259 152 until;
+#X obj 263 329 dbtorms;
+#X obj 339 227 t f f;
+#X msg 51 101 bang;
+#X obj 51 130 t b b;
+#X obj 129 199 f;
+#X obj 167 199 + 1;
+#X msg 145 169 0;
+#X obj 51 159 until;
+#X obj 131 234 t f f;
+#X obj 59 339 tabwrite array-dbdb;
+#X obj 263 355 tabwrite array-ampdb;
+#X msg 505 98 bang;
+#X obj 505 127 t b b;
+#X obj 583 196 f;
+#X obj 621 196 + 1;
+#X msg 599 166 0;
+#X obj 505 156 until;
+#X obj 585 231 t f f;
+#X obj 559 432 expr $f1 * $f1 * $f1 * $f1;
+#X obj 559 341 expr 1 + $f2 * ($f1 - 1);
+#X obj 705 253 loadbang;
+#X floatatom 703 309 0 0 0;
+#X msg 705 281 1;
+#X obj 559 385 max 0;
+#X obj 561 464 tabwrite array-4thpow;
+#X obj 263 274 + 100;
+#X obj 51 232 sel 40;
+#X obj 258 221 sel 40;
+#X obj 503 226 sel 40;
+#X obj 559 300 / 40;
+#X obj 263 302 - 40;
+#X obj 93 303 / 40;
+#X msg 43 465 \; graph1 xlabel -0.03 0 10 20 30 40 \; graph1 ylabel
+-2 0.25 0.5 0.75 1;
+#X text 53 27 (here's how I computed the three transfer functions...)
+;
+#X connect 0 0 39 0;
+#X connect 1 0 2 0;
+#X connect 2 0 6 0;
+#X connect 2 1 5 0;
+#X connect 3 0 4 0;
+#X connect 3 0 8 0;
+#X connect 3 0 34 0;
+#X connect 4 0 3 1;
+#X connect 5 0 3 1;
+#X connect 6 0 3 0;
+#X connect 7 0 17 0;
+#X connect 8 0 32 0;
+#X connect 8 1 17 1;
+#X connect 9 0 10 0;
+#X connect 10 0 14 0;
+#X connect 10 1 13 0;
+#X connect 11 0 12 0;
+#X connect 11 0 15 0;
+#X connect 11 0 33 0;
+#X connect 12 0 11 1;
+#X connect 13 0 11 1;
+#X connect 14 0 11 0;
+#X connect 15 0 38 0;
+#X connect 15 1 16 1;
+#X connect 18 0 19 0;
+#X connect 19 0 23 0;
+#X connect 19 1 22 0;
+#X connect 20 0 21 0;
+#X connect 20 0 24 0;
+#X connect 20 0 35 0;
+#X connect 21 0 20 1;
+#X connect 22 0 20 1;
+#X connect 23 0 20 0;
+#X connect 24 0 36 0;
+#X connect 24 1 31 1;
+#X connect 25 0 31 0;
+#X connect 26 0 30 0;
+#X connect 27 0 29 0;
+#X connect 28 0 26 1;
+#X connect 29 0 28 0;
+#X connect 30 0 25 0;
+#X connect 32 0 37 0;
+#X connect 33 0 14 1;
+#X connect 34 0 6 1;
+#X connect 35 0 23 1;
+#X connect 36 0 26 0;
+#X connect 37 0 7 0;
+#X connect 38 0 16 0;
+#X restore 53 608 pd otherstuff;
+#X text 292 403 linear;
+#X text 279 509 decibels;
+#X text 387 518 quartic;
+#X text 45 5 QUARTIC CURVES AS THE IDEAL AMPLITUDE AND FREQUENCY SCALERS
+;
+#X text 346 611 updated for Pd version 0.34;
+#X text 246 578 units-->;
+#X text 45 447 amplitude;
+#X text 79 429 |;
+#X text 79 420 |;
+#X text 79 410 |;
+#X text 79 402 |;
+#X text 78 398 ^;
+#X text 38 149 The graph below shows that a simple quartic curve \,
+x-to-the-fourth-power \, twists like decibels but--unlike decibels--actually
+hits zero at left. You get the best of both worlds. Moreover \, raising
+something to the fourth power is very cheap: just two multiplications--whereas
+\, if you're computing envelopes in dB \, eventually you'll have to
+exponentiate \, sample by sample \, to get to linear units.;
+#X text 36 34 It's an old saw that we perceive amplitude and frequency
+logarithmically. But using decibels as a unit for controlling amplitude
+and frequency gets ugly for two reasons. First \, it's expensive to
+do the conversion. Second and more profoundly \, decibels grow by shifting
+\, and things should grow by scaling \, so that \, for example \, zero
+really means "nothing.";
diff --git a/pd/doc/3.audio.examples/J02.more.quartic.pd b/pd/doc/3.audio.examples/J02.more.quartic.pd
new file mode 100644
index 00000000..fdb01dab
--- /dev/null
+++ b/pd/doc/3.audio.examples/J02.more.quartic.pd
@@ -0,0 +1,147 @@
+#N canvas 130 66 880 587 12;
+#X floatatom 89 506 0 0 100;
+#N canvas 159 26 516 274 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 396 182 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 391 110 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 391 85 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 20 182 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 104 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 90 outlet;
+#X msg 214 65 \; pd dsp 1;
+#X obj 83 198 line~;
+#X obj 20 207 *~;
+#X obj 20 232 dac~;
+#X obj 83 173 pack 0 50;
+#X text 20 159 audio;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 21 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X restore 51 534 pd output;
+#X msg 127 507 MUTE;
+#X obj 32 441 *~;
+#X obj 12 469 -~;
+#X obj 73 446 *~;
+#X floatatom 170 421 1 0 100;
+#X obj 365 337 osc~;
+#X obj 365 362 *~;
+#X obj 425 342 line~;
+#X obj 365 312 line~;
+#X obj 550 468 osc~;
+#X obj 599 496 *~;
+#X obj 621 379 line~;
+#X obj 550 379 line~;
+#X obj 550 326 sqrt;
+#X obj 550 352 sqrt;
+#X obj 621 326 sqrt;
+#X obj 621 352 sqrt;
+#X obj 550 411 *~;
+#X obj 550 441 *~;
+#X obj 621 411 *~;
+#X obj 621 440 *~;
+#X obj 550 301 unpack;
+#X obj 621 301 unpack;
+#X obj 365 287 r freq;
+#X obj 425 318 r amp;
+#X obj 550 276 r freq;
+#X obj 621 276 r amp;
+#X obj 365 388 s~ linear;
+#X obj 599 523 s~ quartic;
+#X obj 12 377 r~ linear;
+#X obj 56 406 r~ quartic;
+#X msg 27 185 \; amp 0 5000 \;;
+#X msg 29 139 \; amp 1 5000 \;;
+#X msg 139 185 \; amp 0 1000 \;;
+#X msg 141 139 \; amp 1 1000 \;;
+#X msg 26 238 \; freq 1760 5000 \;;
+#X msg 29 286 \; freq 55 5000 \;;
+#X msg 180 238 \; freq 1760 1000 \;;
+#X msg 183 286 \; freq 55 1000 \;;
+#X text 90 15 QUARTIC AND LINEAR ENVELOPES COMPARED;
+#X obj 202 488 loadbang;
+#X msg 202 516 \; amp 1 \; freq 1760;
+#X text 194 414 1 for quartic \; 0 for linear;
+#X text 19 39 This patch has two sine wave oscillators \, one with
+linear envelopes \, the other with quartic ones which sound more uniform.
+The "toggle switch" at bottom selects between the two \, and the message
+boxes sweep the amplitude and frequency up and down.;
+#X text 366 257 LINEAR;
+#X text 555 249 QUARTIC;
+#X text 335 120 The two oscillators are below. In the quartic one \,
+for both the amplitude and the frequency \, we have to take the fourth
+root of the target value (which we get by taking square root twice.)
+Then we raise the line~ output to the fourth power by squaring twice
+(the *~ objects \, whose left and right inlets are the same.) The cost
+is mostly that of the four additional *~ objects.;
+#X text 579 560 updated for Pd version 0.34;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 3 0 4 1;
+#X connect 4 0 1 0;
+#X connect 5 0 1 0;
+#X connect 6 0 5 1;
+#X connect 6 0 3 1;
+#X connect 7 0 8 0;
+#X connect 8 0 29 0;
+#X connect 9 0 8 1;
+#X connect 10 0 7 0;
+#X connect 11 0 12 0;
+#X connect 12 0 30 0;
+#X connect 13 0 21 0;
+#X connect 13 0 21 1;
+#X connect 14 0 19 0;
+#X connect 14 0 19 1;
+#X connect 15 0 16 0;
+#X connect 16 0 14 0;
+#X connect 17 0 18 0;
+#X connect 18 0 13 0;
+#X connect 19 0 20 0;
+#X connect 19 0 20 1;
+#X connect 20 0 11 0;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 22 0 12 1;
+#X connect 23 0 15 0;
+#X connect 23 1 14 1;
+#X connect 24 0 17 0;
+#X connect 24 1 13 1;
+#X connect 25 0 10 0;
+#X connect 26 0 9 0;
+#X connect 27 0 23 0;
+#X connect 28 0 24 0;
+#X connect 31 0 3 0;
+#X connect 31 0 4 0;
+#X connect 32 0 5 0;
+#X connect 42 0 43 0;
diff --git a/pd/doc/3.audio.examples/J03.qlist.pd b/pd/doc/3.audio.examples/J03.qlist.pd
new file mode 100644
index 00000000..58495ca1
--- /dev/null
+++ b/pd/doc/3.audio.examples/J03.qlist.pd
@@ -0,0 +1,102 @@
+#N canvas 233 179 684 516 12;
+#X floatatom 57 459 0 0 0;
+#N canvas 159 26 497 272 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 182 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 159 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 19 488 pd output;
+#X msg 95 459 MUTE;
+#X obj 19 211 osc-voice amp1 pit1;
+#X obj 19 240 osc-voice amp2 pit2;
+#X obj 19 269 osc-voice amp3 pit3;
+#X obj 19 298 osc-voice amp4 pit4;
+#X obj 19 327 osc-voice amp5 pit5;
+#X obj 19 356 osc-voice amp6 pit6;
+#X obj 19 385 osc-voice amp7 pit7;
+#X obj 19 414 osc-voice amp8 pit8;
+#X obj 467 382 qlist;
+#X msg 389 226 stop;
+#X msg 527 339 read qlist.txt;
+#X obj 527 294 loadbang;
+#X text 261 203 start;
+#X text 391 202 stop;
+#X text 537 318 reread file;
+#X msg 470 238 rewind;
+#X msg 538 238 next;
+#X msg 258 254 tempo 100 \, bang;
+#X msg 253 227 tempo 1 \, bang;
+#X text 82 11 USING QLIST TO SEQUENCE AN OSCILLATOR BANK;
+#X text 474 215 single step;
+#X obj 556 454 r #;
+#X text 35 61 Here is an eight voice additive synthesis patch controlled
+by a qlist. Open a text editor on the file \, "qlist.txt" \, to see
+how the oscillators' amplitudes and frequencies are specified. The
+abstraction \, "osc-voice" \, shows an effective way to make patches
+react to qlists but also to mousing.;
+#X text 258 453 this is where qlist comments go:;
+#X text 418 485 updatged for Pd version 0.34;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 3 0 4 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 9 0 10 0;
+#X connect 10 0 1 0;
+#X connect 12 0 11 0;
+#X connect 13 0 11 0;
+#X connect 14 0 13 0;
+#X connect 18 0 11 0;
+#X connect 19 0 11 0;
+#X connect 20 0 11 0;
+#X connect 21 0 11 0;
diff --git a/pd/doc/3.audio.examples/J04.more.adsr.pd b/pd/doc/3.audio.examples/J04.more.adsr.pd
new file mode 100644
index 00000000..5b38917a
--- /dev/null
+++ b/pd/doc/3.audio.examples/J04.more.adsr.pd
@@ -0,0 +1,117 @@
+#N canvas 105 38 705 609 12;
+#X obj 39 140 r trigger;
+#X floatatom 70 376 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 351 166 t b;
+#X obj 351 114 f;
+#X obj 351 62 inlet;
+#X text 358 30 mute;
+#X obj 351 192 f;
+#X msg 442 185 0;
+#X msg 351 88 bang;
+#X obj 351 140 moses 1;
+#X obj 442 159 t b f;
+#X obj 413 122 moses 1;
+#X obj 86 154 dbtorms;
+#X obj 413 96 r master-lvl;
+#X obj 86 44 r master-lvl;
+#X obj 351 218 s master-lvl;
+#X obj 23 188 inlet~;
+#X obj 207 42 inlet;
+#X text 207 19 level;
+#X obj 207 104 s master-lvl;
+#X msg 100 67 set \$1;
+#X obj 100 93 outlet;
+#X msg 222 66 \; pd dsp 1;
+#X obj 86 202 line~;
+#X obj 23 221 *~;
+#X obj 23 250 dac~;
+#X obj 86 178 pack 0 50;
+#X text 21 165 audio;
+#X text 97 114 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 39 406 pd output;
+#X msg 107 376 MUTE;
+#X text 150 375 <-- output amplitude;
+#X text 518 189 <-- attack;
+#X text 485 281 <-- release;
+#X obj 39 338 *~;
+#X obj 39 282 *~;
+#X obj 39 310 *~;
+#X obj 80 340 osc~ 440;
+#X text 88 9 ADSR envelope;
+#X text 35 29 You can use the quartic trick to simplify patches using
+ADSR envelopes. For amplitude control it's especially simple. It's
+usually good enough in practice to control amplitudes by ranging an
+ADSR from 0 to 1 (divide by 100 so your input range can be a comfortable
+0-100) \, then take fourth power:;
+#X obj 77 227 / 100;
+#X floatatom 77 197 3 0 100;
+#X msg 383 269 \; trigger 0;
+#X obj 39 166 unpack;
+#X floatatom 39 197 1 0 100;
+#X msg 383 175 \; trigger 1 100;
+#X text 503 229 <-- softer attack;
+#X msg 382 222 \; trigger 1 60;
+#X text 441 583 updated for Pd version 0.34;
+#X text 14 437 Note that the units aren't dB \; for most of the range
+0-100 it's about 0.4 dB per unit. If you want something closer to dB
+\, you can set the scale as 0-40 instead of 0-100 (just change "/ 100"
+to "/ 40") and then you'll get the response shown in the first patch
+in this section.;
+#X obj 596 519 *~;
+#X obj 596 547 *~;
+#X floatatom 605 390 3 0 100;
+#X obj 605 416 mtof;
+#X obj 605 441 sqrt;
+#X obj 605 466 sqrt;
+#X text 174 526 To use ADSR to control pitch \, you should;
+#X text 173 545 usually just use real pitch units like this-->;
+#X obj 596 490 adsr 0;
+#X obj 39 253 adsr 0 100 200 70 300;
+#X connect 0 0 16 0;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 7 0 2 0;
+#X connect 8 0 9 0;
+#X connect 8 0 9 1;
+#X connect 9 0 7 0;
+#X connect 10 0 7 1;
+#X connect 13 0 32 1;
+#X connect 14 0 13 0;
+#X connect 16 0 17 0;
+#X connect 16 1 14 0;
+#X connect 17 0 32 0;
+#X connect 23 0 24 0;
+#X connect 23 0 24 1;
+#X connect 25 0 26 0;
+#X connect 26 0 27 0;
+#X connect 27 0 28 0;
+#X connect 28 0 31 1;
+#X connect 31 0 23 0;
+#X connect 31 0 23 1;
+#X connect 32 0 8 0;
+#X connect 32 0 8 1;
diff --git a/pd/doc/3.audio.examples/J05.vibrato.pd b/pd/doc/3.audio.examples/J05.vibrato.pd
new file mode 100644
index 00000000..78c38efd
--- /dev/null
+++ b/pd/doc/3.audio.examples/J05.vibrato.pd
@@ -0,0 +1,158 @@
+#N canvas 80 10 736 726 12;
+#X obj 27 220 r trigger;
+#X floatatom 65 581 0 0 0;
+#N canvas 159 26 531 288 output 0;
+#X obj 351 166 t b;
+#X obj 351 114 f;
+#X obj 351 62 inlet;
+#X text 358 30 mute;
+#X obj 351 192 f;
+#X msg 442 185 0;
+#X msg 351 88 bang;
+#X obj 351 140 moses 1;
+#X obj 413 122 moses 1;
+#X obj 86 154 dbtorms;
+#X obj 413 96 r master-lvl;
+#X obj 86 44 r master-lvl;
+#X obj 351 218 s master-lvl;
+#X obj 24 163 inlet~;
+#X obj 207 42 inlet;
+#X text 207 19 level;
+#X obj 207 104 s master-lvl;
+#X msg 100 67 set \$1;
+#X obj 100 93 outlet;
+#X msg 222 66 \; pd dsp 1;
+#X obj 86 202 line~;
+#X obj 23 221 *~;
+#X obj 23 250 dac~;
+#X obj 86 178 pack 0 50;
+#X text 22 140 audio;
+#X obj 442 159 t b;
+#X obj 21 191 hip~ 1;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 25 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 25 0 5 0;
+#X connect 26 0 21 0;
+#X restore 26 610 pd output;
+#X msg 102 581 MUTE;
+#X obj 27 446 *~;
+#X obj 27 474 *~;
+#X floatatom 62 277 3 0 100;
+#X msg 484 482 \; trigger 0;
+#X obj 27 246 unpack;
+#X floatatom 27 277 1 0 100;
+#X text 463 668 updated for Pd version 0.34;
+#X obj 26 525 +~ 0.3;
+#X obj 26 551 cos~;
+#X obj 26 499 osc~;
+#X text 88 9 PORTAMENTO AND VIBRATO;
+#X obj 62 300 mtof;
+#X obj 62 325 sqrt;
+#X obj 62 350 sqrt;
+#X text 619 402 <-- midC;
+#X text 607 444 <-- octave up;
+#X msg 484 388 \; trigger 1 60;
+#X msg 483 435 \; trigger 1 72;
+#X text 584 488 <-- release;
+#X text 590 506 is optional;
+#X obj 27 416 *~;
+#X obj 236 396 +~ 1;
+#X graph graph1 0 -1 130 1 433 643 633 543;
+#X array array62 131 float 1;
+#A 0 0.970031 1 0.970031 0.881921 0.740952 0.555571 0.336891 0.0980184
+-0.146729 -0.382682 -0.595698 -0.773009 -0.88 -0.9 -0.92 -0.92 -0.85773
+-0.707109 -0.514106 -0.290288 -0.0490716 0.195086 0.427551 0.63439
+0.803205 0.86 0.88 0.88 0.88 0.84 0.82 0.471402 0.242986 6.63397e-06
+-0.242974 -0.471391 -0.671554 -0.831465 -0.941541 -0.995184 -0.989178
+-0.923883 -0.803213 -0.68 -0.42 -0.24 0.1 0.4 0.6 0.7071 0.857723 0.956937
+0.998795 0.980787 0.903994 0.773018 0.595708 0.382694 0.146742 -0.0980052
+-0.336878 -0.55556 -0.7 -0.8 -0.88 -0.88 -0.88 -0.84 -0.82 -0.555582
+-0.336903 -0.0980316 0.146716 0.38267 0.595687 0.773001 0.903983 0.980782
+0.998796 0.956945 0.857737 0.707119 0.514117 0.290301 0.0490849 -0.195073
+-0.427539 -0.63438 -0.803197 -0.923873 -0.989174 -0.995187 -0.94155
+-0.83148 -0.671573 -0.471414 -0.242999 -1.99019e-05 0.242961 0.471379
+0.671544 0.831458 0.88 0.9 0.9 0.88 0.803221 0.63441 0.08 -0.14 -0.28
+-0.48 -0.64 -0.72 -0.857717 -0.956933 -0.998794 -0.98079 -0.904 -0.773026
+-0.595719 -0.382706 -0.146755 0.097992 0.336866 0.555549 0.740934 0.881909
+0.970025 1 0.970038;
+#X pop;
+#X obj 236 342 tabosc4~ array62;
+#X floatatom 236 286 3 0 0;
+#X obj 236 313 / 6;
+#X obj 236 370 *~;
+#X floatatom 390 323 3 0 0;
+#X text 235 421 since we'll multiply \,;
+#X text 234 436 vibrato output should;
+#X text 234 453 be centered at 1 \, not 0;
+#X text 275 372 multiply by vib depth;
+#X obj 390 350 / 6923;
+#X text 28 35 Portamento can be treated as a special case of an ADSR
+envelope \, with 100 percent sustain. Vibrato is properly computed
+in units of pitch \, but it's also easy to add vibrato to the envelope--before
+raising it to the fourth power \, so that it acts pseudo-logarithmically.
+Rather than add to the ADSR output \, we multiply a signal which controls
+relative frequency. The relative frequency change is one plus an oscillator.
+;
+#X text 61 417 apply vibrato;
+#X text 65 445 fourth;
+#X text 68 461 power;
+#X text 96 529 waveform;
+#X text 95 509 simple;
+#X text 465 344 4/(exp(log(2)/1200)-1);
+#X text 469 325 conversion factor is;
+#X text 383 279 vibrato depth;
+#X text 382 296 in cents;
+#X text 233 245 vibrato speed;
+#X text 232 262 in Hertz;
+#X text 152 168 I made a table with 6 cycles of vibrato and made small
+changes with the mouse to get a not-exactly-repeating vibrato \, and
+thus have to divide vibrato frequency by 6 You can just use a sine
+or triangle wave if you prefer.;
+#X obj 27 375 adsr 0 100 200 100 300;
+#X connect 0 0 8 0;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 4 0 5 0;
+#X connect 4 0 5 1;
+#X connect 5 0 13 0;
+#X connect 6 0 15 0;
+#X connect 8 0 9 0;
+#X connect 8 1 6 0;
+#X connect 9 0 50 0;
+#X connect 11 0 12 0;
+#X connect 12 0 2 0;
+#X connect 13 0 11 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 0;
+#X connect 17 0 50 1;
+#X connect 24 0 4 0;
+#X connect 24 0 4 1;
+#X connect 25 0 24 1;
+#X connect 27 0 30 0;
+#X connect 28 0 29 0;
+#X connect 29 0 27 0;
+#X connect 30 0 25 0;
+#X connect 31 0 36 0;
+#X connect 36 0 30 1;
+#X connect 50 0 24 0;
diff --git a/pd/doc/3.audio.examples/J06.adsr.sequenced.pd b/pd/doc/3.audio.examples/J06.adsr.sequenced.pd
new file mode 100644
index 00000000..26300054
--- /dev/null
+++ b/pd/doc/3.audio.examples/J06.adsr.sequenced.pd
@@ -0,0 +1,217 @@
+#N canvas 32 15 950 613 12;
+#X obj 33 220 r trigger;
+#X floatatom 70 520 0 0 0;
+#N canvas 159 26 584 307 output 0;
+#X obj 390 189 t b;
+#X obj 390 129 f;
+#X obj 390 69 inlet;
+#X text 397 32 mute;
+#X obj 390 219 f;
+#X msg 451 217 0;
+#X msg 390 99 bang;
+#X obj 390 159 moses 1;
+#X obj 460 137 moses 1;
+#X obj 100 178 dbtorms;
+#X obj 460 107 r master-lvl;
+#X obj 100 50 r master-lvl;
+#X obj 390 249 s master-lvl;
+#X obj 26 217 inlet~;
+#X obj 239 49 inlet;
+#X text 239 22 level;
+#X obj 239 120 s master-lvl;
+#X msg 115 78 set \$1;
+#X obj 115 107 outlet;
+#X msg 257 77 \; pd dsp 1;
+#X obj 100 233 line~;
+#X obj 26 254 *~;
+#X obj 26 289 dac~;
+#X obj 100 205 pack 0 50;
+#X text 24 190 audio;
+#X text 112 132 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 21 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X restore 32 546 pd output;
+#X msg 108 521 MUTE;
+#X obj 33 438 *~;
+#X obj 33 331 *~ 0.01;
+#X obj 33 366 *~;
+#X obj 33 396 *~;
+#X obj 80 360 r pitch;
+#X obj 80 410 mtof;
+#X floatatom 80 385 4 0 0;
+#X floatatom 57 272 4 0 0;
+#X obj 57 247 r level;
+#X floatatom 131 272 4 0 0;
+#X obj 131 247 r attack;
+#X floatatom 216 272 4 0 0;
+#X obj 216 247 r decay;
+#X floatatom 291 272 4 0 0;
+#X floatatom 385 272 4 0 0;
+#X obj 291 247 r sustain;
+#X obj 385 247 r release;
+#X obj 509 106 r note;
+#X msg 510 195 \; trigger 1;
+#X obj 634 185 del;
+#X msg 634 210 \; trigger 0;
+#X obj 9 167 qlist;
+#X obj 8 6 r qlist;
+#X msg 30 35 bang;
+#X msg 30 60 rewind;
+#X obj 37 89 r tempo;
+#X floatatom 37 114 4 0 0;
+#X msg 37 139 tempo \$1;
+#X obj 509 156 t b f;
+#X obj 564 157 s pitch;
+#X obj 656 120 r duration;
+#X floatatom 656 145 4 0 0;
+#X floatatom 509 131 4 0 0;
+#X obj 289 320 r trigger;
+#X floatatom 315 376 4 0 0;
+#X floatatom 387 406 4 0 0;
+#X floatatom 477 406 4 0 0;
+#X floatatom 563 406 4 0 0;
+#X floatatom 659 406 4 0 0;
+#X obj 315 351 r level2;
+#X obj 387 381 r attack2;
+#X obj 477 381 r decay2;
+#X obj 563 381 r sustain2;
+#X obj 659 381 r release2;
+#X obj 80 435 tabosc4~ array1;
+#X floatatom 239 366 4 0 0;
+#X obj 33 482 vcf~;
+#X floatatom 140 488 4 0 0;
+#X obj 140 463 r q;
+#X obj 33 306 adsr 0 0 0 0 0;
+#X obj 289 444 adsr 0 0 0 0 0;
+#X obj 315 401 / 69.23;
+#X obj 239 391 mtof;
+#X obj 239 416 sqrt;
+#X obj 239 441 sqrt;
+#X obj 197 336 r filter;
+#X obj 240 494 *~;
+#X obj 240 519 *~;
+#X obj 289 469 +~ 1;
+#X obj 239 466 *~;
+#X text 139 215 ADSR for amplitude:;
+#X text 402 300 ADSR for filter. Here \, I thought it better to make
+the envelope modify a constant "filter pitch"--so the "filter" receive
+gets the "mtof" treatment and the ADSR is an offset in halftones (thus
+the "/ 69.23" as compared to the previous patch.);
+#X text 141 5 USING QLIST TO MAKE SEQUENCES OF "NOTES";
+#N canvas -10 258 703 380 otherstuff 0;
+#X obj 289 86 loadbang;
+#X obj 418 85 loadbang;
+#X graph graph2 0 -1 66 1 62 221 262 81;
+#X array array1 67 float 1;
+#A 0 0 0 0 0 0.714286 0.742857 0.757143 0.771429 0.778571 0.785714
+0.785714 0.785714 0.785714 0.790476 0.795238 0.614286 0.585714 0.442857
+0.271429 -0.128571 -0.142857 -0.157143 -0.171429 -0.642857 -0.528571
+-0.614286 -0.685714 -0.828571 -0.828571 0 0 0 0 0 0 0 0 0 0 0 0 0 0
+0.557143 0.571429 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
+#X pop;
+#X msg 418 115 \; qlist read qlist2.txt;
+#X msg 289 111 \; level 100 \; attack 20 \; decay 300 \; sustain 70
+\; release 300 \; duration 300 \; pitch 72 \; filter 38 \; level2 49
+\; attack2 19 \; decay2 300 \; sustain2 17 \; release2 700 \; q 3 \;
+tempo 1;
+#X connect 0 0 4 0;
+#X connect 1 0 3 0;
+#X restore 32 571 pd otherstuff;
+#X text 82 34 <--start loop;
+#X text 99 62 <--stop loop;
+#X text 85 114 <--set tempo;
+#X text 248 34 The qlist reads the file \, "qlist2.txt" \, which contains
+four "note" messages and a message at the end that restarts the qlist
+at the beginning. The "note" messages are translated into a pitch change
+and triggers for the ADSRs:;
+#X text 694 573 updated for Pd version 0.34;
+#X text 155 573 <--loadbangs and table;
+#X msg 468 518 \; qlist read qlist2.txt;
+#X text 462 494 click to reload qlist2.txt;
+#X text 149 521 <--output;
+#X connect 0 0 53 0;
+#X connect 1 0 2 1;
+#X connect 2 0 1 0;
+#X connect 3 0 2 2;
+#X connect 4 0 50 0;
+#X connect 5 0 6 0;
+#X connect 5 0 6 1;
+#X connect 6 0 7 0;
+#X connect 6 0 7 1;
+#X connect 7 0 4 0;
+#X connect 8 0 10 0;
+#X connect 9 0 48 0;
+#X connect 10 0 9 0;
+#X connect 11 0 53 1;
+#X connect 12 0 11 0;
+#X connect 13 0 53 2;
+#X connect 14 0 13 0;
+#X connect 15 0 53 3;
+#X connect 16 0 15 0;
+#X connect 17 0 53 4;
+#X connect 18 0 53 5;
+#X connect 19 0 17 0;
+#X connect 20 0 18 0;
+#X connect 21 0 36 0;
+#X connect 23 0 24 0;
+#X connect 26 0 25 0;
+#X connect 27 0 25 0;
+#X connect 28 0 25 0;
+#X connect 29 0 30 0;
+#X connect 30 0 31 0;
+#X connect 31 0 25 0;
+#X connect 32 0 23 0;
+#X connect 32 0 22 0;
+#X connect 32 1 33 0;
+#X connect 34 0 35 0;
+#X connect 35 0 23 1;
+#X connect 36 0 32 0;
+#X connect 37 0 54 0;
+#X connect 38 0 55 0;
+#X connect 39 0 54 2;
+#X connect 40 0 54 3;
+#X connect 41 0 54 4;
+#X connect 42 0 54 5;
+#X connect 43 0 38 0;
+#X connect 44 0 39 0;
+#X connect 45 0 40 0;
+#X connect 46 0 41 0;
+#X connect 47 0 42 0;
+#X connect 48 0 4 1;
+#X connect 49 0 56 0;
+#X connect 50 0 2 0;
+#X connect 51 0 50 2;
+#X connect 52 0 51 0;
+#X connect 53 0 5 0;
+#X connect 54 0 62 0;
+#X connect 55 0 54 1;
+#X connect 56 0 57 0;
+#X connect 57 0 58 0;
+#X connect 58 0 63 0;
+#X connect 59 0 49 0;
+#X connect 60 0 61 0;
+#X connect 60 0 61 1;
+#X connect 61 0 50 1;
+#X connect 62 0 63 1;
+#X connect 63 0 60 0;
+#X connect 63 0 60 1;
diff --git a/pd/doc/3.audio.examples/J07.execution.order.pd b/pd/doc/3.audio.examples/J07.execution.order.pd
new file mode 100644
index 00000000..2bea8e92
--- /dev/null
+++ b/pd/doc/3.audio.examples/J07.execution.order.pd
@@ -0,0 +1,127 @@
+#N canvas 100 17 724 631 12;
+#X floatatom 448 290 0 0 0;
+#X obj 70 432 +~;
+#X obj 91 401 vd~ delay1;
+#X floatatom 108 559 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 397 110 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 85 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 18 152 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 197 104 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 16 129 audio;
+#X text 93 110 show level;
+#X obj 18 179 hip~ 5;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 21 0;
+#X restore 70 585 pd output;
+#X msg 145 559 MUTE;
+#X text 184 558 <-- output amplitude;
+#X text 86 9 ORDER OF EXECUTION OF DELWRITE~ AND DELREAD~/VD~;
+#X text 43 35 If you're writing to and reading from a delay line \,
+you have to get the write sorted before the read or else you'll never
+get less than a block's delay. This patch compares a "wrong" flanger
+with a "right" one:;
+#X obj 69 299 noise~;
+#X obj 91 375 line~;
+#X obj 448 344 pack 0 100;
+#X text 518 292 <-- delay in samples;
+#X obj 92 505 *~;
+#X obj 92 481 -~;
+#X floatatom 175 505 1 0 0;
+#X obj 293 297 noise~;
+#X obj 423 398 line~;
+#N canvas 0 0 600 400 delay-writer 0;
+#X obj 96 107 inlet~;
+#X obj 96 180 outlet~;
+#X obj 116 144 delwrite~ delay2 1000;
+#X connect 0 0 1 0;
+#X connect 0 0 2 0;
+#X restore 293 325 pd delay-writer;
+#N canvas 0 0 280 330 delay-reader 0;
+#X obj 96 107 inlet~;
+#X obj 89 267 outlet~;
+#X obj 112 163 inlet~;
+#X obj 112 198 vd~ delay2;
+#X obj 89 237 +~;
+#X connect 0 0 4 0;
+#X connect 2 0 3 0;
+#X connect 3 0 4 1;
+#X connect 4 0 1 0;
+#X restore 293 427 pd delay-reader;
+#X obj 70 533 +~;
+#X text 194 505 <-- 0 to hear left-hand side \, 1 to hear right hand
+side.;
+#X text 46 105 All it took was to put the delread~ and vd~ objects
+in subpatches. The audio connections between the subpatches force the
+"reader" to be sorted after the "writer". DSP sorting in Pd follows
+the hierarchy of windows.;
+#X obj 447 318 / 44.1;
+#X obj 82 329 delwrite~ delay1 1000;
+#X text 450 596 updated for Pd version 0.34;
+#X text 43 173 To hear the difference scroll the delay time between
+0 and 100 samples. The patch at left doesn't let you get below 64 samples.
+;
+#X text 43 228 You can use the same strategy to avoid picking up 64-sample
+delays in send~/receive~ and throw~/catch~ pairs.;
+#X connect 0 0 23 0;
+#X connect 1 0 14 1;
+#X connect 1 0 20 0;
+#X connect 2 0 1 1;
+#X connect 3 0 4 1;
+#X connect 4 0 3 0;
+#X connect 5 0 4 2;
+#X connect 9 0 1 0;
+#X connect 9 0 24 0;
+#X connect 10 0 2 0;
+#X connect 11 0 10 0;
+#X connect 11 0 17 0;
+#X connect 13 0 20 1;
+#X connect 14 0 13 0;
+#X connect 15 0 13 1;
+#X connect 16 0 18 0;
+#X connect 17 0 19 1;
+#X connect 18 0 19 0;
+#X connect 19 0 14 0;
+#X connect 20 0 4 0;
+#X connect 23 0 11 0;
diff --git a/pd/doc/3.audio.examples/J08.control.blocksize.pd b/pd/doc/3.audio.examples/J08.control.blocksize.pd
new file mode 100644
index 00000000..05bad0d2
--- /dev/null
+++ b/pd/doc/3.audio.examples/J08.control.blocksize.pd
@@ -0,0 +1,111 @@
+#N canvas 100 17 662 466 12;
+#X floatatom 130 389 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 397 110 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 85 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 18 152 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 197 104 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 16 129 audio;
+#X text 93 110 show level;
+#X obj 18 179 hip~ 5;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 12 0;
+#X connect 5 0 12 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 5 0;
+#X connect 8 1 4 1;
+#X connect 9 0 23 0;
+#X connect 10 0 1 1;
+#X connect 10 0 8 0;
+#X connect 11 0 9 0;
+#X connect 11 0 17 0;
+#X connect 13 0 26 0;
+#X connect 14 0 16 0;
+#X connect 14 0 19 0;
+#X connect 17 0 18 0;
+#X connect 20 0 21 1;
+#X connect 21 0 22 0;
+#X connect 21 0 22 1;
+#X connect 23 0 20 0;
+#X connect 26 0 21 0;
+#X restore 92 415 pd output;
+#X msg 167 389 MUTE;
+#X text 206 388 <-- output amplitude;
+#X obj 51 203 noise~;
+#N canvas 0 0 760 350 delay-writer 0;
+#X obj 75 100 inlet~;
+#X obj 79 250 outlet~;
+#X obj 90 194 delwrite~ delay3 1000;
+#X obj 379 97 block~ 1;
+#X obj 145 131 delread~ delay3;
+#X obj 144 159 *~ 0.99;
+#X obj 79 164 +~;
+#X obj 146 100 inlet;
+#X text 84 22 Because of the feedback \, the delwrite~ has to go after
+the delread~. So we set the blocksize to 1 to minimize the resulting
+delay.;
+#X connect 0 0 6 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 1;
+#X connect 6 0 2 0;
+#X connect 6 0 1 0;
+#X connect 7 0 4 0;
+#X restore 91 328 pd delay-writer;
+#X text 401 435 updated for Pd version 0.34;
+#X obj 77 285 *~;
+#X obj 273 275 expr 1000/$f1;
+#X obj 273 249 mtof;
+#X msg 176 220 1;
+#X msg 176 282 0;
+#X obj 177 164 metro 500;
+#X obj 273 195 random 60;
+#X obj 177 135 loadbang;
+#X obj 216 217 del 2;
+#X obj 273 221 + 30;
+#X obj 51 228 lop~ 1000;
+#X text 86 9 CONTROLLING DELAY WITH BLOCK~;
+#X text 75 52 In situations where a delay read feeds pack to a delay
+write \, you can shorten the minimum delay by changing the block size.
+Do this in a subpatch...;
+#X text 238 328 <-- here is the delay loop;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 4 0 17 0;
+#X connect 5 0 1 0;
+#X connect 7 0 5 0;
+#X connect 8 0 5 1;
+#X connect 9 0 8 0;
+#X connect 10 0 7 1;
+#X connect 11 0 7 1;
+#X connect 12 0 10 0;
+#X connect 12 0 13 0;
+#X connect 12 0 15 0;
+#X connect 13 0 16 0;
+#X connect 14 0 12 0;
+#X connect 15 0 11 0;
+#X connect 16 0 9 0;
+#X connect 17 0 7 0;
diff --git a/pd/doc/3.audio.examples/J09.up.downsampling.pd b/pd/doc/3.audio.examples/J09.up.downsampling.pd
new file mode 100644
index 00000000..cf50f9b9
--- /dev/null
+++ b/pd/doc/3.audio.examples/J09.up.downsampling.pd
@@ -0,0 +1,191 @@
+#N canvas 32 25 1089 690 10;
+#X obj 57 567 osc~ 412;
+#X floatatom 58 543 5 0 0;
+#X obj 122 595 tabwrite~ scope;
+#X msg 122 571 bang;
+#X msg 205 43 bang;
+#X obj 42 191 tabwrite~ scope;
+#X msg 54 165 bang;
+#N canvas 316 181 600 400 simple 0;
+#X obj 185 46 inlet;
+#X obj 185 102 tabwrite~ scope;
+#X obj 78 38 inlet~;
+#X obj 78 258 outlet~;
+#X obj 317 103 block~ 64 1 0.25;
+#X connect 0 0 1 0;
+#X connect 2 0 1 0;
+#X connect 2 0 3 0;
+#X restore 42 64 pd simple downsampling 4;
+#X msg 451 42 bang;
+#X obj 275 190 tabwrite~ scope;
+#X msg 287 164 bang;
+#X graph graph2 0 -1 511 1 297 629 897 489;
+#X array scope 512 float 0;
+#X pop;
+#X msg 683 45 bang;
+#X obj 520 193 tabwrite~ scope;
+#X msg 532 167 bang;
+#X msg 929 44 bang;
+#X obj 753 192 tabwrite~ scope;
+#X msg 765 166 bang;
+#N canvas 165 168 600 400 simple 0;
+#X obj 185 74 inlet;
+#X obj 185 102 tabwrite~ scope;
+#X obj 78 38 inlet~;
+#X obj 78 258 outlet~;
+#X text 130 38 zero-padding upsampling;
+#X obj 317 103 block~ 64 1 4;
+#X connect 0 0 1 0;
+#X connect 2 0 1 0;
+#X connect 2 0 3 0;
+#X restore 520 66 pd simple upsampling 4;
+#X obj 42 38 r~ sine;
+#X obj 275 39 r~ sine;
+#X obj 57 595 s~ sine;
+#X obj 520 41 r~ sine;
+#X obj 753 41 r~ sine;
+#X obj 41 415 tabwrite~ scope;
+#X msg 47 369 bang;
+#X msg 804 265 bang;
+#X obj 711 415 tabwrite~ scope;
+#X msg 723 389 bang;
+#X obj 41 262 r~ sine;
+#X obj 711 264 r~ sine;
+#X obj 152 416 tabwrite~ scope;
+#X msg 158 370 bang;
+#X text 43 431 zero-padded;
+#N canvas 290 149 600 400 downsampling 0;
+#X obj 78 38 inlet~;
+#X obj 78 258 outlet~;
+#X obj 152 258 outlet~ hold;
+#X obj 317 103 block~ 64 1 0.25;
+#X connect 0 0 1 0;
+#X connect 0 0 2 0;
+#X restore 41 288 pd downsampling 4 (mixed);
+#N canvas 261 147 600 400 bad 0;
+#X obj 185 81 inlet;
+#X obj 185 102 tabwrite~ scope;
+#X text 172 257 "lin" is for linear upsampling;
+#X text 160 39 "lin" has no meaning when downsampling;
+#X obj 317 103 block~ 64 2;
+#X obj 78 258 outlet~;
+#X obj 78 38 inlet~;
+#X connect 0 0 1 0;
+#X connect 6 0 1 0;
+#X connect 6 0 5 0;
+#X restore 711 288 pd bad overlap;
+#X msg 1018 263 bang;
+#X obj 841 415 tabwrite~ scope;
+#X msg 853 389 bang;
+#X obj 841 264 r~ sine;
+#N canvas 121 72 600 400 bad 0;
+#X obj 185 81 inlet;
+#X obj 185 102 tabwrite~ scope;
+#X obj 78 258 outlet~ lin;
+#X obj 78 38 inlet~ lin;
+#X text 167 38 "lin" is for linear upsampling;
+#X text 166 259 "lin" has no meaning when downsampling;
+#X obj 317 103 block~ 64 2 2;
+#X connect 0 0 1 0;
+#X connect 3 0 1 0;
+#X connect 3 0 2 0;
+#X restore 841 288 pd bad overlap (upsampled);
+#X msg 458 267 bang;
+#X obj 323 417 tabwrite~ scope;
+#X msg 335 391 bang;
+#X obj 323 266 r~ sine;
+#X text 155 433 sample&hold;
+#X msg 653 265 bang;
+#X obj 511 416 tabwrite~ scope;
+#X msg 523 390 bang;
+#X obj 511 265 r~ sine;
+#N canvas 249 128 600 400 downsampled 0;
+#X obj 185 81 inlet;
+#X obj 185 102 tabwrite~ scope;
+#X obj 78 258 outlet~ lin;
+#X obj 78 230 *~ 0.5;
+#X obj 78 38 inlet~;
+#X obj 317 103 block~ 128 2 0.25;
+#X connect 0 0 1 0;
+#X connect 3 0 2 0;
+#X connect 4 0 1 0;
+#X connect 4 0 3 0;
+#X restore 511 289 pd downsampled overlap;
+#N canvas 175 94 600 400 upsampled 0;
+#X obj 185 81 inlet;
+#X obj 185 102 tabwrite~ scope;
+#X obj 78 258 outlet~ lin;
+#X obj 78 38 inlet~ lin;
+#X obj 78 230 *~ 0.5;
+#X obj 317 103 block~ 256 2 2;
+#X connect 0 0 1 0;
+#X connect 3 0 1 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X restore 323 290 pd upsampled overlap;
+#N canvas 350 164 600 400 upsampling 0;
+#X obj 185 81 inlet;
+#X obj 185 102 tabwrite~ scope;
+#X obj 78 38 inlet~ hold;
+#X obj 78 258 outlet~;
+#X text 160 39 "hold" is for sample&hold upsampling;
+#X obj 317 103 block~ 64 1 16;
+#X connect 0 0 1 0;
+#X connect 2 0 1 0;
+#X connect 2 0 3 0;
+#X restore 753 65 pd upsampling 16 (sample&hold);
+#N canvas 236 170 600 400 downsampling 0;
+#X obj 185 81 inlet;
+#X obj 185 102 tabwrite~ scope;
+#X obj 78 258 outlet~ lin;
+#X obj 78 38 inlet~ lin;
+#X text 172 257 "lin" is for linear upsampling;
+#X obj 320 102 block~ 64 1 0.125;
+#X text 330 137 0.125 = 1/8 = 8*downsampling;
+#X text 160 39 "lin" has (still !) no meaning when downsampling;
+#X connect 0 0 1 0;
+#X connect 3 0 1 0;
+#X connect 3 0 2 0;
+#X restore 275 63 pd downsampling 8 (linear);
+#X text 718 314 a pd-bug !;
+#X connect 0 0 2 0;
+#X connect 0 0 21 0;
+#X connect 1 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 7 1;
+#X connect 6 0 5 0;
+#X connect 7 0 5 0;
+#X connect 8 0 53 1;
+#X connect 10 0 9 0;
+#X connect 12 0 18 1;
+#X connect 14 0 13 0;
+#X connect 15 0 52 1;
+#X connect 17 0 16 0;
+#X connect 18 0 13 0;
+#X connect 19 0 7 0;
+#X connect 20 0 53 0;
+#X connect 22 0 18 0;
+#X connect 23 0 52 0;
+#X connect 25 0 24 0;
+#X connect 26 0 35 1;
+#X connect 28 0 27 0;
+#X connect 29 0 34 0;
+#X connect 30 0 35 0;
+#X connect 32 0 31 0;
+#X connect 34 0 24 0;
+#X connect 34 1 31 0;
+#X connect 35 0 27 0;
+#X connect 36 0 40 1;
+#X connect 38 0 37 0;
+#X connect 39 0 40 0;
+#X connect 40 0 37 0;
+#X connect 41 0 51 1;
+#X connect 43 0 42 0;
+#X connect 44 0 51 0;
+#X connect 46 0 50 1;
+#X connect 48 0 47 0;
+#X connect 49 0 50 0;
+#X connect 50 0 47 0;
+#X connect 51 0 42 0;
+#X connect 52 0 16 0;
+#X connect 53 0 9 0;
diff --git a/pd/doc/3.audio.examples/J10.waveshaping.pd b/pd/doc/3.audio.examples/J10.waveshaping.pd
new file mode 100644
index 00000000..b217112f
--- /dev/null
+++ b/pd/doc/3.audio.examples/J10.waveshaping.pd
@@ -0,0 +1,133 @@
+#N canvas 222 24 761 466 12;
+#X floatatom 61 408 0 0 0;
+#N canvas 159 26 495 266 output 0;
+#X obj 338 160 t b;
+#X obj 338 110 f;
+#X obj 338 60 inlet;
+#X text 344 29 mute;
+#X obj 338 185 f;
+#X msg 425 178 0;
+#X msg 338 85 bang;
+#X obj 338 135 moses 1;
+#X obj 425 153 t b f;
+#X obj 397 117 moses 1;
+#X obj 83 148 dbtorms;
+#X obj 397 92 r master-lvl;
+#X obj 83 42 r master-lvl;
+#X obj 338 210 s master-lvl;
+#X obj 22 181 inlet~;
+#X obj 199 41 inlet;
+#X text 199 18 level;
+#X obj 199 100 s master-lvl;
+#X msg 96 65 set \$1;
+#X obj 96 89 outlet;
+#X msg 214 64 \; pd dsp 1;
+#X obj 83 194 line~;
+#X obj 22 212 *~;
+#X obj 22 241 dac~;
+#X obj 83 171 pack 0 50;
+#X text 20 158 audio;
+#X text 93 110 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 23 433 pd output;
+#X msg 99 405 MUTE;
+#X text 139 406 <-- output amplitude;
+#X obj 336 272 loadbang;
+#X text 35 6 ANALOG SYNTH SEQUENCER;
+#X obj 215 152 metro 100;
+#X obj 214 178 f;
+#X obj 248 181 + 1;
+#X obj 248 205 mod 11;
+#X graph graph1 0 36 11 96 511 197 711 97;
+#X array array1 11 float 0;
+#X pop;
+#X floatatom 215 127 0 0 0;
+#X floatatom 304 152 0 0 0;
+#X obj 214 230 tabread array1;
+#X obj 214 256 mtof;
+#X obj 214 283 osc~ 0;
+#X msg 26 171 1;
+#X obj 24 303 *~;
+#X obj 24 350 cos~;
+#X obj 24 375 hip~ 5;
+#X obj 24 327 +~ 0.1;
+#X msg 336 298 \; array1 0 50 51 52 50 52 56 50 56 58 52 58;
+#X floatatom 43 219 0 0 0;
+#X floatatom 163 221 0 0 0;
+#X floatatom 93 219 0 0 0;
+#X floatatom 128 220 0 0 0;
+#X msg 93 311 0;
+#X msg 93 329 0.1;
+#X msg 93 348 0.25;
+#X msg 215 101 1;
+#X text 244 101 <--START;
+#X text 126 331 <--symmetry;
+#X text 72 185 ADSR controls;
+#X text 43 199 lvl;
+#X text 95 200 A;
+#X text 137 201 D;
+#X text 170 202 S;
+#X floatatom 298 181 0 0 0;
+#X text 332 183 <--increment;
+#X text 339 155 <--msec;
+#X text 20 35 Analog synths had sequencers which could be used in a
+wide variety of ways. You can use an array to hold a sequence of control
+values as shown here.;
+#X obj 23 274 adsr 1 65 13 10 1000;
+#X obj 42 243 / 100;
+#X text 336 340 You can also do microtones \; 50.5 is a quarter tone
+sharper than 50;
+#X text 505 431 updated for Pd version 0.34;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 4 0 21 0;
+#X connect 6 0 7 0;
+#X connect 6 0 16 0;
+#X connect 7 0 8 0;
+#X connect 7 0 13 0;
+#X connect 8 0 9 0;
+#X connect 9 0 7 1;
+#X connect 11 0 6 0;
+#X connect 12 0 6 1;
+#X connect 13 0 14 0;
+#X connect 14 0 15 0;
+#X connect 15 0 17 1;
+#X connect 16 0 41 0;
+#X connect 17 0 20 0;
+#X connect 18 0 19 0;
+#X connect 19 0 1 0;
+#X connect 20 0 18 0;
+#X connect 22 0 42 0;
+#X connect 23 0 41 4;
+#X connect 24 0 41 2;
+#X connect 25 0 41 3;
+#X connect 26 0 20 1;
+#X connect 27 0 20 1;
+#X connect 28 0 20 1;
+#X connect 29 0 11 0;
+#X connect 37 0 8 1;
+#X connect 41 0 17 0;
+#X connect 42 0 41 1;
diff --git a/pd/doc/3.audio.examples/adsr.pd b/pd/doc/3.audio.examples/adsr.pd
index b6b2d7d2..351f354c 100644
--- a/pd/doc/3.audio.examples/adsr.pd
+++ b/pd/doc/3.audio.examples/adsr.pd
@@ -1,64 +1,77 @@
-#N canvas 112 36 785 655 12;
-#X obj 205 119 inlet;
-#X obj 412 147 inlet;
-#X text 201 94 trigger;
-#X obj 205 147 sel 0;
-#X obj 258 157 t b;
-#X obj 134 335 f \$1;
-#X obj 134 360 pack 0 \$2;
-#X obj 476 148 inlet;
-#X obj 403 281 del \$2;
+#N canvas 371 139 752 655 12;
+#X obj 105 111 inlet;
+#X obj 435 151 inlet;
+#X text 101 86 trigger;
+#X obj 105 139 sel 0;
+#X obj 244 155 t b;
+#X obj 166 264 f \$1;
+#X obj 166 289 pack 0 \$2;
+#X obj 492 151 inlet;
+#X obj 438 281 del \$2;
#X obj 458 429 line~;
-#X obj 432 304 f \$4;
-#X obj 466 379 pack 0 \$3;
-#X obj 537 149 inlet;
-#X obj 605 149 inlet;
-#X obj 678 148 inlet;
-#X msg 205 178 stop;
-#X obj 576 301 pack 0 \$5;
-#X text 410 124 level;
-#X obj 466 355 * \$1;
-#X text 31 306 ATTACK;
+#X obj 462 304 f \$4;
+#X obj 501 379 pack 0 \$3;
+#X obj 554 151 inlet;
+#X obj 616 151 inlet;
+#X obj 689 150 inlet;
+#X msg 105 170 stop;
+#X obj 612 306 pack 0 \$5;
+#X text 435 129 level;
+#X obj 501 355 * \$1;
#X obj 458 454 outlet~;
-#X text 6 329 recall level;
-#X text 6 349 and pack with;
-#X text 7 369 attack time;
-#X text 131 134 if zero;
-#X text 132 151 release;
-#X text 112 168 and cancel;
-#X text 143 185 decay;
-#X text 262 139 bang if attack;
-#X text 245 272 on attack \, set a;
-#X text 200 286 delay to go to sustain;
-#X text 242 303 recall sustain value;
-#X text 237 354 multiply by overall level;
-#X text 281 375 pack with decay time;
-#X text 569 327 on release ramp;
-#X text 570 344 back to zero;
-#X text 17 487 When you send this patch a nonzero trigger it schedules
-a line~ to do an attack and decay \, and if zero \, it starts the release
-ramp.;
-#X obj 432 329 * 0.01;
-#X text 16 539 Objects such as "f" and "pack" can be given dollar sign
+#X text 102 378 and pack with;
+#X text 103 398 attack time;
+#X text 31 126 if zero;
+#X text 32 143 release;
+#X text 12 160 and cancel;
+#X text 43 177 decay;
+#X text 284 272 on attack \, set a;
+#X text 278 305 recall sustain value;
+#X text 315 378 pack with decay time;
+#X text 605 332 on release ramp;
+#X text 606 349 back to zero;
+#X obj 462 329 * 0.01;
+#X text 47 567 Objects such as "f" and "pack" can be given dollar sign
arguments to initialize their contents from adsr's creation arguments.
Inlets are supplied to change them on the fly.;
-#X text 505 613 Updated for Pd version 0.34;
-#X text 86 4 ADSR ENVELOPE;
-#X text 245 327 convert from percent;
-#X text 76 24 Arguments: level \, attack time \, decay time \, sustain
+#X text 13 2 ADSR ENVELOPE;
+#X text 488 129 attack;
+#X text 555 128 decay;
+#X text 609 129 sustain;
+#X text 686 129 release;
+#X text 202 71 attack;
+#X obj 204 92 moses;
+#X obj 194 122 t b b;
+#X msg 128 290 0;
+#X text 20 273 optionally;
+#X text 10 291 bash to zero;
+#X text 25 246 ATTACK:;
+#X text 49 477 When you send this patch a positive trigger it schedules
+a line~ to do an attack and decay \, and if zero \, it starts the release
+ramp.;
+#X text 495 629 Updated for Pd version 0.37;
+#X text 255 89 test for negative trigger;
+#X text 253 113 if so \, zero;
+#X text 254 129 the output;
+#X text 278 165 in any case;
+#X text 303 355 multiply by peak level;
+#X text 280 286 delay for sustain;
+#X text 276 328 convert from percent;
+#X text 155 340 ... then;
+#X text 103 359 recall peak level;
+#X text 439 113 peak;
+#X text 281 149 ... do this;
+#X text 47 529 Negative triggers cause the output to jump to zero and
+then attack (instead of attacking from the current location).;
+#X text 208 1 Arguments: level \, attack time \, decay time \, sustain
level \, release time. A \, D \, and R are in msec and S is in percent.
-This patch is used as an abstraction in 25.envelope.pd and others.
-;
-#X text 472 127 attack;
-#X text 538 126 decay;
-#X text 598 127 sustain;
-#X text 675 127 release;
+This patch is used as an abstraction in various examples.;
#X connect 0 0 3 0;
#X connect 1 0 5 1;
#X connect 1 0 18 1;
#X connect 3 0 15 0;
#X connect 3 0 16 0;
-#X connect 3 1 4 0;
+#X connect 3 1 39 0;
#X connect 4 0 5 0;
#X connect 4 0 8 0;
#X connect 5 0 6 0;
@@ -66,8 +79,8 @@ This patch is used as an abstraction in 25.envelope.pd and others.
#X connect 7 0 6 1;
#X connect 7 0 8 1;
#X connect 8 0 10 0;
-#X connect 9 0 20 0;
-#X connect 10 0 37 0;
+#X connect 9 0 19 0;
+#X connect 10 0 31 0;
#X connect 11 0 9 0;
#X connect 12 0 11 1;
#X connect 13 0 10 1;
@@ -75,4 +88,9 @@ This patch is used as an abstraction in 25.envelope.pd and others.
#X connect 15 0 8 0;
#X connect 16 0 9 0;
#X connect 18 0 11 0;
-#X connect 37 0 18 0;
+#X connect 31 0 18 0;
+#X connect 39 0 40 0;
+#X connect 39 1 4 0;
+#X connect 40 0 4 0;
+#X connect 40 1 41 0;
+#X connect 41 0 9 0;
diff --git a/pd/doc/3.audio.examples/output~.pd b/pd/doc/3.audio.examples/output~.pd
index 13ae9252..d1ccdc9f 100644
--- a/pd/doc/3.audio.examples/output~.pd
+++ b/pd/doc/3.audio.examples/output~.pd
@@ -7,13 +7,13 @@
#X obj 630 518 t b f;
#X obj 596 479 moses 1;
#X obj 30 117 dbtorms;
-#X obj 83 208 inlet~;
+#X obj 86 207 inlet~;
#X msg 341 285 \; pd dsp 1;
-#X obj 27 208 line~;
-#X obj 61 242 *~;
-#X obj 61 272 dac~;
+#X obj 30 207 line~;
+#X obj 64 241 *~;
+#X obj 64 271 dac~;
#X obj 30 147 pack 0 50;
-#X text 110 184 audio in;
+#X text 113 183 audio in;
#X text 301 496 test if less than 1 -->;
#X text 267 523 if true convert to bang -->;
#X text 101 116 <-- convert from dB to linear units;
@@ -21,8 +21,8 @@
#X obj 516 449 bng 15 250 50 0 empty empty mute -38 7 0 12 -262144
-1 -1;
#X text 119 146 <-- make a ramp to avoid clicks or zipper noise;
-#X obj 172 209 inlet~;
-#X obj 151 241 *~;
+#X obj 175 208 inlet~;
+#X obj 154 240 *~;
#X text 502 399 MUTE logic:;
#X obj 341 193 r \$0-master-lvl;
#X obj 516 573 s \$0-master-lvl;
@@ -46,8 +46,8 @@ patch.;
#X connect 6 1 2 1;
#X connect 7 0 13 0;
#X connect 8 0 11 1;
-#X connect 10 0 11 1;
#X connect 10 0 22 0;
+#X connect 10 0 11 0;
#X connect 11 0 12 0;
#X connect 13 0 10 0;
#X connect 18 0 9 0;
diff --git a/pd/doc/3.audio.examples/qlist-sampler.txt b/pd/doc/3.audio.examples/qlist-sampler.txt
new file mode 100644
index 00000000..0c412767
--- /dev/null
+++ b/pd/doc/3.audio.examples/qlist-sampler.txt
@@ -0,0 +1,147 @@
+note 60 90 50 2 50 30 30;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+15 note 60;
+100 note 59 90 100;
+comment measure 1;
+100 note 60 90 150 2 0;
+ note 36 90 200 2 50;
+200 note 48 90 250 2 0;
+ note 40 90 200 2 50;
+ note 43 90 200 2 50;
+200 note 48 90 250 2 0;
+ note 31 90 200 2 50;
+200 note 55 90 100;
+ note 41 90 200;
+ note 43 90 200;
+100 note 53 90 100;
+100 note 52 90 100;
+ note 36 90 200;
+100 note 55 90 100;
+100 note 60 90 100;
+ note 40 90 200;
+ note 43 90 200;
+100 note 59 90 100;
+100 note 60 90 100;
+ note 25 90 200;
+100 note 64 90 100;
+100 note 62 90 100;
+ note 39 90 200;
+ note 43 90 200;
+100 note 61 90 100;
+
+comment measure 2;
+100 note 62 90 150 2 0;
+ note 26 90 200;
+200 note 50 90 250 2 50;
+ note 41 90 200;
+ note 42 90 200;
+200 note 50 90 250;
+ note 29 90 200;
+200 note 50 90 100;
+ note 30 90 200;
+ note 44 90 200;
+ note 48 90 200;
+100 note 48 90 100;
+100 note 47 90 100;
+ note 31 90 200;
+ note 43 90 200;
+ note 47 90 200;
+100 note 50 90 100;
+100 note 55 90 100;
+ note 34 90 200;
+ note 42 90 200;
+ note 46 90 200;
+100 note 54 90 100;
+100 note 55 90 200;
+ note 35 90 200;
+ note 42 90 200;
+ note 45 90 200;
+200 note 57 90 100;
+ note 41 90 200;
+ note 47 90 200;
+100 note 59 90 100;
+comment measure 3;
+100 note 60 90 100;
+ note 24 90 200;
+ note 40 90 200;
+ note 48 90 200 2 0;
+
+100 note 59 90 100 2 50;
+100 note 57 90 100;
+100 note 55 90 100;
+
+100 note 57 90 100;
+ note 28 90 200;
+ note 38 90 200;
+ note 46 90 200;
+100 note 55 90 100;
+100 note 53 90 100;
+100 note 52 90 100;
+
+100 note 53 90 100;
+ note 29 90 100;
+ note 36 90 100;
+ note 45 90 100;
+100 note 52 90 100;
+100 note 50 90 100;
+ note 29 90 300;
+ note 36 90 300;
+ note 45 90 300;
+100 note 48 90 100;
+
+100 note 50 90 100;
+100 note 48 90 100;
+100 note 47 90 100;
+ note 29 90 300;
+ note 38 90 300;
+ note 44 90 300 2 0;
+100 note 45 90 100 2 50;
+
+comment measure 4;
+100 note 43 90 100;
+ note 31 90 200;
+ note 38 90 200;
+100 note 48 90 100;
+100 note 47 90 100;
+ note 31 90 300;
+ note 40 90 300;
+ note 43 90 300 2 0;
+100 note 50 90 100 2 50;
+
+100 note 48 90 100;
+100 note 52 90 100;
+100 note 50 90 100;
+ note 31 90 300 2 0;
+ note 41 90 300;
+ note 43 90 300;
+100 note 53 90 100 2 50;
+
+100 note 52 90 200;
+ note 31 90 300 2 50;
+200 note 48 90 200;
+ note 19 90 200 2 50;
+ note 29 90 200 2 50;
+ note 36 90 200 2 50;
+
+200 note 48 90 100 2 50 0 4000;
+ note 12 90 300;
+ note 28 90 300;
+ note 36 90 300;
+
+
+
diff --git a/pd/doc/3.audio.examples/qlist.txt b/pd/doc/3.audio.examples/qlist.txt
index fe105141..719dc89b 100644
--- a/pd/doc/3.audio.examples/qlist.txt
+++ b/pd/doc/3.audio.examples/qlist.txt
@@ -1,4 +1,4 @@
-# This is a qlist for patch number 60, which demonstrates an oscillator
+# This is a qlist for patch number 68, which demonstrates an oscillator
bank.
;
# comments start with a "#" which must be followed by a space. The comment
diff --git a/pd/doc/3.audio.examples/shepvoice.pd b/pd/doc/3.audio.examples/shepvoice.pd
new file mode 100644
index 00000000..f1929976
--- /dev/null
+++ b/pd/doc/3.audio.examples/shepvoice.pd
@@ -0,0 +1,37 @@
+#N canvas 63 20 638 403 12;
+#X obj 300 253 pack 0 50;
+#X obj 243 203 pack 0 50;
+#X obj 151 216 inlet~;
+#X obj 243 232 line~;
+#X obj 300 278 line~;
+#X obj 243 297 *~;
+#X obj 151 316 +~;
+#X obj 151 342 outlet~;
+#X obj 399 121 r pitch+;
+#X obj 326 108 r interval+;
+#X obj 297 144 expr $f1 * $f2 + $f3;
+#X obj 537 90 r dropoff+;
+#X obj 297 75 expr ($i1% 10000) * 0.0002 - 1;
+#X obj 296 20 r phase;
+#X obj 296 47 + \$1;
+#X obj 457 114 expr exp(-$f1*$f1*$f2);
+#X obj 243 179 mtof;
+#X obj 243 258 osc~;
+#X connect 0 0 4 0;
+#X connect 1 0 3 0;
+#X connect 2 0 6 0;
+#X connect 3 0 17 0;
+#X connect 4 0 5 1;
+#X connect 5 0 6 1;
+#X connect 6 0 7 0;
+#X connect 8 0 10 2;
+#X connect 9 0 10 1;
+#X connect 10 0 16 0;
+#X connect 11 0 15 1;
+#X connect 12 0 10 0;
+#X connect 12 0 15 0;
+#X connect 13 0 14 0;
+#X connect 14 0 12 0;
+#X connect 15 0 0 0;
+#X connect 16 0 1 0;
+#X connect 17 0 5 0;
diff --git a/pd/doc/3.audio.examples/sinevoice.pd b/pd/doc/3.audio.examples/sinevoice.pd
new file mode 100644
index 00000000..d8d1848b
--- /dev/null
+++ b/pd/doc/3.audio.examples/sinevoice.pd
@@ -0,0 +1,67 @@
+#N canvas 621 65 547 441 12;
+#X obj 120 299 line~;
+#X obj 120 323 *~;
+#X obj 120 346 *~;
+#X obj 125 232 sqrt;
+#X obj 96 39 inlet;
+#X obj 125 253 sqrt;
+#X obj 51 360 inlet~;
+#X obj 51 413 outlet~;
+#X obj 120 370 *~;
+#X obj 206 351 osc~;
+#X obj 51 388 +~;
+#X obj 261 210 pack;
+#X text 142 40 inlet: volume \, pitch \, duration;
+#X obj 96 88 unpack 0 0 0;
+#X text 12 2 arguments: \$1 = relative amplitude \, \$2 = pitch multiplier
+\, \$3 = detune \, \$4 = time multiplier;
+#X obj 157 117 dbtorms;
+#X obj 157 139 * \$1;
+#X obj 125 211 f;
+#X obj 206 216 f;
+#X obj 228 117 mtof;
+#X obj 228 142 * \$2;
+#X obj 228 164 + \$3;
+#X obj 273 118 * \$4;
+#X msg 8 148 0 5;
+#X msg 99 118 bang;
+#X obj 42 148 del 5;
+#X obj 106 65 outlet;
+#X msg 99 161 0;
+#X obj 125 272 pack 0 5;
+#X obj 99 139 del 10;
+#X connect 0 0 1 0;
+#X connect 0 0 1 1;
+#X connect 1 0 2 0;
+#X connect 1 0 2 1;
+#X connect 2 0 8 0;
+#X connect 3 0 5 0;
+#X connect 4 0 13 0;
+#X connect 4 0 26 0;
+#X connect 5 0 28 0;
+#X connect 6 0 10 0;
+#X connect 8 0 10 1;
+#X connect 9 0 8 1;
+#X connect 10 0 7 0;
+#X connect 11 0 0 0;
+#X connect 13 0 15 0;
+#X connect 13 0 23 0;
+#X connect 13 0 24 0;
+#X connect 13 1 19 0;
+#X connect 13 2 22 0;
+#X connect 15 0 16 0;
+#X connect 16 0 17 1;
+#X connect 17 0 3 0;
+#X connect 18 0 9 0;
+#X connect 19 0 20 0;
+#X connect 20 0 21 0;
+#X connect 21 0 18 1;
+#X connect 22 0 11 1;
+#X connect 23 0 0 0;
+#X connect 24 0 25 0;
+#X connect 24 0 29 0;
+#X connect 25 0 17 0;
+#X connect 25 0 18 0;
+#X connect 27 0 11 0;
+#X connect 28 0 0 0;
+#X connect 29 0 27 0;
diff --git a/pd/doc/5.reference/acoustics-help.pd b/pd/doc/5.reference/acoustics-help.pd
new file mode 100644
index 00000000..2a46f589
--- /dev/null
+++ b/pd/doc/5.reference/acoustics-help.pd
@@ -0,0 +1,40 @@
+#N canvas 163 25 582 408 12;
+#X obj 15 269 ftom;
+#X obj 8 10 mtof;
+#X obj 15 217 mtof;
+#X floatatom 15 189 0 0 0;
+#X floatatom 15 244 0 0 0;
+#X obj 64 10 ftom;
+#X floatatom 15 293 0 0 0;
+#X obj 120 11 dbtorms;
+#X obj 196 11 rmstodb;
+#X obj 275 11 dbtopow;
+#X obj 352 11 powtodb;
+#X text 21 53 The mtof object transposes a midi value into a frequency
+in Hertz \, so that "69" goes to "440". You can specify microtonal
+pitches as in "69.5" (a quarter tone higher than 69). Ftom does the
+reverse.;
+#X floatatom 147 185 0 0 0;
+#X floatatom 147 240 0 0 0;
+#X floatatom 147 289 0 0 0;
+#X obj 147 213 dbtorms;
+#X obj 147 265 rmstodb;
+#X floatatom 261 186 0 0 0;
+#X floatatom 261 241 0 0 0;
+#X floatatom 261 290 0 0 0;
+#X obj 261 214 dbtopow;
+#X obj 261 266 powtodb;
+#X text 27 336 Overflows and underflows are clipped.;
+#X text 300 376 updated for pd version 0.33;
+#X connect 0 0 6 0;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 4 0 0 0;
+#X connect 12 0 15 0;
+#X connect 13 0 16 0;
+#X connect 15 0 13 0;
+#X connect 16 0 14 0;
+#X connect 17 0 20 0;
+#X connect 18 0 21 0;
+#X connect 20 0 18 0;
+#X connect 21 0 19 0;
diff --git a/pd/doc/5.reference/acoustics~-help.pd b/pd/doc/5.reference/acoustics~-help.pd
new file mode 100644
index 00000000..f7515339
--- /dev/null
+++ b/pd/doc/5.reference/acoustics~-help.pd
@@ -0,0 +1,81 @@
+#N canvas 35 42 813 458 12;
+#X obj 158 118 mtof~;
+#X obj 158 174 snapshot~;
+#X obj 698 132 metro 100;
+#X floatatom 158 205 0 0 0;
+#X obj 49 174 snapshot~;
+#X floatatom 49 55 0 0 0;
+#X floatatom 49 205 0 0 0;
+#X obj 49 118 ftom~;
+#X obj 264 174 snapshot~;
+#X floatatom 264 205 0 0 0;
+#X obj 264 118 dbtorms~;
+#X obj 697 58 loadbang;
+#X msg 709 88 \; pd dsp 1;
+#X obj 49 86 sig~;
+#X floatatom 158 55 0 0 0;
+#X obj 158 86 sig~;
+#X floatatom 264 54 0 0 0;
+#X obj 264 86 sig~;
+#X obj 492 172 snapshot~;
+#X floatatom 492 203 0 0 0;
+#X obj 383 172 snapshot~;
+#X floatatom 383 53 0 0 0;
+#X floatatom 383 203 0 0 0;
+#X obj 607 172 snapshot~;
+#X floatatom 607 203 0 0 0;
+#X obj 383 84 sig~;
+#X floatatom 492 53 0 0 0;
+#X obj 492 84 sig~;
+#X floatatom 607 53 0 0 0;
+#X obj 607 84 sig~;
+#X obj 383 115 rmstodb~;
+#X obj 492 115 dbtopow~;
+#X obj 607 115 powtodb~;
+#X obj 17 10 mtof~;
+#X text 70 11 (etc) - conversions for audio signals;
+#X text 60 400 see also:;
+#X obj 145 400 mtof;
+#X text 192 400 (etc.);
+#X text 547 416 updated for Pd version 0.33;
+#X text 43 241 These objects convert MIDI pitch to frequency and back
+\, and dB to and from RMS and power. THey take audio signals as input
+and output (and work sample by sample.) Since they call library math
+functions \, they may be much more expensive than other workaday tilde
+objects such as *~ and osc~ \, depending on your hardware and math
+library.;
+#X text 41 343 Boundary conditions are handled "reasonably". 100 db
+is assigned an RMS of 1 \, and dbtorms~ and dbtopow~ output true zero
+for 0 dB and less.;
+#X connect 0 0 1 0;
+#X connect 1 0 3 0;
+#X connect 2 0 1 0;
+#X connect 2 0 8 0;
+#X connect 2 0 4 0;
+#X connect 2 0 20 0;
+#X connect 2 0 18 0;
+#X connect 2 0 23 0;
+#X connect 4 0 6 0;
+#X connect 5 0 13 0;
+#X connect 7 0 4 0;
+#X connect 8 0 9 0;
+#X connect 10 0 8 0;
+#X connect 11 0 2 0;
+#X connect 11 0 12 0;
+#X connect 13 0 7 0;
+#X connect 14 0 15 0;
+#X connect 15 0 0 0;
+#X connect 16 0 17 0;
+#X connect 17 0 10 0;
+#X connect 18 0 19 0;
+#X connect 20 0 22 0;
+#X connect 21 0 25 0;
+#X connect 23 0 24 0;
+#X connect 25 0 30 0;
+#X connect 26 0 27 0;
+#X connect 27 0 31 0;
+#X connect 28 0 29 0;
+#X connect 29 0 32 0;
+#X connect 30 0 20 0;
+#X connect 31 0 18 0;
+#X connect 32 0 23 0;
diff --git a/pd/doc/5.reference/adc~_dac~-help.pd b/pd/doc/5.reference/adc~_dac~-help.pd
new file mode 100644
index 00000000..e97429b6
--- /dev/null
+++ b/pd/doc/5.reference/adc~_dac~-help.pd
@@ -0,0 +1,11 @@
+#N canvas 195 155 575 293 12;
+#X obj 8 11 adc~;
+#X obj 72 11 dac~;
+#X obj 63 121 adc~ 5;
+#X text 143 121 (input from channel 5 only);
+#X obj 61 145 dac~ 1 2 5 23;
+#X text 184 145 (output to channels 1 \, 2 \, 5 \, and 23);
+#X text 16 173 The actual number of channels Pd inputs and outputs are set on Pd's command line. You can open patches that want to use more channels \, and channel numbers out of rance will be dropped (dac~) or appear as zero (adc~).;
+#X text 308 254 updated for Pd version 0.33;
+#X text 122 9 - audio I/O;
+#X text 8 46 Adc~ and dac~ rovide real-time audio input and output for Pd \, respectively \, whether analog or digital. By default they are stereo but you can specify channel numbers as in:;
diff --git a/pd/doc/5.reference/append-help.pd b/pd/doc/5.reference/append-help.pd
new file mode 100644
index 00000000..7cacefe4
--- /dev/null
+++ b/pd/doc/5.reference/append-help.pd
@@ -0,0 +1,44 @@
+#N canvas 330 8 595 450 12;
+#X text 15 344 see also:;
+#N canvas 164 72 425 146 help-append-template1 0;
+#X obj 60 21 template float x float y float z;
+#X obj 18 81 filledpolygon z z 0 0 0 20 0 20 30 0 30;
+#X restore 357 373 pd help-append-template1;
+#X obj 141 393 template;
+#X obj 16 368 get;
+#X obj 48 368 set;
+#X obj 148 368 getsize;
+#X obj 215 368 setsize;
+#X obj 218 393 element;
+#X obj 15 394 sublist;
+#X obj 83 393 scalar;
+#N canvas 0 0 276 163 help-append-data 1;
+#X restore 357 351 pd help-append-data;
+#X obj 212 255 pointer;
+#X obj 21 10 append;
+#X text 75 9 -- add item to a list;
+#X msg 212 231 traverse pd-help-append-data \, bang;
+#X obj 34 295 append help-append-template1 x y z;
+#X floatatom 34 246 5 0 0;
+#X obj 34 266 t f f;
+#X msg 356 311 \; pd-help-append-data clear;
+#X text 27 28 "append" maintains a pointer to a scalar \, or else an
+empty pointer to the head of a list. You may set the pointer using
+the leftmost inlet. The creation arguments specify the template of
+a new scalar to append \, and the names of the fields (there should
+be at least one) you will wish to initialize. To append an object \,
+send a number to the leftmost inlet. "Append"'s pointer is updated
+to point to the new scalar \, and the new pointer is also output.;
+#X text 28 149 To insert to the beginning of a list \, you can append
+to the "head" of the list. You may append objects of different templates
+using different "append" objects.;
+#X obj 81 368 pointer;
+#X text 341 408 updated for Pd version 0.35;
+#X text 34 226 click this first->;
+#X text 230 210 go to (and output) "head" of the list;
+#X connect 11 0 15 3;
+#X connect 14 0 11 0;
+#X connect 16 0 17 0;
+#X connect 17 0 15 0;
+#X connect 17 1 15 1;
+#X connect 17 1 15 2;
diff --git a/pd/doc/5.reference/bag-help.pd b/pd/doc/5.reference/bag-help.pd
new file mode 100644
index 00000000..cdd5bfff
--- /dev/null
+++ b/pd/doc/5.reference/bag-help.pd
@@ -0,0 +1,27 @@
+#N canvas 118 56 577 366 12;
+#X text 18 337 see also:;
+#X obj 148 337 makenote;
+#X msg 76 151 60 64;
+#X msg 127 151 60 0;
+#X msg 171 151 62 64;
+#X msg 218 151 62 0;
+#X obj 76 278 print;
+#X text 121 279 Output is in the printout window.;
+#X msg 218 197 clear;
+#X obj 66 15 bag;
+#X text 101 14 - COLLECTION OF NUMBERS;
+#X text 12 42 The bag object takes (value \, flag) pairs. If the flag is true (nonzero) \, the value is added to the collection \; if false \, it's removed. The collection may have many copies of the same value. You can output the collection (and empty it) with a "flush" message \, or just empty it with "clear." You can use this to mimic a sustain pedal \, for example.;
+#X msg 217 174 flush;
+#X obj 104 337 poly;
+#X obj 76 248 bag;
+#X text 267 151 <-- add or delete elements;
+#X text 271 174 <-- output them;
+#X text 273 198 <-- start over;
+#X text 328 337 updated for Pd version 0.33;
+#X connect 2 0 14 0;
+#X connect 3 0 14 0;
+#X connect 4 0 14 0;
+#X connect 5 0 14 0;
+#X connect 8 0 14 0;
+#X connect 12 0 14 0;
+#X connect 14 0 6 0;
diff --git a/pd/doc/5.reference/bang-help.pd b/pd/doc/5.reference/bang-help.pd
new file mode 100644
index 00000000..1f522268
--- /dev/null
+++ b/pd/doc/5.reference/bang-help.pd
@@ -0,0 +1,13 @@
+#N canvas 118 56 581 250 12;
+#X obj 49 182 print;
+#X text 107 183 Output is in the printout window.;
+#X obj 66 15 bang;
+#X text 112 14 - SEND "BANG" MSSESSAGE;
+#X msg 61 105 walk the cat;
+#X msg 49 79 45;
+#X obj 49 152 bang;
+#X text 336 233 updated for Pd version 0.27;
+#X text 23 42 Outputs a "bang" message whatever it receives.;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 0 0;
diff --git a/pd/doc/5.reference/bang~-help.pd b/pd/doc/5.reference/bang~-help.pd
new file mode 100644
index 00000000..debade2f
--- /dev/null
+++ b/pd/doc/5.reference/bang~-help.pd
@@ -0,0 +1,18 @@
+#N canvas 0 0 529 299 12;
+#X obj 112 128 bang~;
+#X obj 112 159 print;
+#X msg 210 223 \; pd dsp 1;
+#X msg 297 216 \; pd dsp 0;
+#X msg 210 144 bang;
+#X obj 19 20 bang~;
+#X obj 306 193 loadbang;
+#X obj 297 169 delay 100;
+#X text 211 122 click to test;
+#X text 71 21 - output bang after each DSP cycle;
+#X text 5 59 Bang~ outputs a bang after each DSP cycle (at the same logical time as the DSP cycle.) This is primarily useful for sampling the outputs of analysis algorithms.;
+#X text 251 266 updated for Pd version 0.33;
+#X connect 0 0 1 0;
+#X connect 4 0 2 0;
+#X connect 4 0 7 0;
+#X connect 6 0 3 0;
+#X connect 7 0 3 0;
diff --git a/pd/doc/5.reference/biquad~-help.pd b/pd/doc/5.reference/biquad~-help.pd
new file mode 100644
index 00000000..b7757244
--- /dev/null
+++ b/pd/doc/5.reference/biquad~-help.pd
@@ -0,0 +1,36 @@
+#N canvas 327 119 689 397 12;
+#X obj 15 12 biquad~;
+#X msg 510 20 \; pd dsp 1;
+#X msg 504 66 \; pd dsp 0;
+#X obj 84 248 env~;
+#X floatatom 84 275 0 0 0 0 - - -;
+#X floatatom 15 110 0 0 0 0 - - -;
+#X obj 15 246 env~;
+#X floatatom 15 274 0 0 0 0 - - -;
+#X text 13 297 Compare the value of the straight signal on the left
+with the value of the filtered signal on the right.;
+#X obj 84 215 biquad~ 1.41407 -0.9998 1 -1.41421 1;
+#X msg 101 121 1.41407 -0.9998 1 -1.41421 1;
+#X text 76 31 calculates the following difference equation:;
+#X text 77 44 y(n) = ff1 * w(n) + ff2 * w(n-1) + ff3 * w(n-2);
+#X text 77 60 w(n) = x(n) + fb1 * w(n-1) + fb2 * w(n-2);
+#X text 18 76 Syntax: biquad~ fb1 fb2 ff1 ff2 ff3;
+#X text 259 239 this biquad~ is a notch filter for fn = Pi/4;
+#X text 265 258 (= SR/8 = 5512.5 Hz @44.1k);
+#X text 91 14 2-pole-2-zero-filter;
+#X text 113 99 list sets filter parameters;
+#X msg 119 161 set 0 0;
+#X msg 120 186 clear;
+#X obj 15 170 osc~ 5512.5;
+#X text 422 337 updated for Pd version-0.30;
+#X text 189 163 set internal state;
+#X text 187 185 ... or just clear it;
+#X connect 3 0 4 0;
+#X connect 5 0 21 0;
+#X connect 6 0 7 0;
+#X connect 9 0 3 0;
+#X connect 10 0 9 0;
+#X connect 19 0 9 0;
+#X connect 20 0 9 0;
+#X connect 21 0 6 0;
+#X connect 21 0 9 0;
diff --git a/pd/doc/5.reference/bng-help.pd b/pd/doc/5.reference/bng-help.pd
new file mode 100644
index 00000000..d48d560a
--- /dev/null
+++ b/pd/doc/5.reference/bng-help.pd
@@ -0,0 +1,265 @@
+#N canvas 11 201 538 357 10;
+#X obj 1 1 cnv 8 100 60 empty empty bng 20 20 1 18 -262144 -1109 0
+;
+#X text 10 288 (c) musil@iem.kug.ac.at;
+#X text 52 301 IEM KUG;
+#X text 118 61 click properties to;
+#X text 106 72 modify geometry \, colors \, etc.;
+#X obj 64 257 print;
+#N canvas 598 330 290 225 once 0;
+#X msg 38 73 1;
+#X obj 38 47 t b b;
+#X obj 68 124 sel 0;
+#X obj 68 103 f 0;
+#X obj 38 24 inlet;
+#X obj 68 154 outlet;
+#X connect 0 0 3 1;
+#X connect 1 0 0 0;
+#X connect 1 1 3 0;
+#X connect 2 0 5 0;
+#X connect 3 0 2 0;
+#X connect 4 0 1 0;
+#X restore 64 234 pd once;
+#X obj 36 258 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X obj 3 130 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X obj 36 173 bng 50 950 50 1 foo5_snd foo5_rcv big-bang 63 2 192 12
+-262131 -260818 -143491;
+#X msg 36 53 33;
+#X msg 50 75 -3.14;
+#X msg 73 117 11 22 33.33;
+#X msg 63 95 open xxx;
+#X msg 96 142 funny;
+#X text 101 11 gui-bang:;
+#X obj 202 135 s foo5_rcv;
+#X obj 202 155 r foo5_snd;
+#X obj 202 115 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144
+-1 -1;
+#X obj 202 175 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144
+-1 -1;
+#X msg 4 53 0;
+#X text 125 205 UP- \, DOWN- \, LEFT- or RIGHT-key;
+#X text 124 216 for moving selected gui-objects;
+#N canvas 425 170 699 530 edit 0;
+#X obj 39 197 f;
+#X msg 17 176 bang;
+#X floatatom 55 175 3 63 88;
+#X floatatom 90 197 3 0 37;
+#X obj 39 220 pack 0 0;
+#X text 117 197 y-label;
+#X text 83 175 x-label;
+#X floatatom 259 143 3 8 75;
+#X text 286 143 size;
+#X obj 279 236 f;
+#X msg 257 215 bang;
+#X floatatom 295 214 3 -10 10;
+#X floatatom 330 236 3 -10 10;
+#X obj 279 259 pack 0 0;
+#X obj 304 348 f;
+#X msg 282 327 bang;
+#X floatatom 320 326 3 20 90;
+#X floatatom 355 348 3 150 200;
+#X obj 304 371 pack 0 0;
+#X text 323 214 x-delta;
+#X text 357 236 y-delta;
+#X text 348 326 x-position;
+#X text 382 348 y-position;
+#X obj 59 312 f;
+#X msg 37 291 bang;
+#X floatatom 75 290 3 0 2;
+#X floatatom 110 312 3 4 36;
+#X obj 59 335 pack 0 0;
+#X text 103 290 font;
+#X text 139 312 height;
+#X msg 36 399 \; foo5_rcv label blabla;
+#X msg 59 360 \; foo5_rcv label_font \$1 \$2;
+#X msg 39 245 \; foo5_rcv label_pos \$1 \$2;
+#X msg 47 135 \; foo5_rcv color \$1 \$2 \$3;
+#X msg 259 172 \; foo5_rcv size \$1;
+#X msg 279 284 \; foo5_rcv delta \$1 \$2;
+#X msg 304 396 \; foo5_rcv pos \$1 \$2;
+#X msg 483 133 \; foo5_rcv receive foo5a_rcv;
+#X msg 482 171 \; foo5a_rcv receive foo5_rcv;
+#X msg 483 50 \; foo5_rcv send foo5a_snd;
+#X msg 483 88 \; foo5_rcv send foo5_snd;
+#X text 526 349 no init;
+#X msg 505 368 \; foo5_rcv init 0;
+#X msg 512 435 \; foo5_rcv init 1;
+#X obj 493 260 f;
+#X msg 471 239 bang;
+#X floatatom 509 238 4 10 100;
+#X floatatom 544 261 5 100 3000;
+#X obj 493 283 pack 0 0;
+#X msg 493 308 \; foo5_rcv flashtime \$1 \$2;
+#X text 548 237 interrupt-time;
+#X text 585 262 hold-time;
+#X msg 36 435 \; foo5_rcv label big-bang;
+#X text 502 417 init bang on loadbang;
+#X text 519 221 flash-time:;
+#X obj 47 114 pack 0 0 0;
+#X obj 47 86 f;
+#X msg 24 38 bang;
+#X floatatom 63 36 3 0 29;
+#X floatatom 79 56 3 0 29;
+#X floatatom 112 72 3 0 29;
+#X text 91 36 background;
+#X text 106 56 front-color;
+#X text 140 73 label-color;
+#X msg 285 35 back;
+#X msg 285 55 front;
+#X msg 285 75 label;
+#X msg 247 35 bang;
+#N canvas 15 207 606 448 RGB_____________ 0;
+#X obj 97 56 inlet;
+#X obj 262 53 inlet;
+#X obj 339 55 inlet;
+#X obj 405 56 inlet;
+#X obj 97 270 bang;
+#X msg 77 295 0;
+#X msg 104 295 1;
+#X obj 146 268 bang;
+#X msg 132 295 0;
+#X msg 160 295 1;
+#X obj 196 269 bang;
+#X msg 187 295 0;
+#X msg 214 295 1;
+#X obj 265 313 spigot;
+#X obj 312 313 spigot;
+#X obj 359 313 spigot;
+#X obj 249 385 outlet;
+#X text 93 33 select;
+#X text 267 28 red;
+#X text 337 30 green;
+#X text 409 30 blue;
+#X obj 405 102 t b f;
+#X obj 339 160 +;
+#X obj 339 185 t b f;
+#X obj 339 216 +;
+#X obj 296 385 outlet;
+#X obj 343 385 outlet;
+#X obj 28 180 loadbang;
+#X obj 97 135 route back front label bang;
+#X obj 343 362 f;
+#X obj 296 361 f;
+#X obj 249 361 f;
+#X obj 262 79 * -65536;
+#X obj 339 80 * -256;
+#X obj 405 80 * -1;
+#X obj 339 247 - 1;
+#X obj 235 168 t b b b b;
+#X connect 0 0 28 0;
+#X connect 1 0 32 0;
+#X connect 2 0 33 0;
+#X connect 3 0 34 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 14 1;
+#X connect 5 0 15 1;
+#X connect 6 0 13 1;
+#X connect 7 0 8 0;
+#X connect 7 0 9 0;
+#X connect 8 0 13 1;
+#X connect 8 0 15 1;
+#X connect 9 0 14 1;
+#X connect 10 0 11 0;
+#X connect 10 0 12 0;
+#X connect 11 0 13 1;
+#X connect 11 0 14 1;
+#X connect 12 0 15 1;
+#X connect 13 0 31 1;
+#X connect 14 0 30 1;
+#X connect 15 0 29 1;
+#X connect 21 0 22 0;
+#X connect 21 1 22 1;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 23 1 24 1;
+#X connect 24 0 35 0;
+#X connect 27 0 6 0;
+#X connect 28 0 4 0;
+#X connect 28 1 7 0;
+#X connect 28 2 10 0;
+#X connect 28 3 36 0;
+#X connect 29 0 26 0;
+#X connect 30 0 25 0;
+#X connect 31 0 16 0;
+#X connect 32 0 24 0;
+#X connect 33 0 22 0;
+#X connect 34 0 21 0;
+#X connect 35 0 15 0;
+#X connect 35 0 14 0;
+#X connect 35 0 13 0;
+#X connect 36 0 31 0;
+#X connect 36 1 30 0;
+#X connect 36 2 29 0;
+#X connect 36 3 35 0;
+#X restore 285 96 pd RGB_____________;
+#X floatatom 327 65 3 0 255;
+#X floatatom 370 65 3 0 255;
+#X floatatom 413 66 3 0 255;
+#X text 34 10 preset-colors;
+#X text 296 7 RGB-colors;
+#X text 327 47 red;
+#X text 363 46 green;
+#X text 411 46 blue;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 4 1;
+#X connect 4 0 32 0;
+#X connect 7 0 34 0;
+#X connect 9 0 13 0;
+#X connect 10 0 9 0;
+#X connect 11 0 9 1;
+#X connect 12 0 13 1;
+#X connect 13 0 35 0;
+#X connect 14 0 18 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 1;
+#X connect 17 0 18 1;
+#X connect 18 0 36 0;
+#X connect 23 0 27 0;
+#X connect 24 0 23 0;
+#X connect 25 0 23 1;
+#X connect 26 0 27 1;
+#X connect 27 0 31 0;
+#X connect 44 0 48 0;
+#X connect 45 0 44 0;
+#X connect 46 0 44 1;
+#X connect 47 0 48 1;
+#X connect 48 0 49 0;
+#X connect 55 0 33 0;
+#X connect 56 0 55 0;
+#X connect 57 0 56 0;
+#X connect 58 0 56 1;
+#X connect 59 0 55 1;
+#X connect 60 0 55 2;
+#X connect 64 0 68 0;
+#X connect 65 0 68 0;
+#X connect 66 0 68 0;
+#X connect 67 0 68 0;
+#X connect 68 0 55 0;
+#X connect 68 1 55 1;
+#X connect 68 2 55 2;
+#X connect 69 0 68 1;
+#X connect 70 0 68 2;
+#X connect 71 0 68 3;
+#X restore 297 144 pd edit;
+#X obj 248 34 bng 15 250 50 0 aaa aaa empty 20 8 192 8 -262144 -1 -1
+;
+#X text 185 312 updated for Pd version 0.35;
+#X text 27 313 graz \, austria 2002;
+#X obj 180 11 x_all_guis aaa bbb ccc ddd eee fff ggg hhh iii;
+#X connect 6 0 5 0;
+#X connect 8 0 9 0;
+#X connect 9 0 7 0;
+#X connect 9 0 6 0;
+#X connect 10 0 9 0;
+#X connect 11 0 9 0;
+#X connect 12 0 9 0;
+#X connect 13 0 9 0;
+#X connect 14 0 9 0;
+#X connect 17 0 19 0;
+#X connect 18 0 16 0;
+#X connect 20 0 9 0;
diff --git a/pd/doc/5.reference/bp~-help.pd b/pd/doc/5.reference/bp~-help.pd
new file mode 100644
index 00000000..8bcd86b4
--- /dev/null
+++ b/pd/doc/5.reference/bp~-help.pd
@@ -0,0 +1,40 @@
+#N canvas 533 67 651 393 12;
+#X obj 124 11 bp~;
+#X text 159 11 - BANDPASS FILTER;
+#X obj 70 263 env~;
+#X floatatom 70 283 0 0 0;
+#X floatatom 104 193 0 0 0;
+#X obj 12 261 env~;
+#X floatatom 12 282 0 0 0;
+#X text 119 264 env~ gives the amplitude of the signal envelop in dB.
+;
+#X floatatom 12 123 0 0 0;
+#X msg 544 67 \; pd dsp 0;
+#X obj 12 146 osc~ 100;
+#X text 57 121 <-- scroll to change input frequency;
+#X msg 72 170 clear;
+#X text 122 169 <-- reinitialize internal state;
+#X text 398 361 updated for Pd version-0.30;
+#X msg 544 28 \; pd dsp 1;
+#X text 13 73 The left inlet is the incoming audio signal \, the middle
+control input sets center frequency and the rigth input sets "Q".;
+#X text 136 194 <-- center frequency;
+#X obj 72 241 bp~ 100 10;
+#X text 169 242 Arguments initialize center frequency and Q.;
+#X text 12 301 Compare the amplitude of the original signal on the
+left with the amplitude of the filtered signal on the right.;
+#X floatatom 153 215 0 0 0;
+#X text 185 216 <-- Q;
+#X text 16 35 bp~ passes a sinusoid at the center frequency at unit
+gain (approximately). Other frequencies are attenuated.;
+#X text 21 357 see also:;
+#X obj 110 356 vcf~;
+#X connect 2 0 3 0;
+#X connect 4 0 18 1;
+#X connect 5 0 6 0;
+#X connect 8 0 10 0;
+#X connect 10 0 5 0;
+#X connect 10 0 18 0;
+#X connect 12 0 18 0;
+#X connect 18 0 2 0;
+#X connect 21 0 18 2;
diff --git a/pd/doc/5.reference/canvas-help.pd b/pd/doc/5.reference/canvas-help.pd
new file mode 100644
index 00000000..a6e33be5
--- /dev/null
+++ b/pd/doc/5.reference/canvas-help.pd
@@ -0,0 +1,19 @@
+#N canvas 210 82 579 437 12;
+#X obj 66 15 table;
+#X text 123 16 - Array of numbers;
+#X obj 34 199 table help-tab1 25;
+#X text 10 43 "Table" builds a subpatch with a graphical array inside.
+The creation arguments specify the name and an optional size in points.
+;
+#X msg 70 265 \; help-tab1 read table.txt;
+#X msg 70 309 \; help-tab1 write /tmp/table.txt;
+#X text 70 243 You can also send messages to the array by name:;
+#X text 216 200 <- optional creation args: name \, size;
+#X text 17 355 Unfortunately there's no way to set vertical range \,
+etc.;
+#X text 9 101 Note that the data (and other properties) of the array
+aren't saved with the patch. You can resize \, save to and/or read
+from an external file as you would with "array" objects. See "arrays"
+in the 2.control examples under the "pure documentation" help menu
+item.;
+#X text 325 391 updated for Pd version 0.35;
diff --git a/pd/doc/5.reference/change-help.pd b/pd/doc/5.reference/change-help.pd
new file mode 100644
index 00000000..74e16f6a
--- /dev/null
+++ b/pd/doc/5.reference/change-help.pd
@@ -0,0 +1,23 @@
+#N canvas 376 130 540 355 12;
+#X msg 67 124 bang;
+#X floatatom 67 266 0 0 0;
+#X floatatom 79 154 0 0 0;
+#X floatatom 104 182 0 0 0;
+#X text 284 309 updated for Pd version 0.27;
+#X text 173 239 creation argument initializes first value;
+#X obj 66 15 change;
+#X text 114 16 - ELIMINATE REDUNDANCY IN A NUMBER STEAM;
+#X text 12 42 The change object outputs its input only when it changes.
+You can "set" the current value \, or bang to force output.;
+#X obj 67 240 change 6.5;
+#X msg 105 211 set \$1;
+#X text 136 183 set the value;
+#X text 112 123 output current value;
+#X text 110 154 if different from current value \, output and set;
+#X obj 67 293 print;
+#X connect 0 0 9 0;
+#X connect 1 0 14 0;
+#X connect 2 0 9 0;
+#X connect 3 0 10 0;
+#X connect 9 0 1 0;
+#X connect 10 0 9 0;
diff --git a/pd/doc/5.reference/clip~-help.pd b/pd/doc/5.reference/clip~-help.pd
new file mode 100644
index 00000000..61c222fa
--- /dev/null
+++ b/pd/doc/5.reference/clip~-help.pd
@@ -0,0 +1,30 @@
+#N canvas 182 132 778 399 12;
+#X obj 75 164 clip~ -0.5 0.5;
+#X obj 75 104 osc~ 1000;
+#X graph graph1 0 1 100 -1 78 280 278 380;
+#X array array99 100 float 0;
+#X pop;
+#X obj 91 213 metro 500;
+#X obj 91 188 r metro;
+#X text 239 235 <-- graph the output;
+#X obj 75 237 tabwrite~ array99;
+#X msg 519 69 \; metro 0;
+#X msg 515 12 \; pd dsp 1 \; metro 1;
+#X text 604 26 <-- Click to start;
+#X text 589 73 <-- Click to stop;
+#X obj 42 19 clip~;
+#X text 88 18 - restrict a signal to lie between two limits;
+#X text 243 136 inlets to reset clip range;
+#X floatatom 135 136 4 0 0;
+#X floatatom 196 137 4 0 0;
+#X text 210 164 creation arguments initialize clip range;
+#X text 4 55 The clip~ object passes its signal input to its output
+\, clipping it to lie between two limits.;
+#X text 470 371 updated for Pd version 0.33;
+#X connect 0 0 6 0;
+#X connect 1 0 0 0;
+#X connect 3 0 6 0;
+#X connect 4 0 3 0;
+#X connect 4 0 3 0;
+#X connect 14 0 0 1;
+#X connect 15 0 0 2;
diff --git a/pd/doc/5.reference/cos~-help.pd b/pd/doc/5.reference/cos~-help.pd
new file mode 100644
index 00000000..ba6f918e
--- /dev/null
+++ b/pd/doc/5.reference/cos~-help.pd
@@ -0,0 +1,32 @@
+#N canvas 134 143 768 332 12;
+#X obj 112 12 cos~;
+#X obj 23 200 cos~;
+#X obj 23 249 snapshot~;
+#X obj 23 152 sig~;
+#X floatatom 23 275 0 0 0;
+#X obj 23 125 * 0.01;
+#X floatatom 23 98 0 0 0;
+#X obj 90 215 metro 500;
+#X obj 90 189 r metro;
+#X msg 540 93 \; metro 0;
+#X msg 521 39 \; pd dsp 1 \; metro 1;
+#X text 159 13 - COSINE WAVESHAPER;
+#X text 86 125 Divide by 100;
+#X text 71 153 convert to audio;
+#X text 78 100 <-- Scroll to set input value;
+#X text 64 276 <-- output of the cos~ object;
+#X text 291 195 see also:;
+#X obj 379 197 osc~;
+#X obj 423 197 tabread4~;
+#X text 494 293 updated for Pd version 0.33;
+#X text 608 54 <-Click to start;
+#X text 609 99 <-Click to stop;
+#X text 9 45 The cos~ object outputs the cosine of its signal input.;
+#X connect 1 0 2 0;
+#X connect 2 0 4 0;
+#X connect 2 0 4 0;
+#X connect 3 0 1 0;
+#X connect 5 0 3 0;
+#X connect 6 0 5 0;
+#X connect 7 0 2 0;
+#X connect 8 0 7 0;
diff --git a/pd/doc/5.reference/cputime-help.pd b/pd/doc/5.reference/cputime-help.pd
new file mode 100644
index 00000000..c0a0f43a
--- /dev/null
+++ b/pd/doc/5.reference/cputime-help.pd
@@ -0,0 +1,15 @@
+#N canvas 302 232 550 286 12;
+#X msg 74 144 bang;
+#X msg 30 115 bang;
+#X floatatom 30 206 0 0 0;
+#X text 71 113 Click here to reset;
+#X text 27 232 Output is in milliseconds;
+#X obj 30 175 cputime;
+#X text 124 144 Click here to get elapsed CPU time;
+#X text 6 51 The cputime object measures elapsed CPU time \, as measured by your operating system. This appears to work on NT \, IRIX \, and Linux \, but not on W98.;
+#X obj 66 15 cputime;
+#X text 123 16 - measure CPU usage;
+#X text 297 261 updated for Pd version 0.33;
+#X connect 0 0 5 1;
+#X connect 1 0 5 0;
+#X connect 5 0 2 0;
diff --git a/pd/doc/5.reference/delay-help.pd b/pd/doc/5.reference/delay-help.pd
new file mode 100644
index 00000000..5f90cd4b
--- /dev/null
+++ b/pd/doc/5.reference/delay-help.pd
@@ -0,0 +1,30 @@
+#N canvas 3 0 513 348 12;
+#X obj 66 15 delay;
+#X obj 13 229 50;
+#X msg 13 98 bang;
+#X floatatom 13 255;
+#X floatatom 116 182;
+#X obj 51 230 0;
+#X text 111 16 - CALLBACK AFTER TIME DELAY;
+#X text 130 205 <-- creation argument initializes delay time;
+#X text 6 41 The delay object sends a bang to its outlet after a delay in milliseconds specified by its right inlet or its creation argument.;
+#X obj 51 204 delay 1000;
+#X text 58 86 Click here to test the delay object by initializing the number box below to 50 and then clearing it after the specified delay.;
+#X text 94 132 Click here to CANCEL delay's action;
+#X msg 51 133 stop;
+#X text 43 324 see also:;
+#X obj 155 323 timer;
+#X obj 111 323 metro;
+#X msg 62 155 2000;
+#X text 102 154 Number in right inlet sets time and schedules the action.;
+#X text 316 320 updated for Pd version 0.3;
+#X text 145 183 <-- scroll to change delay time in milliseconds;
+#X text 14 280 Note: sending a bang to a delay which is already set will reschedule its output \, cancelling the old one.;
+#X connect 1 0 3 0;
+#X connect 2 0 1 0;
+#X connect 2 0 9 0;
+#X connect 4 0 9 1;
+#X connect 5 0 3 0;
+#X connect 9 0 5 0;
+#X connect 12 0 9 0;
+#X connect 16 0 9 0;
diff --git a/pd/doc/5.reference/delread~-help.pd b/pd/doc/5.reference/delread~-help.pd
new file mode 100644
index 00000000..682f6e98
--- /dev/null
+++ b/pd/doc/5.reference/delread~-help.pd
@@ -0,0 +1,33 @@
+#N canvas 24 20 796 472 12;
+#X text 351 276 1st argument: name of delay line;
+#X floatatom 116 253 0 0 0;
+#X text 151 255 float input (delay time in ms);
+#X text 127 310 signal output (delayed signal);
+#X text 21 52 You can use more than one delread~ objects for the same delay line.;
+#X text 20 81 If the specified delay time is longer than the size of the delay line or less than zero it is clipped to the length of the delay line.;
+#X obj 383 226 delwrite~ del_example 1000;
+#X floatatom 383 177 0 0 0;
+#X obj 116 375 snapshot~;
+#X floatatom 116 399 0 0 0;
+#X obj 24 246 loadbang;
+#X obj 24 313 metro 200;
+#X msg 32 273 \; pd dsp 1;
+#X obj 116 286 delread~ del_example 1000;
+#X obj 24 16 delread~;
+#X text 424 176 input to delay line;
+#X obj 383 201 sig~;
+#X text 433 443 updated for Pd version 0.33;
+#X text 89 16 - read a signal from a delay line;
+#X text 21 133 Note: if the delaywrite~ runs after the delread~ the minimum delay is actually one DSP period \, not zero.;
+#X text 351 292 2nd argument: (initial) delay time in ms;
+#X obj 126 444 delwrite~;
+#X obj 217 444 vd~;
+#X text 36 443 see also:;
+#X connect 1 0 13 0;
+#X connect 7 0 16 0;
+#X connect 8 0 9 0;
+#X connect 10 0 11 0;
+#X connect 10 0 12 0;
+#X connect 11 0 8 0;
+#X connect 13 0 8 0;
+#X connect 16 0 6 0;
diff --git a/pd/doc/5.reference/delwrite~-help.pd b/pd/doc/5.reference/delwrite~-help.pd
new file mode 100644
index 00000000..50ca3f63
--- /dev/null
+++ b/pd/doc/5.reference/delwrite~-help.pd
@@ -0,0 +1,15 @@
+#N canvas 12 24 663 281 12;
+#X obj 24 16 delwrite~;
+#X obj 24 158 delwrite~ del_line_xxx 500;
+#X text 88 123 signal input;
+#X text 116 16 writes a signal in a delay line;
+#X text 271 156 1st argument: name of delay line;
+#X text 411 243 updated for Pd version 0.33;
+#X obj 24 124 sig~ 0;
+#X text 19 50 Delwrite~ allocates memory for a delay line and writes an audio signal into it. Delread~ objects by hte same name read from the delay line.;
+#X text 294 186 (= max. delay time);
+#X text 271 172 2nd argument: length of delay line in msec;
+#X text 24 203 see also:;
+#X obj 112 205 delread~;
+#X obj 193 205 vd~;
+#X connect 6 0 1 0;
diff --git a/pd/doc/5.reference/drawnumber-help.pd b/pd/doc/5.reference/drawnumber-help.pd
new file mode 100644
index 00000000..a62a8103
--- /dev/null
+++ b/pd/doc/5.reference/drawnumber-help.pd
@@ -0,0 +1,35 @@
+#N struct help-drawnumber-template float x float y float cat float
+dog;
+#N canvas 369 6 538 189 12;
+#X text 15 103 see also:;
+#X obj 18 7 drawnumber;
+#X obj 204 132 plot;
+#X obj 100 131 drawpolygon;
+#X obj 22 130 template;
+#X text 114 7 -- draw numeric fields from data structures;
+#N canvas 14 10 297 129 help-drawnumber-data 1;
+#X scalar help-drawnumber-template 50 100 23 43 \;;
+#X scalar help-drawnumber-template 150 50 3.14 -1.618 \;;
+#X restore 273 71 pd help-drawnumber-data;
+#N canvas 57 283 580 439 help-drawnumber-template 1;
+#X text 24 316 This object defines the fields for this template. Their
+values are initialized in the "works" subwindow. You can see them by
+right-clicking on the object in the "data" window and selecting "properties."
+;
+#X text 44 104 - RGB color (0=black \, 999=white \, 900=red \, 90=green
+\, 9=blue \, 555=grey \, etc.);
+#X obj 11 294 template float x float y float cat float dog;
+#X text 22 166 Any of these can be numbers or field names \, like "dog"
+and "cat" here.;
+#X text 22 202 When not in "edit" mode \, you can click and drag vertically
+on the numbers to change their values. (In edit mode you can move \,
+cut \, copy \, and paste the objects.);
+#X text 24 251 Keyboard entry isn't supported yet.;
+#X obj 24 15 drawnumber cat 0 0 0 cat=;
+#X obj 259 16 drawnumber dog 0 -15 900 dog=;
+#X text 44 136 - an optional label ("cat=" for instance);
+#X text 26 44 drawnumber takes arguments specifying:;
+#X text 44 84 - an (x \, y) pair giving relative coordinates \;;
+#X text 44 64 - the number to draw;
+#X restore 273 45 pd help-drawnumber-template;
+#X text 275 159 updated for Pd version 0.35;
diff --git a/pd/doc/5.reference/drawpolygon-help.pd b/pd/doc/5.reference/drawpolygon-help.pd
new file mode 100644
index 00000000..fc422af4
--- /dev/null
+++ b/pd/doc/5.reference/drawpolygon-help.pd
@@ -0,0 +1,41 @@
+#N struct help-drawpolygon-template float x float y float cat float
+dog float weasel;
+#N canvas 411 8 565 187 12;
+#X text 13 130 see also:;
+#X obj 111 149 drawnumber;
+#X obj 207 149 plot;
+#X obj 21 10 drawpolygon;
+#X obj 21 33 drawcurve;
+#X obj 126 11 filledpolygon;
+#X obj 127 33 filledcurve;
+#X text 225 10 -- draw shapes for data structures;
+#N canvas 30 290 587 435 help-drawpolygon-template 1;
+#X obj 14 335 template float x float y float cat float dog float weasel
+;
+#X obj 19 24 drawpolygon 0 2 0 0 0 weasel;
+#X text 26 44 drawpolygon and drawcurve take arguments specifying:
+;
+#X text 29 137 Any of these can be numbers or field names \, like "weasel"
+here. The example above draws a vertical black line of height "weasel".
+;
+#X obj 19 194 filledpolygon 900 dog 3 10 0 20 cat 30 0;
+#X text 31 216 filledpolyconn and filledcurve take the same arguments
+\, except that a new first argument is added to specify interior color.
+Here the interior color is red (900) \, the outline color is controlled
+by the "dog" field \, and the three points describe a triangle of altitude
+"cat". The fields x and y automatically govern the placement of the
+object as a whole.;
+#X text 45 62 - RGB color (0=black \, 999=white \, 900=red \, 90=green
+\, 9=blue \, 555=grey \, etc.);
+#X text 46 95 - line width;
+#X text 46 116 - two or more (x \, y) pairs giving coordinates.;
+#X text 24 357 This object defines the fields for this template. You
+can see teh fields' values by right-clicking on the object in the "data"
+window and selecting "properties.";
+#X restore 274 93 pd help-drawpolygon-template;
+#X obj 34 149 template;
+#N canvas 10 18 384 178 help-drawpolygon-data 1;
+#X scalar help-drawpolygon-template 50 40 30 9 80 \;;
+#X scalar help-drawpolygon-template 150 40 -20 90 50 \;;
+#X restore 274 119 pd help-drawpolygon-data;
+#X text 312 168 updated for Pd version 0.35;
diff --git a/pd/doc/5.reference/element-help.pd b/pd/doc/5.reference/element-help.pd
new file mode 100644
index 00000000..a3faeecf
--- /dev/null
+++ b/pd/doc/5.reference/element-help.pd
@@ -0,0 +1,51 @@
+#N struct help-element-template float x float y array array1 help-element-array1-template
+;
+#N struct help-element-array1-template float y;
+#N canvas 330 34 668 442 12;
+#X text 24 373 see also:;
+#X obj 21 393 template;
+#N canvas 393 10 491 261 help-element-template 0;
+#X obj 27 76 plot array1 500 1 10 15 20;
+#X obj 27 174 filledpolygon 509 509 0 -10 -10 10 -10 10 10 -10 10;
+#X obj 24 16 template float x float y array array1 help-element-array1-template
+;
+#X restore 414 349 pd help-element-template;
+#N canvas 0 0 288 159 help-element-data 1;
+#X scalar help-element-template 35 24 \; 0 \; 10 \; 0 \; 10 \; 20 \;
+10 \; 20 \; 70 \; 10 \; \;;
+#X restore 450 328 pd help-element-data;
+#N canvas 196 292 365 134 help-element-array1-template 0;
+#X obj 30 71 filledpolygon 0 0 0 -5 0 0 5 5 0 0 -5;
+#X obj 32 27 template float y;
+#X restore 354 371 pd help-element-array1-template;
+#X obj 22 11 element;
+#X text 91 10 -- get pointer to an element of an array;
+#X obj 98 393 pointer;
+#X obj 166 393 getsize;
+#X obj 234 393 setsize;
+#X text 24 44 "element" takes a pointer at right and a number at left.
+It looks up a field from the pointer \, which should be an array \,
+and outputs the element of the array specified by the number. There
+are no pointers to arrays themselves \, just to individual elements.
+The template and field mane are specified as creation arguments.;
+#X obj 150 228 pointer;
+#X msg 150 204 traverse pd-help-element-data \, next;
+#X floatatom 38 230 5 0 0;
+#X obj 38 256 element help-element-template array1;
+#X obj 38 303 get help-element-array1-template y;
+#X floatatom 38 330 5 0 0;
+#X text 370 256 arguments: template \, field name;
+#X text 247 230 pointer inlet;
+#X text 36 209 index;
+#X text 43 277 outlet is pointer to single element;
+#X text 89 328 here we just get the value of y.;
+#X text 24 143 Indices range from 0 to the number of elements minus
+one \; indices out of range are quietly replaced by the nearest endpoint.
+;
+#X text 152 184 click here first;
+#X text 407 416 updated for Pd version 0.35;
+#X connect 11 0 14 1;
+#X connect 12 0 11 0;
+#X connect 13 0 14 0;
+#X connect 14 0 15 0;
+#X connect 15 0 16 0;
diff --git a/pd/doc/5.reference/env~-help.pd b/pd/doc/5.reference/env~-help.pd
new file mode 100644
index 00000000..64a245ae
--- /dev/null
+++ b/pd/doc/5.reference/env~-help.pd
@@ -0,0 +1,28 @@
+#N canvas 40 55 711 401 12;
+#X floatatom 103 303 0 0 0;
+#X obj 74 14 env~;
+#X text 120 16 - envelope follower;
+#X obj 103 275 env~ 16384;
+#X obj 103 214 osc~ 400;
+#X obj 103 241 *~;
+#X floatatom 217 220 3 -99 300;
+#X obj 217 244 dbtorms;
+#X text 9 46 The env~ object takes a signal and outputs its RMS amplitude
+in dB (with 1 normalized to 100 dB.) Output is bounded below by zero.
+;
+#X text 8 105 The analysis is Hanning windowed.;
+#X text 9 131 The optional creation argument is the analysis window
+size in samples \, and should be a power of two. The analysis windows
+overlap by two \, so that the period of output is half the window size.
+;
+#X text 206 274 <- creation argument sets window size;
+#X text 265 221 <- set peak-to-peak amplitude here in dB.;
+#X text 185 305 <- the output is RMS amplitude which is about 3 dB
+below peak-to-peak amplitude.;
+#X text 459 375 updated for Pd version 0.35;
+#X connect 3 0 0 0;
+#X connect 3 0 0 0;
+#X connect 4 0 5 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 7 0 5 1;
diff --git a/pd/doc/5.reference/fft~-help.pd b/pd/doc/5.reference/fft~-help.pd
new file mode 100644
index 00000000..149a6634
--- /dev/null
+++ b/pd/doc/5.reference/fft~-help.pd
@@ -0,0 +1,64 @@
+#N canvas 22 7 886 436 12;
+#X text 85 158 frequency;
+#X floatatom 16 173 0 0 0;
+#X obj 16 120 * 44100;
+#X floatatom 16 94 0 0 0;
+#X text 88 92 frequency;
+#X text 91 111 in bins;
+#X text 85 175 in Hz.;
+#X obj 16 229 osc~;
+#X obj 36 16 fft~;
+#X obj 86 17 ifft~;
+#X text 146 15 - forward and inverse complex FFT;
+#X obj 36 42 rfft~;
+#X obj 86 43 rifft~;
+#X text 146 41 - forward and inverse real FFT;
+#X obj 16 254 rfft~;
+#X obj 16 148 / 64;
+#X obj 574 21 loadbang;
+#X msg 574 47 \; pd dsp 1;
+#X text 636 403 updated for Pd version 0.33;
+#X obj 16 322 rifft~;
+#X obj 102 310 print~ real;
+#X obj 115 285 print~ imaginary;
+#X obj 16 352 /~ 64;
+#X obj 16 407 print~ resynthesized;
+#X msg 30 380 bang;
+#X msg 101 248 bang;
+#X msg 100 199 0.25;
+#X msg 152 199 0;
+#X text 195 200 <-- bash phase;
+#X text 152 249 <-- print analysis;
+#X text 79 380 <-- print resynthesis;
+#X text 76 352 <-- renormalize;
+#X text 347 294 There is no normalization \, so that an FFT followed
+by an IFFT has a gain of N.;
+#X text 346 343 See the FFT examples to see how to use these in practice.
+;
+#X text 346 112 The FFT objects do Fourier analyses and resyntheses
+of incoming real or complex signals. Complex signals are handled as
+pairs of signals (real and imaginary part.) The analysis size is one
+block (you can use the block~ or switch~ obejcts to control block size).
+;
+#X text 347 205 The real FFT outputs N/2+1 real parts and N/2-1 imaginary
+parts. The other outputs are zero. At DC and at the Nyquist there is
+no imaginary part \, but the second through Nth output is as a real
+and imaginary pair \, which can be thought of as the cosine and sin
+component strengths.;
+#X connect 1 0 7 0;
+#X connect 2 0 15 0;
+#X connect 3 0 2 0;
+#X connect 7 0 14 0;
+#X connect 14 0 20 0;
+#X connect 14 0 19 0;
+#X connect 14 1 21 0;
+#X connect 14 1 19 1;
+#X connect 15 0 1 0;
+#X connect 16 0 17 0;
+#X connect 19 0 22 0;
+#X connect 22 0 23 0;
+#X connect 24 0 23 0;
+#X connect 25 0 20 0;
+#X connect 25 0 21 0;
+#X connect 26 0 7 1;
+#X connect 27 0 7 1;
diff --git a/pd/doc/5.reference/float-help.pd b/pd/doc/5.reference/float-help.pd
new file mode 100644
index 00000000..efc5235a
--- /dev/null
+++ b/pd/doc/5.reference/float-help.pd
@@ -0,0 +1,18 @@
+#N canvas 23 20 429 272 12;
+#X msg 30 107 bang;
+#X obj 30 183 float 6.5;
+#X floatatom 30 209;
+#X floatatom 42 129;
+#X floatatom 88 153;
+#X obj 55 12 float;
+#X text 97 11 - STORE A (FLOATING POINT) NUMBER;
+#X text 12 36 The float object stores a number \, initialized by its creation argument \, which may be reset using its inlet and output by sending it the "bang" message. Sending a number sets a new value and outputs it.;
+#X text 77 103 outputs the value;
+#X text 74 130 sets and outputs the value;
+#X text 123 155 sets the value;
+#X text 108 184 creation argument initializes the value;
+#X text 223 242 updated for Pd version 0.3;
+#X connect 0 0 1 0;
+#X connect 1 0 2 0;
+#X connect 3 0 1 0;
+#X connect 4 0 1 1;
diff --git a/pd/doc/5.reference/framp~-help.pd b/pd/doc/5.reference/framp~-help.pd
new file mode 100644
index 00000000..cbf3f047
--- /dev/null
+++ b/pd/doc/5.reference/framp~-help.pd
@@ -0,0 +1,40 @@
+#N canvas 22 7 857 377 12;
+#X text 85 158 frequency;
+#X floatatom 16 173 0 0 0;
+#X obj 16 120 * 44100;
+#X floatatom 16 94 0 0 0;
+#X text 88 92 frequency;
+#X text 91 111 in bins;
+#X text 85 175 in Hz.;
+#X obj 17 238 rfft~;
+#X obj 16 148 / 64;
+#X obj 653 14 loadbang;
+#X msg 653 40 \; pd dsp 1;
+#X text 599 339 updated for Pd version 0.33;
+#X msg 103 260 bang;
+#X text 154 261 <-- print analysis;
+#X obj 36 16 framp~;
+#X text 119 15 - estimate frequency and amplitude of FFT components
+;
+#X obj 16 270 framp~;
+#X obj 103 322 print~ frequency;
+#X obj 118 297 print~ amplitude;
+#X obj 16 204 osc~;
+#X text 324 98 Framp~ takes as input a rectangular-windowed FFT and
+outputs \, for each FFT channel \, the estimated amplitude and frequency
+of any component feedinf that channel. A sinusoidal component should
+appear in four components (or three in the special case of a sinusoid
+exactly tuned to a bin.) Frequency output is in bins \, i.e. \, units
+of SR/N.;
+#X connect 1 0 19 0;
+#X connect 2 0 8 0;
+#X connect 3 0 2 0;
+#X connect 7 0 16 0;
+#X connect 7 1 16 1;
+#X connect 8 0 1 0;
+#X connect 9 0 10 0;
+#X connect 12 0 17 0;
+#X connect 12 0 18 0;
+#X connect 16 0 17 0;
+#X connect 16 1 18 0;
+#X connect 19 0 7 0;
diff --git a/pd/doc/5.reference/gatom-help.pd b/pd/doc/5.reference/gatom-help.pd
new file mode 100644
index 00000000..2dd7ce61
--- /dev/null
+++ b/pd/doc/5.reference/gatom-help.pd
@@ -0,0 +1,32 @@
+#N canvas 138 65 675 508 12;
+#X floatatom 107 9 0 0 0;
+#X text 155 10 atoms (number boxes);
+#X floatatom 38 85 0 0 0;
+#X floatatom 38 125 0 0 0;
+#X msg 51 260 set 45;
+#X floatatom 51 288 0 0 0;
+#X floatatom 51 317 0 0 0;
+#X text 84 40 Number boxes allow you to display numbers or to enter
+numbers using the mouse and keyboard. When a number arrives at the
+number box's inlet \, it is displayed and sent to the outlet. You can
+click on a number box and drag upward or downward to change the value
+continuously.;
+#X text 88 130 You can shift-click and drag to change the number by
+hundredths instead of units. Alt clicking toggles the value between
+0 and the last nonzero value.;
+#X text 83 184 You can also type in values by clicking and typing a
+number followed by "enter.";
+#X text 30 220 the "set" message sets the number box's value but does
+not send it to the outlet.;
+#X text 423 482 updated for Pd version 0.34;
+#X text 39 339 You can set the width of the box by right-clicking and
+choosing "properties." By default the width is 5 characters. If you
+select a width of 0 \, the number box will grow as needed to hold the
+number--BUT BEWARE \, THIS IS EXPENSIVE IN CPU TIME. In a production
+patch \, you'll want to set a specific width.;
+#X floatatom 547 439 1 0 0;
+#X text 41 438 A width of one gives a clickable toggle switch ala Max:
+;
+#X connect 2 0 3 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
diff --git a/pd/doc/5.reference/get-help.pd b/pd/doc/5.reference/get-help.pd
new file mode 100644
index 00000000..6784a6ce
--- /dev/null
+++ b/pd/doc/5.reference/get-help.pd
@@ -0,0 +1,46 @@
+#N struct help-get-template1 float x float y;
+#N canvas 293 5 629 429 12;
+#X text 13 325 see also:;
+#X obj 143 370 template;
+#X obj 84 345 set;
+#X obj 116 345 append;
+#X obj 175 345 getsize;
+#X obj 243 345 setsize;
+#X obj 311 345 element;
+#X obj 16 370 sublist;
+#X obj 84 370 scalar;
+#X msg 60 130 next;
+#N canvas 164 72 425 146 help-get-template1 0;
+#X obj 41 87 filledpolygon 9 0 1 0 0 20 0 20 30 0 30;
+#X obj 60 21 template float x float y;
+#X restore 376 234 pd help-get-template1;
+#N canvas 0 0 276 156 help-get-data 1;
+#X scalar help-get-template1 46 23 \;;
+#X scalar help-get-template1 106 73 \;;
+#X restore 376 212 pd help-get-data;
+#X obj 21 10 get;
+#X text 86 10 -- get values from a scalar;
+#X msg 45 102 traverse pd-help-get-data \, next;
+#X floatatom 45 214 5 0 0;
+#X floatatom 222 210 5 0 0;
+#X obj 45 157 pointer;
+#X text 337 101 output first scalar in list;
+#X text 103 129 output next item;
+#X text 21 277 If you have data whose template varies (from a heterogeneous
+list \, for example) you can use "pointer" to select according to template
+before sending to "get".;
+#X obj 45 185 get help-get-template1 x y;
+#X text 31 37 "Get" \, when sent a pointer to a scalar \, retrieves
+fields from it by name. The fields can be float or symbol. In the future
+this will also allow access to sublists of scalars.;
+#X text 293 167 First argument selects template.;
+#X text 294 182 Remaining args are names of fields.;
+#X text 41 233 x output;
+#X text 220 232 y output;
+#X obj 16 345 pointer;
+#X text 373 399 updated for Pd version 0.35;
+#X connect 9 0 17 0;
+#X connect 14 0 17 0;
+#X connect 17 0 21 0;
+#X connect 21 0 15 0;
+#X connect 21 1 16 0;
diff --git a/pd/doc/5.reference/getsize-help.pd b/pd/doc/5.reference/getsize-help.pd
new file mode 100644
index 00000000..f2b17e2f
--- /dev/null
+++ b/pd/doc/5.reference/getsize-help.pd
@@ -0,0 +1,41 @@
+#N struct help-getsize-template float x float y array array1 help-getsize-array1-template
+;
+#N struct help-getsize-array1-template float y;
+#N canvas 340 20 655 398 12;
+#X text 28 319 see also:;
+#X obj 25 339 template;
+#N canvas 393 10 491 261 help-getsize-template 0;
+#X obj 27 76 plot array1 500 1 10 15 20;
+#X obj 27 174 filledpolygon 509 509 0 -10 -10 10 -10 10 10 -10 10;
+#X obj 24 16 template float x float y array array1 help-getsize-array1-template
+;
+#X restore 338 311 pd help-getsize-template;
+#N canvas 0 0 301 193 help-getsize-data 1;
+#X scalar help-getsize-template 43 37 \; 0 \; 10 \; 0 \; 10 \; 20 \;
+10 \; 20 \; 70 \; 10 \; \;;
+#X restore 337 290 pd help-getsize-data;
+#N canvas 196 292 365 134 help-getsize-array1-template 0;
+#X obj 30 71 filledpolygon 0 0 0 -5 0 0 5 5 0 0 -5;
+#X obj 32 27 template float y;
+#X restore 337 334 pd help-getsize-array1-template;
+#X obj 102 339 pointer;
+#X obj 236 338 setsize;
+#X obj 25 166 pointer;
+#X msg 25 142 traverse pd-help-getsize-data \, next;
+#X floatatom 25 242 5 0 0;
+#X text 360 214 arguments: template \, field name;
+#X text 76 240 here we just get the value of y.;
+#X obj 25 213 getsize help-getsize-template array1;
+#X text 34 192 inlet for pointer;
+#X obj 35 21 getsize;
+#X text 98 22 -- get number of elements of an array;
+#X text 24 44 When sent a pointer \, "element" looks up a field \,
+which should be an array \, and outputs the number of elements of the
+array. The template and field name are specified as creation arguments.
+;
+#X text 23 110 The smallest possible size is one.;
+#X obj 169 339 element;
+#X text 397 374 updated for Pd version 0.35;
+#X connect 7 0 12 0;
+#X connect 8 0 7 0;
+#X connect 12 0 9 0;
diff --git a/pd/doc/5.reference/graph-help.pd b/pd/doc/5.reference/graph-help.pd
new file mode 100644
index 00000000..1badaee3
--- /dev/null
+++ b/pd/doc/5.reference/graph-help.pd
@@ -0,0 +1,13 @@
+#N canvas 28 3 693 300 12;
+#X graph graph1 0 -1 99 1 188 290 338 190;
+#X array array99 100 float;
+#X pop;
+#X text 174 19 GRAPHS;
+#X text 20 42 A graph in Pd is a rectangular subregion of the window in
+which you can store numeric arrays.;
+#X text 19 140 You can change the array values by redrawing it in the graph.
+See also "11.arrays" and passim in the "control examples".;
+#X text 406 266 last updated for release 0.33;
+#X text 18 85 If you create a new array Pd will usually make a new graph
+to put it in (you can change this using the "array" dialog that pops up.)
+;
diff --git a/pd/doc/5.reference/hdial-help.pd b/pd/doc/5.reference/hdial-help.pd
new file mode 100644
index 00000000..006c0f8b
--- /dev/null
+++ b/pd/doc/5.reference/hdial-help.pd
@@ -0,0 +1,282 @@
+#N canvas 106 314 612 281 10;
+#X obj 1 1 cnv 8 100 60 empty empty hdial=hdl 20 20 1 18 -262144 -1109
+0;
+#X text 16 213 (c) musil@iem.kug.ac.at;
+#X text 58 226 IEM KUG;
+#X text 289 52 click properties to;
+#X text 277 63 modify geometry \, colors \, etc.;
+#X obj 356 172 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144
+-1 -1;
+#X obj 21 54 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X obj 355 124 s foo8_rcv;
+#X obj 356 150 r foo8_snd;
+#X obj 44 100 hdl 25 1 1 10 foo8_snd foo8_rcv hdial_0_9 156 -8 192
+10 -99865 -262144 -260818 2;
+#X msg 44 142 \$1;
+#X floatatom 44 164 4 0 0;
+#X obj 44 186 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X obj 89 161 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 89 140 route 0 1 2 3 4 5 6 7 8 9;
+#X msg 176 64 set \$1;
+#X floatatom 176 43 4 0 9;
+#X floatatom 44 54 4 0 9;
+#X msg 91 41 7 0 -5.44;
+#X msg 95 63 3 3 4.55;
+#X obj 106 161 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 123 161 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 1
+1;
+#X obj 140 161 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 157 161 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 174 161 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 191 161 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 208 161 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 225 161 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 242 161 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 82 178 print;
+#X floatatom 380 198 4 0 0;
+#X msg 380 172 \$1;
+#X msg 355 103 set \$1;
+#X floatatom 355 82 4 0 9;
+#X text 128 178 UP- \, DOWN- \, LEFT- or RIGHT-key;
+#X text 127 189 for moving selected gui-objects;
+#N canvas 226 227 699 530 edit 0;
+#X obj 42 198 f;
+#X msg 20 177 bang;
+#X floatatom 58 176 3 63 156;
+#X floatatom 93 198 3 -20 37;
+#X obj 42 221 pack 0 0;
+#X text 120 198 y-label;
+#X text 86 176 x-label;
+#X floatatom 270 187 3 8 50;
+#X text 297 187 size;
+#X obj 286 293 f;
+#X msg 264 272 bang;
+#X floatatom 302 271 3 -10 10;
+#X floatatom 337 293 3 -10 10;
+#X obj 286 316 pack 0 0;
+#X obj 300 412 f;
+#X msg 278 391 bang;
+#X floatatom 316 390 3 20 60;
+#X floatatom 351 412 3 100 200;
+#X obj 300 435 pack 0 0;
+#X text 330 271 x-delta;
+#X text 364 293 y-delta;
+#X text 344 390 x-position;
+#X text 378 412 y-position;
+#X obj 62 313 f;
+#X msg 40 292 bang;
+#X floatatom 78 291 3 0 2;
+#X floatatom 113 313 3 4 36;
+#X obj 62 336 pack 0 0;
+#X text 106 291 font;
+#X text 142 313 height;
+#X text 504 293 no init;
+#X text 475 348 init value on loadbang;
+#X floatatom 482 228 5 2 20;
+#X msg 47 125 \; foo8_rcv color \$1 \$2 \$3;
+#X msg 42 246 \; foo8_rcv label_pos \$1 \$2;
+#X msg 62 361 \; foo8_rcv label_font \$1 \$2;
+#X msg 34 423 \; foo8_rcv label blabla;
+#X msg 300 460 \; foo8_rcv pos \$1 \$2;
+#X msg 286 341 \; foo8_rcv delta \$1 \$2;
+#X msg 270 216 \; foo8_rcv size \$1;
+#X msg 482 171 \; foo8a_rcv receive foo8_rcv;
+#X msg 483 133 \; foo8_rcv receive foo8a_rcv;
+#X msg 483 88 \; foo8_rcv send foo8_snd;
+#X msg 483 50 \; foo8_rcv send foo8a_snd;
+#X msg 483 312 \; foo8_rcv init 0;
+#X msg 485 366 \; foo8_rcv init 1;
+#X msg 490 436 \; foo8_rcv single_change;
+#X msg 490 470 \; foo8_rcv double_change;
+#X text 491 417 changing-behavior;
+#X msg 482 254 \; foo8_rcv number \$1;
+#X text 526 228 number of buttons;
+#X obj 47 104 pack 0 0 0;
+#X obj 47 76 f;
+#X msg 24 28 bang;
+#X floatatom 63 26 3 0 29;
+#X floatatom 79 46 3 0 29;
+#X floatatom 112 62 3 0 29;
+#X text 91 26 background;
+#X text 106 46 front-color;
+#X text 140 63 label-color;
+#X msg 285 25 back;
+#X msg 285 45 front;
+#X msg 285 65 label;
+#X msg 247 25 bang;
+#N canvas 15 207 606 448 RGB_____________ 0;
+#X obj 97 56 inlet;
+#X obj 262 53 inlet;
+#X obj 339 55 inlet;
+#X obj 405 56 inlet;
+#X obj 97 270 bang;
+#X msg 77 295 0;
+#X msg 104 295 1;
+#X obj 146 268 bang;
+#X msg 132 295 0;
+#X msg 160 295 1;
+#X obj 196 269 bang;
+#X msg 187 295 0;
+#X msg 214 295 1;
+#X obj 265 313 spigot;
+#X obj 312 313 spigot;
+#X obj 359 313 spigot;
+#X obj 249 385 outlet;
+#X text 93 33 select;
+#X text 267 28 red;
+#X text 337 30 green;
+#X text 409 30 blue;
+#X obj 405 102 t b f;
+#X obj 339 160 +;
+#X obj 339 185 t b f;
+#X obj 339 216 +;
+#X obj 296 385 outlet;
+#X obj 343 385 outlet;
+#X obj 28 180 loadbang;
+#X obj 97 135 route back front label bang;
+#X obj 343 362 f;
+#X obj 296 361 f;
+#X obj 249 361 f;
+#X obj 262 79 * -65536;
+#X obj 339 80 * -256;
+#X obj 405 80 * -1;
+#X obj 339 247 - 1;
+#X obj 235 168 t b b b b;
+#X connect 0 0 28 0;
+#X connect 1 0 32 0;
+#X connect 2 0 33 0;
+#X connect 3 0 34 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 14 1;
+#X connect 5 0 15 1;
+#X connect 6 0 13 1;
+#X connect 7 0 8 0;
+#X connect 7 0 9 0;
+#X connect 8 0 13 1;
+#X connect 8 0 15 1;
+#X connect 9 0 14 1;
+#X connect 10 0 11 0;
+#X connect 10 0 12 0;
+#X connect 11 0 13 1;
+#X connect 11 0 14 1;
+#X connect 12 0 15 1;
+#X connect 13 0 31 1;
+#X connect 14 0 30 1;
+#X connect 15 0 29 1;
+#X connect 21 0 22 0;
+#X connect 21 1 22 1;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 23 1 24 1;
+#X connect 24 0 35 0;
+#X connect 27 0 6 0;
+#X connect 28 0 4 0;
+#X connect 28 1 7 0;
+#X connect 28 2 10 0;
+#X connect 28 3 36 0;
+#X connect 29 0 26 0;
+#X connect 30 0 25 0;
+#X connect 31 0 16 0;
+#X connect 32 0 24 0;
+#X connect 33 0 22 0;
+#X connect 34 0 21 0;
+#X connect 35 0 15 0;
+#X connect 35 0 14 0;
+#X connect 35 0 13 0;
+#X connect 36 0 31 0;
+#X connect 36 1 30 0;
+#X connect 36 2 29 0;
+#X connect 36 3 35 0;
+#X restore 285 86 pd RGB_____________;
+#X floatatom 327 55 3 0 255;
+#X floatatom 370 55 3 0 255;
+#X floatatom 413 56 3 0 255;
+#X text 34 0 preset-colors;
+#X text 296 -3 RGB-colors;
+#X text 327 37 red;
+#X text 363 36 green;
+#X text 411 36 blue;
+#X msg 34 459 \; foo8_rcv label hdial_0_9;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 4 1;
+#X connect 4 0 34 0;
+#X connect 7 0 39 0;
+#X connect 9 0 13 0;
+#X connect 10 0 9 0;
+#X connect 11 0 9 1;
+#X connect 12 0 13 1;
+#X connect 13 0 38 0;
+#X connect 14 0 18 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 1;
+#X connect 17 0 18 1;
+#X connect 18 0 37 0;
+#X connect 23 0 27 0;
+#X connect 24 0 23 0;
+#X connect 25 0 23 1;
+#X connect 26 0 27 1;
+#X connect 27 0 35 0;
+#X connect 32 0 49 0;
+#X connect 51 0 33 0;
+#X connect 52 0 51 0;
+#X connect 53 0 52 0;
+#X connect 54 0 52 1;
+#X connect 55 0 51 1;
+#X connect 56 0 51 2;
+#X connect 60 0 64 0;
+#X connect 61 0 64 0;
+#X connect 62 0 64 0;
+#X connect 63 0 64 0;
+#X connect 64 0 51 0;
+#X connect 64 1 51 1;
+#X connect 64 2 51 2;
+#X connect 65 0 64 1;
+#X connect 66 0 64 2;
+#X connect 67 0 64 3;
+#X restore 469 108 pd edit;
+#X obj 346 35 hdl 15 1 0 8 eee eee empty 20 8 192 8 -262144 -1 -1 0
+;
+#X obj 260 11 x_all_guis aaa bbb ccc ddd eee fff ggg hhh iii;
+#X text 183 11 gui-hdial:;
+#X text 33 238 graz \, austria 2002;
+#X text 251 232 updated for Pd version 0.35;
+#X connect 6 0 9 0;
+#X connect 8 0 5 0;
+#X connect 8 0 31 0;
+#X connect 9 0 10 0;
+#X connect 9 0 14 0;
+#X connect 9 0 29 0;
+#X connect 10 0 11 0;
+#X connect 11 0 12 0;
+#X connect 14 0 13 0;
+#X connect 14 1 20 0;
+#X connect 14 2 21 0;
+#X connect 14 3 22 0;
+#X connect 14 4 23 0;
+#X connect 14 5 24 0;
+#X connect 14 6 25 0;
+#X connect 14 7 26 0;
+#X connect 14 8 27 0;
+#X connect 14 9 28 0;
+#X connect 15 0 9 0;
+#X connect 16 0 15 0;
+#X connect 17 0 9 0;
+#X connect 18 0 9 0;
+#X connect 19 0 9 0;
+#X connect 31 0 30 0;
+#X connect 32 0 7 0;
+#X connect 33 0 32 0;
diff --git a/pd/doc/5.reference/help-metro.pd b/pd/doc/5.reference/help-metro.pd
new file mode 100644
index 00000000..f848e582
--- /dev/null
+++ b/pd/doc/5.reference/help-metro.pd
@@ -0,0 +1,29 @@
+#N canvas 39 7 634 372 12;
+#X text 19 36 The metro object sends a series of bangs at a constant rate. The right inlet takes the value in milliseconds between each bang. The left inlet takes a 1 or 0 \, turning the metronome on or off.;
+#X obj 67 285 + 1;
+#X obj 32 284 int;
+#X floatatom 32 317 4 0 0;
+#X obj 32 243 metro 500;
+#X obj 5 6 metro;
+#X floatatom 81 220 4 0 0;
+#X text 104 282 These objects work together as a counter. For each bang sent by metro \, the output adds 1;
+#X obj 32 103 loadbang;
+#X msg 32 125 1;
+#X text 92 135 nonzero number or "bang" to start;
+#X msg 49 172 0;
+#X msg 38 148 bang;
+#X msg 49 194 stop;
+#X text 99 181 zero or "stop" to stop.;
+#X text 351 332 Updated for Pd version 0.33;
+#X text 130 220 right inlet sets the rate in msec per tick.;
+#X text 127 243 creation argument initializes rate in msec;
+#X connect 1 0 2 1;
+#X connect 2 0 3 0;
+#X connect 2 0 1 0;
+#X connect 4 0 2 0;
+#X connect 6 0 4 1;
+#X connect 8 0 9 0;
+#X connect 9 0 4 0;
+#X connect 11 0 4 0;
+#X connect 12 0 4 0;
+#X connect 13 0 4 0;
diff --git a/pd/doc/5.reference/help-x_all_guis.pd b/pd/doc/5.reference/help-x_all_guis.pd
new file mode 100644
index 00000000..3c18031b
--- /dev/null
+++ b/pd/doc/5.reference/help-x_all_guis.pd
@@ -0,0 +1,20 @@
+#N canvas 209 342 290 271 10;
+#X obj 23 31 bng 15 250 50 532480 \$1 \$1 empty 20 8 192 8 -262144
+-1 -1;
+#X obj 23 63 tgl 15 1.06496e+06 \$2 \$2 empty 20 8 192 8 -262144 -1
+-1 0 1;
+#X obj 22 95 vsl 15 128 0 127 0 1.59744e+06 \$3 \$3 empty 20 8 192
+8 -262144 -1 -1 0 1;
+#X obj 65 30 hsl 128 15 0 127 0 2.12992e+06 \$4 \$4 empty 20 8 192
+8 -262144 -1 -1 0 1;
+#X obj 63 63 hdl 15 1 2.6624e+06 8 \$5 \$5 empty 20 8 192 8 -262144
+-1 -1 0;
+#X obj 62 99 vu 15 120 \$6 empty 35 8 64 8 -66577 -1 1 49152;
+#X obj 115 99 cnv 15 100 60 \$7 \$7 \$7 20 12 917696 14 -233017 -66577
+3.72736e+06;
+#X obj 41 308 inlet;
+#X obj 41 334 outlet;
+#X obj 227 30 vdl 15 1 4.79232e+06 8 \$9 \$9 empty 20 8 192 8 -262144
+-1 -1 0;
+#X obj 116 176 nbx 5 14 -1e+37 1e+37 0 4.25984e+06 \$8 \$8 empty 45
+7 192 10 -262144 -1 -1 0;
diff --git a/pd/doc/5.reference/hip~-help.pd b/pd/doc/5.reference/hip~-help.pd
new file mode 100644
index 00000000..bc8c408d
--- /dev/null
+++ b/pd/doc/5.reference/hip~-help.pd
@@ -0,0 +1,31 @@
+#N canvas 21 5 556 324 12;
+#X obj 70 228 env~;
+#X floatatom 70 248;
+#X floatatom 107 178;
+#X obj 70 206 hip~ 5;
+#X text 119 201 The high pass filter is initialized to cutoff frequencies below 5 Hz.;
+#X obj 12 226 env~;
+#X floatatom 12 245;
+#X text 108 227 env~ gives the amplitude of the signal envelop in dB.;
+#X floatatom 12 107;
+#X msg 452 24 \; pd dsp 1;
+#X msg 452 58 \; pd dsp 0;
+#X obj 83 6 lop~;
+#X text 9 68 The left inlet is the incoming audio signal. The right inlet is the cutoff frequency in Hz.;
+#X obj 12 130 osc~ 100;
+#X text 57 105 <-- scroll to change input frequency;
+#X text 12 266 Compare the value of the original signal on the left with the value of the filtered signal on the right.;
+#X text 8 35 lop~ is a one-pole low pass filter with a specified rolloff frequency.;
+#X text 114 7 - one-pole low pass filter;
+#X msg 70 154 clear;
+#X text 114 153 <-- reinitialize internal state;
+#X text 139 179 <-- set cutoff frequency;
+#X text 361 306 updated for Pd version-0.30;
+#X connect 0 0 1 0;
+#X connect 2 0 3 1;
+#X connect 3 0 0 0;
+#X connect 5 0 6 0;
+#X connect 8 0 13 0;
+#X connect 13 0 5 0;
+#X connect 13 0 3 0;
+#X connect 18 0 3 0;
diff --git a/pd/doc/5.reference/hslider-help.pd b/pd/doc/5.reference/hslider-help.pd
new file mode 100644
index 00000000..80bd83a5
--- /dev/null
+++ b/pd/doc/5.reference/hslider-help.pd
@@ -0,0 +1,303 @@
+#N canvas 243 228 551 413 10;
+#X obj 1 1 cnv 8 100 60 empty empty hslider=hsl 20 20 1 18 -262144
+-1109 0;
+#X floatatom 38 127 9 0 0;
+#X msg 47 84 set \$1;
+#X floatatom 38 41 7 0 0;
+#X text 13 355 (c) musil@iem.kug.ac.at;
+#X text 55 368 IEM KUG;
+#X obj 38 149 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X obj 18 41 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X obj 41 107 hsl 101 15 25 75 0 1 foo1_snd foo1_rcv empty 8 -8 192
+10 -225280 -1109 -1 6200 1;
+#X text 174 11 gui-horicontal-slider:;
+#X floatatom 47 62 7 0 0;
+#X floatatom 116 150 9 0 0;
+#X obj 110 308 r goo2_snd;
+#X obj 145 248 s goo2_rcv;
+#X floatatom 105 40 7 0 0;
+#X floatatom 145 206 7 0 0;
+#X obj 60 170 print;
+#N canvas 276 200 290 224 once 0;
+#X obj 38 47 t b b f;
+#X msg 56 85 1;
+#X obj 31 108 f 0;
+#X obj 31 131 pack 0 0;
+#X obj 31 156 route 0;
+#X obj 38 24 inlet;
+#X obj 31 180 outlet;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 0 2 3 1;
+#X connect 1 0 2 1;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 4 0 6 0;
+#X connect 5 0 0 0;
+#X restore 60 147 pd once;
+#X obj 40 265 hsl 73 15 55 3520 1 1 goo2_snd goo2_rcv log.freq. 8 -8
+192 10 -42246 -260818 -90133 1600 1;
+#X obj 37 308 ftom;
+#X floatatom 37 330 9 0 0;
+#X floatatom 64 287 9 0 0;
+#X floatatom 110 329 9 0 0;
+#X text 175 176 click properties to;
+#X floatatom 37 203 8 0 0;
+#X obj 37 226 mtof;
+#X text 12 184 --------------------;
+#X text 163 187 modify geometry \, colors \, etc.;
+#X obj 105 82 s foo1_rcv;
+#X obj 116 130 r foo1_snd;
+#X msg 105 61 set \$1;
+#X msg 145 227 set \$1;
+#X text 197 120 (0.01 pixels);
+#X text 183 99 shift-click & drag;
+#X text 189 109 for fine-tuning;
+#X text 148 270 UP- \, DOWN- \, LEFT- or RIGHT-key;
+#X text 147 281 for moving selected gui-objects;
+#N canvas 207 113 716 530 edit 0;
+#X obj 32 220 f;
+#X msg 10 199 bang;
+#X floatatom 48 198 3 63 88;
+#X floatatom 83 220 3 0 37;
+#X obj 32 243 pack 0 0;
+#X text 110 220 y-label;
+#X text 76 198 x-label;
+#X obj 279 246 f;
+#X msg 257 225 bang;
+#X floatatom 295 224 3 -10 10;
+#X floatatom 330 246 3 -10 10;
+#X obj 279 269 pack 0 0;
+#X obj 292 358 f;
+#X msg 270 337 bang;
+#X floatatom 308 336 3 20 60;
+#X floatatom 343 358 3 150 200;
+#X obj 292 381 pack 0 0;
+#X text 323 224 x-delta;
+#X text 357 246 y-delta;
+#X text 336 336 x-position;
+#X text 370 358 y-position;
+#X obj 52 335 f;
+#X msg 30 314 bang;
+#X floatatom 68 313 3 0 2;
+#X floatatom 103 335 3 4 36;
+#X obj 52 358 pack 0 0;
+#X text 96 313 font;
+#X text 132 335 height;
+#X floatatom 476 188 1 0 1;
+#X text 523 401 no init;
+#X text 493 453 init value on loadbang;
+#X msg 47 154 \; goo2_rcv color \$1 \$2 \$3;
+#X msg 32 268 \; goo2_rcv label_pos \$1 \$2;
+#X msg 52 383 \; goo2_rcv label_font \$1 \$2;
+#X msg 34 427 \; goo2_rcv label blabla;
+#X msg 292 406 \; goo2_rcv pos \$1 \$2;
+#X msg 279 294 \; goo2_rcv delta \$1 \$2;
+#X msg 475 21 \; goo2_rcv send goo2a_snd;
+#X msg 475 59 \; goo2_rcv send goo2_snd;
+#X msg 476 105 \; goo2_rcv receive goo2a_rcv;
+#X msg 476 143 \; goo2a_rcv receive goo2_rcv;
+#X msg 502 420 \; goo2_rcv init 0;
+#X msg 503 471 \; goo2_rcv init 1;
+#X text 520 188 steady;
+#X obj 486 291 f;
+#X msg 464 270 bang;
+#X floatatom 502 269 3 55 440;
+#X floatatom 537 291 6 440 3520;
+#X obj 486 314 pack 0 0;
+#X text 530 269 left-range-bound;
+#X text 586 291 right-range-bound;
+#X msg 486 339 \; goo2_rcv range \$1 \$2;
+#X msg 363 465 \; goo2_rcv log;
+#X msg 269 466 \; goo2_rcv lin;
+#X text 269 448 linear / logarithmical;
+#X obj 275 133 f;
+#X msg 250 112 bang;
+#X floatatom 291 111 3 15 73;
+#X floatatom 326 133 3 8 50;
+#X obj 275 156 pack 0 0;
+#X text 319 111 width;
+#X text 357 134 height;
+#X msg 275 181 \; goo2_rcv size \$1 \$2;
+#X msg 34 463 \; goo2_rcv label log.freq.;
+#X msg 476 212 \; goo2_rcv steady \$1;
+#X obj 47 100 pack 0 0 0;
+#X obj 47 72 f;
+#X msg 24 24 bang;
+#X floatatom 63 22 3 0 29;
+#X floatatom 79 42 3 0 29;
+#X floatatom 112 58 3 0 29;
+#X text 91 22 background;
+#X text 106 42 front-color;
+#X text 140 59 label-color;
+#X msg 277 22 back;
+#X msg 277 42 front;
+#X msg 277 62 label;
+#X msg 239 22 bang;
+#N canvas 15 207 606 448 RGB_____________ 0;
+#X obj 97 56 inlet;
+#X obj 262 53 inlet;
+#X obj 339 55 inlet;
+#X obj 405 56 inlet;
+#X obj 97 270 bang;
+#X msg 77 295 0;
+#X msg 104 295 1;
+#X obj 146 268 bang;
+#X msg 132 295 0;
+#X msg 160 295 1;
+#X obj 196 269 bang;
+#X msg 187 295 0;
+#X msg 214 295 1;
+#X obj 265 313 spigot;
+#X obj 312 313 spigot;
+#X obj 359 313 spigot;
+#X obj 249 385 outlet;
+#X text 93 33 select;
+#X text 267 28 red;
+#X text 337 30 green;
+#X text 409 30 blue;
+#X obj 405 102 t b f;
+#X obj 339 160 +;
+#X obj 339 185 t b f;
+#X obj 339 216 +;
+#X obj 296 385 outlet;
+#X obj 343 385 outlet;
+#X obj 28 180 loadbang;
+#X obj 97 135 route back front label bang;
+#X obj 343 362 f;
+#X obj 296 361 f;
+#X obj 249 361 f;
+#X obj 262 79 * -65536;
+#X obj 339 80 * -256;
+#X obj 405 80 * -1;
+#X obj 339 247 - 1;
+#X obj 235 168 t b b b b;
+#X connect 0 0 28 0;
+#X connect 1 0 32 0;
+#X connect 2 0 33 0;
+#X connect 3 0 34 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 14 1;
+#X connect 5 0 15 1;
+#X connect 6 0 13 1;
+#X connect 7 0 8 0;
+#X connect 7 0 9 0;
+#X connect 8 0 13 1;
+#X connect 8 0 15 1;
+#X connect 9 0 14 1;
+#X connect 10 0 11 0;
+#X connect 10 0 12 0;
+#X connect 11 0 13 1;
+#X connect 11 0 14 1;
+#X connect 12 0 15 1;
+#X connect 13 0 31 1;
+#X connect 14 0 30 1;
+#X connect 15 0 29 1;
+#X connect 21 0 22 0;
+#X connect 21 1 22 1;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 23 1 24 1;
+#X connect 24 0 35 0;
+#X connect 27 0 6 0;
+#X connect 28 0 4 0;
+#X connect 28 1 7 0;
+#X connect 28 2 10 0;
+#X connect 28 3 36 0;
+#X connect 29 0 26 0;
+#X connect 30 0 25 0;
+#X connect 31 0 16 0;
+#X connect 32 0 24 0;
+#X connect 33 0 22 0;
+#X connect 34 0 21 0;
+#X connect 35 0 15 0;
+#X connect 35 0 14 0;
+#X connect 35 0 13 0;
+#X connect 36 0 31 0;
+#X connect 36 1 30 0;
+#X connect 36 2 29 0;
+#X connect 36 3 35 0;
+#X restore 277 82 pd RGB_____________;
+#X floatatom 319 52 3 0 255;
+#X floatatom 362 52 3 0 255;
+#X floatatom 405 53 3 0 255;
+#X text 34 -1 preset-colors;
+#X text 290 1 RGB-colors;
+#X text 319 34 red;
+#X text 355 33 green;
+#X text 403 33 blue;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 4 1;
+#X connect 4 0 32 0;
+#X connect 7 0 11 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 1;
+#X connect 10 0 11 1;
+#X connect 11 0 36 0;
+#X connect 12 0 16 0;
+#X connect 13 0 12 0;
+#X connect 14 0 12 1;
+#X connect 15 0 16 1;
+#X connect 16 0 35 0;
+#X connect 21 0 25 0;
+#X connect 22 0 21 0;
+#X connect 23 0 21 1;
+#X connect 24 0 25 1;
+#X connect 25 0 33 0;
+#X connect 28 0 64 0;
+#X connect 44 0 48 0;
+#X connect 45 0 44 0;
+#X connect 46 0 44 1;
+#X connect 47 0 48 1;
+#X connect 48 0 51 0;
+#X connect 55 0 59 0;
+#X connect 56 0 55 0;
+#X connect 57 0 55 1;
+#X connect 58 0 59 1;
+#X connect 59 0 62 0;
+#X connect 65 0 31 0;
+#X connect 66 0 65 0;
+#X connect 67 0 66 0;
+#X connect 68 0 66 1;
+#X connect 69 0 65 1;
+#X connect 70 0 65 2;
+#X connect 74 0 78 0;
+#X connect 75 0 78 0;
+#X connect 76 0 78 0;
+#X connect 77 0 78 0;
+#X connect 78 0 65 0;
+#X connect 78 1 65 1;
+#X connect 78 2 65 2;
+#X connect 79 0 78 1;
+#X connect 80 0 78 2;
+#X connect 81 0 78 3;
+#X restore 314 245 pd edit;
+#X obj 221 61 hsl 128 15 0 127 0 0 ddd ddd empty 20 8 192 8 -262144
+-1 -1 10600 1;
+#X text 187 379 updated for Pd version 0.35;
+#X text 30 380 graz \, austria 2002;
+#X obj 168 34 x_all_guis aaa bbb ccc ddd eee fff ggg hhh iii;
+#X connect 1 0 6 0;
+#X connect 2 0 8 0;
+#X connect 3 0 8 0;
+#X connect 7 0 8 0;
+#X connect 8 0 1 0;
+#X connect 8 0 17 0;
+#X connect 10 0 2 0;
+#X connect 12 0 22 0;
+#X connect 14 0 30 0;
+#X connect 15 0 31 0;
+#X connect 17 0 16 0;
+#X connect 18 0 21 0;
+#X connect 18 0 19 0;
+#X connect 19 0 20 0;
+#X connect 24 0 25 0;
+#X connect 25 0 18 0;
+#X connect 29 0 11 0;
+#X connect 30 0 28 0;
+#X connect 31 0 13 0;
diff --git a/pd/doc/5.reference/int-help.pd b/pd/doc/5.reference/int-help.pd
new file mode 100644
index 00000000..6b6de2f6
--- /dev/null
+++ b/pd/doc/5.reference/int-help.pd
@@ -0,0 +1,24 @@
+#N canvas 4 30 605 319 12;
+#X msg 61 101 bang;
+#X floatatom 61 248 0 0 0;
+#X floatatom 73 125 0 0 0;
+#X floatatom 102 198 0 0 0;
+#X text 108 97 outputs the value;
+#X text 110 126 sets and outputs the value;
+#X text 113 220 creation argument initializes the value;
+#X obj 61 222 int 6;
+#X msg 73 148 9.6;
+#X text 106 148 non-integers get truncated;
+#X msg 71 173 -9.6;
+#X text 113 173 toward zero;
+#X text 136 200 set the value but no output;
+#X obj 60 11 int;
+#X text 108 12 - STORE AN INTEGER;
+#X text 37 33 The int object stores a number \, initialized by its creation argument \, which may be reset using its inlet and output by sending it the "bang" message. The output is truncated to an integer ala Max.;
+#X text 315 270 updated for Pd version 0.33;
+#X connect 0 0 7 0;
+#X connect 2 0 7 0;
+#X connect 3 0 7 1;
+#X connect 7 0 1 0;
+#X connect 8 0 7 0;
+#X connect 10 0 7 0;
diff --git a/pd/doc/5.reference/key-help.pd b/pd/doc/5.reference/key-help.pd
new file mode 100644
index 00000000..1ab0337c
--- /dev/null
+++ b/pd/doc/5.reference/key-help.pd
@@ -0,0 +1,24 @@
+#N canvas 146 45 546 288 12;
+#X obj 21 10 key;
+#X obj 54 9 keyup;
+#X obj 105 9 keyname;
+#X text 173 8 -- grab keyboard;
+#X obj 38 67 key;
+#X floatatom 38 95 3 0 0 0 - - -;
+#X floatatom 77 93 3 0 0 0 - - -;
+#X obj 77 67 keyup;
+#X floatatom 128 93 3 0 0 0 - - -;
+#X obj 128 67 keyname;
+#X symbolatom 172 94 10 0 0 0 - - -;
+#X text 280 262 updated for Pd version 0.32.;
+#X text 26 133 Key and keyup report the (system dependent) numbers
+of "printing" keys of the keyboard. Keyname gives the symbolic name
+of the key \, with a 1 or 0 if it's up or down \, and works with non-printing
+keys like shift or "F1".;
+#X text 18 200 Caveat -- this only works if Pd actually gets the key
+events which can depend on the stacking order of windows and/or the
+pointer location \, depending on the system.;
+#X connect 4 0 5 0;
+#X connect 7 0 6 0;
+#X connect 9 0 8 0;
+#X connect 9 1 10 0;
diff --git a/pd/doc/5.reference/line-help.pd b/pd/doc/5.reference/line-help.pd
new file mode 100644
index 00000000..fd0c02d4
--- /dev/null
+++ b/pd/doc/5.reference/line-help.pd
@@ -0,0 +1,32 @@
+#N canvas 31 15 669 403 12;
+#X floatatom 22 339 0 0 0 0 - - -;
+#X msg 31 232 0 1000;
+#X msg 46 254 39;
+#X obj 66 15 line;
+#X text 106 14 - ramp generator;
+#X msg 22 209 1 1000;
+#X text 18 36 The line object takes (target \, time) pairs and slews
+to the specified target over the time given \, updating its output
+at a "grain rate" given by the creation argument. If you dont' specify
+a time \, line jumps immediately to the target. Note that the inlet
+does not remember old values (unlike every other inlet in Pd) -- sending
+a float causes a jump in the output regardless of whatever time value
+was specified in some previous message. If the line object receives
+a message specifying some new target before reaching the previous one
+\, it takes off from its current value.;
+#X text 93 221 send a pair to ramp to a new value;
+#X text 105 251 send a single number to jump;
+#X text 46 363 see also:;
+#X obj 132 361 line~;
+#X msg 57 279 stop;
+#X text 98 278 "stop" message to stop output;
+#X obj 22 313 line 0 100;
+#X text 383 369 updated for Pd version 0.37;
+#X text 125 310 creation arguments:;
+#X text 316 310 1 initial value;
+#X text 318 330 2 time grain in milliseconds;
+#X connect 1 0 13 0;
+#X connect 2 0 13 0;
+#X connect 5 0 13 0;
+#X connect 11 0 13 0;
+#X connect 13 0 0 0;
diff --git a/pd/doc/5.reference/line~-help.pd b/pd/doc/5.reference/line~-help.pd
new file mode 100644
index 00000000..7b470c2d
--- /dev/null
+++ b/pd/doc/5.reference/line~-help.pd
@@ -0,0 +1,33 @@
+#N canvas 121 54 813 370 12;
+#X obj 33 301 snapshot~;
+#X obj 21 8 line~;
+#X obj 33 226 line~;
+#X floatatom 33 324 0 0 0;
+#X obj 43 274 metro 100;
+#X obj 43 249 r start;
+#X msg 550 21 \; pd dsp 1 \; start bang;
+#X msg 34 106 1 1000;
+#X text 89 105 a pair of numbers starts a ramp;
+#X msg 60 176 2;
+#X text 91 150 a single number jumps to value;
+#X msg 61 200 stop;
+#X text 104 199 "stop" message freezes line~ at its current value;
+#X msg 60 153 0;
+#X msg 43 128 0 5000;
+#X text 10 28 The line~ object generates linear ramps whose levels and timing are determined by messages you send it. The messages may be a single target value (causing the output to jump to the target) or a target and a time in milliseconds (to start a new ramp.);
+#X text 644 36 Click to start;
+#X text 639 94 Click to stop;
+#X text 185 300 see also:;
+#X obj 271 302 line;
+#X msg 550 75 \; pd dsp 0 \; start 0;
+#X text 75 7 - audio ramp generator;
+#X text 576 335 updated for version 0.33;
+#X connect 0 0 3 0;
+#X connect 2 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 7 0 2 0;
+#X connect 9 0 2 0;
+#X connect 11 0 2 0;
+#X connect 13 0 2 0;
+#X connect 14 0 2 0;
diff --git a/pd/doc/5.reference/lop~-help.pd b/pd/doc/5.reference/lop~-help.pd
new file mode 100644
index 00000000..9f3e85f8
--- /dev/null
+++ b/pd/doc/5.reference/lop~-help.pd
@@ -0,0 +1,31 @@
+#N canvas 402 99 566 329 12;
+#X obj 70 228 env~;
+#X floatatom 70 248;
+#X floatatom 107 178;
+#X obj 70 206 hip~ 5;
+#X text 119 201 The high pass filter is initialized to cutoff frequencies below 5 Hz.;
+#X obj 12 226 env~;
+#X floatatom 12 245;
+#X text 108 227 env~ gives the amplitude of the signal envelop in dB.;
+#X floatatom 12 107;
+#X msg 452 24 \; pd dsp 1;
+#X msg 452 58 \; pd dsp 0;
+#X obj 83 6 lop~;
+#X text 9 68 The left inlet is the incoming audio signal. The right inlet is the cutoff frequency in Hz.;
+#X obj 12 130 osc~ 100;
+#X text 57 105 <-- scroll to change input frequency;
+#X text 12 266 Compare the value of the original signal on the left with the value of the filtered signal on the right.;
+#X text 8 35 lop~ is a one-pole low pass filter with a specified rolloff frequency.;
+#X text 114 7 - one-pole low pass filter;
+#X msg 70 154 clear;
+#X text 114 153 <-- reinitialize internal state;
+#X text 139 179 <-- set cutoff frequency;
+#X text 364 306 updated for Pd version-0.30;
+#X connect 0 0 1 0;
+#X connect 2 0 3 1;
+#X connect 3 0 0 0;
+#X connect 5 0 6 0;
+#X connect 8 0 13 0;
+#X connect 13 0 5 0;
+#X connect 13 0 3 0;
+#X connect 18 0 3 0;
diff --git a/pd/doc/5.reference/makefilename-help.pd b/pd/doc/5.reference/makefilename-help.pd
new file mode 100644
index 00000000..6850699b
--- /dev/null
+++ b/pd/doc/5.reference/makefilename-help.pd
@@ -0,0 +1,17 @@
+#N canvas 18 58 583 301 12;
+#X floatatom 30 169 0 0 0;
+#X obj 30 223 print;
+#X obj 30 196 makefilename dog%d.aif;
+#X msg 245 166 symbol meat;
+#X msg 355 167 symbol hair;
+#X obj 245 223 print;
+#X obj 245 196 makefilename dog%s.aif;
+#X text 28 49 The Makefilename object generates symbols according to a format string \, for use as a series of filenames \, table names \, or whatnot. You can plug in a variable number or symbol by putting "%d" or "%s" in the string. If you put "%s" in the string be sure to send it a symbol and vice versa... there's no checking.;
+#X text 319 257 updated for Pd version 0.33;
+#X obj 49 17 makefilename;
+#X text 170 18 - format a "name" with a variable field;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
+#X connect 3 0 6 0;
+#X connect 4 0 6 0;
+#X connect 6 0 5 0;
diff --git a/pd/doc/5.reference/makenote-help.pd b/pd/doc/5.reference/makenote-help.pd
new file mode 100644
index 00000000..e3d003fc
--- /dev/null
+++ b/pd/doc/5.reference/makenote-help.pd
@@ -0,0 +1,26 @@
+#N canvas 39 28 663 385 12;
+#X floatatom 180 207 0 0 0;
+#X floatatom 110 176 0 0 0;
+#X msg 48 127 60;
+#X obj 41 262 print x1;
+#X obj 180 262 print x2;
+#X floatatom 41 104 0 0 0;
+#X obj 29 14 makenote;
+#X text 113 14 - send note-on messages and schedule note-off for later;
+#X text 19 41 Makenote makes MIDI-style note-on/note-off pairs \, which you can use for MIDI output or to drive note-like processes within Pd.;
+#X msg 48 153 60.5;
+#X text 80 105 numbers at left are "pitches" which may be integers or not.;
+#X text 146 178 "velocity";
+#X text 215 210 duration in milliseconds;
+#X obj 41 235 makenote 3.2 500;
+#X text 193 235 creation arguments initialize velocity and duration;
+#X text 38 316 see also;
+#X obj 117 316 stripnote;
+#X text 389 325 updated for Pd version 0.33;
+#X connect 0 0 13 2;
+#X connect 1 0 13 1;
+#X connect 2 0 13 0;
+#X connect 5 0 13 0;
+#X connect 9 0 13 0;
+#X connect 13 0 3 0;
+#X connect 13 1 4 0;
diff --git a/pd/doc/5.reference/math-help.pd b/pd/doc/5.reference/math-help.pd
new file mode 100644
index 00000000..5464b8aa
--- /dev/null
+++ b/pd/doc/5.reference/math-help.pd
@@ -0,0 +1,60 @@
+#N canvas 0 0 554 555 12;
+#X floatatom 283 263 0 0 0;
+#X floatatom 226 349 0 0 0;
+#X floatatom 226 262 0 0 0;
+#X floatatom 281 486 0 0 0;
+#X floatatom 281 425 0 0 0;
+#X floatatom 185 486 0 0 0;
+#X floatatom 185 425 0 0 0;
+#X floatatom 117 486 0 0 0;
+#X floatatom 117 425 0 0 0;
+#X floatatom 117 326 0 0 0;
+#X floatatom 117 265 0 0 0;
+#X floatatom 30 486 0 0 0;
+#X floatatom 30 425 0 0 0;
+#X floatatom 218 186 0 0 0;
+#X floatatom 135 182 0 0 0;
+#X obj 66 146 sin;
+#X floatatom 66 53 0 0 0;
+#X floatatom 66 180 0 0 0;
+#X obj 66 113 * 6.28319;
+#X obj 66 83 / 360;
+#X obj 135 148 cos;
+#X obj 218 152 tan;
+#X obj 30 456 sqrt;
+#X obj 117 296 atan;
+#X obj 117 456 log;
+#X obj 185 456 exp;
+#X obj 281 456 abs;
+#X obj 226 290 float;
+#X obj 283 290 t b f;
+#X obj 226 319 atan2;
+#X text 87 17 Higher math in Pd;
+#X text 171 58 trig functions take inputs in radians;
+#X text 24 213 The arc tangent takes two forms. The atan2 version takes an (x \, y) pair and gives you an output between -pi and pi.;
+#X text 23 380 also \, square root \, natural logarithm and exponential \, and absolute value:;
+#X text 292 529 updated for Pd version 0.33;
+#X connect 0 0 28 0;
+#X connect 2 0 27 0;
+#X connect 4 0 26 0;
+#X connect 6 0 25 0;
+#X connect 8 0 24 0;
+#X connect 10 0 23 0;
+#X connect 12 0 22 0;
+#X connect 15 0 17 0;
+#X connect 16 0 19 0;
+#X connect 18 0 15 0;
+#X connect 18 0 20 0;
+#X connect 18 0 21 0;
+#X connect 19 0 18 0;
+#X connect 20 0 14 0;
+#X connect 21 0 13 0;
+#X connect 22 0 11 0;
+#X connect 23 0 9 0;
+#X connect 24 0 7 0;
+#X connect 25 0 5 0;
+#X connect 26 0 3 0;
+#X connect 27 0 29 0;
+#X connect 28 0 27 0;
+#X connect 28 1 29 1;
+#X connect 29 0 1 0;
diff --git a/pd/doc/5.reference/message-help.pd b/pd/doc/5.reference/message-help.pd
new file mode 100644
index 00000000..13a74f55
--- /dev/null
+++ b/pd/doc/5.reference/message-help.pd
@@ -0,0 +1,46 @@
+#N canvas 0 365 726 512 12;
+#X msg 88 13 message boxes;
+#X text 55 36 Message boxes hold one or more message. Anytime the message
+box receives any message at all \, the messages in the box are all
+sent to their destinations.;
+#X obj 178 301 print;
+#X msg 178 241 60 64;
+#X msg 178 271 pitch \$1 \, velocity \$2;
+#X msg 49 378 123 \; my-receiver-name 858 \; another-receiver -45;
+#X text 55 84 Clicking on a message also sends it \, so you can use
+messsage boxes for push buttins. For instance \, click here while watching
+the printout window:;
+#X msg 164 141 walk the dog;
+#X obj 164 170 print;
+#X text 281 141 <--- message;
+#X text 265 167 <--- object (different border);
+#X text 35 200 You can separate multiple messages by commas. Also \,
+you can use "$1" \, "$2" \, etc. to make variable messages:;
+#X text 14 323 Finally \, if you separate messages by a semicolon instead
+of a comma \, the following message(s) are re-routed to named objects
+such as "receives":;
+#X obj 49 433 print;
+#X obj 253 378 receive my-receiver-name;
+#X floatatom 253 402 0 0 0;
+#X floatatom 252 449 0 0 0;
+#X obj 252 425 receive another-receiver;
+#X msg 559 349 dog bird monkey \; monkey \;;
+#X msg 559 229 set dog;
+#X msg 567 252 set cat;
+#X text 593 189 this is;
+#X text 592 206 arcane:;
+#X msg 576 303 add monkey;
+#X msg 581 327 add2 bird;
+#X msg 573 277 set;
+#X text 415 479 updated for Pd version 0.34;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X connect 5 0 13 0;
+#X connect 7 0 8 0;
+#X connect 14 0 15 0;
+#X connect 17 0 16 0;
+#X connect 19 0 18 0;
+#X connect 20 0 18 0;
+#X connect 23 0 18 0;
+#X connect 24 0 18 0;
+#X connect 25 0 18 0;
diff --git a/pd/doc/5.reference/midi-help.pd b/pd/doc/5.reference/midi-help.pd
new file mode 100644
index 00000000..4b731688
--- /dev/null
+++ b/pd/doc/5.reference/midi-help.pd
@@ -0,0 +1,129 @@
+#N canvas 68 50 876 553 12;
+#X floatatom 318 379 0 0 0;
+#X floatatom 282 468 0 0 0;
+#X floatatom 200 469 0 0 0;
+#X text 96 330 off;
+#X floatatom 52 383 0 0 0;
+#X floatatom 70 134 0 0 0;
+#X obj 34 108 notein;
+#X floatatom 34 134 0 0 0;
+#X obj 52 488 noteout;
+#X obj 52 462 makenote 64 250;
+#X obj 52 409 metro 500;
+#X msg 52 356 1;
+#X msg 84 356 0;
+#X text 52 333 on;
+#X msg 52 436 60;
+#X obj 200 496 pgmout;
+#X obj 282 494 bendout;
+#X floatatom 416 379 0 0 0;
+#X floatatom 197 136 0 0 0;
+#X floatatom 145 136 0 0 0;
+#X text 41 79 omni;
+#X floatatom 106 134 0 0 0;
+#X obj 145 109 notein 1;
+#X text 145 85 channel 1;
+#X text 194 17 MIDI I/O objects;
+#X text 85 54 notes;
+#X text 334 47 control change;
+#X text 264 69 everything;
+#X floatatom 309 137 0 0 0;
+#X floatatom 271 137 0 0 0;
+#X floatatom 347 136 0 0 0;
+#X obj 271 110 ctlin;
+#X floatatom 440 138 0 0 0;
+#X floatatom 396 138 0 0 0;
+#X obj 396 111 ctlin 7;
+#X text 364 71 specific controller number;
+#X text 410 88 omni;
+#X text 496 89 channel 1;
+#X floatatom 493 140 0 0 0;
+#X obj 493 114 ctlin 7 1;
+#X obj 61 221 pgmin;
+#X floatatom 97 248 0 0 0;
+#X floatatom 61 248 0 0 0;
+#X floatatom 197 250 0 0 0;
+#X floatatom 161 250 0 0 0;
+#X floatatom 307 253 0 0 0;
+#X floatatom 272 253 0 0 0;
+#X floatatom 382 255 0 0 0;
+#X floatatom 343 253 0 0 0;
+#X floatatom 420 256 0 0 0;
+#X obj 161 222 bendin;
+#X obj 272 226 touchin;
+#X obj 343 227 polytouchin;
+#X text 49 167 these can also take an optional channel number as argument but by default are omni:;
+#X text 32 197 program change;
+#X text 155 198 pitch bend;
+#X text 271 203 channel and poly aftertouch;
+#X floatatom 191 380 0 0 0;
+#X floatatom 224 380 0 0 0;
+#X floatatom 260 382 0 0 0;
+#X obj 191 407 ctlout;
+#X obj 318 406 ctlout 7;
+#X text 192 349 control out;
+#X text 314 353 control 7;
+#X text 409 354 control 7 \, channel 4;
+#X obj 416 406 ctlout 7 4;
+#X text 101 277 outputs work similarly. They all take an optional channel as creation argument \, and ctlin takes a control number and a channel. You get inlets to change them in any case. IF you specify no channel \, it's channel 1;
+#X floatatom 355 467 0 0 0;
+#X floatatom 440 466 0 0 0;
+#X obj 355 493 touchout;
+#X obj 440 492 polytouchout;
+#X floatatom 479 467 0 0 0;
+#X floatatom 520 467 0 0 0;
+#X obj 625 218 midiin;
+#X floatatom 625 249 0 0 0;
+#X floatatom 656 249 0 0 0;
+#X floatatom 695 249 0 0 0;
+#X floatatom 726 250 0 0 0;
+#X text 590 155 These two are always omni and;
+#X text 590 174 output the port number instead;
+#X text 594 192 of the channel:;
+#X obj 697 218 sysexin;
+#X obj 623 472 midiout;
+#X text 571 413 use this to output raw MIDI;
+#X text 566 433 (the second inlet is the port;
+#X text 569 451 number.);
+#X text 625 514 updated for Pd release 0.33;
+#X connect 0 0 61 0;
+#X connect 1 0 16 0;
+#X connect 2 0 15 0;
+#X connect 4 0 10 0;
+#X connect 6 0 7 0;
+#X connect 6 1 5 0;
+#X connect 6 2 21 0;
+#X connect 9 0 8 0;
+#X connect 9 1 8 1;
+#X connect 10 0 14 0;
+#X connect 11 0 4 0;
+#X connect 12 0 4 0;
+#X connect 14 0 9 0;
+#X connect 17 0 65 0;
+#X connect 22 0 19 0;
+#X connect 22 1 18 0;
+#X connect 31 0 29 0;
+#X connect 31 1 28 0;
+#X connect 31 2 30 0;
+#X connect 34 0 33 0;
+#X connect 34 1 32 0;
+#X connect 39 0 38 0;
+#X connect 40 0 42 0;
+#X connect 40 1 41 0;
+#X connect 50 0 44 0;
+#X connect 50 1 43 0;
+#X connect 51 0 46 0;
+#X connect 51 1 45 0;
+#X connect 52 0 48 0;
+#X connect 52 1 47 0;
+#X connect 52 2 49 0;
+#X connect 57 0 60 0;
+#X connect 58 0 60 1;
+#X connect 59 0 60 2;
+#X connect 67 0 69 0;
+#X connect 68 0 70 0;
+#X connect 71 0 70 1;
+#X connect 72 0 70 2;
+#X connect 73 0 74 0;
+#X connect 73 1 75 0;
+#X connect 81 0 76 0;
diff --git a/pd/doc/5.reference/moses-help.pd b/pd/doc/5.reference/moses-help.pd
new file mode 100644
index 00000000..c1f23c90
--- /dev/null
+++ b/pd/doc/5.reference/moses-help.pd
@@ -0,0 +1,17 @@
+#N canvas 0 0 624 300 12;
+#X obj 72 196 moses 10;
+#X floatatom 72 164 4 0 0;
+#X floatatom 139 167 4 0 0;
+#X floatatom 72 229 4 0 0;
+#X floatatom 139 230 4 0 0;
+#X obj 63 24 moses;
+#X text 118 23 - part a stream of numbers;
+#X text 303 235 updated for Pd version 0.33;
+#X text 24 64 Moses takes numbers and outputs them at left if they're
+less than a control value \, and at right if they're greater or equal
+to it. The creation argument initializes the control value (10 in this
+example) and the right inlet changes it.;
+#X connect 0 0 3 0;
+#X connect 0 1 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
diff --git a/pd/doc/5.reference/my_canvas-help.pd b/pd/doc/5.reference/my_canvas-help.pd
new file mode 100644
index 00000000..decda628
--- /dev/null
+++ b/pd/doc/5.reference/my_canvas-help.pd
@@ -0,0 +1,243 @@
+#N canvas 482 81 568 339 10;
+#X obj 1 1 cnv 15 300 60 foo10_snd foo10_rcv my_canvas=cnv 63 37 192
+17 -257472 -355 0;
+#X text 4 232 (c) musil@iem.kug.ac.at;
+#X text 46 245 IEM KUG;
+#N canvas 219 100 699 530 edit 0;
+#X obj 39 226 f;
+#X msg 17 205 bang;
+#X floatatom 55 204 3 63 88;
+#X floatatom 90 226 3 0 37;
+#X obj 39 249 pack 0 0;
+#X text 117 226 y-label;
+#X text 83 204 x-label;
+#X obj 297 281 f;
+#X msg 275 260 bang;
+#X floatatom 313 259 3 -10 10;
+#X floatatom 348 281 3 -10 10;
+#X obj 297 304 pack 0 0;
+#X obj 309 396 f;
+#X msg 287 375 bang;
+#X floatatom 325 374 3 20 60;
+#X floatatom 360 396 3 150 200;
+#X obj 309 419 pack 0 0;
+#X text 341 259 x-delta;
+#X text 375 281 y-delta;
+#X text 353 374 x-position;
+#X text 387 396 y-position;
+#X obj 59 341 f;
+#X msg 37 320 bang;
+#X floatatom 75 319 3 0 2;
+#X floatatom 110 341 3 4 36;
+#X obj 59 364 pack 0 0;
+#X text 103 319 font;
+#X text 139 341 height;
+#X floatatom 275 183 3 2 20;
+#X msg 52 137 \; foo10_rcv color \$1 \$2;
+#X msg 39 274 \; foo10_rcv label_pos \$1 \$2;
+#X msg 59 390 \; foo10_rcv label_font \$1 \$2;
+#X msg 36 430 \; foo10_rcv label blabla;
+#X msg 36 466 \; foo10_rcv label my_canvas;
+#X msg 309 444 \; foo10_rcv pos \$1 \$2;
+#X msg 297 329 \; foo10_rcv delta \$1 \$2;
+#X obj 505 234 f;
+#X msg 483 213 bang;
+#X floatatom 521 212 5 100 1000;
+#X floatatom 556 234 4 50 500;
+#X obj 505 257 pack 0 0;
+#X text 566 212 width;
+#X text 594 236 height;
+#X msg 505 282 \; foo10_rcv vis_size \$1 \$2;
+#X msg 275 211 \; foo10_rcv size \$1;
+#X text 305 183 selectable size;
+#X msg 483 156 \; foo10a_rcv receive foo10_rcv;
+#X msg 483 119 \; foo10_rcv receive foo10a_rcv;
+#X msg 482 29 \; foo10_rcv send foo10a_snd;
+#X msg 482 67 \; foo10_rcv send foo10_snd;
+#X msg 509 372 \; foo10_rcv get_pos;
+#X obj 510 407 r foo10_snd;
+#X obj 510 428 unpack 0 0;
+#X floatatom 510 453 4 0 0;
+#X floatatom 575 452 4 0 0;
+#X text 490 452 x=;
+#X text 557 452 y=;
+#X obj 52 79 f;
+#X msg 29 31 bang;
+#X floatatom 68 29 3 0 29;
+#X floatatom 103 47 3 0 29;
+#X text 96 29 background;
+#X text 131 48 label-color;
+#X msg 290 25 back;
+#X msg 290 49 label;
+#X msg 252 25 bang;
+#N canvas 15 207 606 448 RGB_____________ 0;
+#X obj 97 56 inlet;
+#X obj 262 53 inlet;
+#X obj 339 55 inlet;
+#X obj 405 56 inlet;
+#X obj 97 270 bang;
+#X msg 77 295 0;
+#X msg 104 295 1;
+#X obj 146 268 bang;
+#X msg 132 295 0;
+#X msg 160 295 1;
+#X obj 265 313 spigot;
+#X obj 312 313 spigot;
+#X obj 249 385 outlet;
+#X text 93 33 select;
+#X text 267 28 red;
+#X text 337 30 green;
+#X text 409 30 blue;
+#X obj 405 102 t b f;
+#X obj 339 160 +;
+#X obj 339 185 t b f;
+#X obj 339 216 +;
+#X obj 296 385 outlet;
+#X obj 28 180 loadbang;
+#X obj 296 361 f;
+#X obj 249 361 f;
+#X obj 262 79 * -65536;
+#X obj 339 80 * -256;
+#X obj 405 80 * -1;
+#X obj 339 247 - 1;
+#X obj 97 135 route back label bang;
+#X obj 235 168 t b b b;
+#X connect 0 0 29 0;
+#X connect 1 0 25 0;
+#X connect 2 0 26 0;
+#X connect 3 0 27 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 11 1;
+#X connect 6 0 10 1;
+#X connect 7 0 8 0;
+#X connect 7 0 9 0;
+#X connect 8 0 10 1;
+#X connect 9 0 11 1;
+#X connect 10 0 24 1;
+#X connect 11 0 23 1;
+#X connect 17 0 18 0;
+#X connect 17 1 18 1;
+#X connect 18 0 19 0;
+#X connect 19 0 20 0;
+#X connect 19 1 20 1;
+#X connect 20 0 28 0;
+#X connect 22 0 6 0;
+#X connect 23 0 21 0;
+#X connect 24 0 12 0;
+#X connect 25 0 20 0;
+#X connect 26 0 18 0;
+#X connect 27 0 17 0;
+#X connect 28 0 11 0;
+#X connect 28 0 10 0;
+#X connect 29 0 4 0;
+#X connect 29 1 7 0;
+#X connect 29 2 30 0;
+#X connect 30 0 24 0;
+#X connect 30 1 23 0;
+#X connect 30 2 28 0;
+#X restore 290 86 pd RGB_____________;
+#X floatatom 332 55 3 0 255;
+#X floatatom 375 55 3 0 255;
+#X floatatom 418 56 3 0 255;
+#X text 39 3 preset-colors;
+#X text 301 0 RGB-colors;
+#X text 332 37 red;
+#X text 368 36 green;
+#X text 416 36 blue;
+#X obj 52 104 pack 0 0;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 4 1;
+#X connect 4 0 30 0;
+#X connect 7 0 11 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 1;
+#X connect 10 0 11 1;
+#X connect 11 0 35 0;
+#X connect 12 0 16 0;
+#X connect 13 0 12 0;
+#X connect 14 0 12 1;
+#X connect 15 0 16 1;
+#X connect 16 0 34 0;
+#X connect 21 0 25 0;
+#X connect 22 0 21 0;
+#X connect 23 0 21 1;
+#X connect 24 0 25 1;
+#X connect 25 0 31 0;
+#X connect 28 0 44 0;
+#X connect 36 0 40 0;
+#X connect 37 0 36 0;
+#X connect 38 0 36 1;
+#X connect 39 0 40 1;
+#X connect 40 0 43 0;
+#X connect 51 0 52 0;
+#X connect 52 0 53 0;
+#X connect 52 1 54 0;
+#X connect 57 0 75 0;
+#X connect 58 0 57 0;
+#X connect 59 0 57 1;
+#X connect 60 0 75 1;
+#X connect 63 0 66 0;
+#X connect 64 0 66 0;
+#X connect 65 0 66 0;
+#X connect 66 0 75 0;
+#X connect 66 1 75 1;
+#X connect 67 0 66 1;
+#X connect 68 0 66 2;
+#X connect 69 0 66 3;
+#X connect 75 0 29 0;
+#X restore 305 20 pd edit;
+#X floatatom 110 193 4 0 0;
+#X floatatom 147 193 4 0 0;
+#X text 121 209 x;
+#X text 158 209 y;
+#X obj 7 161 metro 100;
+#X obj 33 141 tgl 15 1 empty empty empty 20 8 0 10 -262144 -1 -1 1
+1;
+#X obj 110 145 r from_K1;
+#X floatatom 188 194 4 0 0;
+#X floatatom 225 194 4 0 0;
+#X text 198 210 x;
+#X text 236 210 y;
+#X obj 188 146 r from_K2;
+#X msg 7 185 \; to_K get_pos;
+#N canvas 0 296 395 395 room 1;
+#X obj 1 1 cnv 1 400 400 empty empty type...ctrl+e 150 140 2 17 -33289
+-24198 0;
+#X obj 15 16 cnv 1 1 360 empty empty move_K1_and_K2 115 160 2 17 -166441
+-24198 0;
+#X obj 374 15 cnv 1 1 360 empty empty empty 20 12 2 20 -99865 -66577
+0;
+#X obj 15 15 cnv 1 360 1 empty empty empty 20 12 2 20 -166441 -66577
+0;
+#X obj 17 375 cnv 1 358 1 empty empty empty 20 12 2 20 -99865 -66577
+0;
+#X obj 23 22 cnv 25 25 25 from_K1 to_K K1 1 13 194 14 -261681 -123526
+0;
+#X obj 342 342 cnv 25 25 25 from_K2 to_K K2 1 13 194 14 -225280 -1109
+0;
+#X restore 307 147 pd room;
+#X obj 110 169 unpack;
+#X obj 188 170 unpack;
+#X text 51 92 to modify geometry \, colors \, etc.;
+#X obj 2 115 cnv 1 470 1 empty empty empty 20 12 2 20 -261681 -66577
+0;
+#X text 40 78 of the light-blue;
+#X text 166 78 my_canvas-object \,;
+#X text 5 64 click the properties-dialog on the top-left corner;
+#X obj 361 195 r foo10_rcv;
+#X obj 403 215 s ggg;
+#X text 172 257 updated for Pd version 0.35;
+#X text 21 257 graz \, austria 2002;
+#X obj 187 236 x_all_guis aaa bbb ccc ddd eee fff ggg hhh iii;
+#X connect 8 0 16 0;
+#X connect 9 0 8 0;
+#X connect 10 0 18 0;
+#X connect 15 0 19 0;
+#X connect 18 0 4 0;
+#X connect 18 1 5 0;
+#X connect 19 0 11 0;
+#X connect 19 1 12 0;
+#X connect 25 0 26 0;
diff --git a/pd/doc/5.reference/namecanvas-help.pd b/pd/doc/5.reference/namecanvas-help.pd
new file mode 100644
index 00000000..4c408bcb
--- /dev/null
+++ b/pd/doc/5.reference/namecanvas-help.pd
@@ -0,0 +1,8 @@
+#N canvas 38 53 532 261 12;
+#X obj 66 15 namecanvas;
+#X text 169 15 - ATTACH THIS CANVAS TO A NAME;
+#X obj 204 107 namecanvas bonzo;
+#X msg 205 64 \; bonzo msg 50 50 hi there;
+#X text 252 224 updated for Pd version 0.33;
+#X msg 79 180 \; pd-namecanvas.pd msg 50 70 this is better;
+#X text 44 153 This is obsolete. Instead \, you can just say:;
diff --git a/pd/doc/5.reference/netreceive-help.pd b/pd/doc/5.reference/netreceive-help.pd
new file mode 100644
index 00000000..b4bd3f9c
--- /dev/null
+++ b/pd/doc/5.reference/netreceive-help.pd
@@ -0,0 +1,23 @@
+#N canvas 50 24 682 520 12;
+#X obj 100 323 netreceive 3000;
+#X floatatom 202 353 0 0 0;
+#X obj 100 414 netreceive 3001 1;
+#X text 33 36 The Netreceive object opens a socket for TCP ("stream") or UDP ("datagram") network reception on a specified port. If using TCP \, an outlet gives you the number of Netsend objects (or other compatible clients) have opened connections here.;
+#X text 31 117 Incoming network messages appear on "receive" objects \; it's up to the sender to select which one. Here \, a "receive foo" fields messages sent from the Netsend help window \, q.v.;
+#X text 108 270 first argument: portnumber = 3000;
+#X text 105 291 second argument: 0 or none for TCP \, nonzero for UDP;
+#X text 238 322 <-- TCP \, port 3000;
+#X text 262 413 <-- UDP \, port 3001;
+#X text 236 354 <--- number of open connections;
+#X text 85 12 Netreceive -- listen for incoming messages from network;
+#X text 26 383 incoming messages;
+#X text 203 488 see also:;
+#X obj 289 490 netsend;
+#X obj 100 353 print tcp;
+#X obj 100 442 print udp;
+#X text 425 484 updated for Pd version 0.33;
+#X text 30 207 SECURITY ALERT: don't publish the port number of your netreceive unless you wouldn't mind other people being able to send you messages.;
+#X text 32 168 There are some possibilities for intercommunication with other programs... see the help for "netsend.";
+#X connect 0 0 14 0;
+#X connect 0 1 1 0;
+#X connect 2 0 15 0;
diff --git a/pd/doc/5.reference/netsend-help.pd b/pd/doc/5.reference/netsend-help.pd
new file mode 100644
index 00000000..f2eb9bad
--- /dev/null
+++ b/pd/doc/5.reference/netsend-help.pd
@@ -0,0 +1,55 @@
+#N canvas 84 44 866 530 12;
+#X obj 15 425 netsend;
+#X msg 15 263 connect localhost 3000;
+#X msg 24 403 send foo \$1;
+#X floatatom 24 376 0 0 0;
+#X msg 15 344 disconnect;
+#X msg 285 397 send foo \$1;
+#X floatatom 285 370 0 0 0;
+#X msg 268 344 disconnect;
+#X obj 268 422 netsend 1;
+#X msg 268 263 connect localhost 3001;
+#X floatatom 15 452 0 0 0;
+#X floatatom 268 449 0 0 0;
+#X text 359 422 creation argument: 0 or none for TCP \, nonzero for
+UDP;
+#X text 66 242 TCP;
+#X text 343 239 UDP;
+#X text 197 9 Netsend -- send Pd messages over a network;
+#X text 475 261 Connect to "localhost" port 3000/3001;
+#X text 373 345 Close the connection;
+#X text 325 372 Send messages to "foo" on remote machine;
+#X text 10 473 Outlet is nonzero if connection is open \, zero otherwise.
+;
+#X text 87 38 The Netsend object connects to another machine over the
+network for sending TCP ("stream") or UDP ("datagram") messages. An
+outlet reports whether the connection is open or not. A connection
+request should specify the name or IP address of the other host and
+the port number. There should be a "Netreceive" on the remote host
+with a matching port number.;
+#X obj 409 497 netreceive;
+#X text 318 497 see also:;
+#X text 607 498 updated for Pd version 0.33;
+#X text 87 150 Opt@web.fm has made compatible objects for Max so that
+Pd and Max can intercommunicate: see ftp://fals.ch/pub/pdnets/.;
+#X text 87 186 The Linux version of Pd comes with "pdsend" and "pdreceive"
+standalone programs. These haven't been tested in Windows yet (but
+the source is included in the Pd distribution.);
+#X msg 15 290 connect molloy 3000;
+#X msg 268 290 connect molloy 3001;
+#X msg 15 317 connect bug 3000;
+#X msg 268 317 connect bug 3000;
+#X connect 0 0 10 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 4 0 0 0;
+#X connect 5 0 8 0;
+#X connect 6 0 5 0;
+#X connect 7 0 8 0;
+#X connect 8 0 11 0;
+#X connect 9 0 8 0;
+#X connect 26 0 0 0;
+#X connect 27 0 8 0;
+#X connect 28 0 0 0;
+#X connect 29 0 8 0;
diff --git a/pd/doc/5.reference/noise~-help.pd b/pd/doc/5.reference/noise~-help.pd
new file mode 100644
index 00000000..cafc15c3
--- /dev/null
+++ b/pd/doc/5.reference/noise~-help.pd
@@ -0,0 +1,18 @@
+#N canvas 174 90 458 270 12;
+#X floatatom 77 178 4 0 0;
+#X obj 77 111 noise~;
+#X obj 167 149 print~;
+#X msg 167 123 bang;
+#X obj 282 89 loadbang;
+#X msg 282 114 \; pd dsp 1;
+#X obj 77 150 env~ 4096;
+#X text 67 204 RMS in dB;
+#X text 171 242 updated for Pd version 0.33;
+#X obj 20 11 noise~;
+#X text 84 11 - uniformly distributed white noise;
+#X text 38 49 the output range is -1 to 1...;
+#X connect 1 0 2 0;
+#X connect 1 0 6 0;
+#X connect 3 0 2 0;
+#X connect 4 0 5 0;
+#X connect 6 0 0 0;
diff --git a/pd/doc/5.reference/numbox2-help.pd b/pd/doc/5.reference/numbox2-help.pd
new file mode 100644
index 00000000..a26db250
--- /dev/null
+++ b/pd/doc/5.reference/numbox2-help.pd
@@ -0,0 +1,302 @@
+#N canvas 290 235 617 416 10;
+#X obj 1 1 cnv 8 100 60 empty empty numbox=nbx 20 20 1 18 -262144 -1109
+0;
+#X floatatom 38 300 9 0 0;
+#X msg 47 84 set \$1;
+#X floatatom 38 43 7 0 0;
+#X text 25 363 (c) musil@iem.kug.ac.at;
+#X text 67 376 IEM KUG;
+#X obj 38 324 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X obj 18 47 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X floatatom 47 63 7 0 0;
+#X floatatom 116 324 9 0 0;
+#X floatatom 106 42 7 0 0;
+#X floatatom 183 113 7 0 0;
+#X obj 111 249 ftom;
+#X floatatom 111 271 9 0 0;
+#X floatatom 147 244 9 0 0;
+#X floatatom 221 266 9 0 0;
+#X text 217 151 click properties to;
+#X floatatom 111 112 9 0 0;
+#X obj 111 134 mtof;
+#X text 202 65 (0.01 pixels);
+#X text 57 99 ------------------------------------------;
+#X text 57 286 --------------------------------------------;
+#X text 205 162 modify geometry \, colors \, etc.;
+#X msg 106 63 set \$1;
+#X text 188 44 shift-click & drag;
+#X text 194 54 for fine-tuning;
+#X text 195 203 UP- \, DOWN- \, LEFT- or RIGHT-key;
+#X text 193 214 for moving selected gui-objects;
+#N canvas 239 379 699 530 edit 0;
+#X obj 37 233 f;
+#X msg 15 212 bang;
+#X floatatom 53 211 3 6 88;
+#X floatatom 88 233 3 -20 37;
+#X obj 37 256 pack 0 0;
+#X text 115 233 y-label;
+#X text 81 211 x-label;
+#X obj 287 271 f;
+#X msg 265 250 bang;
+#X floatatom 303 249 3 -10 10;
+#X floatatom 338 271 3 -10 10;
+#X obj 287 294 pack 0 0;
+#X obj 299 381 f;
+#X msg 277 360 bang;
+#X floatatom 315 359 3 20 90;
+#X floatatom 350 381 3 150 200;
+#X obj 299 404 pack 0 0;
+#X text 331 249 x-delta;
+#X text 365 271 y-delta;
+#X text 343 359 x-position;
+#X text 377 381 y-position;
+#X obj 57 348 f;
+#X msg 35 327 bang;
+#X floatatom 73 326 3 0 2;
+#X floatatom 108 348 3 4 36;
+#X obj 57 371 pack 0 0;
+#X text 101 326 font;
+#X text 137 348 height;
+#X floatatom 476 188 1 0 1;
+#X text 523 401 no init;
+#X text 493 453 init value on loadbang;
+#X text 520 188 steady;
+#X obj 486 291 f;
+#X msg 464 270 bang;
+#X floatatom 502 269 4 55 440;
+#X floatatom 537 291 6 440 3520;
+#X obj 486 314 pack 0 0;
+#X text 269 469 linear / logarithmical;
+#X msg 47 158 \; goo4_rcv color \$1 \$2 \$3;
+#X msg 37 281 \; goo4_rcv label_pos \$1 \$2;
+#X msg 57 396 \; goo4_rcv label_font \$1 \$2;
+#X msg 40 442 \; goo4_rcv label blabla;
+#X msg 269 487 \; goo4_rcv lin;
+#X msg 363 486 \; goo4_rcv log;
+#X msg 299 429 \; goo4_rcv pos \$1 \$2;
+#X msg 287 319 \; goo4_rcv delta \$1 \$2;
+#X msg 475 21 \; goo4_rcv send goo4a_snd;
+#X msg 475 59 \; goo4_rcv send goo4_snd;
+#X msg 476 105 \; goo4_rcv receive goo4a_rcv;
+#X msg 476 143 \; goo4a_rcv receive goo4_rcv;
+#X msg 486 339 \; goo4_rcv range \$1 \$2;
+#X msg 502 420 \; goo4_rcv init 0;
+#X msg 503 471 \; goo4_rcv init 1;
+#X text 539 270 bottom-range-bound;
+#X text 586 292 top-range-bound;
+#X obj 286 160 f;
+#X msg 264 139 bang;
+#X floatatom 302 138 3 4 55;
+#X floatatom 337 160 3 15 73;
+#X obj 286 183 pack 0 0;
+#X msg 286 208 \; goo4_rcv size \$1 \$2;
+#X text 330 138 width;
+#X text 368 161 height;
+#X msg 41 478 \; goo4_rcv label log.freq.;
+#X msg 476 212 \; goo4_rcv steady \$1;
+#X obj 47 116 pack 0 0 0;
+#X obj 47 88 f;
+#X msg 24 40 bang;
+#X floatatom 63 38 3 0 29;
+#X floatatom 79 58 3 0 29;
+#X floatatom 112 74 3 0 29;
+#X text 91 38 background;
+#X text 106 58 front-color;
+#X text 140 75 label-color;
+#X msg 285 37 back;
+#X msg 285 57 front;
+#X msg 285 77 label;
+#X msg 247 37 bang;
+#N canvas 15 207 606 448 RGB_____________ 0;
+#X obj 97 56 inlet;
+#X obj 262 53 inlet;
+#X obj 339 55 inlet;
+#X obj 405 56 inlet;
+#X obj 97 270 bang;
+#X msg 77 295 0;
+#X msg 104 295 1;
+#X obj 146 268 bang;
+#X msg 132 295 0;
+#X msg 160 295 1;
+#X obj 196 269 bang;
+#X msg 187 295 0;
+#X msg 214 295 1;
+#X obj 265 313 spigot;
+#X obj 312 313 spigot;
+#X obj 359 313 spigot;
+#X obj 249 385 outlet;
+#X text 93 33 select;
+#X text 267 28 red;
+#X text 337 30 green;
+#X text 409 30 blue;
+#X obj 405 102 t b f;
+#X obj 339 160 +;
+#X obj 339 185 t b f;
+#X obj 339 216 +;
+#X obj 296 385 outlet;
+#X obj 343 385 outlet;
+#X obj 28 180 loadbang;
+#X obj 97 135 route back front label bang;
+#X obj 343 362 f;
+#X obj 296 361 f;
+#X obj 249 361 f;
+#X obj 262 79 * -65536;
+#X obj 339 80 * -256;
+#X obj 405 80 * -1;
+#X obj 339 247 - 1;
+#X obj 235 168 t b b b b;
+#X connect 0 0 28 0;
+#X connect 1 0 32 0;
+#X connect 2 0 33 0;
+#X connect 3 0 34 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 14 1;
+#X connect 5 0 15 1;
+#X connect 6 0 13 1;
+#X connect 7 0 8 0;
+#X connect 7 0 9 0;
+#X connect 8 0 13 1;
+#X connect 8 0 15 1;
+#X connect 9 0 14 1;
+#X connect 10 0 11 0;
+#X connect 10 0 12 0;
+#X connect 11 0 13 1;
+#X connect 11 0 14 1;
+#X connect 12 0 15 1;
+#X connect 13 0 31 1;
+#X connect 14 0 30 1;
+#X connect 15 0 29 1;
+#X connect 21 0 22 0;
+#X connect 21 1 22 1;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 23 1 24 1;
+#X connect 24 0 35 0;
+#X connect 27 0 6 0;
+#X connect 28 0 4 0;
+#X connect 28 1 7 0;
+#X connect 28 2 10 0;
+#X connect 28 3 36 0;
+#X connect 29 0 26 0;
+#X connect 30 0 25 0;
+#X connect 31 0 16 0;
+#X connect 32 0 24 0;
+#X connect 33 0 22 0;
+#X connect 34 0 21 0;
+#X connect 35 0 15 0;
+#X connect 35 0 14 0;
+#X connect 35 0 13 0;
+#X connect 36 0 31 0;
+#X connect 36 1 30 0;
+#X connect 36 2 29 0;
+#X connect 36 3 35 0;
+#X restore 285 98 pd RGB_____________;
+#X floatatom 327 67 3 0 255;
+#X floatatom 370 67 3 0 255;
+#X floatatom 413 68 3 0 255;
+#X text 34 12 preset-colors;
+#X text 296 9 RGB-colors;
+#X text 327 49 red;
+#X text 363 48 green;
+#X text 411 48 blue;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 4 1;
+#X connect 4 0 39 0;
+#X connect 7 0 11 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 1;
+#X connect 10 0 11 1;
+#X connect 11 0 45 0;
+#X connect 12 0 16 0;
+#X connect 13 0 12 0;
+#X connect 14 0 12 1;
+#X connect 15 0 16 1;
+#X connect 16 0 44 0;
+#X connect 21 0 25 0;
+#X connect 22 0 21 0;
+#X connect 23 0 21 1;
+#X connect 24 0 25 1;
+#X connect 25 0 40 0;
+#X connect 28 0 64 0;
+#X connect 32 0 36 0;
+#X connect 33 0 32 0;
+#X connect 34 0 32 1;
+#X connect 35 0 36 1;
+#X connect 36 0 50 0;
+#X connect 55 0 59 0;
+#X connect 56 0 55 0;
+#X connect 57 0 55 1;
+#X connect 58 0 59 1;
+#X connect 59 0 60 0;
+#X connect 65 0 38 0;
+#X connect 66 0 65 0;
+#X connect 67 0 66 0;
+#X connect 68 0 66 1;
+#X connect 69 0 65 1;
+#X connect 70 0 65 2;
+#X connect 74 0 78 0;
+#X connect 75 0 78 0;
+#X connect 76 0 78 0;
+#X connect 77 0 78 0;
+#X connect 78 0 65 0;
+#X connect 78 1 65 1;
+#X connect 78 2 65 2;
+#X connect 79 0 78 1;
+#X connect 80 0 78 2;
+#X connect 81 0 78 3;
+#X restore 327 48 pd edit;
+#X obj 61 345 print;
+#N canvas 276 200 290 224 once 0;
+#X obj 38 47 t b b f;
+#X msg 56 85 1;
+#X obj 31 108 f 0;
+#X obj 31 131 pack 0 0;
+#X obj 31 156 route 0;
+#X obj 38 24 inlet;
+#X obj 31 180 outlet;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 0 2 3 1;
+#X connect 1 0 2 1;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 4 0 6 0;
+#X connect 5 0 0 0;
+#X restore 61 322 pd once;
+#X obj 249 87 x_all_guis aaa bbb ccc ddd eee fff ggg hhh iii;
+#X text 218 387 updated for Pd version 0.35;
+#X text 42 388 graz \, austria 2002;
+#X text 192 13 gui-number-box:;
+#X obj 106 84 s foo13_rcv;
+#X obj 183 133 s goo14_rcv;
+#X obj 221 244 r goo14_snd;
+#X obj 116 302 r foo13_snd;
+#X obj 47 172 nbx 4 15 100 300 0 0 foo13_snd foo13_rcv empty 45 7 192
+10 -225280 -1109 -1 100 256;
+#X obj 111 200 nbx 5 18 55 3520 1 0 goo14_snd goo14_rcv log.freq. 45
+-10 192 14 -261681 -260818 -90881 55 72;
+#X obj 464 114 nbx 5 14 -1e+37 1e+37 0 0 hhh hhh empty 45 7 192 10
+-262144 -1 -1 0 256;
+#X connect 1 0 6 0;
+#X connect 2 0 39 0;
+#X connect 3 0 39 0;
+#X connect 7 0 39 0;
+#X connect 8 0 2 0;
+#X connect 10 0 23 0;
+#X connect 11 0 36 0;
+#X connect 12 0 13 0;
+#X connect 17 0 18 0;
+#X connect 18 0 40 0;
+#X connect 23 0 35 0;
+#X connect 30 0 29 0;
+#X connect 37 0 15 0;
+#X connect 38 0 9 0;
+#X connect 39 0 30 0;
+#X connect 39 0 1 0;
+#X connect 40 0 12 0;
+#X connect 40 0 14 0;
diff --git a/pd/doc/5.reference/openpanel-help.pd b/pd/doc/5.reference/openpanel-help.pd
new file mode 100644
index 00000000..15e5d244
--- /dev/null
+++ b/pd/doc/5.reference/openpanel-help.pd
@@ -0,0 +1,11 @@
+#N canvas 35 31 585 245 12;
+#X obj 128 136 openpanel;
+#X msg 128 108 bang;
+#X obj 128 161 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 connect 0 0 2 0;
+#X connect 1 0 0 0;
diff --git a/pd/doc/5.reference/operators-help.pd b/pd/doc/5.reference/operators-help.pd
new file mode 100644
index 00000000..64b47e4d
--- /dev/null
+++ b/pd/doc/5.reference/operators-help.pd
@@ -0,0 +1,31 @@
+#N canvas 52 109 635 355 12;
+#X obj 29 172 +;
+#X floatatom 41 113 0 0 0;
+#X floatatom 29 197 0 0 0;
+#X floatatom 51 143 0 0 0;
+#X msg 29 82 bang;
+#X obj 44 6 +;
+#X text 27 307 see also:;
+#X obj 186 314 +~;
+#X text 79 5 (etc.) -- ARITHMETIC;
+#X text 72 88 Bang outputs sum;
+#X text 79 112 Numbers in left inlet add and output sum;
+#X text 93 142 Numbers in right inlet only change the inlet's value;
+#X obj 113 314 trigger;
+#X text 348 325 last updated for version 0.33;
+#X text 93 189 You can supply a creation argument to initialize the right inlet:;
+#X text 29 29 The floating point binary operators are + \, - \, * \, / \, pow \, max \, and min. Note that pow only works for nonnegative mantissas.;
+#X floatatom 101 225 0 0 0;
+#X floatatom 101 275 0 0 0;
+#X obj 101 250 pow -1;
+#X floatatom 179 225 0 0 0;
+#X floatatom 179 275 0 0 0;
+#X obj 179 250 min 20;
+#X connect 0 0 2 0;
+#X connect 1 0 0 0;
+#X connect 3 0 0 1;
+#X connect 4 0 0 0;
+#X connect 16 0 18 0;
+#X connect 18 0 17 0;
+#X connect 19 0 21 0;
+#X connect 21 0 20 0;
diff --git a/pd/doc/5.reference/osc~-help.pd b/pd/doc/5.reference/osc~-help.pd
new file mode 100644
index 00000000..2bd5f0df
--- /dev/null
+++ b/pd/doc/5.reference/osc~-help.pd
@@ -0,0 +1,58 @@
+#N canvas 85 32 811 508 12;
+#X obj 252 320 dac~ 1;
+#X obj 252 292 *~;
+#X floatatom 156 115 0 0 0;
+#X obj 276 264 line~;
+#X msg 276 208 0.1 100;
+#X msg 295 233 0 100;
+#X text 347 203 on;
+#X text 344 232 off;
+#X text 333 261 envelope;
+#X text 333 274 generator;
+#X text 260 183 amplitude controls:;
+#X text 250 344 audio output;
+#X text 424 426 see also:;
+#X obj 580 428 cos~;
+#X obj 629 428 tabread4~;
+#X obj 68 14 osc~;
+#X text 142 16 - cosine wave oscillator;
+#X obj 126 294 metro 500;
+#X obj 126 269 r metro;
+#X text 88 344 graph the output;
+#X obj 510 427 phasor~;
+#X msg 571 79 \; metro 0;
+#X msg 570 20 \; pd dsp 1 \; metro 1;
+#X floatatom 637 245 0 0 0;
+#X obj 637 275 sig~;
+#X text 522 266 convert to;
+#X text 512 282 audio signal;
+#X text 518 305 oscillator;
+#X text 479 243 frequency control;
+#X obj 637 306 osc~;
+#X text 3 120 change frequency;
+#X text 244 145 <-- creation argument sets initial frequency;
+#X text 231 123 v-- inlet resets phase;
+#X graph graph1 0 -1 100 1 94 388 294 488;
+#X array array99 100 float;
+#X pop;
+#X text 16 39 The osc~ object outputs a cosine wave. If no argument is supplied \, the input is taken to be an audio signal. With a floating-point argument \, osc~ takes floating-point messages to change frequency.;
+#X text 510 336 invoked without argument to;
+#X text 512 360 specify audio signal input;
+#X text 2 105 incoming numbers;
+#X obj 89 322 tabwrite~ array99;
+#X obj 156 144 osc~ 1000;
+#X text 546 480 updated for Pd version 0.33;
+#X text 655 39 <-Click to start;
+#X text 648 88 <-Click to stop;
+#X connect 1 0 0 0;
+#X connect 2 0 39 0;
+#X connect 3 0 1 1;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 17 0 38 0;
+#X connect 18 0 17 0;
+#X connect 18 0 17 0;
+#X connect 23 0 24 0;
+#X connect 24 0 29 0;
+#X connect 39 0 1 0;
+#X connect 39 0 38 0;
diff --git a/pd/doc/5.reference/otherbinops-help.pd b/pd/doc/5.reference/otherbinops-help.pd
new file mode 100644
index 00000000..3f310818
--- /dev/null
+++ b/pd/doc/5.reference/otherbinops-help.pd
@@ -0,0 +1,90 @@
+#N canvas 20 43 698 447 12;
+#X floatatom 524 338 0 0 0;
+#X floatatom 353 338 0 0 0;
+#X floatatom 298 338 0 0 0;
+#X floatatom 413 338 0 0 0;
+#X floatatom 467 338 0 0 0;
+#X obj 524 311 <;
+#X obj 298 262 r left;
+#X obj 540 267 r right;
+#X floatatom 71 335 0 0 0;
+#X floatatom 19 334 0 0 0;
+#X floatatom 119 335 0 0 0;
+#X floatatom 163 334 0 0 0;
+#X obj 16 45 &;
+#X obj 66 45 |;
+#X obj 118 45 &&;
+#X obj 169 45 ||;
+#X obj 19 307 &;
+#X obj 71 308 |;
+#X obj 119 308 &&;
+#X obj 163 307 ||;
+#X text 13 73 The Logical Operators;
+#X obj 19 266 r left;
+#X obj 218 266 r right;
+#X obj 12 118 >;
+#X obj 61 118 >=;
+#X obj 114 118 ==;
+#X obj 215 119 <=;
+#X obj 262 119 <;
+#X text 11 153 The Relational Operators;
+#X obj 298 312 >;
+#X obj 353 312 >=;
+#X obj 413 312 ==;
+#X obj 467 312 <=;
+#X text 16 190 relational output is logical- and negative numbers BAD
+in bitwise logical operators. These operators as defined by C programming
+language. (inputs and outputs are converted to and from floating point).
+;
+#X floatatom 410 65 0 0 0;
+#X obj 410 92 s left;
+#X floatatom 481 66 0 0 0;
+#X obj 481 94 t b f;
+#X obj 481 122 s left;
+#X obj 541 122 s right;
+#X obj 166 118 !=;
+#X text 377 42 set left and right inputs here;
+#X floatatom 202 335 0 0 0;
+#X floatatom 246 334 0 0 0;
+#X obj 208 46 <<;
+#X obj 259 46 >>;
+#X obj 202 308 <<;
+#X obj 246 307 >>;
+#X text 421 383 last updated for version 0.32;
+#X connect 5 0 0 0;
+#X connect 6 0 29 0;
+#X connect 6 0 30 0;
+#X connect 6 0 31 0;
+#X connect 6 0 32 0;
+#X connect 6 0 5 0;
+#X connect 7 0 29 1;
+#X connect 7 0 30 1;
+#X connect 7 0 31 1;
+#X connect 7 0 32 1;
+#X connect 7 0 5 1;
+#X connect 16 0 9 0;
+#X connect 17 0 8 0;
+#X connect 18 0 10 0;
+#X connect 19 0 11 0;
+#X connect 21 0 16 0;
+#X connect 21 0 17 0;
+#X connect 21 0 18 0;
+#X connect 21 0 19 0;
+#X connect 21 0 46 0;
+#X connect 21 0 47 0;
+#X connect 22 0 19 1;
+#X connect 22 0 18 1;
+#X connect 22 0 17 1;
+#X connect 22 0 16 1;
+#X connect 22 0 47 1;
+#X connect 22 0 46 1;
+#X connect 29 0 2 0;
+#X connect 30 0 1 0;
+#X connect 31 0 3 0;
+#X connect 32 0 4 0;
+#X connect 34 0 35 0;
+#X connect 36 0 37 0;
+#X connect 37 0 38 0;
+#X connect 37 1 39 0;
+#X connect 46 0 42 0;
+#X connect 47 0 43 0;
diff --git a/pd/doc/5.reference/pack-help.pd b/pd/doc/5.reference/pack-help.pd
new file mode 100644
index 00000000..c979d480
--- /dev/null
+++ b/pd/doc/5.reference/pack-help.pd
@@ -0,0 +1,37 @@
+#N canvas 14 8 809 354 12;
+#X floatatom 19 86 0 0 0;
+#X msg 29 115 bang;
+#X floatatom 49 138 0 0 0;
+#X floatatom 188 138 0 0 0;
+#X obj 19 254 print;
+#X msg 86 138 symbol cat;
+#X obj 82 9 pack;
+#X text 28 319 See also;
+#X obj 106 321 unpack;
+#X text 14 34 The pack object takes a series of inputs and outputs
+a concatenated list. The number of creation arguments determines the
+number of inlets.;
+#X text 60 85 <-- number in first inlet generates output;
+#X text 70 114 <-- bang generates output without resetting first value
+;
+#X text 226 135 <-- numbers and symbols in the corresponding inlets
+change the values without causing output (see "trigger" for a way to
+change this behavior.);
+#X text 250 187 <-- as with any Pd object \, you can send a list whose
+atoms are automatically distributed to the corresponding inlets.;
+#X msg 175 190 1 2 dog;
+#X obj 167 321 trigger;
+#X obj 19 227 pack 100 0 s 0;
+#X text 121 9 - combine several atoms into one message;
+#X text 155 226 <-- creation arguments specify the number of inlets
+and their types: a number make a numeric outlet (and initializes the
+value). A symbol argument can start with "s" \, "f" \, or "p" to specify
+a "symbol" \, "float" (number) \, or pointer outlet.;
+#X text 538 331 updated for Pd version 0.34;
+#X connect 0 0 16 0;
+#X connect 1 0 16 0;
+#X connect 2 0 16 1;
+#X connect 3 0 16 3;
+#X connect 5 0 16 2;
+#X connect 14 0 16 0;
+#X connect 16 0 4 0;
diff --git a/pd/doc/5.reference/pd-help.pd b/pd/doc/5.reference/pd-help.pd
new file mode 100644
index 00000000..f7db8f66
--- /dev/null
+++ b/pd/doc/5.reference/pd-help.pd
@@ -0,0 +1,52 @@
+#N canvas 32 130 677 385 12;
+#N canvas 0 0 600 400 /SUBPATCH/ 0;
+#X restore 59 10 pd;
+#X text 88 12 - subpatch;
+#X obj 218 10 inlet;
+#X text 263 10 - control inlet;
+#X obj 442 11 inlet~;
+#X text 494 12 - audio inlet;
+#X obj 215 39 outlet;
+#X text 265 39 - control outlet;
+#X obj 435 40 outlet~;
+#X text 494 40 - audio outlet;
+#X text 37 74 Type "pd" into an object box to make a subpatch. When
+in run mode you can click on the object to open the subpatch. You can
+name the subpatch with an argument:;
+#N canvas 0 0 600 396 my-subpatch 0;
+#X restore 133 131 pd my-subpatch;
+#N canvas 0 0 600 392 my-subpatch-with-inlets-and-outlets 0;
+#X obj 68 126 inlet;
+#X text 20 96 control inlet for receiving messages;
+#X floatatom 68 154 0 0 0;
+#X floatatom 71 255 0 0 0;
+#X obj 71 287 outlet;
+#X text 35 225 control outlet for sending message;
+#X obj 403 121 inlet~;
+#X obj 403 172 print~;
+#X msg 418 146 bang;
+#X obj 402 314 outlet~;
+#X obj 402 288 sig~ 34;
+#X connect 0 0 2 0;
+#X connect 3 0 4 0;
+#X connect 6 0 7 0;
+#X connect 8 0 7 0;
+#X connect 10 0 9 0;
+#X restore 86 272 pd my-subpatch-with-inlets-and-outlets;
+#X text 55 174 and you can put inlets and outlets by making "inlet"
+objects \, etc \, in the subpatch (open the patch below to see them.)
+;
+#X obj 423 322 print~;
+#X msg 362 294 bang;
+#X obj 422 243 sig~ 12;
+#X floatatom 86 246 0 0 0;
+#X floatatom 86 298 0 0 0;
+#X text 441 272 (check that audio is on);
+#X text 52 221 messages in and out;
+#X text 392 220 audio in and out;
+#X text 391 351 updated for Pd version 0.26;
+#X connect 12 0 18 0;
+#X connect 12 1 14 0;
+#X connect 15 0 14 0;
+#X connect 16 0 12 1;
+#X connect 17 0 12 0;
diff --git a/pd/doc/5.reference/phasor~-help.pd b/pd/doc/5.reference/phasor~-help.pd
new file mode 100644
index 00000000..2da01cf9
--- /dev/null
+++ b/pd/doc/5.reference/phasor~-help.pd
@@ -0,0 +1,36 @@
+#N canvas 5 31 889 373 12;
+#X graph graph1 0 1 100 -1 67 250 267 350;
+#X array array99 100 float;
+#X pop;
+#X obj 29 181 metro 500;
+#X obj 13 126 phasor~;
+#X floatatom 13 76 0 0 0;
+#X obj 57 12 phasor~;
+#X obj 29 156 r metro;
+#X obj 13 100 sig~ 890;
+#X text 78 75 <-- specify frequency;
+#X text 92 98 <-- convert it to audio signal;
+#X msg 409 75 \; metro 0;
+#X msg 405 18 \; pd dsp 1 \; metro 1;
+#X text 494 32 <-- Click to start;
+#X text 479 79 <-- Click to stop;
+#X text 129 14 - sawtooth generator;
+#X text 170 207 <-- graph the output;
+#X text 82 128 <-- right inlet resets phase;
+#X obj 425 227 phasor~ 440;
+#X floatatom 425 203 0 0 0;
+#X text 348 118 The phasor~ object outputs a sawtooth signal \, traditionally used for table lookup via cos~ or tabread4~. If no argument is supplied \, the input is taken to be an audio signal \; with a floating-point argument \, phasor~ takes floating-point messages to change frequency.;
+#X text 294 246 Invoked above with argument for non-signal input. Incoming messages override the initial value.;
+#X text 311 301 see also:;
+#X obj 396 301 osc~;
+#X obj 439 301 cos~;
+#X obj 481 301 tabread4~;
+#X text 627 345 updated for Pd version 0.33;
+#X obj 13 205 tabwrite~ array99;
+#X connect 1 0 25 0;
+#X connect 2 0 25 0;
+#X connect 3 0 6 0;
+#X connect 5 0 1 0;
+#X connect 5 0 1 0;
+#X connect 6 0 2 0;
+#X connect 17 0 16 0;
diff --git a/pd/doc/5.reference/pipe-help.pd b/pd/doc/5.reference/pipe-help.pd
new file mode 100644
index 00000000..272057ed
--- /dev/null
+++ b/pd/doc/5.reference/pipe-help.pd
@@ -0,0 +1,41 @@
+#N canvas 99 89 737 480 12;
+#X floatatom 52 127 0 0 0;
+#X floatatom 127 227 0 0 0;
+#X floatatom 52 284 0 0 0;
+#X floatatom 544 281 0 0 0;
+#X floatatom 535 392 0 0 0;
+#X obj 534 364 pipe 5 6 7 1000;
+#X obj 543 307 t f f f;
+#X obj 563 338 + 1;
+#X obj 597 337 + 2;
+#X floatatom 590 390 0 0 0;
+#X floatatom 658 391 0 0 0;
+#X text 32 433 see also:;
+#X text 129 13 pipe -- message "delay line";
+#X obj 52 253 pipe 2000;
+#X text 91 125 numbers to store and output later;
+#X text 117 148 output all stored messages immediately;
+#X msg 63 152 flush;
+#X msg 65 180 clear;
+#X text 113 180 forget all stored messages;
+#X text 91 286 delayed output;
+#X obj 116 435 delay;
+#X obj 167 435 timer;
+#X text 51 42 The Pipe object stores a sequence of messages and outputs them after a specified delay time in miliseconds. You can change the delay time as you wish. The outputs are sorted automatically.;
+#X text 140 254 creation argument initializes delay time;
+#X text 163 228 set delay time;
+#X text 487 449 updated for Pd version 0.33;
+#X text 21 330 You can specify compound messages (lists) by adding arguments which set their type and initial value as in "pack." In this case the delay time comes last and is changed by the last inlet. You can also pack symbols and pointers but this feature is UNTESTED.;
+#X connect 0 0 13 0;
+#X connect 1 0 13 1;
+#X connect 3 0 6 0;
+#X connect 5 0 4 0;
+#X connect 5 1 9 0;
+#X connect 5 2 10 0;
+#X connect 6 0 5 0;
+#X connect 6 1 7 0;
+#X connect 6 2 8 0;
+#X connect 7 0 5 1;
+#X connect 8 0 5 2;
+#X connect 13 0 2 0;
+#X connect 16 0 13 0;
diff --git a/pd/doc/5.reference/plot-help.pd b/pd/doc/5.reference/plot-help.pd
new file mode 100644
index 00000000..2070ed69
--- /dev/null
+++ b/pd/doc/5.reference/plot-help.pd
@@ -0,0 +1,58 @@
+#N struct help-plot-template float x float y array array1 help-plot-array1-template
+array array2 help-plot-array2-template array array3 help-plot-array3-template
+;
+#N struct help-plot-array1-template float y;
+#N struct help-plot-array2-template float x float y;
+#N struct help-plot-array3-template float y float w;
+#N canvas 398 0 516 229 12;
+#N canvas 173 285 626 539 help-plot-template 1;
+#X text 29 34 creation arguments:;
+#X text 48 71 - RGB color (0=black \, 999=white \, 900=red \, 90=green
+\, 9=blue \, 555=grey \, etc.);
+#X text 47 52 - OPTIONAL word "curve" to specify bezier;
+#X text 46 98 - line width;
+#X text 46 114 - relative x and y location;
+#X text 47 130 - x spacing;
+#X obj 39 217 plot curve array2 70 3 100 0;
+#X obj 30 308 plot curve array3 9 1 120 50 20;
+#X obj 45 12 plot array1 500 1 10 15 20;
+#X text 29 147 This first example plots the red trace (500) \, width
+1 \, at point (10 \, 15) \, with horizontal spacing 20 The black diamonds
+come from the template of the array1 element itself.;
+#X text 62 239 This is the green spiral (color 70 \, line width 3 \,
+location (100 \, 0). Since the template for array2 contains an "x"
+cariable \, play ignores x spacing requests and takes x from the data
+itself.;
+#X text 50 328 If a "w" variable is present in the template as for
+array3 \, it is added to the line width.;
+#X obj 27 501 filledpolygon 509 509 0 -10 -10 10 -10 10 10 -10 10;
+#X text 27 454 To see the data itself \, select "properties" for the
+scalar by right clicking on the purple square.;
+#X obj 24 387 struct help-plot-template float x float y array array1
+help-plot-array1-template array array2 help-plot-array2-template array
+array3 help-plot-array3-template;
+#X text 33 366 here's the "struct" for all this:;
+#X restore 243 78 pd help-plot-template;
+#N canvas 196 292 273 120 help-plot-array1-template 0;
+#X obj 30 71 filledpolygon 0 0 0 -5 0 0 5 5 0 0 -5;
+#X obj 32 27 template float y;
+#X restore 242 101 pd help-plot-array1-template;
+#N canvas 161 163 273 120 help-plot-array2-template 0;
+#X obj 32 26 template float x float y;
+#X restore 243 123 pd help-plot-array2-template;
+#N canvas 0 0 411 207 help-plot-data 1;
+#X scalar help-plot-template 39 73 \; 0 \; 20 \; 0 \; 30 \; 0 \; \;
+0 0 \; 0 10 \; 20 0 \; 0 -30 \; -40 0 \; 0 50 \; 60 0 \; \; 0 0 \;
+10 10 \; 0 10 \; 0 1 \; 20 1 \; 20 10 \; 20 1 \; \;;
+#X restore 242 57 pd help-plot-data;
+#X text 23 139 see also:;
+#X obj 30 184 drawnumber;
+#X obj 29 163 template;
+#X obj 35 22 plot;
+#X text 87 21 -- draw array elements of scalars;
+#X obj 29 206 drawpolygon;
+#N canvas 161 163 273 120 help-plot-array3-template 0;
+#X obj 43 32 template float y float w;
+#X restore 242 144 pd help-plot-array3-template;
+#X text 8 79 explanation is in here-->;
+#X text 264 203 updated for Pd version 0.35;
diff --git a/pd/doc/5.reference/pointer-help.pd b/pd/doc/5.reference/pointer-help.pd
new file mode 100644
index 00000000..96a22ff1
--- /dev/null
+++ b/pd/doc/5.reference/pointer-help.pd
@@ -0,0 +1,79 @@
+#N struct template2 float x float y;
+#N struct template1 float x float y float z;
+#N canvas 223 0 715 654 12;
+#X text 20 572 see also:;
+#X obj 21 10 pointer;
+#X text 95 10 -- remember the location of a scalar in a list;
+#N canvas 164 72 425 146 help-pointer-template1 0;
+#X obj 18 81 filledpolygon z 0 1 0 0 20 0 20 30 0 30;
+#X obj 60 21 struct template1 float x float y float z;
+#X restore 327 386 pd help-pointer-template1;
+#N canvas 26 456 510 145 help-pointer-template2 0;
+#X obj 52 78 filledcurve 909 0 0 0 0 30 30 60 0 30 -30 0 0;
+#X obj 60 21 struct template2 float x float y;
+#X restore 327 409 pd help-pointer-template2;
+#X obj 23 592 get;
+#X obj 56 592 set;
+#X obj 91 592 append;
+#X obj 152 592 getsize;
+#X obj 220 593 setsize;
+#X obj 290 593 element;
+#X obj 23 617 sublist;
+#N canvas 0 0 312 185 help-pointer-data 1;
+#X scalar template2 20 97 \;;
+#X scalar template1 80 17 90 \;;
+#X scalar template1 120 117 9 \;;
+#X restore 327 364 pd help-pointer-data;
+#X obj 54 360 pointer;
+#X msg 54 231 traverse pd-help-pointer-data;
+#X msg 67 255 bang;
+#X text 109 256 outputs current value;
+#X msg 69 281 next;
+#X obj 54 385 print out1;
+#X obj 167 371 print out2;
+#X text 119 274 moves forward one item and outputs pointer \; if we
+reach the end \, a "bang" goes to out2.;
+#X text 16 426 Optional arguments to pointer allow you to select according
+to the class of the scalar being output:;
+#X msg 74 487 next;
+#X msg 60 464 traverse pd-help-pointer-data;
+#X obj 60 515 pointer help-pointer-template1 help-pointer-template2
+;
+#X obj 60 541 print template1;
+#X obj 198 541 print template2;
+#X obj 338 541 print other;
+#X obj 441 541 print bangout;
+#X text 333 232 sets to the "head" of the list;
+#X text 29 34 "Pointer" is a storage object like "float" \, except
+that the thing stored is the location of a scalar somewhere. You can
+send a pointer a value (perhaps from another "pointer" object). The
+right inlet takes pointers and simply stores them. A bang in the left
+outputs the pointer \, and a pointer in the left both sets and outputs
+the value.;
+#X text 29 132 The value of a pointer can either indicate a real scalar
+\, or else the "head" (before the first element) of the list. This
+allows you to point to an empty list \, and also \, to "append" a scalar
+to the beginning of the list.;
+#X text 29 191 Pointers are "safe": if you delete a scalar pointers
+to it are marked invalid.;
+#X text 166 391 bang at end;
+#X text 167 407 of list;
+#X text 53 405 output;
+#X text 445 617 updated for Pd version 0.35;
+#X obj 92 616 struct;
+#X msg 71 307 vnext 1;
+#X text 149 308 "vnext" gets the next object (if arg is 0) or the next
+selected object (if arg is 1 -- but the window must be visible for
+the "selection" to make sense).;
+#X connect 13 0 18 0;
+#X connect 13 1 19 0;
+#X connect 14 0 13 0;
+#X connect 15 0 13 0;
+#X connect 17 0 13 0;
+#X connect 22 0 24 0;
+#X connect 23 0 24 0;
+#X connect 24 0 25 0;
+#X connect 24 1 26 0;
+#X connect 24 2 27 0;
+#X connect 24 3 28 0;
+#X connect 38 0 13 0;
diff --git a/pd/doc/5.reference/poly-help.pd b/pd/doc/5.reference/poly-help.pd
new file mode 100644
index 00000000..0b34f99e
--- /dev/null
+++ b/pd/doc/5.reference/poly-help.pd
@@ -0,0 +1,30 @@
+#N canvas 0 0 600 496 12;
+#X text 155 228 <-- scroll to change the value of delay in milliseconds.;
+#X text 406 383 updated for Pd version 0.25;
+#X text 42 383 see also:;
+#X obj 66 15 poly;
+#X text 101 14 - MIDI-STYLE POLYPHONIC VOICE ALLOCATOR;
+#X text 12 42 The poly object takes a stream of pitch/velocity pairs and outputs triples containing voice number \, pitch and velocity. You can pack the output and use the route object to route messages among a bank of voices depending on the first outlet. Poly can be configured to do voice stealing or not (the default.);
+#X obj 110 384 route;
+#X obj 154 384 makenote;
+#X obj 52 254 poly 4 1;
+#X text 134 253 <-- first argument \, number of voices \; second argument selects voice stealing;
+#X msg 52 168 60 64;
+#X msg 103 168 60 0;
+#X msg 147 168 62 64;
+#X msg 194 168 62 0;
+#X obj 52 280 pack 0 0 0;
+#X obj 52 306 print;
+#X text 97 305 Output is in the printout window.;
+#X msg 254 177 stop;
+#X msg 296 177 clear;
+#X connect 8 0 14 0;
+#X connect 8 1 14 1;
+#X connect 8 2 14 2;
+#X connect 10 0 8 0;
+#X connect 11 0 8 0;
+#X connect 12 0 8 0;
+#X connect 13 0 8 0;
+#X connect 14 0 15 0;
+#X connect 17 0 8 0;
+#X connect 18 0 8 0;
diff --git a/pd/doc/5.reference/print-help.pd b/pd/doc/5.reference/print-help.pd
new file mode 100644
index 00000000..50af069a
--- /dev/null
+++ b/pd/doc/5.reference/print-help.pd
@@ -0,0 +1,13 @@
+#N canvas 349 65 615 247 12;
+#X msg 102 52 walk the dog;
+#X msg 29 51 bang;
+#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
+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 connect 0 0 3 0;
+#X connect 1 0 3 0;
+#X connect 2 0 3 0;
diff --git a/pd/doc/5.reference/print~-help.pd b/pd/doc/5.reference/print~-help.pd
new file mode 100644
index 00000000..b3a9c429
--- /dev/null
+++ b/pd/doc/5.reference/print~-help.pd
@@ -0,0 +1,18 @@
+#N canvas 118 333 531 212 10;
+#X msg 74 143 2;
+#X msg 455 77 \; pd dsp 0;
+#X msg 454 40 \; pd dsp 1;
+#X obj 62 177 print~;
+#X msg 74 118 bang;
+#X obj 62 92 phasor~ 1000;
+#X text 122 119 bang prints one vector;
+#X obj 454 18 loadbang;
+#X text 109 142 print two or more successive vectors;
+#X obj 32 12 print~;
+#X text 85 12 - print out raw values of a signal;
+#X text 301 171 Updated for Pd version 0.33;
+#X text 19 44 The print~ object takes a signal input and prints one or more vectors out when you send it a bang or a number. By default a vector is 64 samples.;
+#X connect 0 0 3 0;
+#X connect 4 0 3 0;
+#X connect 5 0 3 0;
+#X connect 7 0 2 0;
diff --git a/pd/doc/5.reference/qlist-help.pd b/pd/doc/5.reference/qlist-help.pd
new file mode 100644
index 00000000..a5b2a574
--- /dev/null
+++ b/pd/doc/5.reference/qlist-help.pd
@@ -0,0 +1,76 @@
+#N canvas 7 31 1178 587 12;
+#X obj 546 328 qlist;
+#X msg 592 110 rewind;
+#X msg 591 135 next;
+#X floatatom 546 382 0 0 0;
+#X msg 593 54 bang;
+#X obj 441 515 r this;
+#X obj 544 515 r that;
+#X obj 441 544 print this;
+#X obj 544 544 print that;
+#X obj 560 356 print done;
+#X msg 593 80 tempo 1;
+#X text 18 51 The qlist object reads text files containing time-tagged
+Pd messages. You can have them sequenced automatically (by sending
+a "bang" message \, possibly changing speed via "tempo" messages) or
+manually via the "rewind" and "next" messages.;
+#X text 15 136 To run the qlist automatically \, send it a "read" message
+(the filename is relative to the directory the patch is in) and later
+a "bang." Messages in the file are separated by semicolons. Optional
+leading numbers are delay times in milliseconds. If the tempo is diffrerent
+from 1 the messages are sent faster or slower accordingly. Messages
+should start with a symbol giving the destination object. In the file
+"qlist.q" used here \, the messages go to objects "this" and "that"
+which are receives below.;
+#X text 17 281 To run it manually \, send "rewind" followed by "next".
+All messages not preceeded by numbers are sent. As soon as a message
+starting with one or more numbers is encountered \, the numbers are
+output as a list. There are many ways you could design a sequencer
+around this.;
+#X text 668 48 sequence automatically;
+#X text 670 79 set relative tempo;
+#X text 668 105 go to beginning (and stop);
+#X text 668 132 single-step forward;
+#X text 713 273 read a file;
+#X text 777 300 write one;
+#X text 552 404 This outlet gets a list of leading numbers for the
+next message \, for you to use in designing your own sequencer.;
+#X msg 586 274 read qlist.txt;
+#X msg 586 300 write /tmp/qlist.txt;
+#X text 21 493 see also:;
+#X obj 97 493 textfile;
+#X text 22 362 You can also record textual messages and save them to
+a file. Send "clear" to empty the qlist and "add" to add messages (terminated
+with semicolons.) The message \, "add2" adds a list of atoms without
+finishing with a semicolon in case you want to make variable-length
+messages.;
+#X msg 589 190 clear;
+#X msg 589 216 add 500 this is another message;
+#X msg 590 242 add2 that;
+#X text 666 187 empty the qlist;
+#X text 882 217 add a message to a qlist;
+#X text 683 240 add a message to a qlist but don't terminate it;
+#X text 653 341 This outlet gets a bang when you hit the end of the
+sequence. In the file "qlist.txt" the end is delayed 1000 milliseconds
+after the last message.;
+#X text 379 470 These receives are invoked in the file "qlist.txt"
+in this directory.;
+#X obj 71 13 qlist;
+#X text 132 15 - text-based sequencer;
+#X text 668 158 single-step forward SUPRESSING MESSAGE-SENDING;
+#X msg 591 161 next 1;
+#X text 921 558 updated for Pd version 0.35;
+#X connect 0 0 3 0;
+#X connect 0 1 9 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 4 0 0 0;
+#X connect 5 0 7 0;
+#X connect 6 0 8 0;
+#X connect 10 0 0 0;
+#X connect 21 0 0 0;
+#X connect 22 0 0 0;
+#X connect 26 0 0 0;
+#X connect 27 0 0 0;
+#X connect 28 0 0 0;
+#X connect 37 0 0 0;
diff --git a/pd/doc/5.reference/random-help.pd b/pd/doc/5.reference/random-help.pd
new file mode 100644
index 00000000..b792325c
--- /dev/null
+++ b/pd/doc/5.reference/random-help.pd
@@ -0,0 +1,19 @@
+#N canvas 0 0 630 421 12;
+#X msg 40 212 bang;
+#X obj 40 287 random 5;
+#X floatatom 83 261 0 0 0;
+#X floatatom 40 312 0 0 0;
+#X msg 50 236 seed 123;
+#X text 92 210 bang for output;
+#X text 132 236 message to set the seed;
+#X text 116 259 inlet to reset the range;
+#X text 119 286 argument to initialize the range;
+#X text 378 337 updated for Pd version 0.33;
+#X text 11 46 Random outputs pseudorandom integers from 0 to N-1 where N is the creation argument (5 in the example below.) You can specify a seed if you wish. Seeds are kept locally so that if two Randoms are seeded the same they will have the same output (or indeed you can seed the same one twice to repeat the output.);
+#X text 12 139 On the other hand \, if you don't supply a seed each instance of random gets its own seed. WARNING: nothing is known about the quality of teh pseudorandom number generator. It isn't any standard one!;
+#X obj 20 11 random;
+#X text 84 11 - pseudorandom integers;
+#X connect 0 0 1 0;
+#X connect 1 0 3 0;
+#X connect 2 0 1 1;
+#X connect 4 0 1 0;
diff --git a/pd/doc/5.reference/readsf~-help.pd b/pd/doc/5.reference/readsf~-help.pd
new file mode 100644
index 00000000..29c90988
--- /dev/null
+++ b/pd/doc/5.reference/readsf~-help.pd
@@ -0,0 +1,63 @@
+#N canvas 113 157 888 480 12;
+#X msg 561 8 \; pd dsp 1;
+#X msg 39 240 1;
+#X msg 39 261 0;
+#X obj 516 359 print didit;
+#X obj 139 361 env~ 16384;
+#X floatatom 139 380 0 0 0 0 - - -;
+#X msg 40 283 print;
+#X obj 20 393 dac~;
+#X obj 233 360 env~ 16384;
+#X floatatom 233 379 0 0 0 0 - - -;
+#X obj 30 308 readsf~ 4 1e+06;
+#X obj 327 359 env~ 16384;
+#X floatatom 327 378 0 0 0 0 - - -;
+#X obj 421 359 env~ 16384;
+#X floatatom 421 379 0 0 0 0 - - -;
+#X msg 26 210 open ../sound/bell.aiff 0 200 4 2 b;
+#X obj 80 362 *~ 0.1;
+#X obj 21 363 *~ 0.1;
+#X text 40 7 READSF~ - read a soundfile;
+#X msg 26 189 open ../sound/bell.aiff;
+#X text 185 296 optional arguments: number of channels \; buffer size
+per channnel in bytes.;
+#X text 548 341 when the soundfile is done.;
+#X text 547 327 last outlet gives a "bang";
+#X text 359 186 Open takes a filename \, an onset in sample frames
+\, and \, as an override \, you may also supply a header size to skip
+\, a number of channels \, bytes per channel \, and endianness.;
+#X text 36 24 The readsf~ object reads a soundfile into its signal
+outputs. You must open the soundfile in advance (a couple of seconds
+before you'll need it) using the "open" message. The object immediately
+starts reading from the file \, but output will only appear after you
+send a "1" to start playback. A "0" stops it.;
+#X text 33 121 The wave \, aiff \, and nextstep formats are parsed
+automatically \, although only 2- 3- and 4- byte samples are accepted
+(4 bytes implies floating point and is not available in aiff format.)
+;
+#X text 647 450 Updated for version 0.37;
+#X obj 116 452 soundfiler;
+#X text 24 452 see also:;
+#X obj 216 452 readsf~;
+#X text 94 238 1 starts playback;
+#X text 97 261 0 stops it;
+#X connect 1 0 10 0;
+#X connect 2 0 10 0;
+#X connect 4 0 5 0;
+#X connect 6 0 10 0;
+#X connect 8 0 9 0;
+#X connect 10 0 4 0;
+#X connect 10 0 17 0;
+#X connect 10 1 8 0;
+#X connect 10 1 16 0;
+#X connect 10 2 11 0;
+#X connect 10 2 16 0;
+#X connect 10 3 13 0;
+#X connect 10 3 17 0;
+#X connect 10 4 3 0;
+#X connect 11 0 12 0;
+#X connect 13 0 14 0;
+#X connect 15 0 10 0;
+#X connect 16 0 7 1;
+#X connect 17 0 7 0;
+#X connect 19 0 10 0;
diff --git a/pd/doc/5.reference/realtime-help.pd b/pd/doc/5.reference/realtime-help.pd
new file mode 100644
index 00000000..60fcffaa
--- /dev/null
+++ b/pd/doc/5.reference/realtime-help.pd
@@ -0,0 +1,15 @@
+#N canvas 156 202 565 269 12;
+#X msg 73 146 bang;
+#X msg 30 115 bang;
+#X floatatom 30 206 0 0 0;
+#X text 71 113 Click here to reset;
+#X text 27 232 Output is in milliseconds;
+#X text 114 147 Click here to get elapsed CPU time;
+#X obj 66 15 realtime;
+#X text 12 47 The realtime object measures elapsed real time \, as measured by your operating system.;
+#X obj 30 176 realtime;
+#X text 134 15 - ask OS for elapsed real time;
+#X text 302 244 updated for Pd version 0.33;
+#X connect 0 0 8 1;
+#X connect 1 0 8 0;
+#X connect 8 0 2 0;
diff --git a/pd/doc/5.reference/receive-help.pd b/pd/doc/5.reference/receive-help.pd
new file mode 100644
index 00000000..17bb08cb
--- /dev/null
+++ b/pd/doc/5.reference/receive-help.pd
@@ -0,0 +1,26 @@
+#N canvas 257 45 511 351 12;
+#X text 278 321 updated for Pd version 0.32;
+#X floatatom 36 55 5 0 0;
+#X floatatom 152 58 5 0 0;
+#X floatatom 272 57 5 0 0;
+#X floatatom 38 134 5 0 0;
+#X floatatom 171 136 5 0 0;
+#X floatatom 305 134 5 0 0;
+#X text 62 321 abbreviation:;
+#X obj 36 80 send help-rcv1;
+#X obj 152 81 send help-rcv1;
+#X obj 271 81 send help-rcv2;
+#X obj 38 110 receive help-rcv1;
+#X obj 171 110 receive help-rcv2;
+#X obj 305 110 receive help-rcv2;
+#X text 31 161 "Receive" outputs messages sent via "send." Sends and receives are named to tell them whom to connect to. They work across windows too. Also \, you can use message boxes as shown:;
+#X msg 84 233 \; help-rcv1 34 \; help-rcv2 67;
+#X obj 161 320 r;
+#X obj 21 10 receive;
+#X text 79 10 -- receive messages without patch cords;
+#X connect 1 0 8 0;
+#X connect 2 0 9 0;
+#X connect 3 0 10 0;
+#X connect 11 0 4 0;
+#X connect 12 0 5 0;
+#X connect 13 0 6 0;
diff --git a/pd/doc/5.reference/route-help.pd b/pd/doc/5.reference/route-help.pd
new file mode 100644
index 00000000..224fb0ea
--- /dev/null
+++ b/pd/doc/5.reference/route-help.pd
@@ -0,0 +1,80 @@
+#N canvas 0 0 815 537 12;
+#X obj 183 213 print x1;
+#X obj 261 213 print x2;
+#X obj 339 213 print x3;
+#X obj 422 213 print x4;
+#X obj 183 185 route 23 54 1;
+#X msg 183 155 234 345 456;
+#X msg 308 155 23 34 45;
+#X msg 414 155 54 43;
+#X msg 485 155 1 foo bar;
+#X msg 254 247 impeach ringo starr;
+#X obj 191 275 route big apple;
+#X msg 435 248 apple pie;
+#X msg 191 247 1 2 3;
+#X msg 523 248 big apple pie;
+#X msg 578 155 walk the dog;
+#X text 45 33 Route checks the first element of a message against each
+of its arguments \, which may be numbers or symbols (but not a mixture
+of the two.);
+#X text 44 85 If a match is found \, the rest of the message appears
+on the corresponding outlet. If no match \, the message is repeated
+to the last "rejection" outlet. The number of outlets is the number
+of arguments plus one.;
+#X text 19 185 numeric arguments:;
+#X text 17 275 symbolic arguments:;
+#X obj 157 489 print z1;
+#X obj 233 489 print z2;
+#X msg 124 424 bang;
+#X msg 170 424 list;
+#X msg 213 424 5;
+#X msg 251 424 float 5;
+#X msg 320 424 list 5;
+#X msg 385 424 symbol pie;
+#X msg 560 424 pie;
+#X msg 483 424 list pie;
+#X msg 70 424 1 2 3;
+#X obj 157 461 route list float symbol bang;
+#X obj 310 489 print z3;
+#X obj 387 489 print z4;
+#X obj 461 489 print z5;
+#X obj 191 305 print y1;
+#X obj 269 305 print y2;
+#X obj 347 305 print y3;
+#X text 76 344 To avoid confusion between \, say \, the number 5 and
+the list contining only the number 5 \, both messages match "float"
+\, and ditto for symbols. An empty list matches "bang". In Pd these
+are all considered special cases of lists.;
+#X text 545 506 updated for Pd version 0.35;
+#X text 97 9 - route messages according to their first element;
+#X obj 43 8 route;
+#X connect 4 0 0 0;
+#X connect 4 1 1 0;
+#X connect 4 2 2 0;
+#X connect 4 3 3 0;
+#X connect 5 0 4 0;
+#X connect 6 0 4 0;
+#X connect 7 0 4 0;
+#X connect 8 0 4 0;
+#X connect 9 0 10 0;
+#X connect 10 0 34 0;
+#X connect 10 1 35 0;
+#X connect 10 2 36 0;
+#X connect 11 0 10 0;
+#X connect 12 0 10 0;
+#X connect 13 0 10 0;
+#X connect 14 0 4 0;
+#X connect 21 0 30 0;
+#X connect 22 0 30 0;
+#X connect 23 0 30 0;
+#X connect 24 0 30 0;
+#X connect 25 0 30 0;
+#X connect 26 0 30 0;
+#X connect 27 0 30 0;
+#X connect 28 0 30 0;
+#X connect 29 0 30 0;
+#X connect 30 0 19 0;
+#X connect 30 1 20 0;
+#X connect 30 2 31 0;
+#X connect 30 3 32 0;
+#X connect 30 4 33 0;
diff --git a/pd/doc/5.reference/rsqrt~-help.pd b/pd/doc/5.reference/rsqrt~-help.pd
new file mode 100644
index 00000000..fb0bc350
--- /dev/null
+++ b/pd/doc/5.reference/rsqrt~-help.pd
@@ -0,0 +1,32 @@
+#N canvas 183 264 685 375 12;
+#X obj 68 211 metro 500;
+#X obj 68 186 r metro;
+#X msg 575 106 \; metro 0;
+#X msg 574 48 \; pd dsp 1 \; metro 1;
+#X floatatom 52 112 0 0 0;
+#X floatatom 52 268 0 0 0;
+#X text 419 349 updated for Pd version 0.33;
+#X obj 574 21 loadbang;
+#X obj 52 235 snapshot~;
+#X floatatom 51 351 9 0 0;
+#X obj 51 295 t f f;
+#X obj 51 322 *;
+#X obj 52 138 sig~;
+#X obj 36 16 rsqrt~;
+#X text 105 14 - signal reciprocal square root;
+#X text 18 45 rsqrt~ takes the approximate reciprocal square root of
+the incoming signal \, using a fast \, approximate algorithm which
+is probably accurate to about 120 dB (20 bits).;
+#X obj 52 162 rsqrt~;
+#X connect 0 0 8 0;
+#X connect 1 0 0 0;
+#X connect 1 0 0 0;
+#X connect 4 0 12 0;
+#X connect 5 0 10 0;
+#X connect 7 0 3 0;
+#X connect 8 0 5 0;
+#X connect 10 0 11 0;
+#X connect 10 1 11 1;
+#X connect 11 0 9 0;
+#X connect 12 0 16 0;
+#X connect 16 0 8 0;
diff --git a/pd/doc/5.reference/samphold~-help.pd b/pd/doc/5.reference/samphold~-help.pd
new file mode 100644
index 00000000..1a58bd02
--- /dev/null
+++ b/pd/doc/5.reference/samphold~-help.pd
@@ -0,0 +1,34 @@
+#N canvas 121 54 554 287 10;
+#X obj 32 238 snapshot~;
+#X floatatom 32 257;
+#X obj 41 219 metro 100;
+#X obj 41 197 r start;
+#X msg 387 21 \; pd dsp 1 \; start bang;
+#X text 392 270 updated for version 0.29;
+#X text 454 30 Click to start;
+#X text 447 78 Click to stop;
+#X msg 388 65 \; pd dsp 0 \; start 0;
+#X obj 19 7 samphold~;
+#X text 96 6 - sample and hold unit;
+#X obj 32 170 samphold~;
+#X text 10 26 The samphold~ object samples its left input whenever its right input decreases in value (as a phasor~ does each period \, for example.) Both inputs are audio signals.;
+#X obj 67 129 sig~;
+#X obj 101 148 sig~;
+#X floatatom 67 109;
+#X floatatom 101 127;
+#X msg 32 66 set 34;
+#X msg 38 87 reset;
+#X text 81 65 set output to a number;
+#X text 81 86 force the next sample;
+#X text 97 109 sample signal;
+#X text 135 127 control signal;
+#X connect 0 0 1 0;
+#X connect 2 0 0 0;
+#X connect 3 0 2 0;
+#X connect 11 0 0 0;
+#X connect 13 0 11 0;
+#X connect 14 0 11 1;
+#X connect 15 0 13 0;
+#X connect 16 0 14 0;
+#X connect 17 0 11 0;
+#X connect 18 0 11 0;
diff --git a/pd/doc/5.reference/savepanel-help.pd b/pd/doc/5.reference/savepanel-help.pd
new file mode 100644
index 00000000..b5d7e7a6
--- /dev/null
+++ b/pd/doc/5.reference/savepanel-help.pd
@@ -0,0 +1,12 @@
+#N canvas 9 118 567 234 12;
+#X msg 102 92 bang;
+#X obj 102 145 print;
+#X text 295 199 updated for Pd version 0.24;
+#X text 28 192 see also:;
+#X text 16 35 When Savepanel gets a "bang" a "Save As" file browser appears on the screen \, If you choose a filename \, it appears on the outlet.;
+#X obj 102 120 savepanel;
+#X obj 115 191 openpanel;
+#X obj 19 7 savepanel;
+#X text 104 6 - query you for the name of a file to create;
+#X connect 0 0 5 0;
+#X connect 5 0 1 0;
diff --git a/pd/doc/5.reference/select-help.pd b/pd/doc/5.reference/select-help.pd
new file mode 100644
index 00000000..6bc17ad7
--- /dev/null
+++ b/pd/doc/5.reference/select-help.pd
@@ -0,0 +1,73 @@
+#N canvas 47 29 618 662 12;
+#X floatatom 22 332 0 0 0;
+#X msg 156 120 6;
+#X msg 119 120 234;
+#X floatatom 119 150 0 0 0;
+#X msg 121 301 1;
+#X msg 89 301 54;
+#X obj 22 392 print x1;
+#X obj 100 391 print x2;
+#X msg 58 301 23;
+#X msg 22 302 234;
+#X msg 65 120 6;
+#X obj 28 180 select 6;
+#X msg 28 120 234;
+#X obj 28 210 print x1;
+#X obj 107 211 print x2;
+#X obj 177 391 print x3;
+#X obj 255 392 print x4;
+#X floatatom 28 150 0 0 0;
+#X obj 22 362 select 23 54 1;
+#X text 45 609 abbreviation:;
+#X obj 169 610 sel;
+#X text 20 37 In its simplest form shown below \, Select checks its input agains the constant "6". If they match \, the first outlet gives "bang" and otherwise the input is copied to the second outlet. If Select is used with a single argument \, a second inlet allows you to change the test value.;
+#X text 22 239 You can give several arguments. You get an outlet for each test value and finally an outlet for values which match none of them. In this case you don't get inlets to change the test values:;
+#X obj 32 566 print x1;
+#X obj 114 567 print x2;
+#X msg 34 451 symbol cort;
+#X msg 46 476 symbol zack;
+#X msg 178 476 symbol cort;
+#X msg 184 501 symbol zack;
+#X obj 34 539 select cort;
+#X msg 308 462 symbol cort;
+#X msg 415 462 symbol zack;
+#X obj 308 551 print x1;
+#X obj 385 551 print x2;
+#X obj 308 521 select cort zack;
+#X obj 462 551 print x3;
+#X msg 413 487 symbol bill;
+#X text 24 426 Select can also be used to sort symbols:;
+#X text 83 637 see also:;
+#X obj 175 639 route;
+#X obj 32 10 select;
+#X text 92 10 - compare numbers or symbols;
+#X text 370 629 updated for Pd version 0.33;
+#X connect 0 0 18 0;
+#X connect 1 0 3 0;
+#X connect 2 0 3 0;
+#X connect 3 0 11 1;
+#X connect 4 0 0 0;
+#X connect 5 0 0 0;
+#X connect 8 0 0 0;
+#X connect 9 0 0 0;
+#X connect 10 0 17 0;
+#X connect 11 0 13 0;
+#X connect 11 1 14 0;
+#X connect 12 0 17 0;
+#X connect 17 0 11 0;
+#X connect 18 0 6 0;
+#X connect 18 1 7 0;
+#X connect 18 2 15 0;
+#X connect 18 3 16 0;
+#X connect 25 0 29 0;
+#X connect 26 0 29 0;
+#X connect 27 0 29 1;
+#X connect 28 0 29 1;
+#X connect 29 0 23 0;
+#X connect 29 1 24 0;
+#X connect 30 0 34 0;
+#X connect 31 0 34 0;
+#X connect 34 0 32 0;
+#X connect 34 1 33 0;
+#X connect 34 2 35 0;
+#X connect 36 0 34 0;
diff --git a/pd/doc/5.reference/send-help.pd b/pd/doc/5.reference/send-help.pd
new file mode 100644
index 00000000..f8d44a85
--- /dev/null
+++ b/pd/doc/5.reference/send-help.pd
@@ -0,0 +1,26 @@
+#N canvas 257 45 511 351 12;
+#X text 278 321 updated for Pd version 0.32;
+#X obj 21 10 send;
+#X text 60 11 -- send messages without patch cords;
+#X obj 36 80 send help-send1;
+#X obj 152 81 send help-send1;
+#X obj 271 81 send help-send2;
+#X obj 38 110 receive help-send1;
+#X obj 171 110 receive help-send2;
+#X obj 305 110 receive help-send2;
+#X floatatom 36 55 5 0 0;
+#X floatatom 152 58 5 0 0;
+#X floatatom 272 57 5 0 0;
+#X floatatom 38 134 5 0 0;
+#X floatatom 171 136 5 0 0;
+#X floatatom 305 134 5 0 0;
+#X obj 161 320 s;
+#X text 62 321 abbreviation:;
+#X text 31 161 "Send" sends messages to "receive" objects. Sends and receives are named to tell them whom to connect to. They work across windows too. Also \, you can use message boxes as shown:;
+#X msg 84 233 \; help-send1 34 \; help-send2 67;
+#X connect 6 0 12 0;
+#X connect 7 0 13 0;
+#X connect 8 0 14 0;
+#X connect 9 0 3 0;
+#X connect 10 0 4 0;
+#X connect 11 0 5 0;
diff --git a/pd/doc/5.reference/send~-help.pd b/pd/doc/5.reference/send~-help.pd
new file mode 100644
index 00000000..5c9db395
--- /dev/null
+++ b/pd/doc/5.reference/send~-help.pd
@@ -0,0 +1,32 @@
+#N canvas 31 28 678 406 12;
+#X floatatom 344 238 0 0 0;
+#X obj 344 189 receive~ signal1;
+#X obj 17 215 send~ signal1;
+#X obj 17 192 sig~ 50;
+#X obj 344 213 snapshot~;
+#X obj 42 22 send~;
+#X obj 94 23 receive~;
+#X text 178 23 - one-to-many nonlocal signal connections;
+#X obj 507 133 loadbang;
+#X obj 507 194 metro 200;
+#X msg 517 155 \; pd dsp 1;
+#X floatatom 18 168 4 0 0;
+#X text 48 51 A send~ object copies its input to a local buffer which all receive~ objects of the same name read from. They may be in different windows or even different patches. Any number of receives may be associated with one send~ but it is an error to have two send~s of the same name.;
+#X obj 179 344 tabreceive~;
+#X text 405 368 updated for Pd version 0.33.;
+#X obj 148 187 sig~ 25;
+#X obj 148 215 send~ signal2;
+#X msg 355 139 set signal2;
+#X msg 356 161 set signal1;
+#X text 34 287 Send~/Receive~ only work for the default block size (64) \; for FFT applications see also:;
+#X text 35 262 Receive~ takes "set" messages to switch between send~s.;
+#X connect 1 0 4 0;
+#X connect 3 0 2 0;
+#X connect 4 0 0 0;
+#X connect 8 0 9 0;
+#X connect 8 0 10 0;
+#X connect 9 0 4 0;
+#X connect 11 0 3 0;
+#X connect 15 0 16 0;
+#X connect 17 0 1 0;
+#X connect 18 0 1 0;
diff --git a/pd/doc/5.reference/set-help.pd b/pd/doc/5.reference/set-help.pd
new file mode 100644
index 00000000..227b29b4
--- /dev/null
+++ b/pd/doc/5.reference/set-help.pd
@@ -0,0 +1,45 @@
+#N struct help-set-template1 float x float y;
+#N canvas 300 3 583 365 12;
+#X text 19 263 see also:;
+#X obj 137 308 template;
+#X obj 112 284 append;
+#X obj 170 284 getsize;
+#X obj 237 284 setsize;
+#X obj 215 308 element;
+#X obj 11 308 sublist;
+#X obj 78 308 scalar;
+#X msg 210 155 next;
+#X obj 21 10 get;
+#X floatatom 19 173 5 0 0;
+#X floatatom 108 181 5 0 0;
+#X obj 196 180 pointer;
+#X text 273 113 output first scalar in list;
+#X text 256 155 output next item;
+#X text 262 204 First argument selects template.;
+#X text 263 219 Remaining args are names of fields.;
+#X obj 11 283 pointer;
+#X msg 196 131 traverse pd-help-set-data \, next;
+#N canvas 0 0 276 122 help-set-data 1;
+#X scalar help-set-template1 39 23 \;;
+#X scalar help-set-template1 99 73 \;;
+#X restore 377 244 pd help-set-data;
+#N canvas 164 72 425 146 help-set-template1 0;
+#X obj 41 87 filledpolygon 9 0 1 0 0 20 0 20 30 0 30;
+#X obj 60 21 template float x float y;
+#X restore 377 266 pd help-set-template1;
+#X text 86 10 -- set values in a scalar;
+#X obj 19 204 set help-set-template1 x y;
+#X text 18 155 x value;
+#X text 106 162 y value;
+#X obj 79 283 get;
+#X text 19 32 "Set" takes a pointer to a scalar in its rightmost inlet
+\; the remaining inlets set numeric values of fields. Only the leftmost
+inlet is "hot". You can't "set" arrays or sublists. Instead \, you
+can get pointers into them using "element" and "sublist" (probably
+not working yet) and set individual items.;
+#X text 336 342 updated for Pd version 0.35;
+#X connect 8 0 12 0;
+#X connect 10 0 22 0;
+#X connect 11 0 22 1;
+#X connect 12 0 22 2;
+#X connect 18 0 12 0;
diff --git a/pd/doc/5.reference/setsize-help.pd b/pd/doc/5.reference/setsize-help.pd
new file mode 100644
index 00000000..ce68f5fc
--- /dev/null
+++ b/pd/doc/5.reference/setsize-help.pd
@@ -0,0 +1,54 @@
+#N struct help-setsize-template float x float y array array1 help-setsize-array1-template
+;
+#N struct help-setsize-array1-template float y;
+#N canvas 331 45 678 459 12;
+#X text 31 359 see also:;
+#X obj 28 379 template;
+#N canvas 393 10 491 261 help-setsize-template 0;
+#X obj 27 174 filledpolygon 509 509 0 -10 -10 10 -10 10 10 -10 10;
+#X obj 24 16 template float x float y array array1 help-setsize-array1-template
+;
+#X obj 27 76 plot array1 500 1 10 15 10;
+#X restore 364 261 pd help-setsize-template;
+#N canvas 0 0 295 165 help-setsize-data 1;
+#X scalar help-setsize-template 31 23 \; 0 \; 10 \; 0 \; 10 \; 20 \;
+10 \; 20 \; 70 \; 10 \; \;;
+#X restore 363 240 pd help-setsize-data;
+#N canvas 196 292 365 134 help-setsize-array1-template 0;
+#X obj 30 71 filledpolygon 0 0 0 -5 0 0 5 5 0 0 -5;
+#X obj 32 27 template float y;
+#X restore 363 284 pd help-setsize-array1-template;
+#X obj 107 379 pointer;
+#X obj 242 379 setsize;
+#X obj 272 186 pointer;
+#X msg 272 162 traverse pd-help-setsize-data \, next;
+#X floatatom 25 189 5 0 0;
+#X text 359 210 arguments: template \, field name;
+#X obj 25 213 setsize help-setsize-template array1;
+#X text 115 183 inlet for pointer;
+#X obj 36 11 setsize;
+#X obj 174 379 element;
+#X text 31 156 number sets;
+#X text 30 170 size;
+#X text 99 12 -- resize an array;
+#X text 25 34 "setsize" takes a pointer to a scalar at left and a number
+at right. Its creation arguments specify the template of the pointer
+and the name of an array field. Sending a number then sets the number
+of elements of the array.;
+#X text 24 93 The smallest possible size is one. If the array is resized
+downward the extra data are lost. If resized upward \, the new elements
+are initialized to default values.;
+#X msg 566 335 bang;
+#X text 297 333 click to reload from file -->;
+#X text 274 143 click here first;
+#N canvas 460 63 435 172 readit 1;
+#X msg 66 65 \; pd-help-setsize-data read setsize.txt;
+#X obj 107 18 inlet;
+#X msg 62 123 \; pd-help-setsize-data write setsize.txt;
+#X connect 1 0 0 0;
+#X restore 566 361 pd readit;
+#X text 416 395 updated for Pd version 0.35;
+#X connect 7 0 11 1;
+#X connect 8 0 7 0;
+#X connect 9 0 11 0;
+#X connect 20 0 23 0;
diff --git a/pd/doc/5.reference/sigbinops-help.pd b/pd/doc/5.reference/sigbinops-help.pd
new file mode 100644
index 00000000..b461c846
--- /dev/null
+++ b/pd/doc/5.reference/sigbinops-help.pd
@@ -0,0 +1,60 @@
+#N canvas 18 67 1086 595 10;
+#X obj 8 251 +~;
+#X obj 115 249 -~;
+#X obj 222 249 *~;
+#X obj 327 251 /~;
+#X obj 38 17 +~;
+#X obj 73 17 -~;
+#X obj 106 16 *~;
+#X obj 140 16 /~;
+#X graph graph1 0 -1 100 1 678 446 1078 146;
+#X array array1 100 float;
+#X pop;
+#X obj 327 293 tabwrite~ array1;
+#X obj 8 293 tabwrite~ array1;
+#X obj 115 293 tabwrite~ array1;
+#X obj 222 293 tabwrite~ array1;
+#X text 266 14 -- operators on audio signals;
+#X obj 8 160 osc~ 440;
+#X obj 480 157 osc~ 675;
+#X msg 17 271 bang;
+#X obj 173 15 max~;
+#X obj 207 15 min~;
+#X text 487 458 modified for Pd version 0.27;
+#X obj 536 293 tabwrite~ array1;
+#X obj 431 293 tabwrite~ array1;
+#X obj 431 249 max~;
+#X obj 536 251 min~;
+#X msg 127 272 bang;
+#X msg 233 271 bang;
+#X msg 343 272 bang;
+#X msg 443 271 bang;
+#X msg 553 272 bang;
+#X text 52 332 The binary signal operators can be configured to combine two signals as above \, or \, if you give a numeric argument \, audio signals are combined with scalars:;
+#X obj 204 377 +~ 5;
+#X text 60 406 The right inlet takes audio signals or numbers depending on whether the argument is present or not.;
+#X msg 68 71 \; pd dsp 1;
+#X connect 0 0 10 0;
+#X connect 1 0 11 0;
+#X connect 2 0 12 0;
+#X connect 3 0 9 0;
+#X connect 14 0 0 0;
+#X connect 14 0 1 0;
+#X connect 14 0 3 0;
+#X connect 14 0 2 0;
+#X connect 14 0 22 0;
+#X connect 14 0 23 0;
+#X connect 15 0 3 1;
+#X connect 15 0 2 1;
+#X connect 15 0 1 1;
+#X connect 15 0 0 1;
+#X connect 15 0 22 1;
+#X connect 15 0 23 1;
+#X connect 16 0 10 0;
+#X connect 22 0 21 0;
+#X connect 23 0 20 0;
+#X connect 24 0 11 0;
+#X connect 25 0 12 0;
+#X connect 26 0 9 0;
+#X connect 27 0 21 0;
+#X connect 28 0 20 0;
diff --git a/pd/doc/5.reference/sig~-help.pd b/pd/doc/5.reference/sig~-help.pd
new file mode 100644
index 00000000..72781487
--- /dev/null
+++ b/pd/doc/5.reference/sig~-help.pd
@@ -0,0 +1,20 @@
+#N canvas 132 175 547 284 12;
+#X obj 109 221 snapshot~;
+#X floatatom 110 246 0 0 0;
+#X obj 78 12 sig~;
+#X obj 24 133 sig~;
+#X floatatom 24 108 0 0 0;
+#X text 114 14 - convert numbers to audio signal;
+#X text 11 53 In this example \, the sig~ object converts numbers to an audio signal \, which the snapshot~ converts back again.;
+#X text 64 108 <-- Scroll to set value;
+#X obj 109 131 loadbang;
+#X msg 118 155 \; pd dsp 1;
+#X obj 109 195 metro 200;
+#X text 291 249 updated for Pd version 0.33;
+#X connect 0 0 1 0;
+#X connect 0 0 1 0;
+#X connect 3 0 0 0;
+#X connect 4 0 3 0;
+#X connect 8 0 9 0;
+#X connect 8 0 10 0;
+#X connect 10 0 0 0;
diff --git a/pd/doc/5.reference/snapshot~-help.pd b/pd/doc/5.reference/snapshot~-help.pd
new file mode 100644
index 00000000..468eb678
--- /dev/null
+++ b/pd/doc/5.reference/snapshot~-help.pd
@@ -0,0 +1,33 @@
+#N canvas 85 46 661 400 12;
+#X obj 19 316 snapshot~;
+#X floatatom 19 339 0 0 0 0 - - -;
+#X obj 74 14 snapshot~;
+#X msg 30 264 bang;
+#X text 112 342 This output updates each time bang is clicked above.
+;
+#X text 154 14 - convert a signal to a number on demand;
+#X text 9 46 The snapshot~ object takes a signal and converts it to
+a control value whenever it receives a bang in its left outlet. This
+object is particularly useful for monitoring outputs.;
+#X msg 565 43 \; pd dsp 1;
+#X obj 565 20 loadbang;
+#X obj 19 239 osc~ 0.1;
+#X text 24 221 0.1 Hz cosine;
+#X text 397 373 updated for Pd version 0.37;
+#X msg 35 288 set 5;
+#X text 102 239 signal in to take snapshots of;
+#X text 73 263 bang -- take one snapshot;
+#X text 89 288 set -- set value (which is reset next DSP block.);
+#X msg 565 85 \; pd dsp 0;
+#X text 11 109 In the example below \, a snapshot~ object prints out
+the values of a low frequency cosine wave every time it is sent a bang
+message.;
+#X text 12 161 A 'set' message is provided for the (rare) situations
+where you might make a known change to the signal input \, and then
+read snapshot's value before any ensuing signal computation.;
+#X connect 0 0 1 0;
+#X connect 0 0 1 0;
+#X connect 3 0 0 0;
+#X connect 8 0 7 0;
+#X connect 9 0 0 0;
+#X connect 12 0 0 0;
diff --git a/pd/doc/5.reference/soundfiler-help.pd b/pd/doc/5.reference/soundfiler-help.pd
new file mode 100644
index 00000000..515f102b
--- /dev/null
+++ b/pd/doc/5.reference/soundfiler-help.pd
@@ -0,0 +1,67 @@
+#N canvas 59 252 1102 576 12;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 77971 float 0;
+#X coords 0 1 77971 -1 300 100 1;
+#X restore 71 353 graph;
+#N canvas 0 0 450 300 graph1 0;
+#X array array2 77971 float 0;
+#X coords 0 1 77971 -1 300 100 1;
+#X restore 71 459 graph;
+#X obj 11 313 soundfiler;
+#X msg 17 241 write -aiff /tmp/foo1 array2;
+#X msg 8 152 read ../sound/bell.aiff array2;
+#X msg 17 199 read -raw 128 2 2 b ../sound/bell.aiff array1 array2
+;
+#X text 26 10 SOUNDFILER - read and write soundfiles to arrays;
+#X text 548 3 When reading you can leave soundfiler to figure out which
+of the three known soundfile formats the file belongs to or override
+all header information using the "-raw" flag.;
+#X text 665 52 Flags for reading:;
+#X text 574 68 -skip <sample frames to skip in file>;
+#X text 574 87 -nframes <maximum number of sample frames to read>;
+#X text 575 143 -raw <headersize> <channels> <bytespersample> <endianness>
+;
+#X text 594 161 This causes all header information to be ignored. Endianness
+is "l" ("little") for Intel machines or "b" ("big") for Macintoshes
+and SGIs. You can give "n" (natural) to take the byte order your machine
+prefers.;
+#X text 575 106 -resize;
+#X text 575 124 -maxsize <maximum number of samples we can resize to>
+;
+#X text 560 226 Flags for writing:;
+#X text 575 247 -wave \, -nextstep \, -aiff;
+#X text 576 266 -big \, -little (nextstep only!);
+#X text 575 288 -skip <number of sample frames to skip in array>;
+#X text 576 310 -nframes <maximum number to write>;
+#X text 577 354 -normalize;
+#X text 576 332 -bytes <2 \, 3 \, or 4>;
+#X floatatom 11 337 0 0 0 0 - - -;
+#X msg 15 175 read -resize ../sound/bell.aiff array2;
+#X text 751 539 updated for Pd version 0.29;
+#X msg 17 288 write -nextstep -bytes 4 /tmp/foo3 array1 array2;
+#X msg 16 265 write -wave -nframes 10000 /tmp/foo2 array2;
+#X text 287 150 read a file;
+#X text 362 173 ...optionally resize;
+#X text 225 217 ...or even overriding everything;
+#X text 283 240 write a file;
+#X text 352 309 write stereo;
+#X text 560 385 The number of channels is limited to 64;
+#X text 612 433 see also:;
+#X obj 606 456 tabwrite~;
+#X obj 607 480 tabread4~;
+#X obj 713 435 tabplay~;
+#X obj 711 484 writesf~;
+#X obj 712 461 readsf~;
+#X text 9 31 The soundfiler object reads and writes floating point
+arrays to binary soundfiles which may contain 2 or 3 byte fixed point
+or 4 byte floating point samples in wave \, aiff \, or next formats
+(no floating point aiff \, though.). The number of channels of the
+soundfile need not match the number of arrays given (extras are dropped
+and unsupplied channels are zeroed out.);
+#X connect 2 0 22 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 0;
+#X connect 5 0 2 0;
+#X connect 23 0 2 0;
+#X connect 25 0 2 0;
+#X connect 26 0 2 0;
diff --git a/pd/doc/5.reference/spigot-help.pd b/pd/doc/5.reference/spigot-help.pd
new file mode 100644
index 00000000..3daf9157
--- /dev/null
+++ b/pd/doc/5.reference/spigot-help.pd
@@ -0,0 +1,21 @@
+#N canvas 349 223 586 335 12;
+#X msg 25 157 0.5 1000;
+#X floatatom 74 242 1 0 0;
+#X obj 25 267 spigot;
+#X obj 25 300 print;
+#X msg 38 210 walk the cat;
+#X msg 31 182 bang;
+#X obj 35 11 spigot;
+#X text 100 12 - pass or block messages;
+#X text 99 242 control: nonzero to pass messages \, zero to stop them
+;
+#X text 333 303 updated for Pd version 0.33;
+#X text 35 63 Spigot passes messages from its left inlet to its outlet
+\, as long as a nonzero number is sent to its right inlet. When its
+right inlet gets zero \, incoming messages are "blocked \, " i.e. \,
+ignored.;
+#X connect 0 0 2 0;
+#X connect 1 0 2 1;
+#X connect 2 0 3 0;
+#X connect 4 0 2 0;
+#X connect 5 0 2 0;
diff --git a/pd/doc/5.reference/sqrt~-help.pd b/pd/doc/5.reference/sqrt~-help.pd
new file mode 100644
index 00000000..b7b8e1a4
--- /dev/null
+++ b/pd/doc/5.reference/sqrt~-help.pd
@@ -0,0 +1,32 @@
+#N canvas 182 132 778 399 12;
+#X obj 71 201 metro 500;
+#X obj 71 176 r metro;
+#X msg 575 106 \; metro 0;
+#X msg 574 48 \; pd dsp 1 \; metro 1;
+#X floatatom 55 102 0 0 0;
+#X floatatom 55 258 0 0 0;
+#X text 470 371 updated for Pd version 0.33;
+#X obj 574 21 loadbang;
+#X obj 36 16 sqrt~;
+#X text 88 18 - signal square root;
+#X obj 55 152 sqrt~;
+#X obj 55 225 snapshot~;
+#X floatatom 54 341 9 0 0;
+#X obj 54 285 t f f;
+#X obj 54 312 *;
+#X obj 55 128 sig~;
+#X text 18 45 sqrt~ takes the approximate square root of the incoming
+signal \, using a fast \, approximate algorithm which is probably accurate
+to about 120 dB (20 bits).;
+#X connect 0 0 11 0;
+#X connect 1 0 0 0;
+#X connect 1 0 0 0;
+#X connect 4 0 15 0;
+#X connect 5 0 13 0;
+#X connect 7 0 3 0;
+#X connect 10 0 11 0;
+#X connect 11 0 5 0;
+#X connect 13 0 14 0;
+#X connect 13 1 14 1;
+#X connect 14 0 12 0;
+#X connect 15 0 10 0;
diff --git a/pd/doc/5.reference/stripnote-help.pd b/pd/doc/5.reference/stripnote-help.pd
new file mode 100644
index 00000000..80a8cecb
--- /dev/null
+++ b/pd/doc/5.reference/stripnote-help.pd
@@ -0,0 +1,16 @@
+#N canvas 53 36 458 251 10;
+#X msg 39 100 23 0;
+#X obj 39 175 print x1;
+#X obj 96 175 print x2;
+#X obj 39 139 stripnote;
+#X msg 79 100 34.5 67.8;
+#X obj 65 214 makenote;
+#X text 83 12 - send note-on messages and schedule note-off for later;
+#X text 283 220 updated for Pd version 0.28;
+#X text 10 214 see also;
+#X obj 23 10 stripnote;
+#X text 17 44 Stripnote takes note-off (zero-velocity) messages out of a stream of MIDI-style note message and passes the others through unchanged.;
+#X connect 0 0 3 0;
+#X connect 3 0 1 0;
+#X connect 3 1 2 0;
+#X connect 4 0 3 0;
diff --git a/pd/doc/5.reference/struct-help.pd b/pd/doc/5.reference/struct-help.pd
new file mode 100644
index 00000000..a18fa6e9
--- /dev/null
+++ b/pd/doc/5.reference/struct-help.pd
@@ -0,0 +1,26 @@
+#N canvas 343 45 557 321 12;
+#X text 88 11 -- declare the fields in a data structure.;
+#N canvas 345 476 638 171 help-template1 0;
+#X obj 60 21 struct struct-1 float x float y symbol dog array weasel
+struct-2;
+#X text 40 76 In this example \, the "struct-1" structure is defined
+in which "x" and "y" are "floats" \, i.e. \, numbers \, but "dog" is
+a symbol and "weasel" is an array of objects of structure "struct-2".
+;
+#X restore 324 156 pd help-template1;
+#N canvas 10 274 588 157 help-template2 0;
+#X text 28 95 Here is one which specifies only the floating point "y"
+\; it's used for the elements of the array shown in the other template.
+;
+#X obj 60 21 struct struct-2 float y;
+#X restore 324 183 pd help-template2;
+#X obj 36 215 drawpolygon;
+#X text 36 195 see also:;
+#X obj 141 215 drawnumber;
+#X obj 236 216 plot;
+#X text 281 290 updated for Pd version 0.35;
+#X obj 21 10 struct;
+#X text 16 49 There should be one "struct" object in each Pd window
+you are using as a data structure template. The arguments specify the
+types and names of the fields \; and for array fields \, a third argument
+specifies the template that the array elements should belong to.;
diff --git a/pd/doc/5.reference/sublist-help.pd b/pd/doc/5.reference/sublist-help.pd
new file mode 100644
index 00000000..a3067d5a
--- /dev/null
+++ b/pd/doc/5.reference/sublist-help.pd
@@ -0,0 +1,10 @@
+#N canvas 252 0 559 226 12;
+#X text 311 181 updated for Pd version 0.32;
+#X obj 21 10 sublist;
+#X text 86 10 -- get a list from a field of a scalar;
+#X text 31 37 Don't try this yet -- it's untested.;
+#X text 36 89 "sublist" will take as creation arguments a template
+name and a field name \; its one input takes a pointer. If you send
+a pointer (which should agree with the template name) \, "sublist"
+will output the field (which should be of type "list".) The output
+is in fact a pointer to the head of the sublist.;
diff --git a/pd/doc/5.reference/swap-help.pd b/pd/doc/5.reference/swap-help.pd
new file mode 100644
index 00000000..987a5844
--- /dev/null
+++ b/pd/doc/5.reference/swap-help.pd
@@ -0,0 +1,20 @@
+#N canvas 376 130 488 326 12;
+#X msg 67 124 bang;
+#X floatatom 67 252;
+#X floatatom 79 154;
+#X floatatom 118 194;
+#X obj 66 15 swap;
+#X text 114 16 - SWAP TWO NUMBERS \, RESPECTING RIGHT-TO-LEFT ORDER;
+#X text 284 309 updated for Pd version 0.27;
+#X text 12 42 The swap object stores numbers from its left inlet to output on its right inlet -- after repeating its right hand input out the left.;
+#X text 112 123 outputs 2 stored values;
+#X obj 67 226 swap 6.5;
+#X text 110 154 sets second value and outputs both;
+#X text 150 195 sets first value;
+#X text 142 226 creation argument initializes first value;
+#X floatatom 118 254;
+#X connect 0 0 9 0;
+#X connect 2 0 9 0;
+#X connect 3 0 9 1;
+#X connect 9 0 1 0;
+#X connect 9 1 13 0;
diff --git a/pd/doc/5.reference/switch~-help.pd b/pd/doc/5.reference/switch~-help.pd
new file mode 100644
index 00000000..c3ab8797
--- /dev/null
+++ b/pd/doc/5.reference/switch~-help.pd
@@ -0,0 +1,45 @@
+#N canvas 218 166 619 368 12;
+#X msg 382 133 \; metro 0;
+#X text 462 92 <-Click to start;
+#X text 455 137 <-Click to stop;
+#X text 47 13 switch and block - turn DSP on and off for subpatches
+and control block size;
+#N canvas 15 32 598 301 switched 1;
+#X obj 265 148 switch~;
+#X floatatom 265 121 1 0 0;
+#X floatatom 75 168 4 0 0;
+#X obj 75 104 noise~;
+#X obj 75 136 env~ 512;
+#X text 25 26 DSP in this subwindow is turned on and off by the switch~
+object. Any subwindows of this window can also be switched off here.
+If a patch and a superpatch both have switches \, both must be "on"
+for DSP to run in the patch.;
+#X text 32 203 switch~ takes optional arguments the same as block~.
+If you supply arguments to switch \, the patch will be switched AND
+reblocked.;
+#X text 31 258 Only one switch~ or block~ may appear in any window.
+;
+#X connect 1 0 0 0;
+#X connect 3 0 4 0;
+#X connect 4 0 2 0;
+#X restore 139 124 pd switched;
+#N canvas 13 421 564 200 blocked 1;
+#X obj 184 35 block~ 1024 4;
+#X text 14 76 This object specified that DSP in this subwindow is to
+be computed at a block size of 1024 \, and an overlap of 4 \, i.e.
+\, every 256 samples. You may not (yet) specify a block size smaller
+than your superpatch. This is useful for writing FFT based patches
+(see the "fft examples" tutorial series.);
+#X restore 141 158 pd blocked;
+#X msg 382 87 \; pd dsp 1;
+#X obj 382 61 loadbang;
+#X text 38 82 see the subpatches for explanation:;
+#X text 362 334 updated for Pd version 0.34;
+#X text 34 195 BUG! -- dac~ and adc~ work only with a blocksize of
+64 If you want to reblock audio computation \, do so in a sub-patch
+and keep the adc~ and dac~ objects in a super-patch. Also \, you can't
+send~ or receive~ between windows with different block sizes or overlapping.
+Only the inlet~ and outlet~ objects know how to reblock signals. In
+this example \, you could put a dac~ in this \, outer window \, or
+in the switched subwindow \, but not the blocked one.;
+#X connect 7 0 6 0;
diff --git a/pd/doc/5.reference/tabosc4~-help.pd b/pd/doc/5.reference/tabosc4~-help.pd
new file mode 100644
index 00000000..ada694e1
--- /dev/null
+++ b/pd/doc/5.reference/tabosc4~-help.pd
@@ -0,0 +1,86 @@
+#N canvas 307 35 742 511 12;
+#X floatatom 66 450 0 0 0;
+#N canvas 159 26 495 270 output 0;
+#X obj 414 196 t b;
+#X obj 414 134 f;
+#X obj 414 73 inlet;
+#X text 421 36 mute;
+#X obj 414 227 f;
+#X msg 521 218 0;
+#X msg 414 104 bang;
+#X obj 414 166 moses 1;
+#X obj 521 187 t b f;
+#X obj 486 143 moses 1;
+#X obj 102 181 dbtorms;
+#X obj 486 113 r master-lvl;
+#X obj 102 52 r master-lvl;
+#X obj 414 257 s master-lvl;
+#X obj 26 222 inlet~;
+#X obj 244 50 inlet;
+#X text 244 22 level;
+#X obj 244 122 s master-lvl;
+#X msg 118 80 set \$1;
+#X obj 118 109 outlet;
+#X msg 262 78 \; pd dsp 1;
+#X obj 102 238 line~;
+#X obj 26 259 *~;
+#X obj 26 295 dac~;
+#X obj 102 210 pack 0 50;
+#X text 24 195 audio;
+#X text 114 135 show level;
+#X connect 0 0 4 0;
+#X connect 1 0 7 0;
+#X connect 2 0 6 0;
+#X connect 4 0 13 0;
+#X connect 5 0 13 0;
+#X connect 6 0 1 0;
+#X connect 7 0 0 0;
+#X connect 7 1 8 0;
+#X connect 8 0 5 0;
+#X connect 9 1 4 1;
+#X connect 10 0 24 0;
+#X connect 11 0 1 1;
+#X connect 11 0 9 0;
+#X connect 12 0 10 0;
+#X connect 12 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 15 0 20 0;
+#X connect 18 0 19 0;
+#X connect 21 0 22 1;
+#X connect 22 0 23 0;
+#X connect 22 0 23 1;
+#X connect 24 0 21 0;
+#X restore 32 476 pd output;
+#X msg 102 450 MUTE;
+#X text 148 449 <--- volume in dB;
+#X floatatom 32 296 4 0 0;
+#X obj 32 326 sig~ 100;
+#X obj 547 52 table table1;
+#X obj 547 80 table table2;
+#X msg 372 287 \; table1 sinesum 512 0.5 0.5 0.5 0.5 \; table2 cosinesum 512 0 1;
+#X text 433 474 Updated for Pd version 0.33;
+#X obj 20 11 tabosc4~;
+#X text 110 12 4-point interpolating oscillator;
+#X msg 52 372 set table1;
+#X obj 32 413 tabosc4~ table1;
+#X msg 156 372 set table2;
+#X text 372 343 click above \, start DSP \, and turn output;
+#X text 372 361 volume up to hear this;
+#X text 14 40 tabosc4~ is a traditional computer music style wavetable lookup oscillator using 4-point polynomial interpolation. The table should have a poiwer of two points plus three "guard points" \, one at the beginning and two at the end \, which should be wraparound copies of the last point and the first two points \, respectively. The "sinesum" and "cosinesum" methods for arrays do this automatically for you if you just want to specify partial strengths.;
+#X text 14 178 For good results use 512 points for up to about 15 partials \, or 32*npartials (rounded up to a power of 2) for more than 15;
+#X floatatom 275 391 4 0 0;
+#X text 12 233 Don't send new "sinesum" messages to tables while you're running -- instead \, use "set" messages to switch between tables.;
+#X text 80 298 signal input for frequency (Hz.);
+#X text 46 349 message to switch tables;
+#X text 325 391 inlet to reset phase;
+#X text 166 414 creation argument initializes table;
+#X connect 0 0 1 1;
+#X connect 1 0 0 0;
+#X connect 2 0 1 2;
+#X connect 4 0 5 0;
+#X connect 5 0 13 0;
+#X connect 12 0 13 0;
+#X connect 13 0 1 0;
+#X connect 14 0 13 0;
+#X connect 19 0 13 1;
diff --git a/pd/doc/5.reference/tabplay~-help.pd b/pd/doc/5.reference/tabplay~-help.pd
new file mode 100644
index 00000000..92cdb81e
--- /dev/null
+++ b/pd/doc/5.reference/tabplay~-help.pd
@@ -0,0 +1,66 @@
+#N canvas 28 13 707 471 10;
+#X msg 639 93 \; pd dsp 0;
+#X graph graph1 0 -1 155948 1 428 369 678 169;
+#X array array99 155948 float 0;
+#X pop;
+#X floatatom 11 342 0 0 0;
+#X msg 11 109 set array99;
+#X text 93 109 "set" message permits you to switch between arrays;
+#X text 128 228 creation argument initializes array name;
+#X text 5 392 see also the "array" tutorial in section 2 of the Pd
+documentation \, and these objects:;
+#X obj 6 438 tabwrite~;
+#X obj 140 439 tabread;
+#X obj 194 439 tabwrite;
+#X obj 254 439 tabsend~;
+#X obj 315 439 tabreceive~;
+#X obj 41 13 tabplay~;
+#X text 108 14 play a table as a sample (non-transposing);
+#X obj 11 228 tabplay~ array99;
+#X obj 452 82 soundfiler;
+#X msg 452 48 read -resize ../sound/bell.aiff array99 \; pd dsp 1 \;
+;
+#X floatatom 452 104 0 0 0;
+#X obj 11 316 env~ 16384;
+#X obj 396 439 soundfiler;
+#X obj 73 439 tabread4~;
+#X obj 87 360 dac~ 1;
+#X obj 87 323 *~;
+#X obj 100 304 line~;
+#X msg 100 263 0.1 100;
+#X msg 116 284 0 100;
+#X text 162 264 on;
+#X text 157 283 off;
+#X text 148 301 envelope;
+#X text 148 312 generator;
+#X text 101 248 amplitude controls:;
+#X text 131 362 audio output;
+#X obj 87 342 hip~ 5;
+#X msg 26 179 0 44100;
+#X msg 27 158 44100;
+#X msg 26 138 bang;
+#X text 475 449 updated for Pd version 0.29;
+#X text 29 43 The tabplay~ object plays a sample \, or part of one
+\, with no transposition or interpolation. It is cheaper than tabread4~
+and there are none of tabread4~'s interpolation artifacts.;
+#X text 509 25 click here to load table;
+#X text 80 136 "bang" or 0 plays whole sample;
+#X text 82 157 play starting at 44100th sample;
+#X text 93 177 play starting at beginning for 44100 samples;
+#X msg 25 199 44100 1000;
+#X text 103 198 play from 44100 through 45099 (1000 samples);
+#X connect 3 0 14 0;
+#X connect 14 0 18 0;
+#X connect 14 0 22 0;
+#X connect 15 0 17 0;
+#X connect 16 0 15 0;
+#X connect 18 0 2 0;
+#X connect 22 0 32 0;
+#X connect 23 0 22 1;
+#X connect 24 0 23 0;
+#X connect 25 0 23 0;
+#X connect 32 0 21 0;
+#X connect 33 0 14 0;
+#X connect 34 0 14 0;
+#X connect 35 0 14 0;
+#X connect 42 0 14 0;
diff --git a/pd/doc/5.reference/tabread-help.pd b/pd/doc/5.reference/tabread-help.pd
new file mode 100644
index 00000000..fa671a21
--- /dev/null
+++ b/pd/doc/5.reference/tabread-help.pd
@@ -0,0 +1,21 @@
+#N canvas 44 26 703 454 12;
+#X text 52 181 index;
+#X obj 36 9 tabread;
+#X obj 15 244 tabread array99;
+#X floatatom 15 182 0 0 0;
+#X floatatom 15 278 0 0 0;
+#X graph graph1 0 0 10 10 362 379 612 179;
+#X array array99 10 float;
+#X pop;
+#X msg 31 56 \; readout 1 \; array99 resize 10 \; array99 bounds 0 0 10 10 \; array99 xlabel -0.5 0 1 2 3 4 5 6 7 8 9 10 \; array99 ylabel -1 0 1 2 3 4 5 6 7 8 9 10 \; array99 0 1 4 2 8 5 6 1 4 2 8;
+#X text 60 276 output = array99[index];
+#X text 141 33 click here to initialize;
+#X text 159 236 creation argument;
+#X text 155 254 gives array name;
+#X msg 25 204 set array99;
+#X text 137 204 change array name;
+#X text 422 407 updated for Pd version 0.33;
+#X text 110 8 - read numbers from a table;
+#X connect 2 0 4 0;
+#X connect 3 0 2 0;
+#X connect 11 0 2 0;
diff --git a/pd/doc/5.reference/tabread4~-help.pd b/pd/doc/5.reference/tabread4~-help.pd
new file mode 100644
index 00000000..c28f580a
--- /dev/null
+++ b/pd/doc/5.reference/tabread4~-help.pd
@@ -0,0 +1,43 @@
+#N canvas 59 33 814 475 10;
+#X obj 11 228 tabread4~ array99;
+#X text 21 207 signal input x(n);
+#X msg 727 51 \; pd dsp 0;
+#X graph graph1 0 -1 9 1 514 373 764 173;
+#X array array99 10 float 0;
+#X pop;
+#X text 127 21 4-point-interpolating table lookup;
+#X obj 11 316 snapshot~;
+#X obj 30 290 metro 200;
+#X obj 11 124 sig~;
+#X floatatom 11 98 0 0 0;
+#X obj 30 264 r readout;
+#X floatatom 11 342 0 0 0;
+#X msg 452 50 \; readout 1 \; array99 resize 10 \; array99 0 -0.5 -0.5
+-0.5 0.5 0.5 0.5 \; pd dsp 1 \;;
+#X text 49 94 incoming signal is index. Indices should range from 1
+to (size-2) so that the 4-point interpolation is meaningful. You can
+shift-drag the number box to see the effect of interpolation.;
+#X msg 34 158 set array99;
+#X text 116 158 "set" message permits you to switch between arrays
+;
+#X text 139 228 creation argument initializes array name;
+#X text 5 392 see also the "array" tutorial in section 2 of the Pd
+documentation \, and these objects:;
+#X obj 47 21 tabread4~;
+#X text 509 27 click here to test;
+#X obj 12 442 tabwrite~;
+#X obj 157 442 tabread;
+#X obj 216 442 tabwrite;
+#X obj 281 442 tabsend~;
+#X obj 346 442 tabreceive~;
+#X text 7 58 Tabread4~ is used to build samplers and other table lookup
+algorithms. The interpolation scheme is 4-point polynomial.;
+#X text 616 460 updated for Pd version 0.29;
+#X obj 83 442 tabplay~;
+#X connect 0 0 5 0;
+#X connect 5 0 10 0;
+#X connect 6 0 5 0;
+#X connect 7 0 0 0;
+#X connect 8 0 7 0;
+#X connect 9 0 6 0;
+#X connect 13 0 0 0;
diff --git a/pd/doc/5.reference/tabreceive~-help.pd b/pd/doc/5.reference/tabreceive~-help.pd
new file mode 100644
index 00000000..7de98346
--- /dev/null
+++ b/pd/doc/5.reference/tabreceive~-help.pd
@@ -0,0 +1,6 @@
+#N canvas 109 83 646 239 12;
+#X obj 21 18 tabreceive~;
+#X text 17 53 creation argument: name of array;
+#X text 16 83 By default a block is 64 samples \; this can be reset using the block~ object.;
+#X text 380 201 updated for Pd version 0.33;
+#X text 129 18 - read a block of a signal from an array continuously;
diff --git a/pd/doc/5.reference/tabsend~-help.pd b/pd/doc/5.reference/tabsend~-help.pd
new file mode 100644
index 00000000..85a4183f
--- /dev/null
+++ b/pd/doc/5.reference/tabsend~-help.pd
@@ -0,0 +1,6 @@
+#N canvas 151 91 596 222 12;
+#X obj 31 27 tabsend~;
+#X text 113 26 writes one block of a signal continuously to an array;
+#X text 41 60 creation argument: name of array;
+#X text 29 96 By default a block is 64 samples \; this can be reset using the block~ object.;
+#X text 318 186 updated for Pd version 0.33;
diff --git a/pd/doc/5.reference/tabwrite-help.pd b/pd/doc/5.reference/tabwrite-help.pd
new file mode 100644
index 00000000..60b31513
--- /dev/null
+++ b/pd/doc/5.reference/tabwrite-help.pd
@@ -0,0 +1,21 @@
+#N canvas 44 17 653 456 12;
+#X obj 31 27 tabwrite;
+#X floatatom 9 176 0 0 0;
+#X obj 9 282 tabwrite array99;
+#X text 113 28 write numbers to a table;
+#X graph graph1 0 0 10 10 355 389 605 189;
+#X array array99 10 float;
+#X pop;
+#X msg 9 53 \; readout 1 \; array99 resize 10 \; array99 bounds 0 0 10 10 \; array99 xlabel -0.5 0 1 2 3 4 5 6 7 8 9 10 \; array99 ylabel -1 0 1 2 3 4 5 6 7 8 9 10 \; array99 0 1 4 2 8 5 6 1 4 2 8;
+#X text 406 94 click here to initialize;
+#X floatatom 146 257 0 0 0;
+#X text 158 279 creation argument;
+#X text 160 297 is array name;
+#X text 46 174 set y value;
+#X text 44 239 right inlet selects x value;
+#X msg 25 204 set array99;
+#X text 133 203 change array name;
+#X text 389 423 updated for Pd version 0.33;
+#X connect 1 0 2 0;
+#X connect 7 0 2 1;
+#X connect 12 0 2 0;
diff --git a/pd/doc/5.reference/tabwrite~-help.pd b/pd/doc/5.reference/tabwrite~-help.pd
new file mode 100644
index 00000000..606f4f30
--- /dev/null
+++ b/pd/doc/5.reference/tabwrite~-help.pd
@@ -0,0 +1,30 @@
+#N canvas 119 134 697 332 10;
+#X obj 31 27 tabwrite~;
+#X text 110 27 object to write a signal in an array;
+#X msg 43 131 bang;
+#X obj 23 211 tabwrite~ array99;
+#X graph graph1 0 -1 100 1 460 235 610 135;
+#X array array99 100 float;
+#X pop;
+#X obj 23 82 sig~ 3000;
+#X obj 23 110 phasor~;
+#X text 149 213 creation argument initializes array name;
+#X msg 40 181 set array99;
+#X msg 445 35 \; pd dsp 1;
+#X msg 524 37 \; pd dsp 0;
+#X text 85 133 bang to start recording;
+#X text 126 180 set the destination array;
+#X text 18 251 see also the "array" tutorial in section 2 of the Pd documentation \, and these objects:;
+#X obj 90 282 tabread;
+#X obj 149 282 tabwrite;
+#X obj 214 282 tabsend~;
+#X obj 279 282 tabreceive~;
+#X obj 17 282 tabread4~;
+#X msg 43 153 stop;
+#X text 85 154 stop recording;
+#X text 458 288 updated for Pd version 0.29;
+#X connect 2 0 3 0;
+#X connect 5 0 6 0;
+#X connect 6 0 3 0;
+#X connect 8 0 3 0;
+#X connect 19 0 3 0;
diff --git a/pd/doc/5.reference/text-help.pd b/pd/doc/5.reference/text-help.pd
new file mode 100644
index 00000000..96664048
--- /dev/null
+++ b/pd/doc/5.reference/text-help.pd
@@ -0,0 +1,4 @@
+#N canvas 74 127 544 214 12;
+#X text 281 174 updated for Pd version 0.26;
+#X text 107 13 comments;
+#X text 38 73 This is Pd's help window for comments \, which don't do anything.;
diff --git a/pd/doc/5.reference/textfile-help.pd b/pd/doc/5.reference/textfile-help.pd
new file mode 100644
index 00000000..8da1dde6
--- /dev/null
+++ b/pd/doc/5.reference/textfile-help.pd
@@ -0,0 +1,59 @@
+#N canvas 12 43 1181 529 12;
+#X msg 582 27 rewind;
+#X obj 577 416 print done;
+#X text 745 185 read a file;
+#X text 801 214 write one;
+#X text 97 472 see also:;
+#X obj 521 365 textfile;
+#X msg 584 188 read textfile.txt;
+#X obj 176 473 qlist;
+#X obj 145 20 textfile;
+#X text 236 20 read and write text files;
+#X text 34 92 The textfile object reads and writes text files to and
+from memory. You can read a file and output sequential lines as lists
+\, or collect lines and write them out. You can use this object to
+generate "models" for Gem \, for instance.;
+#X text 665 28 go to beginning;
+#X msg 582 54 bang;
+#X text 665 53 output one line as a list;
+#X msg 584 216 write /tmp/textfile.txt;
+#X msg 584 243 write /tmp/textfile2.txt cr;
+#X text 593 264 write a file \, terminating lines only with carriage
+return (omitting semicolons.) You can read files this way too \, in
+which case carriage returns are mapped to semicolons.;
+#X obj 521 438 print list;
+#X msg 583 312 read textfile.txt cr;
+#X msg 582 82 clear;
+#X text 737 83 empty the object;
+#X text 737 111 add a message;
+#X text 521 464 this outlet gets the lines in sequence.;
+#X text 35 246 You can also use this object simply for storing heterogeneous
+sequences of lists.;
+#X text 608 385 This outlet gets a bang when you hit the end of the
+sequence.;
+#X msg 582 162 set 2 4 6 8;
+#X text 740 163 clear and then add one message;
+#X msg 582 109 add cis boom bah;
+#X msg 582 136 add2 bang;
+#X text 734 136 add an unterminated message;
+#X text 31 160 To record textual messages and save them to a file \,
+first send "clear" to empty the qlist and "add" to add messages (terminated
+with semicolons.) The message \, "add2" adds a list of atoms without
+finishing with a semicolon in case you want to make variable-length
+messages.;
+#X msg 582 339 print;
+#X text 636 342 debugging printout;
+#X text 901 500 updated for Pd version 0.33;
+#X connect 0 0 5 0;
+#X connect 5 0 17 0;
+#X connect 5 1 1 0;
+#X connect 6 0 5 0;
+#X connect 12 0 5 0;
+#X connect 14 0 5 0;
+#X connect 15 0 5 0;
+#X connect 18 0 5 0;
+#X connect 19 0 5 0;
+#X connect 25 0 5 0;
+#X connect 27 0 5 0;
+#X connect 28 0 5 0;
+#X connect 31 0 5 0;
diff --git a/pd/doc/5.reference/threshold~-help.pd b/pd/doc/5.reference/threshold~-help.pd
new file mode 100644
index 00000000..5922d15b
--- /dev/null
+++ b/pd/doc/5.reference/threshold~-help.pd
@@ -0,0 +1,31 @@
+#N canvas 114 43 685 360 12;
+#X msg 452 58 \; pd dsp 0;
+#X msg 452 24 \; pd dsp 1;
+#X obj 124 11 threshold~;
+#X text 200 12 - TRIGGER FROM AUDIO SIGNAL;
+#X obj 49 183 sig~;
+#X obj 49 261 threshold~ 10 100 0 100;
+#X text 303 255 Arguments:;
+#X text 384 255 1 trigger threshold;
+#X floatatom 49 156 5 0 0;
+#X obj 49 289 print trigger;
+#X obj 205 287 print rest;
+#X text 385 271 2 trigger debounce time;
+#X text 385 288 3 rest threshold;
+#X text 384 303 4 rest debounce time;
+#X text 486 342 updated for Pd version 0.32;
+#X msg 205 209 1;
+#X msg 235 210 0;
+#X text 12 39 threshold~ monitors its input signal and outputs bangs when the signal exceeds a specified "trigger" value \, and also when the signal recedes below a "rest" value. You can specify debounce times in milliseconds \, for the threshold~ to wait after the two event types before triggering again.;
+#X msg 131 151 set 0 2000 1 2000;
+#X msg 131 174 set 10 100 0 100;
+#X text 262 150 "set" to change the parameters;
+#X text 268 210 zero or nonszero in inlet to set the state to "high" or "low". There is no debounce period after this.;
+#X connect 4 0 5 0;
+#X connect 5 0 9 0;
+#X connect 5 1 10 0;
+#X connect 8 0 4 0;
+#X connect 15 0 5 1;
+#X connect 16 0 5 1;
+#X connect 18 0 5 0;
+#X connect 19 0 5 0;
diff --git a/pd/doc/5.reference/throw~-help.pd b/pd/doc/5.reference/throw~-help.pd
new file mode 100644
index 00000000..c9a1ce9d
--- /dev/null
+++ b/pd/doc/5.reference/throw~-help.pd
@@ -0,0 +1,34 @@
+#N canvas 80 120 664 313 12;
+#X obj 97 159 throw~ signal1;
+#X floatatom 268 211 0 0 0;
+#X obj 90 193 sig~ 50;
+#X obj 268 181 snapshot~;
+#X obj 90 221 throw~ signal1;
+#X obj 97 88 sig~ 25;
+#X obj 268 135 catch~ signal1;
+#X obj 35 17 throw~;
+#X obj 97 17 catch~;
+#X text 163 16 - summing signal bus and non-local connection;
+#X obj 551 88 loadbang;
+#X msg 561 110 \; pd dsp 1;
+#X obj 551 151 metro 200;
+#X text 33 48 Any number of throw~ objects can add into one catch~ object (but two catch~ objects cannot share the same name.);
+#X floatatom 401 206 0 0 0;
+#X obj 402 182 snapshot~;
+#X obj 402 134 catch~ signal2;
+#X msg 113 111 set signal2;
+#X msg 114 135 set signal1;
+#X text 75 252 You can redirect throw~ via a "set" message.;
+#X text 410 283 updated for Pd version 0.33;
+#X connect 2 0 4 0;
+#X connect 3 0 1 0;
+#X connect 5 0 0 0;
+#X connect 6 0 3 0;
+#X connect 10 0 11 0;
+#X connect 10 0 12 0;
+#X connect 12 0 3 0;
+#X connect 12 0 15 0;
+#X connect 15 0 14 0;
+#X connect 16 0 15 0;
+#X connect 17 0 0 0;
+#X connect 18 0 0 0;
diff --git a/pd/doc/5.reference/timer-help.pd b/pd/doc/5.reference/timer-help.pd
new file mode 100644
index 00000000..0f7b3829
--- /dev/null
+++ b/pd/doc/5.reference/timer-help.pd
@@ -0,0 +1,15 @@
+#N canvas 440 273 514 280 10;
+#X msg 60 146 bang;
+#X msg 30 115 bang;
+#X obj 30 175 timer;
+#X obj 66 15 timer;
+#X text 111 16 - measure logical time;
+#X floatatom 30 206;
+#X text 71 113 Click here to reset;
+#X text 98 147 Click here to get elapsed logical time;
+#X text 27 232 Output is in milliseconds;
+#X text 6 51 The timer object measures elapsed logical time. Logical time moves forward as if all computation were instantaneous and as if all "delay" and "metro" objects were exact.;
+#X text 319 260 updated for Pd version 0.25;
+#X connect 0 0 2 1;
+#X connect 1 0 2 0;
+#X connect 2 0 5 0;
diff --git a/pd/doc/5.reference/toggle-help.pd b/pd/doc/5.reference/toggle-help.pd
new file mode 100644
index 00000000..5cb9ae75
--- /dev/null
+++ b/pd/doc/5.reference/toggle-help.pd
@@ -0,0 +1,273 @@
+#N canvas 205 140 489 376 10;
+#X obj 1 1 cnv 8 100 60 empty empty toggle=tgl 20 20 1 18 -262144 -1109
+0;
+#X text 21 296 (c) musil@iem.kug.ac.at;
+#X text 63 309 IEM KUG;
+#X text 115 41 click properties to;
+#X text 103 52 modify geometry \, colors \, etc.;
+#X obj 168 113 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144
+-1 -1;
+#X obj 168 179 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144
+-1 -1;
+#X obj 168 133 s foo6_rcv;
+#X obj 168 159 r foo6_snd;
+#X text 153 14 gui-toggle:;
+#X obj 26 270 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X obj 10 117 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X msg 26 39 33;
+#X obj 26 180 tgl 60 1 foo6_snd foo6_rcv big_toggle 63 20 194 13 -228992
+-4033 -34 1 1;
+#X msg 42 79 1;
+#X msg 49 99 0;
+#X floatatom 26 249 4 0 0;
+#X msg 33 59 -0.001;
+#X msg 103 135 set 1;
+#X msg 108 157 set 0;
+#X obj 3 155 tgl 15 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0 1
+;
+#X obj 65 249 tgl 15 0 empty empty empty 8 -8 0 10 -262144 -1 -1 1
+1;
+#X msg 95 114 set -0.23;
+#X obj 189 93 tgl 15 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 188 179 tgl 15 0 empty empty empty 8 -8 0 10 -262144 -1 -1 1
+1;
+#X msg 93 93 0 3 4.55;
+#X msg 85 73 0.22 0 -5.44;
+#X msg 189 113 set \$1;
+#X text 96 222 UP- \, DOWN- \, LEFT- or RIGHT-key;
+#X text 95 233 for moving selected gui-objects;
+#N canvas 440 175 699 530 edit 0;
+#X msg 47 151 \; foo6_rcv color \$1 \$2 \$3;
+#X obj 47 126 pack 0 0 0;
+#X obj 47 98 f;
+#X msg 24 50 bang;
+#X floatatom 63 48 3 0 29;
+#X floatatom 79 68 3 0 29;
+#X floatatom 112 84 3 0 29;
+#X text 91 48 background;
+#X text 106 68 front-color;
+#X text 140 85 label-color;
+#X obj 49 223 f;
+#X msg 27 202 bang;
+#X floatatom 65 201 3 63 88;
+#X floatatom 100 223 3 0 37;
+#X obj 49 246 pack 0 0;
+#X text 127 223 y-label;
+#X text 93 201 x-label;
+#X msg 49 271 \; foo6_rcv label_pos \$1 \$2;
+#X floatatom 505 55 3 8 75;
+#X text 532 55 size;
+#X msg 505 76 \; foo6_rcv size \$1;
+#X obj 282 182 f;
+#X msg 260 161 bang;
+#X floatatom 298 160 3 -10 10;
+#X floatatom 333 182 3 -10 10;
+#X obj 282 205 pack 0 0;
+#X msg 282 230 \; foo6_rcv delta \$1 \$2;
+#X obj 296 301 f;
+#X msg 274 280 bang;
+#X floatatom 312 279 3 20 60;
+#X floatatom 347 301 3 150 200;
+#X obj 296 324 pack 0 0;
+#X msg 296 349 \; foo6_rcv pos \$1 \$2;
+#X text 326 160 x-delta;
+#X text 360 182 y-delta;
+#X text 340 279 x-position;
+#X text 374 301 y-position;
+#X obj 305 423 f;
+#X msg 283 402 bang;
+#X floatatom 321 401 3 -10 10;
+#X floatatom 356 423 3 -10 10;
+#X obj 305 446 pack 0 0;
+#X text 383 423 y-label;
+#X text 349 401 x-label;
+#X msg 305 471 \; foo6_rcv delta \$1 \$2;
+#X msg 499 140 \; foo6_rcv send foo6a_snd;
+#X msg 499 178 \; foo6_rcv send foo6_snd;
+#X msg 494 216 \; foo6_rcv receive foo6a_rcv;
+#X msg 494 254 \; foo6a_rcv receive foo6_rcv;
+#X msg 41 448 \; foo6_rcv label blabla;
+#X msg 41 484 \; foo6_rcv label big_toggle;
+#X obj 69 338 f;
+#X msg 47 317 bang;
+#X floatatom 85 316 3 0 2;
+#X floatatom 120 338 3 4 36;
+#X obj 69 361 pack 0 0;
+#X msg 69 386 \; foo6_rcv label_font \$1 \$2;
+#X text 113 316 font;
+#X text 149 338 height;
+#X floatatom 498 307 5 -200 200;
+#X text 542 307 nonzero-value;
+#X msg 498 331 \; foo6_rcv nonzero \$1;
+#X msg 503 412 \; foo6_rcv init 0;
+#X msg 510 479 \; foo6_rcv init 1;
+#X text 524 393 no init;
+#X text 500 461 init value on loadbang;
+#X msg 285 47 back;
+#X msg 285 67 front;
+#X msg 285 87 label;
+#X msg 247 47 bang;
+#N canvas 15 207 606 448 RGB_____________ 0;
+#X obj 97 56 inlet;
+#X obj 262 53 inlet;
+#X obj 339 55 inlet;
+#X obj 405 56 inlet;
+#X obj 97 270 bang;
+#X msg 77 295 0;
+#X msg 104 295 1;
+#X obj 146 268 bang;
+#X msg 132 295 0;
+#X msg 160 295 1;
+#X obj 196 269 bang;
+#X msg 187 295 0;
+#X msg 214 295 1;
+#X obj 265 313 spigot;
+#X obj 312 313 spigot;
+#X obj 359 313 spigot;
+#X obj 249 385 outlet;
+#X text 93 33 select;
+#X text 267 28 red;
+#X text 337 30 green;
+#X text 409 30 blue;
+#X obj 405 102 t b f;
+#X obj 339 160 +;
+#X obj 339 185 t b f;
+#X obj 339 216 +;
+#X obj 296 385 outlet;
+#X obj 343 385 outlet;
+#X obj 28 180 loadbang;
+#X obj 97 135 route back front label bang;
+#X obj 343 362 f;
+#X obj 296 361 f;
+#X obj 249 361 f;
+#X obj 262 79 * -65536;
+#X obj 339 80 * -256;
+#X obj 405 80 * -1;
+#X obj 339 247 - 1;
+#X obj 235 168 t b b b b;
+#X connect 0 0 28 0;
+#X connect 1 0 32 0;
+#X connect 2 0 33 0;
+#X connect 3 0 34 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 14 1;
+#X connect 5 0 15 1;
+#X connect 6 0 13 1;
+#X connect 7 0 8 0;
+#X connect 7 0 9 0;
+#X connect 8 0 13 1;
+#X connect 8 0 15 1;
+#X connect 9 0 14 1;
+#X connect 10 0 11 0;
+#X connect 10 0 12 0;
+#X connect 11 0 13 1;
+#X connect 11 0 14 1;
+#X connect 12 0 15 1;
+#X connect 13 0 31 1;
+#X connect 14 0 30 1;
+#X connect 15 0 29 1;
+#X connect 21 0 22 0;
+#X connect 21 1 22 1;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 23 1 24 1;
+#X connect 24 0 35 0;
+#X connect 27 0 6 0;
+#X connect 28 0 4 0;
+#X connect 28 1 7 0;
+#X connect 28 2 10 0;
+#X connect 28 3 36 0;
+#X connect 29 0 26 0;
+#X connect 30 0 25 0;
+#X connect 31 0 16 0;
+#X connect 32 0 24 0;
+#X connect 33 0 22 0;
+#X connect 34 0 21 0;
+#X connect 35 0 15 0;
+#X connect 35 0 14 0;
+#X connect 35 0 13 0;
+#X connect 36 0 31 0;
+#X connect 36 1 30 0;
+#X connect 36 2 29 0;
+#X connect 36 3 35 0;
+#X restore 285 108 pd RGB_____________;
+#X floatatom 327 77 3 0 255;
+#X floatatom 370 77 3 0 255;
+#X floatatom 413 78 3 0 255;
+#X text 34 22 preset-colors;
+#X text 296 19 RGB-colors;
+#X text 327 59 red;
+#X text 363 58 green;
+#X text 411 58 blue;
+#X connect 1 0 0 0;
+#X connect 2 0 1 0;
+#X connect 3 0 2 0;
+#X connect 4 0 2 1;
+#X connect 5 0 1 1;
+#X connect 6 0 1 2;
+#X connect 10 0 14 0;
+#X connect 11 0 10 0;
+#X connect 12 0 10 1;
+#X connect 13 0 14 1;
+#X connect 14 0 17 0;
+#X connect 18 0 20 0;
+#X connect 21 0 25 0;
+#X connect 22 0 21 0;
+#X connect 23 0 21 1;
+#X connect 24 0 25 1;
+#X connect 25 0 26 0;
+#X connect 27 0 31 0;
+#X connect 28 0 27 0;
+#X connect 29 0 27 1;
+#X connect 30 0 31 1;
+#X connect 31 0 32 0;
+#X connect 37 0 41 0;
+#X connect 38 0 37 0;
+#X connect 39 0 37 1;
+#X connect 40 0 41 1;
+#X connect 41 0 44 0;
+#X connect 51 0 55 0;
+#X connect 52 0 51 0;
+#X connect 53 0 51 1;
+#X connect 54 0 55 1;
+#X connect 55 0 56 0;
+#X connect 59 0 61 0;
+#X connect 66 0 70 0;
+#X connect 67 0 70 0;
+#X connect 68 0 70 0;
+#X connect 69 0 70 0;
+#X connect 70 0 1 0;
+#X connect 70 1 1 1;
+#X connect 70 2 1 2;
+#X connect 71 0 70 1;
+#X connect 72 0 70 2;
+#X connect 73 0 70 3;
+#X restore 278 136 pd edit;
+#X obj 222 276 tgl 15 0 bbb bbb empty 20 8 192 8 -262144 -1 -1 1 1
+;
+#X text 191 320 updated for Pd version 0.35;
+#X text 38 321 graz \, austria 2002;
+#X obj 127 255 x_all_guis aaa bbb ccc ddd eee fff ggg hhh iii;
+#X connect 5 0 7 0;
+#X connect 8 0 6 0;
+#X connect 8 0 24 0;
+#X connect 11 0 13 0;
+#X connect 12 0 13 0;
+#X connect 13 0 16 0;
+#X connect 13 0 21 0;
+#X connect 14 0 13 0;
+#X connect 15 0 13 0;
+#X connect 16 0 10 0;
+#X connect 17 0 13 0;
+#X connect 18 0 13 0;
+#X connect 19 0 13 0;
+#X connect 20 0 13 0;
+#X connect 22 0 13 0;
+#X connect 23 0 27 0;
+#X connect 25 0 13 0;
+#X connect 26 0 13 0;
+#X connect 27 0 7 0;
diff --git a/pd/doc/5.reference/trigger-help.pd b/pd/doc/5.reference/trigger-help.pd
new file mode 100644
index 00000000..a32d5def
--- /dev/null
+++ b/pd/doc/5.reference/trigger-help.pd
@@ -0,0 +1,37 @@
+#N canvas 58 142 685 355 12;
+#X msg 28 149 2.5;
+#X msg 126 151 bang;
+#X msg 68 150 23 64;
+#X obj 28 242 print x1;
+#X obj 112 242 print x2;
+#X obj 196 240 print x3;
+#X obj 43 26 trigger;
+#X obj 286 241 print x4;
+#X text 114 27 - sequence messages in right-to-left order;
+#X text 417 331 updated for Pd version 0.33;
+#X text 81 290 the above can be abbreviated as:;
+#X msg 172 152 symbol dog;
+#X text 39 59 The trigger object outputs its input from right to left
+\, converting to the types indicated by its creation arguments. There
+is also a "pointer" argument type (see the pointer object.);
+#X obj 381 293 t f b l s a;
+#X msg 466 167 dog my cats;
+#X obj 466 199 trigger bang anything;
+#X obj 374 242 print x5;
+#X obj 466 240 print y1;
+#X obj 552 242 print y2;
+#X obj 28 202 trigger float bang symbol list anything;
+#X text 464 122 "anythings" can only;
+#X text 461 142 be converted to bang:;
+#X connect 0 0 19 0;
+#X connect 1 0 19 0;
+#X connect 2 0 19 0;
+#X connect 11 0 19 0;
+#X connect 14 0 15 0;
+#X connect 15 0 17 0;
+#X connect 15 1 18 0;
+#X connect 19 0 3 0;
+#X connect 19 1 4 0;
+#X connect 19 2 5 0;
+#X connect 19 3 7 0;
+#X connect 19 4 16 0;
diff --git a/pd/doc/5.reference/unpack-help.pd b/pd/doc/5.reference/unpack-help.pd
new file mode 100644
index 00000000..5f1a4120
--- /dev/null
+++ b/pd/doc/5.reference/unpack-help.pd
@@ -0,0 +1,28 @@
+#N canvas 234 84 730 277 12;
+#X floatatom 80 180 0 0 0;
+#X floatatom 205 180 0 0 0;
+#X floatatom 243 180 0 0 0;
+#X floatatom 46 180 0 0 0;
+#X obj 117 180 print foo;
+#X obj 133 243 pack;
+#X text 51 242 See also;
+#X obj 101 9 unpack;
+#X text 164 8 - split a message to atoms;
+#X text 196 139 <-- creation arguments specify the types of atoms expected
+;
+#X msg 46 102 1 2;
+#X msg 85 102 3 4 shut;
+#X msg 164 102 5 6 pick 7 8;
+#X text 368 239 updated for Pd version 0.33;
+#X obj 46 139 unpack 0 0 s 0 0;
+#X text 25 36 unpack takes lists of atoms and distributes them to its
+outlets. The creation arguments specify float (any number or the symbol
+'f') \, pointer (symbol 'p') or symbol (symbol 's').;
+#X connect 10 0 14 0;
+#X connect 11 0 14 0;
+#X connect 12 0 14 0;
+#X connect 14 0 3 0;
+#X connect 14 1 0 0;
+#X connect 14 2 4 0;
+#X connect 14 3 1 0;
+#X connect 14 4 2 0;
diff --git a/pd/doc/5.reference/until-help.pd b/pd/doc/5.reference/until-help.pd
new file mode 100644
index 00000000..9da7a9ce
--- /dev/null
+++ b/pd/doc/5.reference/until-help.pd
@@ -0,0 +1,25 @@
+#N canvas 142 97 410 273 10;
+#X msg 65 116 bang;
+#X obj 66 15 until;
+#X text 114 16 - LOOP;
+#X text 24 36 The until object's left inlet starts a loop in which it outputs "bang" until its right inlet gets a bang which stops it. If you start "until" with a number \, it iterates at most that number of times \, as in the Max "uzi" object.;
+#X text 24 85 WARNING: if you bang an "until" which doesn't have a stopping mechanism \, Pd goes into an infinite loop!;
+#X obj 65 168 until;
+#X text 110 115 start;
+#X msg 73 137 3;
+#X text 109 138 start limited to 3 iterations;
+#X obj 65 196 f;
+#X obj 96 198 + 1;
+#X obj 140 198 sel 0;
+#X obj 65 240 print;
+#X obj 96 219 mod 10;
+#X text 225 247 updated for Pd version 0.28;
+#X connect 0 0 5 0;
+#X connect 5 0 9 0;
+#X connect 7 0 5 0;
+#X connect 9 0 10 0;
+#X connect 9 0 12 0;
+#X connect 10 0 13 0;
+#X connect 11 0 5 1;
+#X connect 13 0 9 1;
+#X connect 13 0 11 0;
diff --git a/pd/doc/5.reference/value-help.pd b/pd/doc/5.reference/value-help.pd
new file mode 100644
index 00000000..66c457a3
--- /dev/null
+++ b/pd/doc/5.reference/value-help.pd
@@ -0,0 +1,30 @@
+#N canvas 257 45 500 281 12;
+#X text 290 257 updated for Pd version 0.32;
+#X floatatom 36 55 5 0 0;
+#X text 50 249 abbreviation:;
+#X text 79 10 -- nonlocal shared value (named variable);
+#X floatatom 36 130 5 0 0;
+#X msg 46 78 bang;
+#X obj 21 10 value;
+#X obj 36 105 value help-value1;
+#X obj 149 248 v;
+#X floatatom 163 55 5 0 0;
+#X floatatom 163 130 5 0 0;
+#X msg 173 78 bang;
+#X obj 163 105 value help-value1;
+#X floatatom 291 55 5 0 0;
+#X floatatom 291 130 5 0 0;
+#X msg 301 78 bang;
+#X obj 291 105 value help-value2;
+#X text 31 171 "Value" stores a numeric value which is shared between all values with the same name (which need not be in the same Pd window.);
+#X text 345 54 numbers set the value;
+#X text 349 77 bang retrieves it;
+#X connect 1 0 7 0;
+#X connect 5 0 7 0;
+#X connect 7 0 4 0;
+#X connect 9 0 12 0;
+#X connect 11 0 12 0;
+#X connect 12 0 10 0;
+#X connect 13 0 16 0;
+#X connect 15 0 16 0;
+#X connect 16 0 14 0;
diff --git a/pd/doc/5.reference/vcf~-help.pd b/pd/doc/5.reference/vcf~-help.pd
new file mode 100644
index 00000000..45dde1d8
--- /dev/null
+++ b/pd/doc/5.reference/vcf~-help.pd
@@ -0,0 +1,35 @@
+#N canvas 0 0 644 422 12;
+#X obj 257 200 sig~;
+#X text 14 193 test signal;
+#X text 100 341 amp in (db);
+#X text 92 144 test frequency;
+#X text 224 340 amp out (db);
+#X obj 220 264 vcf~;
+#X text 246 144 center frequency;
+#X text 374 184 q;
+#X floatatom 122 168 5 0 0;
+#X floatatom 257 171 5 0 0;
+#X obj 122 193 osc~;
+#X floatatom 353 203 5 0 0;
+#X obj 122 291 env~ 8192;
+#X obj 220 290 env~ 8192;
+#X floatatom 121 318 5 0 0;
+#X floatatom 220 319 5 0 0;
+#X obj 80 13 vcf~;
+#X text 135 13 -- voltage-controlled bandpass filter;
+#X text 26 395 see also:;
+#X obj 115 394 bp~;
+#X text 302 394 updated for Pd version 0.35;
+#X text 12 45 vcf~ is like bp~ except that it takes an audio signal
+to set center frequency \, which may thus change continuously in time.
+The "Q" or filter sharpness is still only set by messages. More expensive
+than bp~ in CPU time but more powerful too.;
+#X connect 0 0 5 1;
+#X connect 5 0 13 0;
+#X connect 8 0 10 0;
+#X connect 9 0 0 0;
+#X connect 10 0 5 0;
+#X connect 10 0 12 0;
+#X connect 11 0 5 2;
+#X connect 12 0 14 0;
+#X connect 13 0 15 0;
diff --git a/pd/doc/5.reference/vdial-help.pd b/pd/doc/5.reference/vdial-help.pd
new file mode 100644
index 00000000..048c4c2b
--- /dev/null
+++ b/pd/doc/5.reference/vdial-help.pd
@@ -0,0 +1,282 @@
+#N canvas 106 314 558 455 10;
+#X obj 1 1 cnv 8 100 60 empty empty vdial=vdl 20 20 1 18 -262144 -1109
+0;
+#X text 13 390 (c) musil@iem.kug.ac.at;
+#X text 55 403 IEM KUG;
+#X text 132 122 click properties to;
+#X text 120 133 modify geometry \, colors \, etc.;
+#X obj 159 261 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144
+-1 -1;
+#X obj 21 54 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X msg 41 319 \$1;
+#X floatatom 41 341 4 0 0;
+#X obj 41 363 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X obj 86 338 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 86 317 route 0 1 2 3 4 5 6 7 8 9;
+#X msg 194 92 set \$1;
+#X floatatom 194 71 4 0 9;
+#X floatatom 44 54 4 0 9;
+#X msg 91 41 7 0 -5.44;
+#X msg 95 63 3 3 4.55;
+#X obj 103 338 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 120 338 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 1
+1;
+#X obj 137 338 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 154 338 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 171 338 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 188 338 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 205 338 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 222 338 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 239 338 tgl 12 0 empty empty empty 8 -8 0 10 -262144 -1 -1 0
+1;
+#X obj 79 355 print;
+#X floatatom 183 287 4 0 0;
+#X msg 183 261 \$1;
+#X msg 158 192 set \$1;
+#X floatatom 158 171 4 0 9;
+#X text 125 355 UP- \, DOWN- \, LEFT- or RIGHT-key;
+#X text 124 366 for moving selected gui-objects;
+#N canvas 230 247 699 530 edit 0;
+#X obj 42 198 f;
+#X msg 20 177 bang;
+#X floatatom 58 176 3 63 156;
+#X floatatom 93 198 3 -20 37;
+#X obj 42 221 pack 0 0;
+#X text 120 198 y-label;
+#X text 86 176 x-label;
+#X floatatom 270 187 3 8 50;
+#X text 297 187 size;
+#X obj 286 293 f;
+#X msg 264 272 bang;
+#X floatatom 302 271 3 -10 10;
+#X floatatom 337 293 3 -10 10;
+#X obj 286 316 pack 0 0;
+#X obj 300 412 f;
+#X msg 278 391 bang;
+#X floatatom 316 390 3 20 60;
+#X floatatom 351 412 3 100 200;
+#X obj 300 435 pack 0 0;
+#X text 330 271 x-delta;
+#X text 364 293 y-delta;
+#X text 344 390 x-position;
+#X text 378 412 y-position;
+#X obj 62 313 f;
+#X msg 40 292 bang;
+#X floatatom 78 291 3 0 2;
+#X floatatom 113 313 3 4 36;
+#X obj 62 336 pack 0 0;
+#X text 106 291 font;
+#X text 142 313 height;
+#X text 504 293 no init;
+#X text 475 348 init value on loadbang;
+#X floatatom 482 228 5 2 20;
+#X text 491 417 changing-behavior;
+#X text 526 228 number of buttons;
+#X obj 47 104 pack 0 0 0;
+#X obj 47 76 f;
+#X msg 24 28 bang;
+#X floatatom 63 26 3 0 29;
+#X floatatom 79 46 3 0 29;
+#X floatatom 112 62 3 0 29;
+#X text 91 26 background;
+#X text 106 46 front-color;
+#X text 140 63 label-color;
+#X msg 285 25 back;
+#X msg 285 45 front;
+#X msg 285 65 label;
+#X msg 247 25 bang;
+#N canvas 15 207 606 448 RGB_____________ 0;
+#X obj 97 56 inlet;
+#X obj 262 53 inlet;
+#X obj 339 55 inlet;
+#X obj 405 56 inlet;
+#X obj 97 270 bang;
+#X msg 77 295 0;
+#X msg 104 295 1;
+#X obj 146 268 bang;
+#X msg 132 295 0;
+#X msg 160 295 1;
+#X obj 196 269 bang;
+#X msg 187 295 0;
+#X msg 214 295 1;
+#X obj 265 313 spigot;
+#X obj 312 313 spigot;
+#X obj 359 313 spigot;
+#X obj 249 385 outlet;
+#X text 93 33 select;
+#X text 267 28 red;
+#X text 337 30 green;
+#X text 409 30 blue;
+#X obj 405 102 t b f;
+#X obj 339 160 +;
+#X obj 339 185 t b f;
+#X obj 339 216 +;
+#X obj 296 385 outlet;
+#X obj 343 385 outlet;
+#X obj 28 180 loadbang;
+#X obj 97 135 route back front label bang;
+#X obj 343 362 f;
+#X obj 296 361 f;
+#X obj 249 361 f;
+#X obj 262 79 * -65536;
+#X obj 339 80 * -256;
+#X obj 405 80 * -1;
+#X obj 339 247 - 1;
+#X obj 235 168 t b b b b;
+#X connect 0 0 28 0;
+#X connect 1 0 32 0;
+#X connect 2 0 33 0;
+#X connect 3 0 34 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 14 1;
+#X connect 5 0 15 1;
+#X connect 6 0 13 1;
+#X connect 7 0 8 0;
+#X connect 7 0 9 0;
+#X connect 8 0 13 1;
+#X connect 8 0 15 1;
+#X connect 9 0 14 1;
+#X connect 10 0 11 0;
+#X connect 10 0 12 0;
+#X connect 11 0 13 1;
+#X connect 11 0 14 1;
+#X connect 12 0 15 1;
+#X connect 13 0 31 1;
+#X connect 14 0 30 1;
+#X connect 15 0 29 1;
+#X connect 21 0 22 0;
+#X connect 21 1 22 1;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 23 1 24 1;
+#X connect 24 0 35 0;
+#X connect 27 0 6 0;
+#X connect 28 0 4 0;
+#X connect 28 1 7 0;
+#X connect 28 2 10 0;
+#X connect 28 3 36 0;
+#X connect 29 0 26 0;
+#X connect 30 0 25 0;
+#X connect 31 0 16 0;
+#X connect 32 0 24 0;
+#X connect 33 0 22 0;
+#X connect 34 0 21 0;
+#X connect 35 0 15 0;
+#X connect 35 0 14 0;
+#X connect 35 0 13 0;
+#X connect 36 0 31 0;
+#X connect 36 1 30 0;
+#X connect 36 2 29 0;
+#X connect 36 3 35 0;
+#X restore 285 86 pd RGB_____________;
+#X floatatom 327 55 3 0 255;
+#X floatatom 370 55 3 0 255;
+#X floatatom 413 56 3 0 255;
+#X text 34 0 preset-colors;
+#X text 296 -3 RGB-colors;
+#X text 327 37 red;
+#X text 363 36 green;
+#X text 411 36 blue;
+#X msg 47 125 \; foo12_rcv color \$1 \$2 \$3;
+#X msg 42 246 \; foo12_rcv label_pos \$1 \$2;
+#X msg 62 361 \; foo12_rcv label_font \$1 \$2;
+#X msg 34 423 \; foo12_rcv label blabla;
+#X msg 34 459 \; foo12_rcv label vdial_0_9;
+#X msg 300 460 \; foo12_rcv pos \$1 \$2;
+#X msg 286 341 \; foo12_rcv delta \$1 \$2;
+#X msg 270 216 \; foo12_rcv size \$1;
+#X msg 483 50 \; foo12_rcv send foo12a_snd;
+#X msg 483 88 \; foo12_rcv send foo12_snd;
+#X msg 482 171 \; foo12a_rcv receive foo12_rcv;
+#X msg 483 133 \; foo12_rcv receive foo12a_rcv;
+#X msg 482 254 \; foo12_rcv number \$1;
+#X msg 483 312 \; foo12_rcv init 0;
+#X msg 485 366 \; foo12_rcv init 1;
+#X msg 490 436 \; foo12_rcv single_change;
+#X msg 490 470 \; foo12_rcv double_change;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 4 1;
+#X connect 4 0 58 0;
+#X connect 7 0 64 0;
+#X connect 9 0 13 0;
+#X connect 10 0 9 0;
+#X connect 11 0 9 1;
+#X connect 12 0 13 1;
+#X connect 13 0 63 0;
+#X connect 14 0 18 0;
+#X connect 15 0 14 0;
+#X connect 16 0 14 1;
+#X connect 17 0 18 1;
+#X connect 18 0 62 0;
+#X connect 23 0 27 0;
+#X connect 24 0 23 0;
+#X connect 25 0 23 1;
+#X connect 26 0 27 1;
+#X connect 27 0 59 0;
+#X connect 32 0 69 0;
+#X connect 35 0 57 0;
+#X connect 36 0 35 0;
+#X connect 37 0 36 0;
+#X connect 38 0 36 1;
+#X connect 39 0 35 1;
+#X connect 40 0 35 2;
+#X connect 44 0 48 0;
+#X connect 45 0 48 0;
+#X connect 46 0 48 0;
+#X connect 47 0 48 0;
+#X connect 48 0 35 0;
+#X connect 48 1 35 1;
+#X connect 48 2 35 2;
+#X connect 49 0 48 1;
+#X connect 50 0 48 2;
+#X connect 51 0 48 3;
+#X restore 267 222 pd edit;
+#X obj 221 11 x_all_guis aaa bbb ccc ddd eee fff ggg hhh iii;
+#X text 30 415 graz \, austria 2002;
+#X text 223 401 updated for Pd version 0.35;
+#X text 144 11 gui-vdial:;
+#X obj 79 110 vdl 25 1 0 8 foo12_snd foo12_rcv vdial_0_9 20 -8 192
+10 -99865 -262144 -260818 0;
+#X obj 352 36 vdl 15 1 0 8 iii iii empty 20 8 192 8 -262144 -1 -1 0
+;
+#X obj 158 213 s foo12_rcv;
+#X obj 159 239 r foo12_snd;
+#X connect 6 0 38 0;
+#X connect 7 0 8 0;
+#X connect 8 0 9 0;
+#X connect 11 0 10 0;
+#X connect 11 1 17 0;
+#X connect 11 2 18 0;
+#X connect 11 3 19 0;
+#X connect 11 4 20 0;
+#X connect 11 5 21 0;
+#X connect 11 6 22 0;
+#X connect 11 7 23 0;
+#X connect 11 8 24 0;
+#X connect 11 9 25 0;
+#X connect 12 0 38 0;
+#X connect 13 0 12 0;
+#X connect 14 0 38 0;
+#X connect 15 0 38 0;
+#X connect 16 0 38 0;
+#X connect 28 0 27 0;
+#X connect 29 0 40 0;
+#X connect 30 0 29 0;
+#X connect 38 0 11 0;
+#X connect 38 0 26 0;
+#X connect 38 0 7 0;
+#X connect 41 0 5 0;
+#X connect 41 0 28 0;
diff --git a/pd/doc/5.reference/vd~-help.pd b/pd/doc/5.reference/vd~-help.pd
new file mode 100644
index 00000000..5a36ff73
--- /dev/null
+++ b/pd/doc/5.reference/vd~-help.pd
@@ -0,0 +1,19 @@
+#N canvas 109 10 654 410 12;
+#X floatatom 50 194 0 0 0;
+#X obj 50 287 outlet~;
+#X text 130 286 signal output (delayed signal);
+#X obj 24 16 vd~;
+#X text 60 9 reads a signal from a delay line at a variable delay time (4-point-interpolation);
+#X obj 50 222 sig~;
+#X text 99 219 signal input (delay time in ms);
+#X obj 50 254 vd~ del_example;
+#X text 193 252 creation argument: name of delay line;
+#X text 31 51 vd~ implements a 4-point interpolating delay tap from a corresponding delwrite~ object. The delay in milliseconds of the tap is specified by the incoming signal.;
+#X text 35 340 see also:;
+#X obj 123 343 delwrite~;
+#X obj 212 342 delread~;
+#X text 354 373 updated for Pd version 0.33;
+#X text 28 103 The delay time is always at least one sample and at most the length of the delay line (specified by hte delwrite~). In addition \, in case the delwrite~ runs later in the DSP loop than the vd~ \, the delay is constrained below by one vector length (64 samples.);
+#X connect 0 0 5 0;
+#X connect 5 0 7 0;
+#X connect 7 0 1 0;
diff --git a/pd/doc/5.reference/vslider-help.pd b/pd/doc/5.reference/vslider-help.pd
new file mode 100644
index 00000000..69452ad6
--- /dev/null
+++ b/pd/doc/5.reference/vslider-help.pd
@@ -0,0 +1,302 @@
+#N canvas 147 201 617 416 10;
+#X obj 1 1 cnv 8 100 60 empty empty vslider=vsl 20 20 1 18 -262144
+-1109 0;
+#X floatatom 38 300 9 0 0;
+#X msg 47 84 set \$1;
+#X floatatom 38 43 7 0 0;
+#X text 25 363 (c) musil@iem.kug.ac.at;
+#X text 67 376 IEM KUG;
+#X obj 38 324 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X obj 18 47 bng 15 250 50 0 empty empty empty 8 -8 0 10 -262144 -1
+-1;
+#X floatatom 47 63 7 0 0;
+#X floatatom 116 324 9 0 0;
+#X floatatom 106 42 7 0 0;
+#X floatatom 147 113 7 0 0;
+#X obj 75 249 ftom;
+#X floatatom 75 271 9 0 0;
+#X floatatom 111 244 9 0 0;
+#X floatatom 185 266 9 0 0;
+#X text 181 151 click properties to;
+#X floatatom 75 112 9 0 0;
+#X obj 75 134 mtof;
+#X text 166 12 gui-vertical-slider:;
+#X obj 38 162 vsl 15 101 100 300 0 1 foo3_snd foo3_rcv empty 8 -8 192
+10 -225280 -1109 -1 2500 1;
+#X obj 75 168 vsl 15 73 55 3520 1 1 goo4_snd goo4_rcv log.freq. 11
+-6 192 10 -261681 -260818 -90881 0 1;
+#X obj 185 244 r goo4_snd;
+#X obj 147 133 s goo4_rcv;
+#X text 202 65 (0.01 pixels);
+#X text 57 99 ------------------------------------------;
+#X text 57 286 --------------------------------------------;
+#X text 169 162 modify geometry \, colors \, etc.;
+#X obj 106 84 s foo3_rcv;
+#X obj 116 302 r foo3_snd;
+#X msg 106 63 set \$1;
+#X text 188 44 shift-click & drag;
+#X text 194 54 for fine-tuning;
+#X text 119 192 UP- \, DOWN- \, LEFT- or RIGHT-key;
+#X text 118 203 for moving selected gui-objects;
+#N canvas 239 379 699 530 edit 0;
+#X obj 37 233 f;
+#X msg 15 212 bang;
+#X floatatom 53 211 3 6 88;
+#X floatatom 88 233 3 -20 37;
+#X obj 37 256 pack 0 0;
+#X text 115 233 y-label;
+#X text 81 211 x-label;
+#X obj 287 271 f;
+#X msg 265 250 bang;
+#X floatatom 303 249 3 -10 10;
+#X floatatom 338 271 3 -10 10;
+#X obj 287 294 pack 0 0;
+#X obj 299 381 f;
+#X msg 277 360 bang;
+#X floatatom 315 359 3 20 90;
+#X floatatom 350 381 3 150 200;
+#X obj 299 404 pack 0 0;
+#X text 331 249 x-delta;
+#X text 365 271 y-delta;
+#X text 343 359 x-position;
+#X text 377 381 y-position;
+#X obj 57 348 f;
+#X msg 35 327 bang;
+#X floatatom 73 326 3 0 2;
+#X floatatom 108 348 3 4 36;
+#X obj 57 371 pack 0 0;
+#X text 101 326 font;
+#X text 137 348 height;
+#X floatatom 476 188 1 0 1;
+#X text 523 401 no init;
+#X text 493 453 init value on loadbang;
+#X text 520 188 steady;
+#X obj 486 291 f;
+#X msg 464 270 bang;
+#X floatatom 502 269 4 55 440;
+#X floatatom 537 291 6 440 3520;
+#X obj 486 314 pack 0 0;
+#X text 269 469 linear / logarithmical;
+#X msg 47 158 \; goo4_rcv color \$1 \$2 \$3;
+#X msg 37 281 \; goo4_rcv label_pos \$1 \$2;
+#X msg 57 396 \; goo4_rcv label_font \$1 \$2;
+#X msg 40 442 \; goo4_rcv label blabla;
+#X msg 269 487 \; goo4_rcv lin;
+#X msg 363 486 \; goo4_rcv log;
+#X msg 299 429 \; goo4_rcv pos \$1 \$2;
+#X msg 287 319 \; goo4_rcv delta \$1 \$2;
+#X msg 475 21 \; goo4_rcv send goo4a_snd;
+#X msg 475 59 \; goo4_rcv send goo4_snd;
+#X msg 476 105 \; goo4_rcv receive goo4a_rcv;
+#X msg 476 143 \; goo4a_rcv receive goo4_rcv;
+#X msg 486 339 \; goo4_rcv range \$1 \$2;
+#X msg 502 420 \; goo4_rcv init 0;
+#X msg 503 471 \; goo4_rcv init 1;
+#X text 539 270 bottom-range-bound;
+#X text 586 292 top-range-bound;
+#X obj 286 160 f;
+#X msg 264 139 bang;
+#X floatatom 302 138 3 4 55;
+#X floatatom 337 160 3 15 73;
+#X obj 286 183 pack 0 0;
+#X msg 286 208 \; goo4_rcv size \$1 \$2;
+#X text 330 138 width;
+#X text 368 161 height;
+#X msg 41 478 \; goo4_rcv label log.freq.;
+#X msg 476 212 \; goo4_rcv steady \$1;
+#X obj 47 116 pack 0 0 0;
+#X obj 47 88 f;
+#X msg 24 40 bang;
+#X floatatom 63 38 3 0 29;
+#X floatatom 79 58 3 0 29;
+#X floatatom 112 74 3 0 29;
+#X text 91 38 background;
+#X text 106 58 front-color;
+#X text 140 75 label-color;
+#X msg 285 37 back;
+#X msg 285 57 front;
+#X msg 285 77 label;
+#X msg 247 37 bang;
+#N canvas 15 207 606 448 RGB_____________ 0;
+#X obj 97 56 inlet;
+#X obj 262 53 inlet;
+#X obj 339 55 inlet;
+#X obj 405 56 inlet;
+#X obj 97 270 bang;
+#X msg 77 295 0;
+#X msg 104 295 1;
+#X obj 146 268 bang;
+#X msg 132 295 0;
+#X msg 160 295 1;
+#X obj 196 269 bang;
+#X msg 187 295 0;
+#X msg 214 295 1;
+#X obj 265 313 spigot;
+#X obj 312 313 spigot;
+#X obj 359 313 spigot;
+#X obj 249 385 outlet;
+#X text 93 33 select;
+#X text 267 28 red;
+#X text 337 30 green;
+#X text 409 30 blue;
+#X obj 405 102 t b f;
+#X obj 339 160 +;
+#X obj 339 185 t b f;
+#X obj 339 216 +;
+#X obj 296 385 outlet;
+#X obj 343 385 outlet;
+#X obj 28 180 loadbang;
+#X obj 97 135 route back front label bang;
+#X obj 343 362 f;
+#X obj 296 361 f;
+#X obj 249 361 f;
+#X obj 262 79 * -65536;
+#X obj 339 80 * -256;
+#X obj 405 80 * -1;
+#X obj 339 247 - 1;
+#X obj 235 168 t b b b b;
+#X connect 0 0 28 0;
+#X connect 1 0 32 0;
+#X connect 2 0 33 0;
+#X connect 3 0 34 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 14 1;
+#X connect 5 0 15 1;
+#X connect 6 0 13 1;
+#X connect 7 0 8 0;
+#X connect 7 0 9 0;
+#X connect 8 0 13 1;
+#X connect 8 0 15 1;
+#X connect 9 0 14 1;
+#X connect 10 0 11 0;
+#X connect 10 0 12 0;
+#X connect 11 0 13 1;
+#X connect 11 0 14 1;
+#X connect 12 0 15 1;
+#X connect 13 0 31 1;
+#X connect 14 0 30 1;
+#X connect 15 0 29 1;
+#X connect 21 0 22 0;
+#X connect 21 1 22 1;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 23 1 24 1;
+#X connect 24 0 35 0;
+#X connect 27 0 6 0;
+#X connect 28 0 4 0;
+#X connect 28 1 7 0;
+#X connect 28 2 10 0;
+#X connect 28 3 36 0;
+#X connect 29 0 26 0;
+#X connect 30 0 25 0;
+#X connect 31 0 16 0;
+#X connect 32 0 24 0;
+#X connect 33 0 22 0;
+#X connect 34 0 21 0;
+#X connect 35 0 15 0;
+#X connect 35 0 14 0;
+#X connect 35 0 13 0;
+#X connect 36 0 31 0;
+#X connect 36 1 30 0;
+#X connect 36 2 29 0;
+#X connect 36 3 35 0;
+#X restore 285 98 pd RGB_____________;
+#X floatatom 327 67 3 0 255;
+#X floatatom 370 67 3 0 255;
+#X floatatom 413 68 3 0 255;
+#X text 34 12 preset-colors;
+#X text 296 9 RGB-colors;
+#X text 327 49 red;
+#X text 363 48 green;
+#X text 411 48 blue;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 4 1;
+#X connect 4 0 39 0;
+#X connect 7 0 11 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 1;
+#X connect 10 0 11 1;
+#X connect 11 0 45 0;
+#X connect 12 0 16 0;
+#X connect 13 0 12 0;
+#X connect 14 0 12 1;
+#X connect 15 0 16 1;
+#X connect 16 0 44 0;
+#X connect 21 0 25 0;
+#X connect 22 0 21 0;
+#X connect 23 0 21 1;
+#X connect 24 0 25 1;
+#X connect 25 0 40 0;
+#X connect 28 0 64 0;
+#X connect 32 0 36 0;
+#X connect 33 0 32 0;
+#X connect 34 0 32 1;
+#X connect 35 0 36 1;
+#X connect 36 0 50 0;
+#X connect 55 0 59 0;
+#X connect 56 0 55 0;
+#X connect 57 0 55 1;
+#X connect 58 0 59 1;
+#X connect 59 0 60 0;
+#X connect 65 0 38 0;
+#X connect 66 0 65 0;
+#X connect 67 0 66 0;
+#X connect 68 0 66 1;
+#X connect 69 0 65 1;
+#X connect 70 0 65 2;
+#X connect 74 0 78 0;
+#X connect 75 0 78 0;
+#X connect 76 0 78 0;
+#X connect 77 0 78 0;
+#X connect 78 0 65 0;
+#X connect 78 1 65 1;
+#X connect 78 2 65 2;
+#X connect 79 0 78 1;
+#X connect 80 0 78 2;
+#X connect 81 0 78 3;
+#X restore 327 48 pd edit;
+#X obj 61 345 print;
+#N canvas 276 200 290 224 once 0;
+#X obj 38 47 t b b f;
+#X msg 56 85 1;
+#X obj 31 108 f 0;
+#X obj 31 131 pack 0 0;
+#X obj 31 156 route 0;
+#X obj 38 24 inlet;
+#X obj 31 180 outlet;
+#X connect 0 0 1 0;
+#X connect 0 1 2 0;
+#X connect 0 2 3 1;
+#X connect 1 0 2 1;
+#X connect 2 0 3 0;
+#X connect 3 0 4 0;
+#X connect 4 0 6 0;
+#X connect 5 0 0 0;
+#X restore 61 322 pd once;
+#X obj 377 110 vsl 15 128 0 127 0 0 ccc ccc empty 20 8 192 8 -262144
+-1 -1 4200 1;
+#X obj 249 87 x_all_guis aaa bbb ccc ddd eee fff ggg hhh iii;
+#X text 218 387 updated for Pd version 0.35;
+#X text 42 388 graz \, austria 2002;
+#X connect 1 0 6 0;
+#X connect 2 0 20 0;
+#X connect 3 0 20 0;
+#X connect 7 0 20 0;
+#X connect 8 0 2 0;
+#X connect 10 0 30 0;
+#X connect 11 0 23 0;
+#X connect 12 0 13 0;
+#X connect 17 0 18 0;
+#X connect 18 0 21 0;
+#X connect 20 0 1 0;
+#X connect 20 0 37 0;
+#X connect 21 0 14 0;
+#X connect 21 0 12 0;
+#X connect 22 0 15 0;
+#X connect 29 0 9 0;
+#X connect 30 0 28 0;
+#X connect 37 0 36 0;
diff --git a/pd/doc/5.reference/vu-help.pd b/pd/doc/5.reference/vu-help.pd
new file mode 100644
index 00000000..3c94ba52
--- /dev/null
+++ b/pd/doc/5.reference/vu-help.pd
@@ -0,0 +1,247 @@
+#N canvas 171 210 549 418 10;
+#X obj 1 1 cnv 8 100 60 empty empty vu 20 20 1 18 -262144 -1109 0;
+#X text 19 363 (c) musil@iem.kug.ac.at;
+#X text 61 376 IEM KUG;
+#X floatatom 177 129 7 -110 20;
+#X text 202 41 click properties to;
+#X text 190 52 modify geometry \, colors \, etc.;
+#X text 49 13 gui-vu-meter-display:;
+#X obj 99 39 tgl 15 1 empty empty empty 8 -8 0 10 -262144 -1 -1 1 1
+;
+#X obj 12 179 vu 16 120 foo7_rcv vu-meter 60 0 64 10 -1 -355 1 0;
+#X floatatom 11 332 6 0 0;
+#X floatatom 22 310 6 0 0;
+#X text 75 309 dB;
+#X text 63 333 dB;
+#X text 71 128 dB;
+#X text 80 148 dB;
+#X text 103 146 peak-level;
+#X text 101 125 rms-level;
+#X text 96 308 peak-level;
+#X text 83 332 rms-level;
+#X text 108 99 <list> of rms \, peak;
+#X obj 177 231 s foo7_rcv;
+#X obj 177 211 pack 0 0;
+#X floatatom 195 150 7 -110 20;
+#X obj 195 191 t b f;
+#X text 236 129 dB;
+#X text 255 151 dB;
+#X text 71 258 UP- \, DOWN- \, LEFT- or RIGHT-key;
+#X text 70 269 for moving selected gui-objects;
+#X floatatom 11 128 7 -110 20;
+#X floatatom 22 149 7 -110 20;
+#N canvas 236 62 699 530 edit 0;
+#X obj 37 222 f;
+#X msg 15 201 bang;
+#X floatatom 53 200 3 50 88;
+#X floatatom 88 222 3 0 37;
+#X obj 37 245 pack 0 0;
+#X text 115 222 y-label;
+#X text 81 200 x-label;
+#X obj 292 313 f;
+#X msg 270 292 bang;
+#X floatatom 308 291 3 -10 10;
+#X floatatom 343 313 3 -10 10;
+#X obj 292 336 pack 0 0;
+#X obj 304 435 f;
+#X msg 282 414 bang;
+#X floatatom 320 413 3 20 140;
+#X floatatom 355 435 3 150 200;
+#X obj 304 458 pack 0 0;
+#X text 336 291 x-delta;
+#X text 370 313 y-delta;
+#X text 348 413 x-position;
+#X text 382 435 y-position;
+#X obj 57 337 f;
+#X msg 35 316 bang;
+#X floatatom 73 315 3 0 2;
+#X floatatom 108 337 3 8 36;
+#X obj 57 360 pack 0 0;
+#X text 101 315 font;
+#X text 137 337 height;
+#X floatatom 471 106 1 0 1;
+#X msg 52 131 \; foo7_rcv color \$1 \$2;
+#X msg 37 270 \; foo7_rcv label_pos \$1 \$2;
+#X msg 57 386 \; foo7_rcv label_font \$1 \$2;
+#X msg 37 427 \; foo7_rcv label blabla;
+#X msg 292 361 \; foo7_rcv delta \$1 \$2;
+#X msg 304 483 \; foo7_rcv pos \$1 \$2;
+#X msg 469 23 \; foo7_rcv receive foo7a_rcv;
+#X msg 469 60 \; foo7a_rcv receive foo7_rcv;
+#X text 492 106 display scale;
+#X msg 471 132 \; foo7_rcv scale \$1;
+#X obj 279 193 f;
+#X msg 257 172 bang;
+#X floatatom 295 171 3 8 50;
+#X floatatom 330 193 3 110 200;
+#X obj 279 216 pack 0 0;
+#X text 323 171 width;
+#X text 357 193 height;
+#X msg 279 241 \; foo7_rcv size \$1 \$2;
+#X msg 37 463 \; foo7_rcv label vu-meter;
+#X obj 52 79 f;
+#X msg 29 31 bang;
+#X floatatom 68 29 3 0 29;
+#X floatatom 103 47 3 0 29;
+#X text 96 29 background;
+#X text 131 48 label-color;
+#X msg 290 25 back;
+#X msg 290 49 label;
+#X msg 252 25 bang;
+#N canvas 15 207 606 448 RGB_____________ 0;
+#X obj 97 56 inlet;
+#X obj 262 53 inlet;
+#X obj 339 55 inlet;
+#X obj 405 56 inlet;
+#X obj 97 270 bang;
+#X msg 77 295 0;
+#X msg 104 295 1;
+#X obj 146 268 bang;
+#X msg 132 295 0;
+#X msg 160 295 1;
+#X obj 265 313 spigot;
+#X obj 312 313 spigot;
+#X obj 249 385 outlet;
+#X text 93 33 select;
+#X text 267 28 red;
+#X text 337 30 green;
+#X text 409 30 blue;
+#X obj 405 102 t b f;
+#X obj 339 160 +;
+#X obj 339 185 t b f;
+#X obj 339 216 +;
+#X obj 296 385 outlet;
+#X obj 28 180 loadbang;
+#X obj 296 361 f;
+#X obj 249 361 f;
+#X obj 262 79 * -65536;
+#X obj 339 80 * -256;
+#X obj 405 80 * -1;
+#X obj 339 247 - 1;
+#X obj 97 135 route back label bang;
+#X obj 235 168 t b b b;
+#X connect 0 0 29 0;
+#X connect 1 0 25 0;
+#X connect 2 0 26 0;
+#X connect 3 0 27 0;
+#X connect 4 0 5 0;
+#X connect 4 0 6 0;
+#X connect 5 0 11 1;
+#X connect 6 0 10 1;
+#X connect 7 0 8 0;
+#X connect 7 0 9 0;
+#X connect 8 0 10 1;
+#X connect 9 0 11 1;
+#X connect 10 0 24 1;
+#X connect 11 0 23 1;
+#X connect 17 0 18 0;
+#X connect 17 1 18 1;
+#X connect 18 0 19 0;
+#X connect 19 0 20 0;
+#X connect 19 1 20 1;
+#X connect 20 0 28 0;
+#X connect 22 0 6 0;
+#X connect 23 0 21 0;
+#X connect 24 0 12 0;
+#X connect 25 0 20 0;
+#X connect 26 0 18 0;
+#X connect 27 0 17 0;
+#X connect 28 0 11 0;
+#X connect 28 0 10 0;
+#X connect 29 0 4 0;
+#X connect 29 1 7 0;
+#X connect 29 2 30 0;
+#X connect 30 0 24 0;
+#X connect 30 1 23 0;
+#X connect 30 2 28 0;
+#X restore 290 86 pd RGB_____________;
+#X floatatom 332 55 3 0 255;
+#X floatatom 375 55 3 0 255;
+#X floatatom 418 56 3 0 255;
+#X text 39 3 preset-colors;
+#X text 301 0 RGB-colors;
+#X text 332 37 red;
+#X text 368 36 green;
+#X text 416 36 blue;
+#X obj 52 104 pack 0 0;
+#X connect 0 0 4 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
+#X connect 3 0 4 1;
+#X connect 4 0 30 0;
+#X connect 7 0 11 0;
+#X connect 8 0 7 0;
+#X connect 9 0 7 1;
+#X connect 10 0 11 1;
+#X connect 11 0 33 0;
+#X connect 12 0 16 0;
+#X connect 13 0 12 0;
+#X connect 14 0 12 1;
+#X connect 15 0 16 1;
+#X connect 16 0 34 0;
+#X connect 21 0 25 0;
+#X connect 22 0 21 0;
+#X connect 23 0 21 1;
+#X connect 24 0 25 1;
+#X connect 25 0 31 0;
+#X connect 28 0 38 0;
+#X connect 39 0 43 0;
+#X connect 40 0 39 0;
+#X connect 41 0 39 1;
+#X connect 42 0 43 1;
+#X connect 43 0 46 0;
+#X connect 48 0 66 0;
+#X connect 49 0 48 0;
+#X connect 50 0 48 1;
+#X connect 51 0 66 1;
+#X connect 54 0 57 0;
+#X connect 55 0 57 0;
+#X connect 56 0 57 0;
+#X connect 57 0 66 0;
+#X connect 57 1 66 1;
+#X connect 58 0 57 1;
+#X connect 59 0 57 2;
+#X connect 60 0 57 3;
+#X connect 66 0 29 0;
+#X restore 313 188 pd edit;
+#N canvas 147 336 290 278 source 0;
+#X obj 40 95 random 102;
+#X obj 40 171 - 101;
+#X obj 40 205 pack 0 0;
+#X obj 40 45 metro 300;
+#X obj 40 69 t b b;
+#X obj 133 95 random 20;
+#X obj 40 117 t f f;
+#X obj 91 147 +;
+#X obj 91 172 - 101;
+#X obj 40 21 inlet;
+#X obj 40 230 outlet;
+#X connect 0 0 6 0;
+#X connect 1 0 2 0;
+#X connect 2 0 10 0;
+#X connect 3 0 4 0;
+#X connect 4 0 0 0;
+#X connect 4 1 5 0;
+#X connect 5 0 7 1;
+#X connect 6 0 1 0;
+#X connect 6 1 7 0;
+#X connect 7 0 8 0;
+#X connect 8 0 2 1;
+#X connect 9 0 3 0;
+#X restore 99 62 pd source;
+#X obj 263 94 s fff;
+#X obj 186 302 x_all_guis aaa bbb ccc ddd eee fff ggg hhh iii;
+#X text 210 386 updated for Pd version 0.35;
+#X text 36 388 graz \, austria 2002;
+#X connect 3 0 21 0;
+#X connect 7 0 31 0;
+#X connect 8 0 9 0;
+#X connect 8 1 10 0;
+#X connect 21 0 20 0;
+#X connect 22 0 23 0;
+#X connect 23 0 21 0;
+#X connect 23 1 21 1;
+#X connect 28 0 8 0;
+#X connect 29 0 8 1;
+#X connect 31 0 8 0;
+#X connect 31 0 32 0;
diff --git a/pd/doc/5.reference/wrap~-help.pd b/pd/doc/5.reference/wrap~-help.pd
new file mode 100644
index 00000000..81681f30
--- /dev/null
+++ b/pd/doc/5.reference/wrap~-help.pd
@@ -0,0 +1,26 @@
+#N canvas 182 132 703 319 12;
+#X obj 58 220 metro 500;
+#X obj 58 195 r metro;
+#X msg 575 106 \; metro 0;
+#X msg 574 48 \; pd dsp 1 \; metro 1;
+#X floatatom 42 121 0 0 0;
+#X floatatom 42 277 0 0 0;
+#X text 443 271 updated for Pd version 0.33;
+#X obj 574 21 loadbang;
+#X obj 42 244 snapshot~;
+#X obj 42 147 sig~;
+#X obj 36 16 wrap~;
+#X text 93 16 - remainder modulo 1;
+#X text 18 45 wrap~ gives the difference between the input and the
+largest integer not exceeding it (for positive numbers this is the
+fractional part).;
+#X obj 42 171 wrap~;
+#X text 127 123 <-- shift-drag here to get non-integers to try;
+#X connect 0 0 8 0;
+#X connect 1 0 0 0;
+#X connect 1 0 0 0;
+#X connect 4 0 9 0;
+#X connect 7 0 3 0;
+#X connect 8 0 5 0;
+#X connect 9 0 13 0;
+#X connect 13 0 8 0;
diff --git a/pd/doc/5.reference/writesf~-help.pd b/pd/doc/5.reference/writesf~-help.pd
new file mode 100644
index 00000000..7cbb915b
--- /dev/null
+++ b/pd/doc/5.reference/writesf~-help.pd
@@ -0,0 +1,41 @@
+#N canvas 279 74 734 440 12;
+#X msg 592 11 \; pd dsp 1;
+#X msg 141 163 print;
+#X msg 53 83 bang;
+#X msg 140 115 start;
+#X msg 142 141 stop;
+#X obj 53 114 del 1000;
+#X text 41 9 writesf~ -- write audio signals to a soundfile;
+#X text 230 212 creation argument is number of channels;
+#X text 259 234 (1 to 64).;
+#X text 193 115 start streaming audio;
+#X text 188 141 stop streaming audio;
+#X obj 131 207 writesf~ 2;
+#X msg 131 31 open /tmp/foo.wav;
+#X obj 115 408 soundfiler;
+#X text 454 407 updated for Pd version 0.37;
+#X text 23 408 see also:;
+#X obj 145 185 osc~ 440;
+#X text 34 257 writesf~ creates a subthread whose task is to write
+audio streams to disk. You need not provide any disk access time between
+"open" and "start" \, but between "stop" and the next "open" you must
+give the object time to flush all the output to disk.;
+#X msg 131 86 open -bytes 4 /tmp/foo.wav;
+#X text 300 30 create a new 16-bit soundfile;
+#X text 377 59 create 24-bit soundfile;
+#X text 376 86 create 32-bit floating-point soundfile;
+#X msg 131 59 open -bytes 3 /tmp/foo.wav;
+#X text 32 338 The soundfile is 2- or 3-byte fixed point ("pcm") or
+4-byte floating-point. The soundfile format is determined by the file
+extent ("foo.wav" \, "foo.aiff" \, or "foo.snd").;
+#X obj 217 410 readsf~;
+#X connect 1 0 11 0;
+#X connect 2 0 3 0;
+#X connect 2 0 5 0;
+#X connect 3 0 11 0;
+#X connect 4 0 11 0;
+#X connect 5 0 4 0;
+#X connect 12 0 11 0;
+#X connect 16 0 11 0;
+#X connect 18 0 11 0;
+#X connect 22 0 11 0;
diff --git a/pd/doc/6.externs/makefile b/pd/doc/6.externs/makefile
index f807ba0b..a4e9308c 100644
--- a/pd/doc/6.externs/makefile
+++ b/pd/doc/6.externs/makefile
@@ -5,28 +5,34 @@ clean: ; rm -f *.pd_linux *.o
# ----------------------- NT -----------------------
-pd_nt: foo1.dll foo2.dll dspobj~.dll
+pd_nt: obj1.dll obj2.dll obj3.dll obj4.dll obj5.dll dspobj~.dll
-.SUFFIXES: .dll
+.SUFFIXES: .obj .dll
PDNTCFLAGS = /W3 /WX /DNT /DPD /nologo
VC="C:\Program Files\Microsoft Visual Studio\Vc98"
-PDNTINCLUDE = /I. /I\tcl\include /I\ftp\pd\src /I$(VC)\include
+PDNTINCLUDE = /I. /I\tcl\include /I..\..\src /I$(VC)\include
PDNTLDIR = $(VC)\lib
PDNTLIB = $(PDNTLDIR)\libc.lib \
$(PDNTLDIR)\oldnames.lib \
$(PDNTLDIR)\kernel32.lib \
- \ftp\pd\bin\pd.lib
+ ..\..\bin\pd.lib
.c.dll:
cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
link /dll /export:$*_setup $*.obj $(PDNTLIB)
+# override explicitly for tilde objects like this:
+dspobj~.dll: dspobj~.c;
+ cl $(PDNTCFLAGS) $(PDNTINCLUDE) /c $*.c
+ link /dll /export:dspobj_tilde_setup $*.obj $(PDNTLIB)
+
# ----------------------- IRIX 5.x -----------------------
-pd_irix5: foo1.pd_irix5 foo2.pd_irix5 dspobj~.pd_irix5
+pd_irix5: obj1.pd_irix5 obj2.pd_irix5 \
+ obj3.pd_irix5 obj4.pd_irix5 obj5.pd_irix5 dspobj~.pd_irix5
.SUFFIXES: .pd_irix5
@@ -40,24 +46,10 @@ SGIINCLUDE = -I../../src/
ld -elf -shared -rdata_shared -o $*.pd_irix5 $*.o
rm $*.o
-# ----------------------- IRIX 6.x -----------------------
-
-pd_irix6: foo1.pd_irix6 foo2.pd_irix6 dspobj~.pd_irix6
-
-.SUFFIXES: .pd_irix6
-
-SGICFLAGS6 = -n32 -DPD -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \
- -OPT:roundoff=3 -OPT:IEEE_arithmetic=3 -OPT:cray_ivdep=true \
- -Ofast=ip32
-
-.c.pd_irix6:
- cc $(SGICFLAGS6) $(SGIINCLUDE) -o $*.o -c $*.c
- ld -IPA -n32 -shared -rdata_shared -o $*.pd_irix6 $*.o
- rm $*.o
-
# ----------------------- LINUX i386 -----------------------
-pd_linux: foo1.pd_linux foo2.pd_linux dspobj~.pd_linux
+pd_linux: obj1.pd_linux obj2.pd_linux obj3.pd_linux obj4.pd_linux \
+ obj5.pd_linux dspobj~.pd_linux
.SUFFIXES: .pd_linux
@@ -73,3 +65,18 @@ LINUXINCLUDE = -I../../src
strip --strip-unneeded $*.pd_linux
rm $*.o
+# ----------------------- Mac OSX -----------------------
+
+pd_darwin: obj1.pd_darwin obj2.pd_darwin \
+ obj3.pd_darwin obj4.pd_darwin obj5.pd_darwin dspobj~.pd_darwin
+
+.SUFFIXES: .pd_darwin
+
+DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
+ -Wno-unused -Wno-parentheses -Wno-switch
+
+.c.pd_darwin:
+ cc $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
+ cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
+ rm -f $*.o
+
diff --git a/pd/doc/6.externs/obj1.c b/pd/doc/6.externs/obj1.c
new file mode 100644
index 00000000..0618d646
--- /dev/null
+++ b/pd/doc/6.externs/obj1.c
@@ -0,0 +1,47 @@
+/* code for "obj1" pd class. This takes two messages: floating-point
+numbers, and "rats", and just prints something out for each message. */
+
+#include "m_pd.h"
+
+ /* the data structure for each copy of "obj1". In this case we
+ on;y need pd's obligatory header (of type t_object). */
+typedef struct obj1
+{
+ t_object x_ob;
+} t_obj1;
+
+ /* this is called back when obj1 gets a "float" message (i.e., a
+ number.) */
+void obj1_float(t_obj1 *x, t_floatarg f)
+{
+ post("obj1: %f", f);
+}
+
+ /* this is called when obj1 gets the message, "rats". */
+void obj1_rats(t_obj1 *x)
+{
+ post("obj1: rats");
+}
+
+ /* this is a pointer to the class for "obj1", which is created in the
+ "setup" routine below and used to create new ones in the "new" routine. */
+t_class *obj1_class;
+
+ /* this is called when a new "obj1" object is created. */
+void *obj1_new(void)
+{
+ t_obj1 *x = (t_obj1 *)pd_new(obj1_class);
+ post("obj1_new");
+ return (void *)x;
+}
+
+ /* this is called once at setup time, when this code is loaded into Pd. */
+void obj1_setup(void)
+{
+ post("obj1_setup");
+ obj1_class = class_new(gensym("obj1"), (t_newmethod)obj1_new, 0,
+ sizeof(t_obj1), 0, 0);
+ class_addmethod(obj1_class, (t_method)obj1_rats, gensym("rats"), 0);
+ class_addfloat(obj1_class, obj1_float);
+}
+
diff --git a/pd/doc/6.externs/obj2.c b/pd/doc/6.externs/obj2.c
new file mode 100644
index 00000000..14cd134a
--- /dev/null
+++ b/pd/doc/6.externs/obj2.c
@@ -0,0 +1,45 @@
+/* code for the "obj2" pd class. This one, in addition to the "obj1"
+code, has an inlet taking numbers. */
+
+#include "m_pd.h"
+
+typedef struct obj2
+{
+ t_object x_ob;
+} t_obj2;
+
+void obj2_float(t_obj2 *x, t_floatarg f)
+{
+ post("obj2: %f", f);
+}
+
+void obj2_rats(t_obj2 *x)
+{
+ post("obj2: rats");
+}
+
+void obj2_ft1(t_obj2 *x, t_floatarg g)
+{
+ post("ft1: %f", g);
+}
+
+t_class *obj2_class;
+
+void *obj2_new(void)
+{
+ t_obj2 *x = (t_obj2 *)pd_new(obj2_class);
+ inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1"));
+ post("obj2_new");
+ return (void *)x;
+}
+
+void obj2_setup(void)
+{
+ post("obj2_setup");
+ obj2_class = class_new(gensym("obj2"), (t_newmethod)obj2_new,
+ 0, sizeof(t_obj2), 0, 0);
+ class_addmethod(obj2_class, (t_method)obj2_rats, gensym("rats"), 0);
+ class_addmethod(obj2_class, (t_method)obj2_ft1, gensym("ft1"), A_FLOAT, 0);
+ class_addfloat(obj2_class, obj2_float);
+}
+
diff --git a/pd/doc/6.externs/obj3.c b/pd/doc/6.externs/obj3.c
new file mode 100644
index 00000000..434fbb95
--- /dev/null
+++ b/pd/doc/6.externs/obj3.c
@@ -0,0 +1,39 @@
+/* code for the "obj3" pd class. This adds an outlet and a state variable. */
+
+#include "m_pd.h"
+
+typedef struct obj3
+{
+ t_object x_ob;
+ t_outlet *x_outlet;
+ float x_value;
+} t_obj3;
+
+void obj3_float(t_obj3 *x, t_floatarg f)
+{
+ outlet_float(x->x_outlet, f + x->x_value);
+}
+
+void obj3_ft1(t_obj3 *x, t_floatarg g)
+{
+ x->x_value = g;
+}
+
+t_class *obj3_class;
+
+void *obj3_new(void)
+{
+ t_obj3 *x = (t_obj3 *)pd_new(obj3_class);
+ inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1"));
+ x->x_outlet = outlet_new(&x->x_ob, gensym("float"));
+ return (void *)x;
+}
+
+void obj3_setup(void)
+{
+ obj3_class = class_new(gensym("obj3"), (t_newmethod)obj3_new,
+ 0, sizeof(t_obj3), 0, 0);
+ class_addmethod(obj3_class, (t_method)obj3_ft1, gensym("ft1"), A_FLOAT, 0);
+ class_addfloat(obj3_class, obj3_float);
+}
+
diff --git a/pd/doc/6.externs/obj4.c b/pd/doc/6.externs/obj4.c
new file mode 100644
index 00000000..3da2a84a
--- /dev/null
+++ b/pd/doc/6.externs/obj4.c
@@ -0,0 +1,47 @@
+/* code for the "obj4" pd class. This adds a creation argument, of
+type "float". */
+
+#include "m_pd.h"
+
+typedef struct obj4
+{
+ t_object x_ob;
+ t_outlet *x_outlet;
+ float x_value;
+} t_obj4;
+
+void obj4_float(t_obj4 *x, t_floatarg f)
+{
+ outlet_float(x->x_outlet, x->x_value + f);
+}
+
+void obj4_ft1(t_obj4 *x, t_floatarg g)
+{
+ x->x_value = g;
+}
+
+t_class *obj4_class;
+
+ /* as requested by the new invocation of "class_new" below, the new
+ routine will be called with a "float" argument. */
+void *obj4_new(t_floatarg f)
+{
+ t_obj4 *x = (t_obj4 *)pd_new(obj4_class);
+ inlet_new(&x->x_ob, &x->x_ob.ob_pd, gensym("float"), gensym("ft1"));
+ x->x_outlet = outlet_new(&x->x_ob, gensym("float"));
+ /* just stick the argument in the object structure for later. */
+ x->x_value = f;
+ return (void *)x;
+}
+
+void obj4_setup(void)
+{
+ /* here we add "A_DEFFLOAT" to the (zero-terminated) list of arg
+ types we declare for a new object. The value will be filled
+ in as 0 if not given in the object box. */
+ obj4_class = class_new(gensym("obj4"), (t_newmethod)obj4_new,
+ 0, sizeof(t_obj4), 0, A_DEFFLOAT, 0);
+ class_addmethod(obj4_class, (t_method)obj4_ft1, gensym("ft1"), A_FLOAT, 0);
+ class_addfloat(obj4_class, obj4_float);
+}
+
diff --git a/pd/doc/6.externs/obj5.c b/pd/doc/6.externs/obj5.c
new file mode 100644
index 00000000..687c8e0a
--- /dev/null
+++ b/pd/doc/6.externs/obj5.c
@@ -0,0 +1,54 @@
+/* code for the "obj5" pd class. This shows "gimme" arguments, which have
+variable arguments parsed by the routines (both "new" and "rats".) */
+
+#include "m_pd.h"
+
+typedef struct obj5
+{
+ t_object x_ob;
+} t_obj5;
+
+ /* the "rats" method is called with the selector (just "rats" again)
+ and an array of the typed areguments, which are each either a number
+ or a symbol. We just print them out. */
+void obj5_rats(t_obj5 *x, t_symbol *selector, int argcount, t_atom *argvec)
+{
+ int i;
+ post("rats: selector %s", selector->s_name);
+ for (i = 0; i < argcount; i++)
+ {
+ if (argvec[i].a_type == A_FLOAT)
+ post("float: %f", argvec[i].a_w.w_float);
+ else if (argvec[i].a_type == A_SYMBOL)
+ post("symbol: %s", argvec[i].a_w.w_symbol->s_name);
+ }
+}
+
+t_class *obj5_class;
+
+ /* same for the "new" (creation) routine, except that we don't have
+ "x" as an argument since we have to create "x" in this routine. */
+void *obj5_new(t_symbol *selector, int argcount, t_atom *argvec)
+{
+ t_obj5 *x = (t_obj5 *)pd_new(obj5_class);
+ int i;
+ post("new: selector %s", selector->s_name);
+ for (i = 0; i < argcount; i++)
+ {
+ if (argvec[i].a_type == A_FLOAT)
+ post("float: %f", argvec[i].a_w.w_float);
+ else if (argvec[i].a_type == A_SYMBOL)
+ post("symbol: %s", argvec[i].a_w.w_symbol->s_name);
+ }
+ return (void *)x;
+}
+
+void obj5_setup(void)
+{
+ /* We specify "A_GIMME" as creation argument for both the creation
+ routine and the method (callback) for the "rats" message. */
+ obj5_class = class_new(gensym("obj5"), (t_newmethod)obj5_new,
+ 0, sizeof(t_obj5), 0, A_GIMME, 0);
+ class_addmethod(obj5_class, (t_method)obj5_rats, gensym("rats"), A_GIMME, 0);
+}
+
diff --git a/pd/doc/6.externs/test-obj1.pd b/pd/doc/6.externs/test-obj1.pd
new file mode 100644
index 00000000..f50ce449
--- /dev/null
+++ b/pd/doc/6.externs/test-obj1.pd
@@ -0,0 +1,6 @@
+#N canvas 68 38 317 151 12;
+#X msg 68 52 5;
+#X msg 100 52 rats;
+#X obj 67 90 obj1;
+#X connect 0 0 2 0;
+#X connect 1 0 2 0;
diff --git a/pd/doc/6.externs/test-obj2.pd b/pd/doc/6.externs/test-obj2.pd
new file mode 100644
index 00000000..1d3fd191
--- /dev/null
+++ b/pd/doc/6.externs/test-obj2.pd
@@ -0,0 +1,8 @@
+#N canvas 62 333 310 157 12;
+#X msg 109 51 rats;
+#X msg 157 52 7;
+#X msg 68 52 4;
+#X obj 68 90 obj2;
+#X connect 0 0 3 0;
+#X connect 1 0 3 1;
+#X connect 2 0 3 0;
diff --git a/pd/doc/6.externs/test-obj3.pd b/pd/doc/6.externs/test-obj3.pd
new file mode 100644
index 00000000..1072a4af
--- /dev/null
+++ b/pd/doc/6.externs/test-obj3.pd
@@ -0,0 +1,8 @@
+#N canvas 128 288 310 157 12;
+#X obj 68 91 obj3;
+#X floatatom 67 61 3 0 0 0 - - -;
+#X floatatom 108 59 3 0 0 0 - - -;
+#X floatatom 70 118 3 0 0 0 - - -;
+#X connect 0 0 3 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 1;
diff --git a/pd/doc/6.externs/test-obj4.pd b/pd/doc/6.externs/test-obj4.pd
new file mode 100644
index 00000000..619012f5
--- /dev/null
+++ b/pd/doc/6.externs/test-obj4.pd
@@ -0,0 +1,6 @@
+#N canvas 128 288 310 157 12;
+#X floatatom 67 61 3 0 0 0 - - -;
+#X floatatom 70 118 3 0 0 0 - - -;
+#X obj 68 91 obj4 34;
+#X connect 0 0 2 0;
+#X connect 2 0 1 0;
diff --git a/pd/doc/6.externs/test-obj5.pd b/pd/doc/6.externs/test-obj5.pd
new file mode 100644
index 00000000..550f34a1
--- /dev/null
+++ b/pd/doc/6.externs/test-obj5.pd
@@ -0,0 +1,4 @@
+#N canvas 128 288 310 157 12;
+#X obj 15 74 obj5 1 2 3 cis boom bah;
+#X msg 15 30 rats 4 5 6 tara tara boum boum;
+#X connect 1 0 0 0;
diff --git a/pd/doc/7.stuff/synth/1.poly.synth.pd b/pd/doc/7.stuff/synth/1.poly.synth.pd
index bd2a95a8..a92a0815 100644
--- a/pd/doc/7.stuff/synth/1.poly.synth.pd
+++ b/pd/doc/7.stuff/synth/1.poly.synth.pd
@@ -1,5 +1,5 @@
#N canvas 232 162 657 719 12;
-#X floatatom 424 666 0 0 100;
+#X floatatom 424 666 0 0 100 0 - - -;
#N canvas 269 205 698 344 output 0;
#X obj 388 156 t b;
#X obj 388 105 f;
@@ -230,7 +230,7 @@
#X connect 8 0 5 1;
#X restore 186 132 pd tables;
#X obj 25 117 metro 500;
-#X floatatom 67 178 5 0 0;
+#X floatatom 67 178 5 0 0 0 - - -;
#X obj 25 203 makenote 64 250;
#X obj 27 229 pack;
#X obj 27 253 s syn-midinoteon;
@@ -243,9 +243,9 @@
#X obj 329 474 numset fs x;
#X obj 329 503 numset fr x;
#X obj 329 532 numset q x;
-#X floatatom 101 96 5 0 0;
-#X floatatom 155 176 5 0 0;
-#X floatatom 115 149 5 0 0;
+#X floatatom 101 96 5 0 0 0 - - -;
+#X floatatom 155 176 5 0 0 0 - - -;
+#X floatatom 115 149 5 0 0 0 - - -;
#X obj 25 178 + 24;
#X obj 25 149 random 48;
#X obj 329 15 preset preset1 x;
@@ -253,7 +253,6 @@
#X obj 329 108 preset preset3 x;
#X obj 329 155 preset preset4 x;
#X obj 330 561 numset 2nd x;
-#X obj 330 590 numset 2pc;
#X obj 16 626 pack 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
#X text 451 219 amplitude;
#X text 440 246 amp attack time;
@@ -268,24 +267,25 @@
#X text 448 507 filter release time;
#X text 453 535 q;
#X text 450 566 2nd osc detune;
-#X text 432 596 2nd osc amp (%);
+#X text 444 596 2nd osc amp (%);
#X text 508 666 OUTPUT LEVEL;
#X text 41 14 polyphonic synth with;
#X text 40 37 voice presets;
#X text 21 74 random-note tester;
+#X obj 330 590 numset 2pc x;
#X connect 0 0 1 1;
#X connect 1 0 0 0;
#X connect 2 0 1 2;
-#X connect 3 0 39 0;
-#X connect 3 1 39 1;
+#X connect 3 0 38 0;
+#X connect 3 1 38 1;
#X connect 4 0 5 0;
#X connect 4 1 5 1;
#X connect 5 0 3 0;
-#X connect 6 0 39 2;
-#X connect 7 0 39 3;
-#X connect 8 0 39 6;
-#X connect 9 0 39 4;
-#X connect 10 0 39 5;
+#X connect 6 0 38 2;
+#X connect 7 0 38 3;
+#X connect 8 0 38 6;
+#X connect 9 0 38 4;
+#X connect 10 0 38 5;
#X connect 11 0 1 0;
#X connect 12 0 3 0;
#X connect 15 0 32 0;
@@ -294,18 +294,18 @@
#X connect 17 1 18 1;
#X connect 18 0 19 0;
#X connect 20 0 15 0;
-#X connect 21 0 39 7;
-#X connect 22 0 39 8;
-#X connect 23 0 39 9;
-#X connect 24 0 39 10;
-#X connect 25 0 39 11;
-#X connect 26 0 39 12;
-#X connect 27 0 39 13;
+#X connect 21 0 38 7;
+#X connect 22 0 38 8;
+#X connect 23 0 38 9;
+#X connect 24 0 38 10;
+#X connect 25 0 38 11;
+#X connect 26 0 38 12;
+#X connect 27 0 38 13;
#X connect 28 0 15 1;
#X connect 29 0 17 2;
#X connect 30 0 32 1;
#X connect 31 0 17 0;
#X connect 32 0 31 0;
-#X connect 37 0 39 14;
-#X connect 38 0 39 15;
-#X connect 39 0 13 0;
+#X connect 37 0 38 14;
+#X connect 38 0 13 0;
+#X connect 57 0 38 15;
diff --git a/pd/doc/7.stuff/synth/preset4.txt b/pd/doc/7.stuff/synth/preset4.txt
index f9ce0b38..ccd58b35 100644
--- a/pd/doc/7.stuff/synth/preset4.txt
+++ b/pd/doc/7.stuff/synth/preset4.txt
@@ -1,3 +1,4 @@
+list 2pc-in 0
list 2nd-in 0
list q-in 3.01
list fr-in 200
diff --git a/pd/doc/sound/voice.wav b/pd/doc/sound/voice.wav
index efb6f45e..8b7f1acc 100644
--- a/pd/doc/sound/voice.wav
+++ b/pd/doc/sound/voice.wav
Binary files differ
diff --git a/pd/extra/README.txt b/pd/extra/README.txt
index 2ff84f68..aaac513a 100644
--- a/pd/extra/README.txt
+++ b/pd/extra/README.txt
@@ -11,9 +11,8 @@ OR IMPLIED, IN CONNECTION WITH THIS SOFTWARE!
Note that "expr" is under the GPL, which is more restrictive than Pd's own
license agreement.
-This package should run under linux, NT, or IRIX, except for
-"bilge" which is for NT only. You can additionally compile fiddle~. bonk~,
-and paf~ for Max/MSP.
+This package should run in Pd under linux, MSW, or Mac OSX.
+You can additionally compile fiddle~. bonk~, and paf~ for Max/MSP.
contents:
@@ -24,12 +23,11 @@ choose - find the "best fit" of incoming vector with stored profiles
paf~ -- phase aligned formant generator
loop~ -- sample looper
expr -- arithmetic expression evaluation (Shahrokh Yadegari)
-bilge (NT only) - play audio CDs through the regular PC sound system
abstractions:
hilbert~ - Hilbert transform for SSB modulation
complex-mod~ - ring modulation for complex (real+imaginary) audio signals
-rev1~ - reverberator
+rev1~ - experimental reverberator
These objects are part of the regular Pd distribution as of Pd version
0.30. Macintosh versions of fiddle~, bonk~, and paf~ are available
diff --git a/pd/extra/bonk~/help-bonk~.pd b/pd/extra/bonk~/help-bonk~.pd
new file mode 100644
index 00000000..5102e860
--- /dev/null
+++ b/pd/extra/bonk~/help-bonk~.pd
@@ -0,0 +1,162 @@
+#N canvas 107 94 958 626 10;
+#X obj 320 579 print;
+#X floatatom 314 501 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;
+#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;
+#X obj 112 24 r bonk-cooked;
+#X obj 112 49 unpack;
+#X obj 112 99 * 12;
+#X obj 112 124 div 7;
+#X obj 112 74 + 1;
+#X obj 112 174 mtof;
+#X obj 112 224 osc~;
+#X obj 112 249 cos~;
+#X obj 112 149 + 47;
+#X obj 209 247 line~;
+#X obj 209 272 *~;
+#X obj 209 297 lop~ 500;
+#X obj 112 274 *~;
+#X obj 103 361 dac~;
+#X obj 253 165 dbtorms;
+#X obj 253 115 * 0.5;
+#X obj 253 140 + 50;
+#X obj 211 189 f;
+#X msg 173 159 bang;
+#X obj 258 83 inlet;
+#X obj 111 307 hip~ 5;
+#X msg 34 24 0 60;
+#X obj 112 199 sig~;
+#X msg 209 222 \$1 \, 0 200;
+#X connect 0 0 1 0;
+#X connect 1 0 4 0;
+#X connect 2 0 3 0;
+#X connect 3 0 8 0;
+#X connect 4 0 2 0;
+#X connect 5 0 18 0;
+#X connect 5 0 22 0;
+#X connect 6 0 7 0;
+#X connect 7 0 12 0;
+#X connect 8 0 5 0;
+#X connect 9 0 10 0;
+#X connect 9 0 10 1;
+#X connect 10 0 11 0;
+#X connect 11 0 12 1;
+#X connect 12 0 20 0;
+#X connect 14 0 17 1;
+#X connect 15 0 16 0;
+#X connect 16 0 14 0;
+#X connect 17 0 23 0;
+#X connect 18 0 17 0;
+#X connect 19 0 15 0;
+#X connect 20 0 13 1;
+#X connect 20 0 13 0;
+#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;
+#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
+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
+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
+(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
+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
+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"
+to erase and record over a template.;
+#X text 595 368 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
+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 634 517 print;
+#X msg 437 456 debug 0;
+#X text 538 466 turn debugging on or off.;
+#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;
diff --git a/pd/extra/choice/help-choice.pd b/pd/extra/choice/help-choice.pd
new file mode 100644
index 00000000..df46ddc0
--- /dev/null
+++ b/pd/extra/choice/help-choice.pd
@@ -0,0 +1,41 @@
+#N canvas 16 5 488 531 12;
+#X obj 8 186 choice;
+#X msg 41 86 print;
+#X msg 29 63 clear;
+#X msg 8 34 add 1 0 0 \, add 0 1 0 \, add 0 0 1 \, add 1 1 1 \, add 1 1 0;
+#X obj 77 162 pack 0 0 0;
+#X floatatom 182 120;
+#X floatatom 148 120;
+#X floatatom 115 120;
+#X obj 77 142 f;
+#X msg 77 120 bang;
+#X floatatom 8 207;
+#X obj 53 187 choice 1;
+#X floatatom 53 208;
+#X obj 76 4 choice;
+#X text 122 5 - search for a best match to an incoming list;
+#X text 19 234 The choice object holds a list of vectors \, each having up to ten elements. When sent a list of numbers \, it outputs the index of the known vector that matches most closely. The quality of the match is the dot product of the two vectors after normalizing them \, i.e. \, the vector whose direction is closest to that of the input wins.;
+#X text 19 316 If given a nonzero creation argument \, choice tries to avoid repetitious outputs by weighting less recently output vectors preferentially.;
+#X text 18 354 You can use this to choose interactively between a number of behaviors depending on their attributes. For example \, you might have stored a number of melodies \, of which some are syncopated \, some chromatic \, some are more than 100 years old \, some are bugle calls \, and some are Christmas carols. You could then ask to find a syncopated bugle call (1 \, 0 \, 0 \, 1 \, 0) and you'll get the thing most closely matching the request.;
+#X text 17 461 You can use numbers other than 0 and 1 to indicate relative strengths of the attributes \, or even use negative numbers to indicate opposites \, either in the incoming lists or in the stored ones.;
+#X text 273 513 updated for Pd version-0.30;
+#X text 72 63 delete all stored vectors;
+#X text 394 36 add vectors;
+#X text 81 85 debugging printout;
+#X text 69 104 tweak the numbers and hit "bang" to input a list;
+#X text 115 187 creation argument to avoid repeated outout;
+#X text 85 208 output is the index of best match \, counting from zero;
+#X connect 0 0 10 0;
+#X connect 1 0 0 0;
+#X connect 2 0 0 0;
+#X connect 2 0 11 0;
+#X connect 3 0 0 0;
+#X connect 3 0 11 0;
+#X connect 4 0 0 0;
+#X connect 4 0 11 0;
+#X connect 5 0 4 2;
+#X connect 6 0 4 1;
+#X connect 7 0 8 1;
+#X connect 8 0 4 0;
+#X connect 9 0 8 0;
+#X connect 11 0 12 0;
diff --git a/pd/extra/choice/makefile b/pd/extra/choice/makefile
index a66e82bd..074ad026 100644
--- a/pd/extra/choice/makefile
+++ b/pd/extra/choice/makefile
@@ -70,8 +70,7 @@ LINUXINCLUDE = -I../../src
cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm
strip --strip-unneeded $*.pd_linux
- rm -f $*.o ../$*.pd_linux
- ln -s $*/$*.pd_linux ..
+ rm -f $*.o
# ----------------------- Mac OSX -----------------------
@@ -84,9 +83,8 @@ DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
.c.pd_darwin:
cc $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
- cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
- rm -f $*.o ../$*.pd_darwin
- ln -s $*/$*.pd_darwin ..
+ cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
+ rm -f $*.o
# ----------------------------------------------------------
diff --git a/pd/extra/fiddle~/help-fiddle~.pd b/pd/extra/fiddle~/help-fiddle~.pd
new file mode 100644
index 00000000..a7feb4f7
--- /dev/null
+++ b/pd/extra/fiddle~/help-fiddle~.pd
@@ -0,0 +1,107 @@
+#N canvas 93 26 980 745 10;
+#X obj 262 522 phasor~;
+#X obj 531 616 unpack;
+#X floatatom 531 666;
+#X msg 437 449 print;
+#X obj 262 500 sig~;
+#X floatatom 262 478;
+#X obj 262 456 mtof;
+#X floatatom 262 434;
+#X floatatom 545 643;
+#X obj 531 576 route 1 2 3 4;
+#X obj 614 616 unpack;
+#X floatatom 614 666;
+#X floatatom 628 643;
+#X obj 698 616 unpack;
+#X floatatom 698 666;
+#X floatatom 712 643;
+#X obj 389 616 unpack;
+#X floatatom 389 666;
+#X floatatom 403 643;
+#X obj 334 545 *~;
+#X obj 322 394 loadbang;
+#X obj 353 522 sig~;
+#X floatatom 353 500;
+#X msg 322 478 1;
+#X msg 353 478 0;
+#X floatatom 466 666;
+#X obj 281 666 print attack;
+#X obj 190 666 print pitch;
+#X msg 555 45 \; pd dsp 1;
+#X text 460 39 click here;
+#X text 460 61 to start DSP;
+#X text 226 4 FIDDLE - pitch estimator and sinusoidal peak finder;
+#X text 8 70 The Fiddle object estimates the pitch and amplitude of an incoming sound \, both continuously and as a stream of discrete "note" events. Fiddle optionally outputs a list of detected sinusoidal peaks used to make the pitch determination. Fiddle is described theoretically in the 1998 ICMC proceedings \, reprinted on http://man104nfs.ucsd.edu/~mpuckett.;
+#X text 8 170 Fiddle's creation arguments specify an analysis window size \, the maximum polyphony (i.e. \, the number of simultaneous "pitches" to try to find) \, the number of peaks in the spectrum to consider \, and the number of peaks \, if any \, to output "raw." The outlets give discrete pitch (a number) \, detected attacks in the amplitude envelope (a bang) \, one or more voices of continuous pitch and amplitude \, overall amplitude \, and optionally a sequence of messages with the peaks.;
+#X text 8 296 The analysis hop size is half the window size so in the example shown here \, one analysis is done every 512 samples (11.6 msec at 44K1) \, and the analysis uses the most recent 1024 samples (23.2 msec at 44K1). The minimum frequency that Fiddle will report is 2-1/2 cycles per analysis windows \, or about 108 Hz. (just below MIDI 45.);
+#X text 669 535 number of pitch outlets (1-3 \, default 1);
+#X text 669 557 number of peaks to find (1-100 \, default 20);
+#X text 669 579 number of peaks to output (default 0.);
+#X msg 441 107 amp-range 40 50;
+#X msg 439 227 reattack 100 10;
+#X msg 438 282 npartial 7;
+#X msg 438 170 vibrato 50 0.5;
+#X text 560 91 a low and high amplitude threshold: if signal amplitude is below the low threshold \, no pitches or peaks are output. The high threshold is a minimum at which "cooked" outputs may appear.;
+#X text 560 152 A period in milliseconds (50) over which the raw pitch may not deviate more than an interval in half-tones (0.5) from the average pitch to report it as a note to the "cooked" pitch outlet.;
+#X text 560 213 A period in milliseconds (100) over which a re-attack is reported if the amplitude rises more than (1) dB. The re-attack will result in a "bang" in the attack outlet and may give rise to repeated notes in the cooked pitch output.;
+#X text 142 432 test input pitch;
+#X text 330 444 test input;
+#X text 330 457 amplitude;
+#X obj 410 545 fiddle~ 1024 1 20 3;
+#X text 538 690 individual sinusoidal components;
+#X text 466 688 amplitude;
+#X text 476 703 (dB);
+#X text 389 688 raw pitch;
+#X text 376 712 and amplitude;
+#X text 364 729 (up to 3 outputs);
+#X text 287 686 bang on;
+#X text 287 708 attack;
+#X text 185 686 cooked pitch;
+#X text 202 703 output;
+#X text 545 545 ------ arguments:;
+#X msg 262 412 57;
+#X msg 440 340 auto 1;
+#X msg 440 362 auto 0;
+#X msg 440 407 bang;
+#X text 561 405 poll current values --- useful if not in auto mode \,;
+#X text 560 274 Higher partials are weighed less strongly than lower ones in determining the pitch. This specifies the number of the partial (7) which will be weighted half as strongly as the fundamental.;
+#X text 560 335 start and stop "auto" mode (on by default.) If off \, output only appears on "bang" (poll mode).;
+#X text 561 448 print out all settings;
+#X text 669 513 window size (128-2048 \, default 1024);
+#X connect 0 0 19 0;
+#X connect 1 0 2 0;
+#X connect 1 1 8 0;
+#X connect 3 0 48 0;
+#X connect 4 0 0 0;
+#X connect 5 0 4 0;
+#X connect 6 0 5 0;
+#X connect 7 0 6 0;
+#X connect 9 0 1 0;
+#X connect 9 1 10 0;
+#X connect 9 2 13 0;
+#X connect 10 0 11 0;
+#X connect 10 1 12 0;
+#X connect 13 0 14 0;
+#X connect 13 1 15 0;
+#X connect 16 0 17 0;
+#X connect 16 1 18 0;
+#X connect 19 0 48 0;
+#X connect 20 0 60 0;
+#X connect 20 0 23 0;
+#X connect 21 0 19 1;
+#X connect 22 0 21 0;
+#X connect 23 0 22 0;
+#X connect 24 0 22 0;
+#X connect 38 0 48 0;
+#X connect 39 0 48 0;
+#X connect 40 0 48 0;
+#X connect 41 0 48 0;
+#X connect 48 0 27 0;
+#X connect 48 1 26 0;
+#X connect 48 2 16 0;
+#X connect 48 3 25 0;
+#X connect 48 4 9 0;
+#X connect 60 0 7 0;
+#X connect 61 0 48 0;
+#X connect 62 0 48 0;
+#X connect 63 0 48 0;
diff --git a/pd/extra/help-expr.pd b/pd/extra/help-expr.pd
new file mode 100644
index 00000000..adc575fb
--- /dev/null
+++ b/pd/extra/help-expr.pd
@@ -0,0 +1,497 @@
+#N canvas 70 36 1012 579 10;
+#X text 66 10 expression evaluation family - expr \, expr~ \, fexpr~
+;
+#X text 63 239 Syntyax:;
+#X text 64 311 $f#: float input variable;
+#X text 65 326 $s#: symbol input variable;
+#X text 553 90 Used for expr~ only:;
+#X text 553 105 $v#: signal (vector) input (vector by vector evaluation)
+;
+#X text 550 164 Used for fexpr~ only:;
+#X text 550 220 $y[n]: the output value indexed by n where n has to
+satisfy 0 > n >= -vector size.;
+#X text 550 248 (the vector size can be changed by the "block~" object.)
+;
+#X text 550 179 $x#[n]: the sample from inlet # indexed by n where
+n has to satisfy 0 => n >= -vector size \, ($x# is a shorthand for
+$x#[0] \, specifying the current sample);
+#X text 63 151 expr~ is used for expression evaluaion of signal data
+on the vector by vector basis;
+#X text 63 136 expr is used for expression evaluaion of control data
+;
+#X text 67 39 For a more detailed documentaion refer to http://www.crca.ucsd.edu/~yadegari/expr.html
+;
+#X text 64 254 The syntax is very close to how expressions are written
+in C. Variables are specified as follows where the '#' stands for the
+inlet number:;
+#X text 65 297 $i#: integer input variable;
+#X text 63 179 fexpr~ is used for expression evaluaion on sample level
+data \; i.e. \, filter design. Warning: fexpr~ is very cpu intensive.
+;
+#X text 633 12 updated for Pd 0.35 test 26 and expr* 0.4;
+#X text 67 85 you can define multiple expressoins in the same object.
+semicolon is used to separates the expressions.;
+#X text 635 294 $y -> $y1[-1];
+#X text 550 263 Shorthands: $x -> $x1[0];
+#X text 635 279 $x1 -> $x1[0] $x2 -> $x2[0] .....;
+#X text 635 309 $y1 -> $y1[-1] $y2 -> $y2[-1] .....;
+#N canvas 0 0 828 385 Examples 0;
+#X obj 33 151 expr 1;
+#X floatatom 197 119 0 0 0;
+#X floatatom 33 181 0 0 0;
+#X msg 33 123 bang;
+#X obj 101 149 expr 2 + 3;
+#X msg 101 122 bang;
+#X floatatom 101 177 0 0 0;
+#X floatatom 196 177 0 0 0;
+#X obj 196 149 expr 2+$f1;
+#X floatatom 34 220 0 0 0;
+#X floatatom 34 277 0 0 0;
+#X obj 34 249 expr $f1 * $f2;
+#X floatatom 113 220 0 0 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array array1 10 float 0;
+#X coords 0 10 10 0 200 150 1;
+#X restore 584 180 graph;
+#X floatatom 35 315 0 0 0;
+#X floatatom 35 371 0 0 0;
+#X floatatom 194 219 0 0 0;
+#X floatatom 194 276 0 0 0;
+#X obj 194 248 expr $s2[$f1];
+#X msg 267 220 symbol array1;
+#X obj 35 343 expr sin(2 * 3.14159 * $f1 / 360);
+#X msg 330 281 \; array1 1 4 2 8 5 6 1 4 2 8 5 6;
+#X floatatom 310 184 5 0 0;
+#X floatatom 395 186 5 0 0;
+#X floatatom 480 184 5 0 0;
+#X floatatom 310 105 5 0 0;
+#X obj 310 132 expr $f1 \; if ($f1 > 0 \, $f1 * 2 \, 0) \; if ($f1
+<= 0 \, $f1 / 2 \, 0);
+#X text 34 56 Examples of expr object;
+#X text 304 88 an example of multiple expressions and the use of 'if'
+;
+#X connect 0 0 2 0;
+#X connect 1 0 8 0;
+#X connect 3 0 0 0;
+#X connect 4 0 6 0;
+#X connect 5 0 4 0;
+#X connect 8 0 7 0;
+#X connect 9 0 11 0;
+#X connect 11 0 10 0;
+#X connect 12 0 11 1;
+#X connect 14 0 20 0;
+#X connect 16 0 18 0;
+#X connect 18 0 17 0;
+#X connect 19 0 18 1;
+#X connect 20 0 15 0;
+#X connect 25 0 26 0;
+#X connect 26 0 22 0;
+#X connect 26 1 23 0;
+#X connect 26 2 24 0;
+#X restore 307 398 pd Examples of expr;
+#N canvas 23 24 882 676 Examples 0;
+#X text -88 101 expr~ examples:;
+#X obj -24 355 print~;
+#X msg 13 334 bang;
+#X obj -24 276 sig~ 440;
+#X floatatom 49 293 0 0 0;
+#X floatatom -24 253 0 0 0;
+#X obj -24 316 expr~ $v1*$f2;
+#X obj 85 356 print~;
+#X msg 101 335 bang;
+#X floatatom 85 268 0 0 0;
+#X floatatom 158 270 0 0 0;
+#X floatatom 357 291 0 0 0;
+#X floatatom 244 267 0 0 0;
+#X obj 244 294 osc~;
+#X msg 369 47 \; pd dsp 0;
+#X msg 291 49 \; pd dsp 1;
+#X text 294 26 audio on;
+#X text 377 25 audio off;
+#X text -45 236 vector times scalar;
+#X text 87 236 vector;
+#X obj 243 354 dac~;
+#X text 241 245 frequency;
+#X text 373 273 amplitude;
+#X obj 85 315 expr~ $v1*$v2;
+#X floatatom 207 471 5 0 0;
+#X obj -40 520 tabsend~ a1;
+#N canvas 0 0 450 300 graph4 0;
+#X array a1 64 float 0;
+#X coords 0 1 63 -1 200 140 1;
+#X restore -39 542 graph;
+#X obj -40 497 expr~ max(min($v1 \, $f2/10) \, -$f2/10);
+#X text -38 123 NOTES: the first inlet of expr~ cannot be a $f1 or
+$i1 \, this may change in later releases;
+#X text -87 420 A simple limiter example;
+#X obj 356 158 vsl 15 128 0 127 0 0 empty empty empty 20 8 0 8 -262144
+-1 -1 0 1;
+#X obj 243 315 expr~ $v1*$f2/128;
+#X text -82 28 make sure you turn on audio for the expr~ examples;
+#X obj -40 473 osc~ 2756.25;
+#X text 122 436 Move the value below between 0 and 10;
+#X text 126 451 to change the limiter threshold;
+#X obj 417 522 tabsend~ a2;
+#X obj 580 518 tabsend~ a3;
+#X obj 417 439 osc~ 2756.25;
+#N canvas 0 0 450 300 graph1 0;
+#X array a2 64 float 1;
+#A 0 -0.419198 -0.487122 -0.481805 -0.400382 -0.252053 -0.0571681 0.155563
+0.353314 0.504227 0.582557 0.573016 0.473664 0.296682 0.0669659 -0.18137
+-0.410083 -0.582709 -0.670415 -0.656787 -0.540803 -0.337462 -0.0758923
+0.204826 0.461522 0.653623 0.74958 0.732042 0.600932 0.373867 0.0838359
+-0.225617 -0.506972 -0.716061 -0.819026 -0.797803 -0.653251 -0.405409
+-0.0906877 0.243486 0.545852 0.769218 0.877835 0.853191 0.697093 0.431698
+0.096368 -0.258195 -0.577642 -0.812367 -0.925245 -0.897515 -0.731894
+-0.452386 -0.100793 0.269551 0.601932 0.844984 0.960659 0.930205 0.757204
+0.467199 0.103913 -0.277405 -0.618414;
+#X coords 0 1 63 -1 200 140 1;
+#X restore 347 554 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array a3 64 float 0;
+#X coords 0 1 63 -1 200 140 1;
+#X restore 569 554 graph;
+#X obj 417 473 expr~ $v1 *$v2 \; if ($v2 > 0 \, 0 \, $v1*$v2);
+#X obj 580 439 osc~ 100;
+#X connect 2 0 1 0;
+#X connect 3 0 6 0;
+#X connect 4 0 6 1;
+#X connect 5 0 3 0;
+#X connect 6 0 1 0;
+#X connect 8 0 7 0;
+#X connect 9 0 23 0;
+#X connect 10 0 23 1;
+#X connect 11 0 31 1;
+#X connect 12 0 13 0;
+#X connect 13 0 31 0;
+#X connect 23 0 7 0;
+#X connect 24 0 27 1;
+#X connect 27 0 25 0;
+#X connect 30 0 11 0;
+#X connect 31 0 20 0;
+#X connect 31 0 20 1;
+#X connect 33 0 27 0;
+#X connect 38 0 41 0;
+#X connect 41 0 36 0;
+#X connect 41 1 37 0;
+#X connect 42 0 41 1;
+#X restore 307 433 pd Examples of expr~;
+#X text 40 399 For expr examples click here ->;
+#X text 41 433 For expr~ examples click here ->;
+#X text 40 471 For fexpr~ examples click here ->;
+#N canvas 0 0 1059 688 examples 0;
+#X msg 519 84 \; pd dsp 0;
+#X msg 428 84 \; pd dsp 1;
+#X text 426 64 audio on;
+#X text 518 65 audio off;
+#X floatatom 126 304 0 0 0;
+#X floatatom 259 323 0 0 0;
+#X msg 226 283 -10;
+#X text 53 103 fexpr~ examples:;
+#X obj 125 571 print~;
+#X msg 247 552 bang;
+#X floatatom 125 475 0 0 0;
+#X obj 126 347 fexpr~ ($x1[$f2]+$x1)/2;
+#X obj 125 532 fexpr~ $x1+$y[-1];
+#X floatatom 635 366 0 0 0;
+#X floatatom 795 387 0 0 0;
+#X obj 630 456 dac~;
+#X obj 632 407 fexpr~ ($x1[$f2/1000]+$x1)/2;
+#X msg 864 317 0 10000;
+#X obj 795 368 line 0;
+#X msg 798 318 -10000;
+#X obj 120 389 dac~;
+#X text 96 227 Simple FIR filter;
+#X text 557 134 Simple FIR filter using fractional offset;
+#X msg 704 318 -10000 10000;
+#X obj 635 387 osc~ 2205;
+#X msg 644 343 1102.5;
+#X msg 862 342 0 10000;
+#X msg 796 343 -20000;
+#X msg 702 343 -20000 10000;
+#X msg 635 318 2205;
+#X msg 548 312 start;
+#X msg 550 334 stop;
+#X msg 57 284 start;
+#X msg 56 309 stop;
+#X msg 75 469 start;
+#X msg 74 494 stop;
+#X obj 491 335 loadbang;
+#X obj 18 495 loadbang;
+#X obj 1 309 loadbang;
+#X text 617 291 frequency;
+#X text 707 300 of the simple filter;
+#X msg 293 282 -20;
+#X obj 126 325 osc~ 2205;
+#X msg 156 281 1102.5;
+#X msg 110 281 2205;
+#X msg 260 282 0;
+#X text 123 445 simple accumulator defined as and an IIR filter;
+#X text 52 148 NOTE: fexpr~ could use lots of CPU power \, by default
+fexpr~ is on when it is loaded. In this page we are turning them off
+with loadbang \, so to hear them you have to turn them on explicitly.
+You can use the "start" and "stop" messages to start and stop fexpr~
+and expr~;
+#X text 706 288 index defining the frequency;
+#X text 95 240 -10 offset will fully filter audio frequency of 2205
+\, and -20 offset will filter audio at frequency of 1102.5;
+#X text 559 215 Thus \, the offset -10000 will filter audio at frequency
+of 2205 and the offset value -20000 will filter the audio at frequency
+of 1102.5.;
+#X text 558 161 When fractional offset is used \, fexpr~ determines
+indexed by linear interpolation. In the following example the offset
+value is divided by 1000 \, thus we can continuously change the offset
+without an audible click in the output.;
+#X text 288 318 If you change this value you;
+#X text 290 330 hear a click;
+#X text 51 87 make sure you turn on audio for the fexpr~ examples;
+#X text 55 -323 Used for fexpr~ only:;
+#X text 55 -267 $y[n]: the output value indexed by n where n has to
+satisfy 0 > n >= -vector size.;
+#X text 55 -239 (the vector size can be changed by the "block~" object.)
+;
+#X text 55 -308 $x#[n]: the sample from inlet # indexed by n where
+n has to satisfy 0 => n >= -vector size \, ($x# is a shorthand for
+$x#[0] \, specifying the current sample);
+#X text 140 -193 $y -> $y1[-1];
+#X text 55 -224 Shorthands: $x -> $x1[0];
+#X text 140 -208 $x1 -> $x1[0] $x2 -> $x2[0] .....;
+#X text 140 -178 $y1 -> $y1[-1] $y2 -> $y2[-1] .....;
+#X text 64 -125 fexpr~ responds to the following methods;
+#X text 66 -106 clear - clears all the previous input and output buffers
+;
+#X text 65 -92 clear x# - clears the previous values of the #th input
+;
+#X text 66 -79 clear y# - clears the previous values of the #th output
+;
+#X text 66 -33 set x# val-1 val-2 ... - sets the as many supplied values
+of the #th input;
+#X text 513 -22 e.g. \, set x2 3.4 0.4 sets x2[-1]=3.4 and x2[-2]=0.4
+;
+#X text 66 -2 set y# val-1 val-2 ... - sets the as many supplied values
+of the #th input;
+#X text 514 4 e.g. \, set y3 1.1 3.3 4.5 sets y3[-1]=1.1 y3[-2]=3.3
+and y3[-3]=4.5;
+#X text 64 -54 set val val ... - sets the first past values of each
+output;
+#X text 513 -59 e.g. \, set 0.1 2.2 0.4 sets y1[-1]=0.1 y2[-1]=2.2
+\, and y3[-1]=0.4;
+#X msg 244 475 set 4000;
+#X obj 125 504 sig~ 0.001;
+#X msg 245 498 clear;
+#X text 22 442 comment;
+#X text 14 431 1 first click the start button;
+#X text 307 494 2 click the set or the clear button;
+#X text 304 547 3 then click bang to see how set and clear work;
+#X connect 4 0 42 0;
+#X connect 5 0 11 1;
+#X connect 6 0 5 0;
+#X connect 9 0 8 0;
+#X connect 10 0 74 0;
+#X connect 11 0 20 0;
+#X connect 11 0 20 1;
+#X connect 12 0 8 0;
+#X connect 13 0 24 0;
+#X connect 14 0 16 1;
+#X connect 16 0 15 0;
+#X connect 16 0 15 1;
+#X connect 17 0 18 0;
+#X connect 18 0 14 0;
+#X connect 19 0 18 0;
+#X connect 23 0 18 0;
+#X connect 24 0 16 0;
+#X connect 25 0 13 0;
+#X connect 26 0 18 0;
+#X connect 27 0 18 0;
+#X connect 28 0 18 0;
+#X connect 29 0 13 0;
+#X connect 30 0 16 0;
+#X connect 31 0 16 0;
+#X connect 32 0 11 0;
+#X connect 33 0 11 0;
+#X connect 34 0 12 0;
+#X connect 35 0 12 0;
+#X connect 36 0 31 0;
+#X connect 37 0 35 0;
+#X connect 38 0 33 0;
+#X connect 41 0 5 0;
+#X connect 42 0 11 0;
+#X connect 43 0 4 0;
+#X connect 44 0 4 0;
+#X connect 45 0 5 0;
+#X connect 73 0 12 0;
+#X connect 74 0 12 0;
+#X connect 75 0 12 0;
+#X restore 306 472 pd examples of fexpr~;
+#X text 42 504 For using fexpr~ for solving;
+#X text 43 520 differential equations click here ->;
+#N canvas 112 22 944 449 lorenz 0;
+#X obj 176 67 v pr;
+#X obj 307 68 v r;
+#X obj 233 69 v b;
+#X floatatom 176 38 5 0 0;
+#X floatatom 307 40 5 0 0;
+#X msg 177 13 10;
+#X obj 231 10 expr 8./3;
+#X msg 128 136 set 1.2 2.3 4.4;
+#X floatatom 233 39 7 0 0;
+#X msg 75 46 stop;
+#X msg 75 67 start;
+#X floatatom 399 40 5 0 0;
+#X obj 399 69 v dt;
+#X msg 310 12 18;
+#X msg 395 13 0.01;
+#X obj 68 296 dac~;
+#X obj 128 -41 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X text 201 -41 <- turn audio on and bang here;
+#X text 463 42 <- experiment with these numbers;
+#X text 472 72 if you hear a buzz \, you have probably gone unstable
+bang on the top again;
+#X obj 489 15 line;
+#X obj 128 241 /~ 20;
+#X obj 234 238 /~ 20;
+#X obj 340 237 /~ 20;
+#X msg 484 -11 0.01 \, 0.04 5000;
+#X obj 128 185 fexpr~ $y1+(pr*$y2-pr*$y1)*dt \; $y2 +(-$y1*$y3 + r*$y1-$y2)*dt
+\; $y3+($y1*$y2 - b*$y3)*dt;
+#X obj 14 65 loadbang;
+#X text 113 -100 This is an example of how fexpr~ could be used for
+solving differential equations \, in this case the lorenz equations
+which generate chotic signals;
+#X text 361 182 Note the following shorthands:;
+#X text 360 198 $y1 -> $y1[-1] \, $y2 -> $y2[-1] \, .....;
+#X text 248 136 the 'set' commands sets the initial previous values
+;
+#X obj 128 298 tabsend~ lorenz1a;
+#X obj 234 278 tabsend~ lorenz2a;
+#X obj 339 259 tabsend~ lorenz3a;
+#N canvas 0 0 450 300 graph1 0;
+#X array lorenz1a 64 float 0;
+#X coords 0 1 63 -1 200 140 1;
+#X restore 73 437 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array lorenz2a 64 float 0;
+#X coords 0 1 63 -1 200 140 1;
+#X restore 331 435 graph;
+#N canvas 0 0 450 300 graph3 0;
+#X array lorenz3a 64 float 0;
+#X coords 0 1 63 -1 200 140 1;
+#X restore 592 436 graph;
+#X text 301 315 You can see the graphs if you scroll down;
+#X text 301 328 but the redrawings may cause clicks in the audio;
+#X connect 3 0 0 0;
+#X connect 4 0 1 0;
+#X connect 5 0 3 0;
+#X connect 6 0 8 0;
+#X connect 7 0 25 0;
+#X connect 8 0 2 0;
+#X connect 9 0 25 0;
+#X connect 10 0 25 0;
+#X connect 11 0 12 0;
+#X connect 13 0 4 0;
+#X connect 14 0 11 0;
+#X connect 16 0 5 0;
+#X connect 16 0 6 0;
+#X connect 16 0 13 0;
+#X connect 16 0 14 0;
+#X connect 16 0 7 0;
+#X connect 16 0 10 0;
+#X connect 20 0 11 0;
+#X connect 21 0 31 0;
+#X connect 21 0 15 0;
+#X connect 21 0 15 1;
+#X connect 22 0 32 0;
+#X connect 23 0 33 0;
+#X connect 24 0 20 0;
+#X connect 25 0 21 0;
+#X connect 25 1 22 0;
+#X connect 25 2 23 0;
+#X connect 26 0 9 0;
+#X restore 308 518 pd lorenz equations for audition;
+#N canvas 97 36 978 656 lorenz 0;
+#X obj 176 67 v pr;
+#X obj 307 68 v r;
+#X obj 233 69 v b;
+#X floatatom 176 38 5 0 0;
+#X floatatom 307 40 5 0 0;
+#X msg 177 13 10;
+#X obj 231 10 expr 8./3;
+#N canvas 0 0 450 300 graph1 0;
+#X array lorenz1 2048 float 0;
+#X coords 0 -1 2047 1 200 140 1;
+#X restore 82 357 graph;
+#N canvas 0 0 450 300 graph2 0;
+#X array lorenz2 2048 float 0;
+#X coords 0 -1 2047 1 200 140 1;
+#X restore 327 353 graph;
+#N canvas 0 0 450 300 graph3 0;
+#X array lorenz3 2048 float 0;
+#X coords 0 -1 2047 1 200 140 1;
+#X restore 570 347 graph;
+#X msg 128 136 set 1.2 2.3 4.4;
+#X floatatom 233 39 7 0 0;
+#X msg 75 46 stop;
+#X msg 75 67 start;
+#X floatatom 399 40 5 0 0;
+#X obj 399 69 v dt;
+#X msg 310 12 18;
+#X msg 395 13 0.01;
+#X obj 128 -41 bng 15 250 50 0 empty empty empty 20 8 0 8 -262144 -1
+-1;
+#X text 201 -41 <- turn audio on and bang here;
+#X text 463 42 <- experiment with these numbers;
+#X text 472 72 if you hear a buzz \, you have probably gone unstable
+bang on the top again;
+#X obj 489 15 line;
+#X obj 128 241 /~ 20;
+#X obj 234 238 /~ 20;
+#X obj 340 237 /~ 20;
+#X msg 484 -11 0.01 \, 0.04 5000;
+#X obj 14 65 loadbang;
+#X text 113 -100 This is an example of how fexpr~ could be used for
+solving differential equations \, in this case the lorenz equations
+which generate chotic signals;
+#X text 361 182 Note the following shorthands:;
+#X text 360 198 $y1 -> $y1[-1] \, $y2 -> $y2[-1] \, .....;
+#X text 248 136 the 'set' commands sets the initial previous values
+;
+#X obj 128 298 tabsend~ lorenz1;
+#X obj 234 278 tabsend~ lorenz2;
+#X obj 339 259 tabsend~ lorenz3;
+#X obj 627 280 block~ 2048;
+#X text 669 133 Lorenz Equations;
+#X obj 128 185 fexpr~ $y1+pr * ($y2-$y1)*dt \; $y2 +(-$y1*$y3 + r*$y1-$y2)*dt
+\; $y3+($y1*$y2 - b*$y3)*dt;
+#X text 672 197 dZ/dt = -bZ;
+#X text 669 167 dX/dt = pr * (X - Y);
+#X text 668 147 written with 3 state variable X \, Y \, and Z;
+#X text 670 182 dY/dt = -XZ + rX - y;
+#X connect 3 0 0 0;
+#X connect 4 0 1 0;
+#X connect 5 0 3 0;
+#X connect 6 0 11 0;
+#X connect 10 0 37 0;
+#X connect 11 0 2 0;
+#X connect 12 0 37 0;
+#X connect 13 0 37 0;
+#X connect 14 0 15 0;
+#X connect 16 0 4 0;
+#X connect 17 0 14 0;
+#X connect 18 0 5 0;
+#X connect 18 0 6 0;
+#X connect 18 0 16 0;
+#X connect 18 0 17 0;
+#X connect 18 0 10 0;
+#X connect 18 0 13 0;
+#X connect 22 0 14 0;
+#X connect 23 0 32 0;
+#X connect 24 0 33 0;
+#X connect 25 0 34 0;
+#X connect 26 0 22 0;
+#X connect 27 0 12 0;
+#X connect 37 0 23 0;
+#X connect 37 1 24 0;
+#X connect 37 2 25 0;
+#X restore 308 541 pd lorenz equations for visualization;
+#X text 68 24 by Shahrokh Yadegari;
diff --git a/pd/extra/help-rev1~.pd b/pd/extra/help-rev1~.pd
new file mode 100644
index 00000000..55580bd5
--- /dev/null
+++ b/pd/extra/help-rev1~.pd
@@ -0,0 +1,119 @@
+#N canvas 55 21 1008 526 12;
+#X obj 148 439 dac~;
+#X obj 58 72 line~;
+#X msg 58 49 0 \, 10000 5;
+#X obj 58 118 cos~;
+#X msg 146 70 1;
+#X obj 146 47 loadbang;
+#X obj 58 95 clip~ 0 0.25;
+#X floatatom 173 264 0 0 0;
+#X obj 251 134 line~;
+#X obj 251 157 cos~;
+#X msg 324 54 -0.25 \, 0.25 100;
+#X obj 251 8 loadbang;
+#X msg 251 31 -0.25;
+#X obj 251 203 *~;
+#X obj 58 140 hip~ 5;
+#X floatatom 162 328 0 0 0;
+#X obj 162 373 pack 0 100;
+#X obj 162 396 line~;
+#X obj 148 416 *~;
+#X obj 162 350 dbtorms;
+#X msg 324 77 -0.25 \, 0.25 400;
+#X floatatom 324 145 0 0 0;
+#X obj 324 191 osc~ 440;
+#X obj 324 168 mtof;
+#X msg 324 31 -0.25 \, 0.25 20;
+#X obj 251 180 *~ 0.1;
+#X msg 324 100 -0.25 \, 0.25 1000;
+#X msg 324 122 -0.25 \, 0.25 2000;
+#X obj 324 226 *~;
+#X obj 342 252 *~;
+#X obj 58 439 dac~;
+#X floatatom 68 323 0 0 0;
+#X obj 68 368 pack 0 100;
+#X obj 68 391 line~;
+#X obj 58 416 *~;
+#X obj 68 346 dbtorms;
+#X msg 324 8 0;
+#X obj 308 257 *~;
+#X obj 58 26 metro 2000;
+#X floatatom 58 4 0 0 0;
+#X msg 220 265 bang;
+#X obj 284 322 env~ 32768;
+#X floatatom 284 344 0 0 0;
+#X text 166 244 1 sec;
+#X text 143 226 dB after;
+#X text 220 245 clear;
+#X text 1 51 impulse;
+#X text 362 7 tone;
+#X text 484 31 beeps;
+#X text 428 167 This is an experimental reverberator design composed
+of a series of allpass filters with exponentially growing delay times.
+Each allpass filter has a gain of 0.7. The reverb time is adjusted
+by adjusting the input gains of the allpass filters. The last unit
+is modified so that its first two "echos" mimic those of an allpass
+but its loop gain depends on reverb time.;
+#X text 430 299 Reverb time is controlled by specifying the dB gain
+(100 normal) after one second \, so that 100 corresponds to infinite
+reverb time \, 70 to two seconds \, 40 to one second \, and 0 to 0
+;
+#X text 671 499 modified for Pd version 0.30.;
+#X msg 560 34 \; pd dsp 1;
+#X text 427 475 The rev1~ module eats about 18% of my 300mHz P2 machine.
+;
+#X obj 148 289 rev1~;
+#X text 428 381 The "clear" button impolitely clears out all the delay
+lines \, You may immediately resume pumping the reverberator \, but
+the input signal should be cleanly enveloped. The output \, too \,
+must be enveloped and may not be opened until 5 msec after the "clear"
+message is sent.;
+#X connect 1 0 6 0;
+#X connect 2 0 1 0;
+#X connect 3 0 14 0;
+#X connect 4 0 1 0;
+#X connect 5 0 4 0;
+#X connect 6 0 3 0;
+#X connect 7 0 54 1;
+#X connect 8 0 9 0;
+#X connect 9 0 25 0;
+#X connect 10 0 8 0;
+#X connect 11 0 12 0;
+#X connect 12 0 8 0;
+#X connect 13 0 14 0;
+#X connect 14 0 34 0;
+#X connect 14 0 54 0;
+#X connect 15 0 19 0;
+#X connect 16 0 17 0;
+#X connect 17 0 18 1;
+#X connect 18 0 0 0;
+#X connect 19 0 16 0;
+#X connect 20 0 8 0;
+#X connect 21 0 23 0;
+#X connect 22 0 13 1;
+#X connect 22 0 28 0;
+#X connect 22 0 28 1;
+#X connect 22 0 29 0;
+#X connect 23 0 22 0;
+#X connect 24 0 8 0;
+#X connect 25 0 13 0;
+#X connect 26 0 8 0;
+#X connect 27 0 8 0;
+#X connect 28 0 29 1;
+#X connect 28 0 13 1;
+#X connect 28 0 37 0;
+#X connect 28 0 37 1;
+#X connect 29 0 13 1;
+#X connect 31 0 35 0;
+#X connect 32 0 33 0;
+#X connect 33 0 34 1;
+#X connect 34 0 30 0;
+#X connect 35 0 32 0;
+#X connect 36 0 8 0;
+#X connect 37 0 13 1;
+#X connect 38 0 2 0;
+#X connect 39 0 38 0;
+#X connect 40 0 54 2;
+#X connect 41 0 42 0;
+#X connect 54 0 18 0;
+#X connect 54 0 41 0;
diff --git a/pd/extra/help-rev2~.pd b/pd/extra/help-rev2~.pd
new file mode 100644
index 00000000..cea8c5da
--- /dev/null
+++ b/pd/extra/help-rev2~.pd
@@ -0,0 +1,130 @@
+#N canvas 167 160 766 354 12;
+#X floatatom 73 185 0 0 120 0 - - -;
+#X floatatom 106 323 0 0 120 0 - - -;
+#N canvas 0 0 539 448 tests 0;
+#X obj 67 33 inlet;
+#X obj 309 189 inlet;
+#X obj 235 207 line~;
+#X obj 235 230 cos~;
+#X obj 235 68 loadbang;
+#X msg 235 91 -0.25;
+#X obj 235 276 *~;
+#X obj 186 309 hip~ 5;
+#X floatatom 308 218 0 0 0 0 - - -;
+#X obj 308 264 osc~ 440;
+#X obj 308 241 mtof;
+#X obj 235 253 *~ 0.1;
+#X obj 308 299 *~;
+#X obj 326 325 *~;
+#X obj 292 330 *~;
+#X msg 279 150 -0.25 \, 0.25 \$1;
+#X obj 41 148 biquad~ 0 0 1 -1 0;
+#X obj 63 70 t b;
+#X obj 104 72 del 3;
+#X obj 57 101 1;
+#X obj 96 101 0;
+#X obj 41 355 outlet~;
+#X obj 279 126 inlet;
+#X connect 0 0 17 0;
+#X connect 1 0 8 0;
+#X connect 2 0 3 0;
+#X connect 3 0 11 0;
+#X connect 4 0 5 0;
+#X connect 5 0 2 0;
+#X connect 6 0 7 0;
+#X connect 7 0 21 0;
+#X connect 8 0 10 0;
+#X connect 9 0 6 1;
+#X connect 9 0 12 0;
+#X connect 9 0 12 1;
+#X connect 9 0 13 0;
+#X connect 10 0 9 0;
+#X connect 11 0 6 0;
+#X connect 12 0 13 1;
+#X connect 12 0 6 1;
+#X connect 12 0 14 0;
+#X connect 12 0 14 1;
+#X connect 13 0 6 1;
+#X connect 14 0 6 1;
+#X connect 15 0 2 0;
+#X connect 16 0 21 0;
+#X connect 17 0 18 0;
+#X connect 17 0 19 0;
+#X connect 18 0 20 0;
+#X connect 19 0 16 0;
+#X connect 20 0 16 0;
+#X connect 22 0 15 0;
+#X restore 17 154 pd tests;
+#X msg 56 35 10;
+#X msg 54 62 20;
+#X msg 53 90 100;
+#X msg 52 115 500;
+#X obj 17 15 bng 15 250 50 0 empty empty empty 0 -6 0 8 -262144 -1
+-1;
+#X text 37 9 impulse;
+#N canvas 0 0 450 300 output 0;
+#X obj 54 202 dac~;
+#X obj 132 119 pack 0 100;
+#X obj 132 142 line~;
+#X obj 54 165 *~;
+#X obj 132 97 dbtorms;
+#X obj 33 42 inlet~;
+#X obj 177 42 inlet;
+#X obj 177 74 clip 0 120;
+#X msg 257 133 \; pd dsp 1;
+#X obj 98 42 inlet~;
+#X obj 94 168 *~;
+#X connect 1 0 2 0;
+#X connect 2 0 3 1;
+#X connect 2 0 10 1;
+#X connect 3 0 0 0;
+#X connect 4 0 1 0;
+#X connect 5 0 3 0;
+#X connect 6 0 7 0;
+#X connect 6 0 8 0;
+#X connect 7 0 4 0;
+#X connect 9 0 10 0;
+#X connect 10 0 0 1;
+#X restore 18 324 pd output;
+#X floatatom 97 127 0 0 0 0 - - -;
+#X text 136 96 tone;
+#X text 135 112 pitch;
+#X text 114 185 level \, dB;
+#X floatatom 117 209 0 0 100 0 - - -;
+#X text 158 209 liveness \, 0-100;
+#X text 505 330 modified for Pd version 0.37;
+#X floatatom 161 235 0 0 120 0 - - -;
+#X floatatom 205 259 0 0 120 0 - - -;
+#X text 192 235 crossover frequency \, Hz.;
+#X text 238 260 HF damping \, percent;
+#X obj 30 290 rev2~ 100 90 3000 20;
+#X text 141 324 output level \, dB;
+#X text 281 8 REV2~ - a simple 1-in \, 4-out reverberator;
+#X text 95 35 tone;
+#X text 96 52 bursts;
+#X text 231 37 The creation arguments (level \, liveness \, crossover
+frequency \, HF damping) may also be supplied in four inlets as shown.
+The "liveness" (actually the internal feedback percentage) should be
+100 for infinite reverb \, 90 for longish \, and 80 for short. The
+crossover frequency and HF damping work together: at frequencies above
+crossover \, the feedback is diminished by the "damping" as a percentage.
+So zero HF damping means equal reverb time at all frequencies \, and
+100% damping means almost nothing above the crossover frequency gets
+through.;
+#X text 132 130 (60 for;
+#X text 115 150 middle C);
+#X connect 0 0 21 1;
+#X connect 1 0 9 2;
+#X connect 2 0 9 0;
+#X connect 2 0 21 0;
+#X connect 3 0 2 1;
+#X connect 4 0 2 1;
+#X connect 5 0 2 1;
+#X connect 6 0 2 1;
+#X connect 7 0 2 0;
+#X connect 10 0 2 2;
+#X connect 14 0 21 2;
+#X connect 17 0 21 3;
+#X connect 18 0 21 4;
+#X connect 21 0 9 0;
+#X connect 21 1 9 1;
diff --git a/pd/extra/loop~/help-loop~.pd b/pd/extra/loop~/help-loop~.pd
new file mode 100644
index 00000000..6acff93c
--- /dev/null
+++ b/pd/extra/loop~/help-loop~.pd
@@ -0,0 +1,66 @@
+#N canvas 33 0 538 640 12;
+#X floatatom 55 169;
+#X obj 273 343 print~;
+#X msg 273 305 bang;
+#X obj 55 303 loop~;
+#X floatatom 80 244;
+#X msg 69 217 bang;
+#X obj 172 350 print~;
+#X msg 170 311 bang;
+#X graph graph1 0 -1 150000 1 306 586 506 436;
+#X array array2 150000 float;
+#X pop;
+#X msg 306 594 \; array2 resize 150000;
+#X obj 29 578 soundfiler;
+#X obj 55 419 tabread4~ array2;
+#X obj 55 373 *~;
+#X obj 55 488 dac~;
+#X obj 55 465 hip~ 5;
+#X obj 101 377 samphold~;
+#X obj 55 396 +~;
+#X floatatom 102 268;
+#X obj 102 291 *~ 1000;
+#X msg 47 533 read ../doc/sound/bell.aiff array2;
+#X msg 47 556 read ../doc/sound/vocal.aiff array2;
+#X msg 61 194 set 0.5;
+#X text 100 164 left signal input is transposition (1 is normal \, 2 is up an octave \, etc);
+#X text 37 6 loop~ - phase generator for looping samplers;
+#X text 121 193 set phase (0 to 1);
+#X text 121 213 reset phase to 0;
+#X text 118 243 right signal input is window size in samples;
+#X text 140 267 here's how to handle onsets;
+#X obj 55 442 *~;
+#X floatatom 171 397;
+#X obj 171 466 line~;
+#X obj 171 420 dbtorms;
+#X obj 171 443 pack 0 50;
+#X text 205 396 output level 0-100;
+#X text 170 290 print outputs;
+#X text 21 25 loop~ takes input signals to set a window size and transposition \, and outputs a phase and a sampled window size. The window size only changes at phase zero crossings and the phase output is adjusted so that changing window size doesn't change the transposition.;
+#X text 22 95 You can send "bang" or "set" message to force the phase to zero--you should mute the output before doing so. This may be desirable if you've set a large window size but then want to decrease it without waiting for the next phase crossing.;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 6 0;
+#X connect 3 0 12 0;
+#X connect 3 0 15 1;
+#X connect 3 1 1 0;
+#X connect 3 1 12 1;
+#X connect 4 0 3 1;
+#X connect 5 0 3 0;
+#X connect 7 0 6 0;
+#X connect 11 0 28 0;
+#X connect 12 0 16 0;
+#X connect 14 0 13 0;
+#X connect 14 0 13 1;
+#X connect 15 0 16 1;
+#X connect 16 0 11 0;
+#X connect 17 0 18 0;
+#X connect 18 0 15 0;
+#X connect 19 0 10 0;
+#X connect 20 0 10 0;
+#X connect 21 0 3 0;
+#X connect 28 0 14 0;
+#X connect 29 0 31 0;
+#X connect 30 0 28 1;
+#X connect 31 0 32 0;
+#X connect 32 0 30 0;
diff --git a/pd/extra/lrshift~/help-rlshift~.pd b/pd/extra/lrshift~/help-rlshift~.pd
new file mode 100644
index 00000000..cdfd8830
--- /dev/null
+++ b/pd/extra/lrshift~/help-rlshift~.pd
@@ -0,0 +1,29 @@
+#N canvas 143 0 673 325 12;
+#X msg 268 277 bang;
+#X obj 244 303 print~;
+#X msg 185 278 bang;
+#X obj 161 304 print~;
+#X text 53 117 click here first;
+#X msg 72 270 bang;
+#X obj 48 296 print~;
+#X text 162 222 shift left;
+#X text 243 224 shift right;
+#X obj 161 252 lrshift~ 1;
+#X obj 244 251 lrshift~ -1;
+#X text 39 37 Acting at whatever vector size the window is running at \, lrshift~ shifts samples to the left (toward the beginning sample) or to the right. The argument gives the direction and the amount of the shift. The rightmost (or leftmost) samples are set to zero.;
+#X graph graph2 0 0 63 1 448 258 648 118;
+#X array shiftin 64 float;
+#X pop;
+#X obj 47 11 rlshift~;
+#X text 115 11 -- shift signal vector elements left or right;
+#X msg 54 138 \; pd dsp 1 \; shiftin 1 1;
+#X obj 48 204 tabreceive~ shiftin;
+#X text 525 308 Updated for Pd 0.31.;
+#X connect 0 0 1 0;
+#X connect 2 0 3 0;
+#X connect 5 0 6 0;
+#X connect 9 0 3 0;
+#X connect 10 0 1 0;
+#X connect 16 0 6 0;
+#X connect 16 0 9 0;
+#X connect 16 0 10 0;
diff --git a/pd/extra/paf~/help-paf~.pd b/pd/extra/paf~/help-paf~.pd
new file mode 100644
index 00000000..c6c63c25
--- /dev/null
+++ b/pd/extra/paf~/help-paf~.pd
@@ -0,0 +1,166 @@
+#N canvas 314 261 819 436 12;
+#X msg 2 279 freq \$1 100;
+#X obj 2 254 mtof;
+#X msg 108 279 amp \$1 100;
+#X obj 108 229 r amp;
+#X obj 206 230 r cf;
+#X obj 206 255 mtof;
+#X msg 206 280 cf \$1 100;
+#X obj 2 229 r pit;
+#X msg 140 374 bang;
+#X obj 71 403 dac~;
+#X obj 519 179 s vfr;
+#X obj 519 104 r vfr;
+#X obj 467 179 s vib;
+#X obj 467 104 r vib;
+#X msg 519 129 set \$1;
+#X floatatom 519 154 0 0 0 0 - - -;
+#X msg 467 129 set \$1;
+#X floatatom 467 154 0 0 0 0 - - -;
+#X obj 418 179 s bw;
+#X obj 369 179 s cf;
+#X obj 250 178 s amp;
+#X obj 309 177 s pit;
+#X obj 309 102 r pit;
+#X msg 309 127 set \$1;
+#X floatatom 309 152 0 0 0 0 - - -;
+#X obj 250 103 r amp;
+#X msg 250 128 set \$1;
+#X floatatom 250 153 0 0 0 0 - - -;
+#X msg 369 129 set \$1;
+#X floatatom 369 154 0 0 0 0 - - -;
+#X obj 369 104 r cf;
+#X msg 418 129 set \$1;
+#X floatatom 418 154 0 0 0 0 - - -;
+#X obj 418 104 r bw;
+#X msg 296 280 bw \$1 100;
+#X obj 296 230 r bw;
+#X obj 296 255 mtof;
+#X obj 385 229 r vib;
+#X msg 385 279 vib \$1 100;
+#X msg 483 279 vfr \$1 100;
+#X obj 483 254 / 8;
+#X obj 483 229 r vfr;
+#X obj 385 254 / 660;
+#X msg 573 129 set \$1;
+#X floatatom 573 154 0 0 0 0 - - -;
+#X obj 573 104 r shift;
+#X obj 573 179 s shift;
+#X obj 584 227 r shift;
+#X msg 584 277 shift \$1 100;
+#X obj 108 254 dbtorms;
+#X obj 85 348 paf~;
+#X obj 21 380 s~ foo;
+#X msg 705 278 phase 0 0 0;
+#X obj 140 399 print~ output;
+#N canvas 447 311 726 483 spectrum 0;
+#N canvas 0 0 450 300 graph1 0;
+#X array pulse-output 882 float 0;
+#X coords 0 1.02 882 -1.02 200 130 1;
+#X restore 405 271 graph;
+#X text 405 403 --------- 0.02 seconds ------;
+#N canvas 0 0 450 300 graph1 0;
+#X array spectrum 128 float 0;
+#X coords 0 500 128 0 256 130 1;
+#X restore 391 78 graph;
+#X obj 137 257 tabwrite~ pulse-output;
+#X msg 106 174 bang;
+#N canvas 204 17 358 238 fft 0;
+#X obj 46 48 inlet~;
+#X obj 159 181 tabwrite~ spectrum;
+#X obj 159 145 inlet;
+#X obj 46 78 rfft~;
+#X obj 46 111 *~;
+#X obj 77 111 *~;
+#X obj 46 141 sqrt~;
+#X obj 191 45 block~ 1024 1;
+#X connect 0 0 3 0;
+#X connect 2 0 1 0;
+#X connect 3 0 4 0;
+#X connect 3 0 4 1;
+#X connect 3 1 5 0;
+#X connect 3 1 5 1;
+#X connect 4 0 6 0;
+#X connect 5 0 6 0;
+#X connect 6 0 1 0;
+#X restore 46 228 pd fft;
+#X text 33 8 PULSE SPECTRUM MEASUREMENT;
+#X text 379 221 0;
+#X text 627 218 5512;
+#X obj 94 123 r~ foo;
+#X obj 41 160 *~ 1;
+#X floatatom 44 113 0 0 0 0 - - -;
+#X obj 179 136 metro 1000;
+#X floatatom 178 108 0 0 0 0 - - -;
+#X obj 56 44 r graph;
+#X obj 140 205 *~ 10;
+#X connect 4 0 3 0;
+#X connect 4 0 5 1;
+#X connect 9 0 10 0;
+#X connect 9 0 15 0;
+#X connect 10 0 5 0;
+#X connect 11 0 10 1;
+#X connect 12 0 4 0;
+#X connect 13 0 12 0;
+#X connect 14 0 11 0;
+#X connect 14 0 13 0;
+#X connect 15 0 3 0;
+#X restore 664 340 pd spectrum;
+#X msg 20 136 \; pd dsp 1 \; pit 60 \; cf 60 \; graph 20;
+#X text 32 3 The "PAF" generator \, described in a paper in JAES 43/1
+pp. 40-47 \, reprinted on Miller Puckette's web page. Often used in
+Philippe Manoury's music. The important controls are center frequency
+("cf") and bandwidth ("bw") here controlled as MIDI values.;
+#X text 15 96 clich here to test;
+#X text 12 114 (then set amplitude);
+#X text 414 338 click here to see spectrum:;
+#X text 295 380 NOTE: the PAF algorithm is patented by IRCAM \, but
+is free for non-commercial use. For commercial use \, please see http://forum.ircam.fr
+;
+#X connect 0 0 50 0;
+#X connect 1 0 0 0;
+#X connect 2 0 50 0;
+#X connect 3 0 49 0;
+#X connect 4 0 5 0;
+#X connect 5 0 6 0;
+#X connect 6 0 50 0;
+#X connect 7 0 1 0;
+#X connect 8 0 53 0;
+#X connect 11 0 14 0;
+#X connect 13 0 16 0;
+#X connect 14 0 15 0;
+#X connect 15 0 10 0;
+#X connect 16 0 17 0;
+#X connect 17 0 12 0;
+#X connect 22 0 23 0;
+#X connect 23 0 24 0;
+#X connect 24 0 21 0;
+#X connect 25 0 26 0;
+#X connect 26 0 27 0;
+#X connect 27 0 20 0;
+#X connect 28 0 29 0;
+#X connect 29 0 19 0;
+#X connect 30 0 28 0;
+#X connect 31 0 32 0;
+#X connect 32 0 18 0;
+#X connect 33 0 31 0;
+#X connect 34 0 50 0;
+#X connect 35 0 36 0;
+#X connect 36 0 34 0;
+#X connect 37 0 42 0;
+#X connect 38 0 50 0;
+#X connect 39 0 50 0;
+#X connect 40 0 39 0;
+#X connect 41 0 40 0;
+#X connect 42 0 38 0;
+#X connect 43 0 44 0;
+#X connect 44 0 46 0;
+#X connect 45 0 43 0;
+#X connect 47 0 48 0;
+#X connect 48 0 50 0;
+#X connect 49 0 2 0;
+#X connect 50 0 9 0;
+#X connect 50 0 51 0;
+#X connect 50 0 9 1;
+#X connect 50 0 53 0;
+#X connect 52 0 50 0;
diff --git a/pd/extra/pique/help-pique.pd b/pd/extra/pique/help-pique.pd
new file mode 100644
index 00000000..1689c95b
--- /dev/null
+++ b/pd/extra/pique/help-pique.pd
@@ -0,0 +1,33 @@
+#N canvas 143 0 729 407 12;
+#X obj 47 11 pique;
+#X text 105 12 -- find peaks in an FFT spectrum;
+#X obj 214 174 rfft~;
+#X obj 131 129 osc~ 2000;
+#X graph graph2 0 -64 63 64 519 179 719 39;
+#X array fft-real 64 float;
+#X pop;
+#X graph graph3 0 -64 63 64 519 327 719 187;
+#X array fft-imag 64 float;
+#X pop;
+#X obj 214 215 tabwrite~ fft-real;
+#X obj 245 240 tabwrite~ fft-imag;
+#X obj 315 158 metro 1000;
+#X obj 315 116 loadbang;
+#X msg 315 138 1;
+#X obj 91 349 pique;
+#X msg 91 322 64 fft-real fft-imag 10;
+#X obj 91 376 print;
+#X obj 205 132 osc~ 5000;
+#X text 25 37 pique takes unwindowed FFT analyses as input (they should be stored in arrays) and outputs a list of peaks \, giving their peak number \, frequency \, amplitude \, and phase (as a cosine/sine pair.);
+#X text 13 289 message argumnets: number of FFT points \, fft real part \, fft imaginary part \, maximum number of peaks to report.;
+#X text 578 387 updated for Pd 0.31.;
+#X connect 2 0 6 0;
+#X connect 2 1 7 0;
+#X connect 3 0 2 0;
+#X connect 8 0 6 0;
+#X connect 8 0 7 0;
+#X connect 9 0 10 0;
+#X connect 10 0 8 0;
+#X connect 11 0 13 0;
+#X connect 12 0 11 0;
+#X connect 14 0 2 0;
diff --git a/pd/extra/pique/makefile b/pd/extra/pique/makefile
index 47a7463e..8158e7cd 100644
--- a/pd/extra/pique/makefile
+++ b/pd/extra/pique/makefile
@@ -70,8 +70,7 @@ LINUXINCLUDE = -I../../src
cc $(LINUXCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
ld -export_dynamic -shared -o $*.pd_linux $*.o -lc -lm
strip --strip-unneeded $*.pd_linux
- rm -f $*.o ../$*.pd_linux
- ln -s $*/$*.pd_linux ..
+ rm -f $*.o
# ----------------------- Mac OSX -----------------------
@@ -84,9 +83,8 @@ DARWINCFLAGS = -DPD -O2 -Wall -W -Wshadow -Wstrict-prototypes \
.c.pd_darwin:
cc $(DARWINCFLAGS) $(LINUXINCLUDE) -o $*.o -c $*.c
- cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
- rm -f $*.o ../$*.pd_darwin
- ln -s $*/$*.pd_darwin ..
+ cc -bundle -undefined suppress -flat_namespace -o $*.pd_darwin $*.o
+ rm -f $*.o
# ----------------------------------------------------------
diff --git a/pd/extra/pique/pique.c.old b/pd/extra/pique/pique.c.old
new file mode 100644
index 00000000..75afc38c
--- /dev/null
+++ b/pd/extra/pique/pique.c.old
@@ -0,0 +1,148 @@
+/* Copyright (c) 1998 The Regents of the University of California. The
+contents of this file are free for any use, but BOTH THE AUTHOR AND UCSD
+DISCLAIM ALL WARRANTIES related to it. Although not written in Java, this
+still should not be used to control any machinery containing a sharp blade or
+combustible materiel, or as part of any life support system or weapon. */
+
+#include "m_pd.h"
+#include <math.h>
+
+static t_class *pique_class;
+
+typedef struct _pique
+{
+ t_object x_obj;
+} t_pique;
+
+static void *pique_new(void)
+{
+ t_pique *x = (t_pique *)pd_new(pique_class);
+ return (x);
+}
+
+ /* we aren't measuring phase yet */
+static void pique_doit(int npts, t_float *fpreal, t_float *fpimag,
+ int npeak, t_float *fpfreq, t_float *fpamp)
+{
+ float srate = sys_getsr(); /* not sure how to get this correctly */
+ float oneovern = 1.0/ (float)npts;
+ float fperbin = srate * oneovern;
+ float pow1, pow2 = 0, pow3 = 0, pow4 = 0, pow5 = 0;
+ float re1, re2 = 0, re3 = *fpreal;
+ float im1, im2 = 0, im3 = 0, powthresh;
+ int count, peakcount = 0, n2 = (npts >> 1);
+ float *fp1, *fp2;
+ for (count = n2, fp1 = fpreal, fp2 = fpimag, powthresh = 0;
+ count--; fp1++, fp2++)
+ powthresh += (*fp1) * (*fp1) + (*fp2) * (*fp2) ;
+ powthresh *= 0.00001;
+ for (count = 1; count < n2; count++)
+ {
+ float windreal, windimag, pi = 3.14159;
+ float detune, pidetune, ampcorrect, freqout, ampout;
+ float rpeak, rpeaknext, rpeakprev;
+ float ipeak, ipeaknext, ipeakprev;
+ fpreal++;
+ fpimag++;
+ re1 = re2;
+ re2 = re3;
+ re3 = *fpreal;
+ im1 = im2;
+ im2 = im3;
+ im3 = *fpimag;
+ if (count < 2) continue;
+ pow1 = pow2;
+ pow2 = pow3;
+ pow3 = pow4;
+ pow4 = pow5;
+ /* get Hanning-windowed spectrum by convolution */
+ windreal = re2 - 0.5 * (re1 + re3);
+ windimag = im2 - 0.5 * (im1 + im3);
+ pow5 = windreal * windreal + windimag * windimag;
+ /* if (count < 30) post("power %f", pow5); */
+ if (count < 5) continue;
+ /* check for a peak. The actual bin is count-3. */
+ if (pow3 <= pow2 || pow3 <= pow4 || pow3 <= pow1 || pow3 <= pow5
+ || pow3 < powthresh)
+ continue;
+ /* go back for the raw FFT values around the peak. */
+ rpeak = fpreal[-3];
+ rpeaknext = fpreal[-2];
+ rpeakprev = fpreal[-4];
+ ipeak = fpimag[-3];
+ ipeaknext = fpimag[-2];
+ ipeakprev = fpimag[-4];
+
+ detune = ((rpeakprev - rpeaknext) *
+ (2.0 * rpeak - rpeakprev - rpeaknext) +
+ (ipeakprev - ipeaknext) *
+ (2.0 * ipeak - ipeakprev - ipeaknext)) /
+ (4.0 * pow3);
+ /* if (count < 30) post("detune %f", detune); */
+ if (detune > 0.7 || detune < -0.7) continue;
+ /* the frequency is the sum of the bin frequency and detuning */
+ freqout = fperbin * ((float)(count-3) + detune);
+ *fpfreq++ = freqout;
+ pidetune = pi * detune;
+ if (pidetune < 0.01 && pidetune > -0.01) ampcorrect = 1;
+ else ampcorrect = 1.0 / (sin(pidetune)/pidetune + 0.5 *
+ (sin(pidetune + pi)/(pidetune+pi) +
+ sin(pidetune-pi)/(pidetune-pi)));
+ /* amplitude is peak height, corrected for Hanning window shape.
+ Multiply by 2 to get real-sinusoid peak amplitude */
+ ampout = 2. * oneovern * sqrt(pow3) * ampcorrect;
+ *fpamp++ = ampout;
+ /* post("peak %f %f", freqout, ampout); */
+ if (++peakcount == npeak) break;
+ }
+ while (peakcount < npeak)
+ {
+ *fpfreq++ = 0;
+ *fpamp++ = 0;
+ peakcount++;
+ }
+}
+
+static void pique_list(t_pique *x, t_symbol *s, int argc, t_atom *argv)
+{
+ int npts = atom_getintarg(0, argc, argv);
+ t_symbol *symreal = atom_getsymbolarg(1, argc, argv);
+ t_symbol *symimag = atom_getsymbolarg(2, argc, argv);
+ int npeak = atom_getintarg(3, argc, argv);
+ t_symbol *symfreq = atom_getsymbolarg(4, argc, argv);
+ t_symbol *symamp = atom_getsymbolarg(5, argc, argv);
+ t_garray *a, *afreq, *aamp;
+ int n;
+ t_float *fpreal, *fpimag, *fpfreq, *fpamp, *fpphase;
+ if (npts < 8 || npeak < 1) error("pique: bad npoints or npeak");
+ else if (!(a = (t_garray *)pd_findbyclass(symreal, garray_class)) ||
+ !garray_getfloatarray(a, &n, &fpreal) ||
+ n < npts)
+ error("%s: missing or bad array", symreal->s_name);
+ else if (!(a = (t_garray *)pd_findbyclass(symimag, garray_class)) ||
+ !garray_getfloatarray(a, &n, &fpimag) ||
+ n < npts)
+ error("%s: missing or bad array", symimag->s_name);
+ else if (!(afreq = (t_garray *)pd_findbyclass(symfreq, garray_class)) ||
+ !garray_getfloatarray(afreq, &n, &fpfreq) ||
+ n < npeak)
+ error("%s: missing or bad array", symfreq->s_name);
+ else if (!(aamp = (t_garray *)pd_findbyclass(symamp, garray_class)) ||
+ !garray_getfloatarray(aamp, &n, &fpamp) ||
+ n < npeak)
+ error("%s: missing or bad array", symamp->s_name);
+ else
+ {
+ pique_doit(npts, fpreal, fpimag, npeak, fpfreq, fpamp);
+ garray_redraw(afreq);
+ garray_redraw(aamp);
+ }
+}
+
+void pique_setup(void)
+{
+ pique_class = class_new(gensym("pique"), pique_new, 0,
+ sizeof(t_pique), 0, 0);
+ class_addlist(pique_class, pique_list);
+}
+
diff --git a/pd/extra/rev2~.pd b/pd/extra/rev2~.pd
new file mode 100644
index 00000000..e2aa7bae
--- /dev/null
+++ b/pd/extra/rev2~.pd
@@ -0,0 +1,240 @@
+#N canvas 333 147 832 664 12;
+#X obj 161 497 +~;
+#X obj 520 105 inlet;
+#X obj 184 407 *~;
+#X obj 486 412 *~;
+#X obj 285 412 *~;
+#X obj 387 412 *~;
+#X obj 443 546 -~;
+#X obj 364 545 -~;
+#X obj 239 537 +~;
+#X obj 161 534 +~;
+#X obj 162 444 +~;
+#X obj 262 440 +~;
+#X obj 464 501 -~;
+#X obj 387 499 +~;
+#X obj 239 500 -~;
+#X obj 452 105 inlet;
+#X obj 609 429 line~;
+#X obj 509 374 line~;
+#X obj 16 121 delread~ \$0-del1 58.6435;
+#X obj 94 143 delread~ \$0-del2 69.4325;
+#X obj 176 165 delread~ \$0-del3 74.5234;
+#X obj 258 189 delread~ \$0-del4 86.1244;
+#X obj 530 500 *~;
+#X obj 599 501 *~;
+#X obj 161 641 delwrite~ \$0-del1 58.6435;
+#X obj 240 617 delwrite~ \$0-del2 69.4325;
+#X obj 365 595 delwrite~ \$0-del3 74.5234;
+#X obj 444 573 delwrite~ \$0-del4 86.1244;
+#X obj 609 357 dbtorms;
+#X obj 609 403 pack 0 30;
+#X obj 520 211 pack 0 50;
+#X obj 9 390 inlet~;
+#X obj 530 525 outlet~;
+#X obj 599 525 outlet~;
+#X obj 520 187 / 200;
+#X obj 520 162 clip 0 100;
+#X obj 52 236 lop~;
+#X obj 452 137 f \$1;
+#X obj 520 138 f \$2;
+#X obj 625 143 f \$3;
+#X obj 696 143 f \$4;
+#X obj 367 106 loadbang;
+#X obj 667 500 *~;
+#X obj 735 501 *~;
+#X obj 667 525 outlet~;
+#X obj 735 525 outlet~;
+#X obj 625 167 moses 1;
+#X msg 631 193 3000;
+#X obj 705 193 clip 0 100;
+#N canvas 345 88 355 597 early-reflect 0;
+#X obj 119 477 delread~ \$0-ref6 13.645;
+#X obj 119 453 delwrite~ \$0-ref6 13.645;
+#X obj 106 400 delread~ \$0-ref5 16.364;
+#X obj 106 376 delwrite~ \$0-ref5 16.364;
+#X obj 102 324 delread~ \$0-ref4 19.392;
+#X obj 102 300 delwrite~ \$0-ref4 19.392;
+#X obj 106 247 delread~ \$0-ref3 25.796;
+#X obj 106 223 delwrite~ \$0-ref3 25.796;
+#X obj 107 169 delread~ \$0-ref2 43.5337;
+#X obj 107 145 delwrite~ \$0-ref2 43.5337;
+#X obj 110 90 delread~ \$0-ref1 75.2546;
+#X obj 84 119 -~;
+#X obj 49 119 +~;
+#X obj 50 195 +~;
+#X obj 85 196 -~;
+#X obj 84 275 -~;
+#X obj 49 274 +~;
+#X obj 82 349 -~;
+#X obj 48 350 +~;
+#X obj 83 428 -~;
+#X obj 49 428 +~;
+#X obj 65 7 inlet~;
+#X obj 110 66 delwrite~ \$0-ref1 75.2546;
+#X obj 49 508 outlet~;
+#X obj 119 507 outlet~;
+#X connect 0 0 24 0;
+#X connect 2 0 20 1;
+#X connect 2 0 19 1;
+#X connect 4 0 18 1;
+#X connect 4 0 17 1;
+#X connect 6 0 16 1;
+#X connect 6 0 15 1;
+#X connect 8 0 13 1;
+#X connect 8 0 14 1;
+#X connect 10 0 12 1;
+#X connect 10 0 11 1;
+#X connect 11 0 9 0;
+#X connect 12 0 14 0;
+#X connect 12 0 13 0;
+#X connect 13 0 16 0;
+#X connect 13 0 15 0;
+#X connect 14 0 7 0;
+#X connect 15 0 5 0;
+#X connect 16 0 18 0;
+#X connect 16 0 17 0;
+#X connect 17 0 3 0;
+#X connect 18 0 20 0;
+#X connect 18 0 19 0;
+#X connect 19 0 1 0;
+#X connect 20 0 23 0;
+#X connect 21 0 12 0;
+#X connect 21 0 11 0;
+#X connect 21 0 22 0;
+#X restore 9 416 pd early-reflect;
+#X obj 618 216 f;
+#X obj 618 105 inlet;
+#X obj 696 109 inlet;
+#X obj 705 216 f;
+#X obj 705 239 * 0.01;
+#X obj 705 263 pack 0 50;
+#X obj 705 287 line~;
+#X obj 29 269 -~;
+#X obj 28 300 *~;
+#X obj 16 331 +~;
+#X obj 132 240 lop~;
+#X obj 106 274 -~;
+#X obj 105 309 *~;
+#X obj 95 333 +~;
+#X obj 214 245 lop~;
+#X obj 188 273 -~;
+#X obj 187 314 *~;
+#X obj 176 339 +~;
+#X obj 308 249 lop~;
+#X obj 281 274 -~;
+#X obj 281 318 *~;
+#X obj 258 342 +~;
+#X obj 609 379 * 0.125;
+#X text 403 10 control inlets:;
+#X text 9 9 rev2 - simple \, cheap reverberator with;
+#X text 400 29 1: output level \, dB \, 0-100;
+#X text 8 30 one signal inlet and four signal outlets.;
+#X text 399 79 4: high frequency damping \, 0-100;
+#X text 400 62 3: crossover frequency in Hz. (3000 default);
+#X text 400 45 2: liveness \, 0-100 \, usually between 85 and 100;
+#X floatatom 437 260 5 0 0 0 - - -;
+#X floatatom 711 332 5 0 0 0 - - -;
+#X connect 0 0 9 0;
+#X connect 0 0 7 0;
+#X connect 1 0 38 0;
+#X connect 2 0 10 1;
+#X connect 3 0 12 1;
+#X connect 3 0 13 1;
+#X connect 3 0 43 0;
+#X connect 4 0 11 1;
+#X connect 5 0 13 0;
+#X connect 5 0 12 0;
+#X connect 5 0 42 0;
+#X connect 6 0 27 0;
+#X connect 7 0 26 0;
+#X connect 8 0 25 0;
+#X connect 9 0 24 0;
+#X connect 10 0 14 0;
+#X connect 10 0 0 0;
+#X connect 10 0 22 0;
+#X connect 11 0 0 1;
+#X connect 11 0 14 1;
+#X connect 11 0 23 0;
+#X connect 12 0 8 1;
+#X connect 12 0 6 1;
+#X connect 13 0 9 1;
+#X connect 13 0 7 1;
+#X connect 14 0 8 0;
+#X connect 14 0 6 0;
+#X connect 15 0 37 0;
+#X connect 16 0 22 1;
+#X connect 16 0 23 1;
+#X connect 16 0 42 1;
+#X connect 16 0 43 1;
+#X connect 17 0 4 1;
+#X connect 17 0 2 1;
+#X connect 17 0 5 1;
+#X connect 17 0 3 1;
+#X connect 18 0 36 0;
+#X connect 18 0 57 1;
+#X connect 18 0 59 0;
+#X connect 19 0 60 0;
+#X connect 19 0 61 1;
+#X connect 19 0 63 0;
+#X connect 20 0 67 0;
+#X connect 20 0 64 0;
+#X connect 20 0 65 1;
+#X connect 21 0 71 0;
+#X connect 21 0 69 1;
+#X connect 21 0 68 0;
+#X connect 22 0 32 0;
+#X connect 23 0 33 0;
+#X connect 28 0 72 0;
+#X connect 29 0 16 0;
+#X connect 30 0 17 0;
+#X connect 30 0 80 0;
+#X connect 31 0 49 0;
+#X connect 34 0 30 0;
+#X connect 35 0 34 0;
+#X connect 36 0 57 0;
+#X connect 37 0 28 0;
+#X connect 38 0 35 0;
+#X connect 39 0 46 0;
+#X connect 40 0 48 0;
+#X connect 41 0 37 0;
+#X connect 41 0 38 0;
+#X connect 41 0 39 0;
+#X connect 41 0 40 0;
+#X connect 42 0 44 0;
+#X connect 43 0 45 0;
+#X connect 46 0 47 0;
+#X connect 46 1 50 0;
+#X connect 47 0 50 0;
+#X connect 48 0 53 0;
+#X connect 49 0 10 0;
+#X connect 49 1 11 0;
+#X connect 50 0 36 1;
+#X connect 50 0 60 1;
+#X connect 50 0 64 1;
+#X connect 50 0 68 1;
+#X connect 51 0 50 0;
+#X connect 52 0 40 0;
+#X connect 53 0 54 0;
+#X connect 54 0 55 0;
+#X connect 55 0 56 0;
+#X connect 56 0 58 1;
+#X connect 56 0 62 1;
+#X connect 56 0 66 1;
+#X connect 56 0 70 1;
+#X connect 57 0 58 0;
+#X connect 58 0 59 1;
+#X connect 59 0 2 0;
+#X connect 60 0 61 0;
+#X connect 61 0 62 0;
+#X connect 62 0 63 1;
+#X connect 63 0 4 0;
+#X connect 64 0 65 0;
+#X connect 65 0 66 0;
+#X connect 66 0 67 1;
+#X connect 67 0 5 0;
+#X connect 68 0 69 0;
+#X connect 69 0 70 0;
+#X connect 70 0 71 1;
+#X connect 71 0 3 0;
+#X connect 72 0 29 0;
diff --git a/pd/portaudio/MSP-README.txt b/pd/portaudio/MSP-README.txt
index e29de09f..bd75626b 100644
--- a/pd/portaudio/MSP-README.txt
+++ b/pd/portaudio/MSP-README.txt
@@ -1,3 +1,6 @@
-This is not the full distribution, just what's needed to get Pd running
-on Mac OSX and ASIO (Windows.) I changed some code in pablio.c as marked.
+These files are from the V19 branch, a CVS snapshot, around 2003.03.21.
+
+I had to hack up "pablio" a fair bit... my copies are named "pablio_pd.c"
+and so on.
+
-MSP
diff --git a/pd/portaudio/Makefile.in b/pd/portaudio/Makefile.in
new file mode 100644
index 00000000..18c2707f
--- /dev/null
+++ b/pd/portaudio/Makefile.in
@@ -0,0 +1,132 @@
+#
+# PortAudio V19 Makefile.in
+#
+# Dominic Mazzoni
+#
+
+PREFIX = @prefix@
+CC = @CC@
+CFLAGS = @CFLAGS@ -Ipa_common @DEFS@
+LIBS = @LIBS@
+AR = @AR@
+RANLIB = @RANLIB@
+INSTALL = @INSTALL@
+SHARED_FLAGS = @SHARED_FLAGS@
+DLL_LIBS = @DLL_LIBS@
+
+OTHER_OBJS = @OTHER_OBJS@
+
+PALIB = libportaudio.a
+PADLL = @PADLL@
+PADLLV = $(PADLL).0.0.19
+PAINC = pa_common/portaudio.h
+
+COMMON_OBJS = \
+ pa_common/pa_allocation.o \
+ pa_common/pa_converters.o \
+ pa_common/pa_cpuload.o \
+ pa_common/pa_dither.o \
+ pa_common/pa_front.o \
+ pa_common/pa_process.o \
+ pa_common/pa_skeleton.o \
+ pa_common/pa_stream.o \
+ pa_common/pa_trace.o
+
+TESTS = \
+ bin/pa_devs \
+ bin/pa_fuzz \
+ bin/patest_sine \
+ bin/patest1
+
+# Most of these don't compile yet. Put them in TESTS, above, if
+# you want to try to compile them...
+ALL_TESTS = \
+ bin/debug_convert \
+ bin/debug_dither_calc \
+ bin/debug_dual \
+ bin/debug_multi_in \
+ bin/debug_multi_out \
+ bin/debug_record \
+ bin/debug_record_reuse \
+ bin/debug_sine_amp \
+ bin/debug_sine \
+ bin/debug_sine_formats \
+ bin/debug_srate \
+ bin/debug_test1 \
+ bin/pa_devs \
+ bin/pa_fuzz \
+ bin/pa_minlat \
+ bin/paqa_devs \
+ bin/paqa_errs \
+ bin/patest1 \
+ bin/patest_buffer \
+ bin/patest_clip \
+ bin/patest_dither \
+ bin/patest_hang \
+ bin/patest_latency \
+ bin/patest_leftright \
+ bin/patest_longsine \
+ bin/patest_many \
+ bin/patest_maxsines \
+ bin/patest_multi_sine \
+ bin/patest_pink \
+ bin/patest_record \
+ bin/patest_ringmix \
+ bin/patest_saw \
+ bin/patest_sine8 \
+ bin/patest_sine \
+ bin/patest_sine_formats \
+ bin/patest_sine_time \
+ bin/patest_start_stop \
+ bin/patest_stop \
+ bin/patest_sync \
+ bin/patest_toomanysines \
+ bin/patest_underflow \
+ bin/patest_wire
+
+OBJS = $(COMMON_OBJS) $(OTHER_OBJS)
+
+all: lib/$(PALIB) lib/$(PADLLV) tests
+
+tests: bin/ $(TESTS)
+
+lib/$(PALIB): lib/ $(OBJS) Makefile $(PAINC)
+ $(AR) ruv lib/$(PALIB) $(OBJS)
+ $(RANLIB) lib/$(PALIB)
+
+lib/$(PADLLV): lib/ $(OBJS) Makefile $(PAINC)
+ $(CC) $(SHARED_FLAGS) -o lib/$(PADLLV) $(OBJS) $(DLL_LIBS)
+
+$(TESTS): bin/%: lib/$(PALIB) Makefile $(PAINC) pa_tests/%.c
+ $(CC) -o $@ $(CFLAGS) pa_tests/$*.c lib/$(PALIB) $(LIBS)
+
+install: lib/$(PALIB) lib/$(PADLLV)
+ $(INSTALL) -m 644 lib/$(PADLLV) $(PREFIX)/lib/$(PADLLV)
+ $(INSTALL) -m 644 lib/$(PALIB) $(PREFIX)/lib/$(PALIB)
+ cd $(PREFIX)/lib && rm -f $(PADLL) && ln -s $(PADLLV) $(PADLL)
+ $(INSTALL) -m 644 pa_common/portaudio.h $(PREFIX)/include/portaudio.h
+ @echo ""
+ @echo "------------------------------------------------------------"
+ @echo "PortAudio was successfully installed."
+ @echo ""
+ @echo "On some systems (e.g. Linux) you should run 'ldconfig' now"
+ @echo "to make the shared object available. You may also need to"
+ @echo "modify your LD_LIBRARY_PATH environment variable to include"
+ @echo "the directory $(PREFIX)/lib"
+ @echo "------------------------------------------------------------"
+ @echo ""
+
+clean:
+ rm -f $(OBJS) $(TESTS) lib/$(PALIB)
+
+%.o: %.c Makefile $(PAINC)
+ $(CC) -c $(CFLAGS) $< -o $@
+
+bin:
+ mkdir bin
+
+lib:
+ mkdir lib
+
+
+
diff --git a/pd/portaudio/Makefile.linux b/pd/portaudio/Makefile.linux
new file mode 100644
index 00000000..4deee60a
--- /dev/null
+++ b/pd/portaudio/Makefile.linux
@@ -0,0 +1,59 @@
+# Make PortAudio for Linux
+# Updated 2001/08/25 Bill Eldridge bill@rfa.org
+# Updated 2001/10/16, philburk@softsynth.com, s/unix_oss/unix_oss/
+# Updated 2002/04/30 Bill Eldridge bill@rfa.org
+# Made the libinstall and tests compile a bit cleaner
+
+# A pretty bare makefile, that figures out all the test files
+# and compiles them against the library in the pa_unix_oss directory.
+
+# Do "make all" and then when happy, "make libinstall"
+# (if not happy, "make clean")
+
+# The ldconfig stuff in libinstall is the wrong way to do it -
+# someone tell me the right way, please
+
+
+LIBS = -lm -lpthread
+
+CDEFINES = -I../pa_common
+CFLAGS = -g
+LIBINST = /usr/local/lib
+
+TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c)
+TESTO:= $(wildcard pa_tests/pa*.o pa_tests/debug*.o)
+
+LIBFILES:= ./pa_common/pa_lib.c ./pa_unix_oss/pa_unix_oss.c
+
+#all: sharedlib libinstall tests
+all: sharedlib libinstall testo testq
+
+.c.o:
+ -gcc -c -I./pa_common $< -o $*.o
+
+.o:
+ -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio
+
+#.c.o:
+# -gcc -c -I./pa_common $< -o $*.o
+# -gcc $*.o -o $* -Lpa_unix_oss $(LIBS) -lportaudio
+
+
+sharedlib: $(LIBFILES:.c=.o)
+ gcc -shared -o ./pa_unix_oss/libportaudio.so ./pa_common/pa_lib.o ./pa_unix_oss/pa_unix_oss.o
+
+libinstall: ./pa_unix_oss/libportaudio.so
+ @cp -f ./pa_unix_oss/libportaudio.so $(LIBINST)
+ @/sbin/ldconfig
+
+testo: $(TESTS:.c=.o)
+
+testq: $(TESTO:.o=)
+
+clean:
+ -@rm -f $(TESTS:.c=.o)
+ -@rm -f $(TESTS:.c=)
+ -@rm -f $(LIBFILES:.c=.o)
+ -@rm -f ./pa_unix_oss/libportaudio.so
+
+
diff --git a/pd/portaudio/Makefile.mingw b/pd/portaudio/Makefile.mingw
new file mode 100644
index 00000000..2043a161
--- /dev/null
+++ b/pd/portaudio/Makefile.mingw
@@ -0,0 +1,57 @@
+
+# Makefile for PortAudio on mingw (http://mingw.sourceforge.net)
+
+# Contributed by Bill Eldridge, bill@rfa.org, Radio Free Asia
+# Copyright 2002/02/20, GPL
+
+# Uses a common mingw32 cross-compiler that defaults
+# to everything in /usr/local/cross-tools
+
+# First edit your path with
+# export PATH=/usr/local/cross-tools/bin:$PATH
+
+# Usage: make -f Makefile.mingw all
+# or make -f Makefile.mingw sharedlib
+# make -f Makefile.mingw tests
+#
+# Then copy executables & portaudio.dll to your Windows machine
+#
+# To make work with pa_win_ds, you'll have to substitue
+# all the pa_win_wmme files with pa_win_ds files, no biggie.
+
+CC= i586-mingw32msvc-gcc
+DLLTOOL= i586-mingw32msvc-dlltool
+DLLWRAP= i586-mingw32msvc-dllwrap
+
+ARCH= pa_win_wmme
+
+TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c)
+
+.c.o:
+ -$(CC) -c -I./pa_common $< -o $*.o
+ -$(CC) $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm
+
+all: sharedlib tests
+
+sharedlib: ./pa_common/pa_lib.c
+ $(CC) -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o
+ $(CC) -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o
+ $(CC) -shared -mthreads -o portaudio.dll pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm
+ $(DLLWRAP) --export-all --output-def=libportaudio.def --output-lib=libportaudio.a --dllname=portaudio.dll --drivername=i586-mingw32msvc-gcc pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm -lm
+ $(CC) -shared -Wl,--enable-auto-image-base -o portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/local/cross-tools/i586-win32msvc/lib -lwinmm
+
+
+tests: $(TESTS:.c=.o)
+
+sine:
+ $(CC) -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o
+ $(CC) pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm
+
+clean:
+ -rm ./pa_tests/*.exe
+ -rm ./pa_tests/*.o
+
+nothing:
+ $(CC) pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm
+
+
diff --git a/pd/portaudio/README.txt b/pd/portaudio/README.txt
index d1e5d7d6..4cfc6166 100644
--- a/pd/portaudio/README.txt
+++ b/pd/portaudio/README.txt
@@ -58,7 +58,7 @@ Important Files and Folders:
Platform Implementations
pa_asio = ASIO for Windows and Macintosh
pa_beos = BeOS
- pa_mac = Macintosh Sound Manager for OS 8,9 and Carbon
+ pa_mac_sm = Macintosh Sound Manager for OS 8,9 and Carbon
pa_mac_core = Macintosh Core Audio for OS X
pa_sgi = Silicon Graphics AL
pa_unix_oss = OSS implementation for various Unixes
diff --git a/pd/portaudio/V19-devel-readme.txt b/pd/portaudio/V19-devel-readme.txt
new file mode 100644
index 00000000..a6bca780
--- /dev/null
+++ b/pd/portaudio/V19-devel-readme.txt
@@ -0,0 +1,230 @@
+STATUS:
+
+MME, DirectSound and ASIO versions are more-or-less working. See FIXMEs @todos
+and the proposals matrix at portaudio.com for further status.
+
+ The following tests might run if you're lucky:
+ tests/pa_devs.c
+ tests/patest_sine.c
+ tests/pa_fuzz.c
+
+ tests/patest1.c
+
+The PaUtil support code is finished enough for other implementations to be
+ported. No changes are expected to be made to the definition of the PaUtil
+functions.
+
+Note that it's not yet 100% clear how the current support functions
+will interact with blocking read/write streams.
+
+BUILD INSTRUCTIONS
+
+to build tests/patest_sine.c you will need to compile and link the following
+files (MME)
+pa_common\pa_process.c
+pa_common\pa_skeleton.c
+pa_common\pa_stream.c
+pa_common\pa_trace.c
+pa_common\pa_byteswappers.c
+pa_common\pa_converters.c
+pa_common\pa_cpuload.c
+pa_common\pa_dither.c
+pa_common\pa_front.c
+pa_common\pa_allocation.h
+pa_win\pa_win_util.c
+pa_win\pa_win_hostapis.c
+pa_win_wmme\pa_win_wmme.c
+
+see below for a description of these files.
+
+
+FILES:
+
+portaudio.h
+ public api header file
+
+pa_front.c
+ implements the interface defined in portaudio.h. manages multiple host apis.
+ validates function parameters before calling through to host apis. tracks
+ open streams and closes them at Pa_Terminate().
+
+pa_util.h
+ declares utility functions for use my implementations. including utility
+ functions which must be implemented separately for each platform.
+
+pa_hostapi.h
+ hostapi representation structure used to interface between pa_front.c
+ and implementations
+
+pa_stream.c/h
+ stream interface and representation structures and helper functions
+ used to interface between pa_front.c and implementations
+
+pa_cpuload.c/h
+ source and header for cpu load calculation facility
+
+pa_trace.c/h
+ source and header for debug trace log facility
+
+pa_byteswappers.c/h
+ byte swapping facility
+
+pa_converters.c/h
+ sample buffer conversion facility
+
+pa_dither.c/h
+ dither noise generator
+
+pa_process.c/h
+ callback buffer processing facility including interleave and block adaption
+
+pa_allocation.c/h
+ allocation context for tracking groups of allocations
+
+pa_skeleton.c
+ an skeleton implementation showing how the common code can be used.
+
+pa_win_util.c
+ Win32 implementation of platform specific PaUtil functions (memory allocation,
+ usec clock, Pa_Sleep().) The file will be used with all Win32 host APIs.
+
+pa_win_hostapis.c
+ contains the paHostApiInitializers array and an implementation of
+ Pa_GetDefaultHostApi() for win32 builds.
+
+pa_win_wmme.c
+ Win32 host api implementation for the windows multimedia extensions audio API.
+
+pa_win_wmme.h
+ public header file containing interfaces to mme-specific functions and the
+ deviceInfo data structure.
+
+
+CODING GUIDELINES:
+
+naming conventions:
+ #defines begin with PA_
+ #defines local to a file end with _
+ global utility variables begin with paUtil
+ global utility types begin with PaUtil (including function types)
+ global utility functions begin with PaUtil_
+ static variables end with _
+ static constants begin with const and end with _
+ static funtions have no special prefix/suffix
+
+In general, implementations should declare all of their members static,
+except for their initializer which should be exported. All exported names
+should be preceeded by Pa<MN>_ where MN is the module name, for example
+the windows mme initializer should be named PaWinWmme_Initialize().
+
+Every host api should define an initializer which returns an error code
+and a PaHostApiInterface*. The initializer should only return an error other
+than paNoError if it encounters an unexpected and fatal error (memory allocation
+error for example). In general, there may be conditions under which it returns
+a NULL interface pointer and also returns paNoError. For example, if the ASIO
+implementation detects that ASIO is not installed, it should return a
+NULL interface, and paNoError.
+
+Platform-specific shared functions should begin with Pa<PN>_ where PN is the
+platform name. eg. PaWin_ for windows, PaUnix_ for unix.
+
+The above two conventions should also be followed whenever it is necessary to
+share functions accross multiple source files.
+
+Two utilities for debug messages are provided. The PA_DEBUG macro defined in
+pa_implementation.h provides a simple way to print debug messages to stderr.
+Due to real-time performance issues, PA_DEBUG may not be suitable for use
+within the portaudio processing callback, or in other threads. In such cases
+the event tracing facility provided in pa_trace.h may be more appropriate.
+
+If PA_LOG_API_CALLS is defined, all calls to the public PortAudio API
+will be logged to stderr along with parameter and return values.
+
+
+TODO:
+ (this list is totally out of date)
+
+ finish coding converter functions in pa_converters.c (anyone?)
+
+ implement block adaption in pa_process.c (phil?)
+
+ fix all current tests to work with new code. this should mostly involve
+ changing PortAudioStream to PaStream, and GetDefaultDeviceID to GetDefaultDevice etc.
+
+ write some new tests to exercise the multi-api functions
+
+ write (doxygen) documentation for pa_trace (phil?)
+
+ remove unused typeids from PaHostAPITypeID
+
+ create a global configuration file which documents which PA_ defines can be
+ used for configuration
+
+ need a coding standard for comment formatting
+
+ migrate directx (phil)
+
+ migrate asio (ross?, stephane?)
+
+ see top of pa_win_wmme.c for MME todo items (ross)
+
+ write style guide document (ross)
+
+
+DESIGN ISSUES:
+ (this list is totally out of date)
+
+ consider removing Pa_ConvertHostApiDeviceIndexToGlobalDeviceIndex() from the API
+
+ switch to new latency parameter mechanism now (?)
+
+ question: if input or outputDriverInfo structures are passed for a different
+ hostApi from the one being called, do we return an error or just ignore
+ them? (i think return error)
+
+ consider renaming PortAudioCallback to PaStreamCallback
+
+ consider renaming PaError, PaResult
+
+
+ASSORTED DISORGANISED NOTES:
+
+ NOTE:
+ pa_lib.c performs the following validations for Pa_OpenStream() which we do not currently do:
+ - checks the device info to make sure that the device supports the requested sample rate,
+ it may also change the sample rate to the "closest available" sample rate if it
+ is within a particular error margin
+
+ rationale for breaking up internalPortAudioStream:
+ each implementation has its own requirements and behavior, and should be
+ able to choose the best way to operate without being limited by the
+ constraints imposed by a common infrastructure. in other words the
+ implementations should be able to pick and choose services from the
+ common infrastructure. currently identified services include:
+
+ - cpu load tracking
+ - buffering and conversion service (same code works for input and output)
+ - should support buffer multiplexing (non-integer length input and output buffers)
+ - in-place conversion where possible (only for callback, read/write always copies)
+ - should manage allocation of temporary buffers if necessary
+ - instrumentation (should be able to be disabled): callback count, framesProcessed
+ - common data: magic, streamInterface, callback, userdata
+
+
+- conversion functions:
+ - should handle temp buffer allocation
+ - dithering (random number state per-stream)
+ - buffer size mismatches
+ - with new buffer slip rules, temp buffers may always be needed
+ - we should aim for in-place conversion wherever possible
+ - does phil's code support in-place conversion? (yes)
+
+- dicuss relationship between user and host buffer sizes
+ - completely independent.. individual implementations may constrain
+ host buffer sizes if necessary
+
+
+- discuss device capabilities:
+ - i'd like to be able to request certain information:
+ - channel count for example
+
diff --git a/pd/portaudio/aclocal.m4 b/pd/portaudio/aclocal.m4
new file mode 100644
index 00000000..c80e0acf
--- /dev/null
+++ b/pd/portaudio/aclocal.m4
@@ -0,0 +1,57 @@
+
+dnl PKG_CHECK_MODULES(GSTUFF, gtk+-2.0 >= 1.3 glib = 1.3.4, action-if, action-not)
+dnl defines GSTUFF_LIBS, GSTUFF_CFLAGS, see pkg-config man page
+dnl also defines GSTUFF_PKG_ERRORS on error
+AC_DEFUN(PKG_CHECK_MODULES, [
+ succeeded=no
+
+ if test -z "$PKG_CONFIG"; then
+ AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
+ fi
+
+ if test "$PKG_CONFIG" = "no" ; then
+ echo "*** The pkg-config script could not be found. Make sure it is"
+ echo "*** in your path, or set the PKG_CONFIG environment variable"
+ echo "*** to the full path to pkg-config."
+ echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+ else
+ PKG_CONFIG_MIN_VERSION=0.9.0
+ if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+ AC_MSG_CHECKING(for $2)
+
+ if $PKG_CONFIG --exists "$2" ; then
+ AC_MSG_RESULT(yes)
+ succeeded=yes
+
+ AC_MSG_CHECKING($1_CFLAGS)
+ $1_CFLAGS=`$PKG_CONFIG --cflags "$2"`
+ AC_MSG_RESULT($$1_CFLAGS)
+
+ AC_MSG_CHECKING($1_LIBS)
+ $1_LIBS=`$PKG_CONFIG --libs "$2"`
+ AC_MSG_RESULT($$1_LIBS)
+ else
+ $1_CFLAGS=""
+ $1_LIBS=""
+ ## If we have a custom action on failure, don't print errors, but
+ ## do set a variable so people can do so.
+ $1_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+ ifelse([$4], ,echo $$1_PKG_ERRORS,)
+ fi
+
+ AC_SUBST($1_CFLAGS)
+ AC_SUBST($1_LIBS)
+ else
+ echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+ echo "*** See http://www.freedesktop.org/software/pkgconfig"
+ fi
+ fi
+
+ if test $succeeded = yes; then
+ ifelse([$3], , :, [$3])
+ else
+ ifelse([$4], , AC_MSG_ERROR([Library requirements ($2) not met; consider adjusting the PKG_CONFIG_PATH environment variable if your libraries are in a nonstandard prefix so pkg-config can find them.]), [$4])
+ fi
+])
+
+
diff --git a/pd/portaudio/config.doxy b/pd/portaudio/config.doxy
new file mode 100644
index 00000000..98342765
--- /dev/null
+++ b/pd/portaudio/config.doxy
@@ -0,0 +1,185 @@
+# Doxyfile 1.2.13-20020210
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = PortAudio
+PROJECT_NUMBER = 2.0
+OUTPUT_DIRECTORY = "./docs/"
+OUTPUT_LANGUAGE = English
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = NO
+STRIP_FROM_PATH =
+INTERNAL_DOCS = NO
+STRIP_CODE_COMMENTS = YES
+CASE_SENSE_NAMES = YES
+SHORT_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+VERBATIM_HEADERS = YES
+SHOW_INCLUDE_FILES = YES
+JAVADOC_AUTOBRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+ALIASES =
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SHOW_USED_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = ./pa_common ./pa_win_wmme ./pa_asio ./pa_win_ds
+FILE_PATTERNS = *.h *.c *.cpp
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS =
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = doxygen_html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = NO
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
+CGI_NAME = search.cgi
+CGI_URL =
+DOC_URL =
+DOC_ABSPATH =
+BIN_ABSPATH = /usr/local/bin/
+EXT_DOC_PATHS =
diff --git a/pd/portaudio/config.guess b/pd/portaudio/config.guess
new file mode 100755
index 00000000..297e5c30
--- /dev/null
+++ b/pd/portaudio/config.guess
@@ -0,0 +1,1308 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+
+timestamp='2001-10-05'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Per Bothner <bothner@cygnus.com>.
+# Please send patches to <config-patches@gnu.org>. Submit a context
+# diff and a properly formatted ChangeLog entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit build system type.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit 0 ;;
+ --version | -v )
+ echo "$version" ; exit 0 ;;
+ --help | --h* | -h )
+ echo "$usage"; exit 0 ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+
+dummy=dummy-$$
+trap 'rm -f $dummy.c $dummy.o $dummy.rel $dummy; exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script.
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+set_cc_for_build='case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int dummy(){}" > $dummy.c ;
+ for c in cc gcc c89 ; do
+ ($c $dummy.c -c -o $dummy.o) >/dev/null 2>&1 ;
+ if test $? = 0 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ rm -f $dummy.c $dummy.o $dummy.rel ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ # Determine the machine/vendor (is the vendor relevant).
+ case "${UNAME_MACHINE}" in
+ amiga) machine=m68k-unknown ;;
+ arm32) machine=arm-unknown ;;
+ atari*) machine=m68k-atari ;;
+ sun3*) machine=m68k-sun ;;
+ mac68k) machine=m68k-apple ;;
+ macppc) machine=powerpc-apple ;;
+ hp3[0-9][05]) machine=m68k-hp ;;
+ ibmrt|romp-ibm) machine=romp-ibm ;;
+ sparc*) machine=`uname -p`-unknown ;;
+ *) machine=${UNAME_MACHINE}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE}" in
+ i386|sparc|amiga|arm*|hp300|mvme68k|vax|atari|luna68k|mac68k|news68k|next68k|pc532|sun3*|x68k)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep __ELF__ >/dev/null
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp300:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ macppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme68k:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvme88k:OpenBSD:*:*)
+ echo m88k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mvmeppc:OpenBSD:*:*)
+ echo powerpc-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ pmax:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sgi:OpenBSD:*:*)
+ echo mipseb-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3:OpenBSD:*:*)
+ echo m68k-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ wgrisc:OpenBSD:*:*)
+ echo mipsel-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ if test $UNAME_RELEASE = "V4.0"; then
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ fi
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ cat <<EOF >$dummy.s
+ .data
+\$Lformat:
+ .byte 37,100,45,37,120,10,0 # "%d-%x\n"
+
+ .text
+ .globl main
+ .align 4
+ .ent main
+main:
+ .frame \$30,16,\$26,0
+ ldgp \$29,0(\$27)
+ .prologue 1
+ .long 0x47e03d80 # implver \$0
+ lda \$2,-1
+ .long 0x47e20c21 # amask \$2,\$1
+ lda \$16,\$Lformat
+ mov \$0,\$17
+ not \$1,\$18
+ jsr \$26,printf
+ ldgp \$29,0(\$26)
+ mov 0,\$16
+ jsr \$26,exit
+ .end main
+EOF
+ eval $set_cc_for_build
+ $CC_FOR_BUILD $dummy.s -o $dummy 2>/dev/null
+ if test "$?" = 0 ; then
+ case `./$dummy` in
+ 0-0)
+ UNAME_MACHINE="alpha"
+ ;;
+ 1-0)
+ UNAME_MACHINE="alphaev5"
+ ;;
+ 1-1)
+ UNAME_MACHINE="alphaev56"
+ ;;
+ 1-101)
+ UNAME_MACHINE="alphapca56"
+ ;;
+ 2-303)
+ UNAME_MACHINE="alphaev6"
+ ;;
+ 2-307)
+ UNAME_MACHINE="alphaev67"
+ ;;
+ 2-1307)
+ UNAME_MACHINE="alphaev68"
+ ;;
+ esac
+ fi
+ rm -f $dummy.s $dummy
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit 0 ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit 0;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit 0 ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit 0;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit 0 ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit 0 ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit 0 ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit 0 ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit 0 ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit 0 ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy \
+ && ./$dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \
+ && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:[45])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null) && HP_ARCH=`./$dummy`
+ if test -z "$HP_ARCH"; then HP_ARCH=hppa; fi
+ rm -f $dummy.c $dummy
+ fi ;;
+ esac
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy && ./$dummy && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3D:*:*:*)
+ echo alpha-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit 0 ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit 0 ;;
+ i*:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit 0 ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit 0 ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i386-pc-interix
+ exit 0 ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit 0 ;;
+ arm*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux
+ exit 0 ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ mips:Linux:*:*)
+ case `sed -n '/^byte/s/^.*: \(.*\) endian/\1/p' < /proc/cpuinfo` in
+ big) echo mips-unknown-linux-gnu && exit 0 ;;
+ little) echo mipsel-unknown-linux-gnu && exit 0 ;;
+ esac
+ ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit 0 ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit 0 ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit 0 ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit 0 ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit 0 ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit 0 ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit 0 ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit 0 ;;
+ i*86:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us. cd to the root directory to prevent
+ # problems with other programs or directories called `ld' in the path.
+ ld_supported_targets=`cd /; ld --help 2>&1 \
+ | sed -ne '/supported targets:/!d
+ s/[ ][ ]*/ /g
+ s/.*supported targets: *//
+ s/ .*//
+ p'`
+ case "$ld_supported_targets" in
+ elf32-i386)
+ TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu"
+ ;;
+ a.out-i386-linux)
+ echo "${UNAME_MACHINE}-pc-linux-gnuaout"
+ exit 0 ;;
+ coff-i386)
+ echo "${UNAME_MACHINE}-pc-linux-gnucoff"
+ exit 0 ;;
+ "")
+ # Either a pre-BFD a.out linker (linux-gnuoldld) or
+ # one that does not give us useful --help.
+ echo "${UNAME_MACHINE}-pc-linux-gnuoldld"
+ exit 0 ;;
+ esac
+ # Determine whether the default compiler is a.out or elf
+ eval $set_cc_for_build
+ cat >$dummy.c <<EOF
+#include <features.h>
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+#ifdef __ELF__
+# ifdef __GLIBC__
+# if __GLIBC__ >= 2
+ printf ("%s-pc-linux-gnu\n", argv[1]);
+# else
+ printf ("%s-pc-linux-gnulibc1\n", argv[1]);
+# endif
+# else
+ printf ("%s-pc-linux-gnulibc1\n", argv[1]);
+# endif
+#else
+ printf ("%s-pc-linux-gnuaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ $CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy "${UNAME_MACHINE}" && rm -f $dummy.c $dummy && exit 0
+ rm -f $dummy.c $dummy
+ test x"${TENTATIVE}" != x && echo "${TENTATIVE}" && exit 0
+ ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit 0 ;;
+ i*86:*:5:[78]*)
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit 0 ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|egrep '^Machine.*Pent ?II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|egrep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit 0 ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit 0 ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i386.
+ echo i386-pc-msdosdjgpp
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M68*:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3${OS_REL} && exit 0
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit 0 ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit 0 ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit 0 ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit 0 ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit 0 ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit 0 ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit 0 ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit 0 ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit 0 ;;
+ *:Darwin:*:*)
+ echo `uname -p`-apple-darwin${UNAME_RELEASE}
+ exit 0 ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ if test "${UNAME_MACHINE}" = "x86pc"; then
+ UNAME_MACHINE=pc
+ fi
+ echo `uname -p`-${UNAME_MACHINE}-nto-qnx
+ exit 0 ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit 0 ;;
+ NSR-[KW]:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit 0 ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit 0 ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit 0 ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit 0 ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit 0 ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit 0 ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit 0 ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit 0 ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit 0 ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit 0 ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit 0 ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit 0 ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit 0 ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include <sys/param.h>
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD $dummy.c -o $dummy 2>/dev/null && ./$dummy && rm -f $dummy.c $dummy && exit 0
+rm -f $dummy.c $dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ ftp://ftp.gnu.org/pub/gnu/config/
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
diff --git a/pd/portaudio/configure b/pd/portaudio/configure
new file mode 100755
index 00000000..1dfe83fc
--- /dev/null
+++ b/pd/portaudio/configure
@@ -0,0 +1,2903 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by Autoconf 2.52.
+#
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Name of the executable.
+as_me=`echo "$0" |sed 's,.*[\\/],,'`
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+as_executable_p="test -f"
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+# NLS nuisances.
+$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; }
+$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; }
+$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; }
+$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; }
+$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; }
+$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; }
+$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; }
+$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; }
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; }
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+cross_compiling=no
+subdirs=
+MFLAGS= MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+ac_unique_file="pa_common/portaudio.h"
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_prev=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_option in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_$ac_feature='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_$ac_package='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
+fi
+
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute path for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: should be removed in autoconf 3.0.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo "$ac_prog" | sed 's%[\\/][^\\/][^\\/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "$as_me: error: cannot find sources in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
+ else
+ { echo "$as_me: error: cannot find sources in $srcdir" >&2
+ { (exit 1); exit 1; }; }
+ fi
+fi
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<EOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+EOF
+
+ cat <<EOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+EOF
+
+ cat <<\EOF
+EOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\EOF
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-alsa (default=auto)
+ --with-jack (default=auto)
+ --with-oss (default=yes)
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+EOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_subdir in : $ac_subdirs_all; do test "x$ac_subdir" = x: && continue
+ cd $ac_subdir
+ # A "../" for each directory in /$ac_subdir.
+ ac_dots=`echo $ac_subdir |
+ sed 's,^\./,,;s,[^/]$,&/,;s,[^/]*/,../,g'`
+
+ case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_sub_srcdir=$srcdir ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_sub_srcdir=$srcdir/$ac_subdir ;;
+ *) # Relative path.
+ ac_sub_srcdir=$ac_dots$srcdir/$ac_subdir ;;
+ esac
+
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_sub_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_sub_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_sub_srcdir/configure; then
+ echo
+ $SHELL $ac_sub_srcdir/configure --help=recursive
+ elif test -f $ac_sub_srcdir/configure.ac ||
+ test -f $ac_sub_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_subdir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\EOF
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+EOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<EOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.52. Invocation command line was
+
+ $ $0 $@
+
+EOF
+{
+cat <<_ASUNAME
+## ---------- ##
+## Platform. ##
+## ---------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+PATH = $PATH
+
+_ASUNAME
+} >&5
+
+cat >&5 <<EOF
+## ------------ ##
+## Core tests. ##
+## ------------ ##
+
+EOF
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell meta-characters.
+ac_configure_args=
+ac_sep=
+for ac_arg
+do
+ case $ac_arg in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"`
+ ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ ac_sep=" " ;;
+ *) ac_configure_args="$ac_configure_args$ac_sep$ac_arg"
+ ac_sep=" " ;;
+ esac
+ # Get rid of the leading space.
+done
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ echo >&5
+ echo "## ----------------- ##" >&5
+ echo "## Cache variables. ##" >&5
+ echo "## ----------------- ##" >&5
+ echo >&5
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} >&5
+ sed "/^$/d" confdefs.h >conftest.log
+ if test -s conftest.log; then
+ echo >&5
+ echo "## ------------ ##" >&5
+ echo "## confdefs.h. ##" >&5
+ echo "## ------------ ##" >&5
+ echo >&5
+ cat conftest.log >&5
+ fi
+ (echo; echo) >&5
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal" >&5
+ echo "$as_me: exit $exit_status" >&5
+ rm -rf conftest* confdefs* core core.* *.core conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ { echo "$as_me:821: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ cat "$ac_site_file" >&5
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:832: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
+else
+ { echo "$as_me:840: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:856: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:860: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:866: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:868: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:870: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status. It doesn't matter if
+ # we pass some twice (in addition to the command line arguments).
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"`
+ ac_configure_args="$ac_configure_args '$ac_arg'"
+ ;;
+ *) ac_configure_args="$ac_configure_args $ac_var=$ac_new_val"
+ ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:889: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:891: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+echo "#! $SHELL" >conftest.sh
+echo "exit 0" >>conftest.sh
+chmod +x conftest.sh
+if { (echo "$as_me:911: PATH=\".;.\"; conftest.sh") >&5
+ (PATH=".;."; conftest.sh) 2>&5
+ ac_status=$?
+ echo "$as_me:914: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ ac_path_separator=';'
+else
+ ac_path_separator=:
+fi
+PATH_SEPARATOR="$ac_path_separator"
+rm -f conftest.sh
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:931: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CC="${ac_tool_prefix}gcc"
+echo "$as_me:946: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:954: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:957: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo "$as_me:966: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_CC="gcc"
+echo "$as_me:981: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:989: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:992: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:1005: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CC="${ac_tool_prefix}cc"
+echo "$as_me:1020: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:1028: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:1031: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:1040: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_CC="cc"
+echo "$as_me:1055: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:1063: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:1066: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:1079: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+fi
+ac_cv_prog_CC="cc"
+echo "$as_me:1099: found $ac_dir/$ac_word" >&5
+break
+done
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" ${1+"$@"}
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:1121: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:1124: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:1135: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+echo "$as_me:1150: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:1158: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:1161: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:1174: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_CC="$ac_prog"
+echo "$as_me:1189: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:1197: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:1200: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
+
+test -z "$CC" && { { echo "$as_me:1212: error: no acceptable cc found in \$PATH" >&5
+echo "$as_me: error: no acceptable cc found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
+
+# Provide some information about the compiler.
+echo "$as_me:1217:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:1220: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:1223: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:1225: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:1228: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:1230: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:1233: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+#line 1237 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:1253: checking for C compiler default output" >&5
+echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:1256: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:1259: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+for ac_file in `ls a.exe conftest.exe 2>/dev/null;
+ ls a.out conftest 2>/dev/null;
+ ls a.* conftest.* 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;;
+ a.out ) # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool --akim.
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:1282: error: C compiler cannot create executables" >&5
+echo "$as_me: error: C compiler cannot create executables" >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:1288: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:1293: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:1299: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1302: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:1309: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ fi
+fi
+echo "$as_me:1317: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:1324: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:1326: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:1329: checking for executable suffix" >&5
+echo $ECHO_N "checking for executable suffix... $ECHO_C" >&6
+if { (eval echo "$as_me:1331: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:1334: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { echo "$as_me:1350: error: cannot compute EXEEXT: cannot compile and link" >&5
+echo "$as_me: error: cannot compute EXEEXT: cannot compile and link" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest$ac_cv_exeext
+echo "$as_me:1356: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:1362: checking for object suffix" >&5
+echo $ECHO_N "checking for object suffix... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1368 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:1380: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1383: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:1395: error: cannot compute OBJEXT: cannot compile" >&5
+echo "$as_me: error: cannot compute OBJEXT: cannot compile" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:1402: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:1406: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1412 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1427: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1430: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1433: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1436: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_compiler_gnu=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:1448: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:1454: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1460 "configure"
+#include "confdefs.h"
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1472: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1475: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1478: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1481: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_g=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_prog_cc_g=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:1491: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1518: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1521: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1524: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1527: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ ''\
+ '#include <stdlib.h>' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1539 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1552: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1555: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1558: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1561: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+continue
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1571 "configure"
+#include "confdefs.h"
+$ac_declaration
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1583: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1586: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1589: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1592: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo "$as_me:1622: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+echo "$as_me:1637: found $ac_dir/$ac_word" >&5
+break
+done
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ echo "$as_me:1645: result: $RANLIB" >&5
+echo "${ECHO_T}$RANLIB" >&6
+else
+ echo "$as_me:1648: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo "$as_me:1657: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ $as_executable_p "$ac_dir/$ac_word" || continue
+ac_cv_prog_ac_ct_RANLIB="ranlib"
+echo "$as_me:1672: found $ac_dir/$ac_word" >&5
+break
+done
+
+ test -z "$ac_cv_prog_ac_ct_RANLIB" && ac_cv_prog_ac_ct_RANLIB=":"
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ echo "$as_me:1681: result: $ac_ct_RANLIB" >&5
+echo "${ECHO_T}$ac_ct_RANLIB" >&6
+else
+ echo "$as_me:1684: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ RANLIB=$ac_ct_RANLIB
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { { echo "$as_me:1710: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo "$as_me:1730: checking for a BSD compatible install" >&5
+echo $ECHO_N "checking for a BSD compatible install... $ECHO_C" >&6
+if test -z "$INSTALL"; then
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ for ac_dir in $PATH; do
+ IFS=$ac_save_IFS
+ # Account for people who put trailing slashes in PATH elements.
+ case $ac_dir/ in
+ / | ./ | .// | /cC/* \
+ | /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* \
+ | /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ if $as_executable_p "$ac_dir/$ac_prog"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$ac_dir/$ac_prog" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$ac_dir/$ac_prog" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL=$ac_install_sh
+ fi
+fi
+echo "$as_me:1779: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+# Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo "$as_me:1792: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_AR+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $AR in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_AR="$AR" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_AR="$ac_dir/$ac_word"
+ echo "$as_me:1809: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ test -z "$ac_cv_path_AR" && ac_cv_path_AR="no"
+ ;;
+esac
+fi
+AR=$ac_cv_path_AR
+
+if test -n "$AR"; then
+ echo "$as_me:1821: result: $AR" >&5
+echo "${ECHO_T}$AR" >&6
+else
+ echo "$as_me:1824: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+if [ $AR = "no" ] ; then
+ { { echo "$as_me:1829: error: \"Could not find ar - needed to create a library\"" >&5
+echo "$as_me: error: \"Could not find ar - needed to create a library\"" >&2;}
+ { (exit 1); exit 1; }; };
+fi
+
+echo "$as_me:1834: checking whether byte ordering is bigendian" >&5
+echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6
+if test "${ac_cv_c_bigendian+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_c_bigendian=unknown
+# See if sys/param.h defines the BYTE_ORDER macro.
+cat >conftest.$ac_ext <<_ACEOF
+#line 1842 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN
+ bogus endian macros
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1859: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1862: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1865: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1868: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ # It does; now see whether it defined to BIG_ENDIAN or not.
+cat >conftest.$ac_ext <<_ACEOF
+#line 1872 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#include <sys/param.h>
+
+int
+main ()
+{
+#if BYTE_ORDER != BIG_ENDIAN
+ not big endian
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:1889: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:1892: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:1895: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1898: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_c_bigendian=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+if test $ac_cv_c_bigendian = unknown; then
+if test "$cross_compiling" = yes; then
+ { { echo "$as_me:1914: error: cannot run test program while cross compiling" >&5
+echo "$as_me: error: cannot run test program while cross compiling" >&2;}
+ { (exit 1); exit 1; }; }
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line 1919 "configure"
+#include "confdefs.h"
+int
+main ()
+{
+ /* Are we little or big endian? From Harbison&Steele. */
+ union
+ {
+ long l;
+ char c[sizeof (long)];
+ } u;
+ u.l = 1;
+ exit (u.c[sizeof (long) - 1] == 1);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:1935: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:1938: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:1940: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:1943: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_c_bigendian=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_c_bigendian=yes
+fi
+rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+fi
+echo "$as_me:1956: result: $ac_cv_c_bigendian" >&5
+echo "${ECHO_T}$ac_cv_c_bigendian" >&6
+if test $ac_cv_c_bigendian = yes; then
+
+cat >>confdefs.h <<\EOF
+#define WORDS_BIGENDIAN 1
+EOF
+
+fi
+
+echo "$as_me:1966: checking for snd_pcm_open in -lasound" >&5
+echo $ECHO_N "checking for snd_pcm_open in -lasound... $ECHO_C" >&6
+if test "${ac_cv_lib_asound_snd_pcm_open+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lasound $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line 1974 "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char snd_pcm_open ();
+int
+main ()
+{
+snd_pcm_open ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:1993: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:1996: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:1999: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:2002: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_asound_snd_pcm_open=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_asound_snd_pcm_open=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:2013: result: $ac_cv_lib_asound_snd_pcm_open" >&5
+echo "${ECHO_T}$ac_cv_lib_asound_snd_pcm_open" >&6
+if test $ac_cv_lib_asound_snd_pcm_open = yes; then
+ have_alsa=yes
+else
+ have_alsa=no
+fi
+
+ succeeded=no
+
+ if test -z "$PKG_CONFIG"; then
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+echo "$as_me:2026: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_path_PKG_CONFIG+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ ac_save_IFS=$IFS; IFS=$ac_path_separator
+ac_dummy="$PATH"
+for ac_dir in $ac_dummy; do
+ IFS=$ac_save_IFS
+ test -z "$ac_dir" && ac_dir=.
+ if $as_executable_p "$ac_dir/$ac_word"; then
+ ac_cv_path_PKG_CONFIG="$ac_dir/$ac_word"
+ echo "$as_me:2043: found $ac_dir/$ac_word" >&5
+ break
+fi
+done
+
+ test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no"
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+
+if test -n "$PKG_CONFIG"; then
+ echo "$as_me:2055: result: $PKG_CONFIG" >&5
+echo "${ECHO_T}$PKG_CONFIG" >&6
+else
+ echo "$as_me:2058: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ fi
+
+ if test "$PKG_CONFIG" = "no" ; then
+ echo "*** The pkg-config script could not be found. Make sure it is"
+ echo "*** in your path, or set the PKG_CONFIG environment variable"
+ echo "*** to the full path to pkg-config."
+ echo "*** Or see http://www.freedesktop.org/software/pkgconfig to get pkg-config."
+ else
+ PKG_CONFIG_MIN_VERSION=0.9.0
+ if $PKG_CONFIG --atleast-pkgconfig-version $PKG_CONFIG_MIN_VERSION; then
+ echo "$as_me:2072: checking for jack" >&5
+echo $ECHO_N "checking for jack... $ECHO_C" >&6
+
+ if $PKG_CONFIG --exists "jack" ; then
+ echo "$as_me:2076: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+ succeeded=yes
+
+ echo "$as_me:2080: checking JACK_CFLAGS" >&5
+echo $ECHO_N "checking JACK_CFLAGS... $ECHO_C" >&6
+ JACK_CFLAGS=`$PKG_CONFIG --cflags "jack"`
+ echo "$as_me:2083: result: $JACK_CFLAGS" >&5
+echo "${ECHO_T}$JACK_CFLAGS" >&6
+
+ echo "$as_me:2086: checking JACK_LIBS" >&5
+echo $ECHO_N "checking JACK_LIBS... $ECHO_C" >&6
+ JACK_LIBS=`$PKG_CONFIG --libs "jack"`
+ echo "$as_me:2089: result: $JACK_LIBS" >&5
+echo "${ECHO_T}$JACK_LIBS" >&6
+ else
+ JACK_CFLAGS=""
+ JACK_LIBS=""
+ ## If we have a custom action on failure, don't print errors, but
+ ## do set a variable so people can do so.
+ JACK_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "jack"`
+
+ fi
+
+ else
+ echo "*** Your version of pkg-config is too old. You need version $PKG_CONFIG_MIN_VERSION or newer."
+ echo "*** See http://www.freedesktop.org/software/pkgconfig"
+ fi
+ fi
+
+ if test $succeeded = yes; then
+ have_jack=yes
+ else
+ have_jack=no
+ fi
+
+# Check whether --with-alsa or --without-alsa was given.
+if test "${with_alsa+set}" = set; then
+ withval="$with_alsa"
+ with_alsa=$withval
+else
+ with_alsa="yes"
+fi;
+
+# Check whether --with-jack or --without-jack was given.
+if test "${with_jack+set}" = set; then
+ withval="$with_jack"
+ with_jack=$withval
+else
+ with_jack="yes"
+fi;
+
+# Check whether --with-oss or --without-oss was given.
+if test "${with_oss+set}" = set; then
+ withval="$with_oss"
+ with_oss=$withval
+else
+ with_oss="yes"
+fi;
+
+CFLAGS="-g -O2 -Wall"
+
+if [ $ac_cv_c_bigendian = "yes" ] ; then
+ CFLAGS="$CFLAGS -DPA_BIG_ENDIAN"
+else
+ CFLAGS="$CFLAGS -DPA_LITTLE_ENDIAN"
+fi
+
+case "${host_os}" in
+ darwin* )
+
+ OTHER_OBJS="pa_mac_core/pa_mac_core.o";
+ LIBS="-framework AudioUnit -framework AudioToolbox -framework CoreAudio";
+ PADLL="libportaudio.dylib";
+ SHARED_FLAGS="-framework AudioUnit -framework AudioToolbox";
+ SHARED_FLAGS="$SHARED_FLAGS -framework CoreAudio -dynamiclib";
+ ;;
+
+ mingw* )
+
+ OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
+ LIBS="-lwinmm -lm";
+ PADLL="portaudio.dll";
+ SHARED_FLAGS="-shared -mthreads";
+ DLL_LIBS="-lwinmm";
+ ;;
+
+ cygwin* )
+
+ OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
+ LIBS="-lwinmm -lm";
+ PADLL="portaudio.dll";
+ SHARED_FLAGS="-shared -mthreads";
+ DLL_LIBS="-lwinmm";
+ ;;
+
+ *)
+
+echo "$as_me:2174: checking for pthread_create in -lpthread" >&5
+echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line 2182 "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:2201: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:2204: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:2207: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:2210: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:2221: result: $ac_cv_lib_pthread_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6
+if test $ac_cv_lib_pthread_pthread_create = yes; then
+ cat >>confdefs.h <<EOF
+#define HAVE_LIBPTHREAD 1
+EOF
+
+ LIBS="-lpthread $LIBS"
+
+else
+ { { echo "$as_me:2231: error: libpthread not found!" >&5
+echo "$as_me: error: libpthread not found!" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+ if [ $have_alsa = "yes" ] && [ $with_alsa != "no" ] ; then
+ LIBS="$LIBS -lasound"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/pa_linux_alsa.o"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/callback_thread.o"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/blocking_calls.o"
+ cat >>confdefs.h <<\EOF
+#define PA_USE_ALSA 1
+EOF
+
+ fi
+
+ if [ $have_jack = "yes" ] && [ $with_jack != "no" ] ; then
+ LIBS="$LIBS $JACK_LIBS"
+ CFLAGS="$CFLAGS $JACK_CFLAGS"
+ OTHER_OBJS="$OTHER_OBJS pa_jack/pa_jack.o"
+ cat >>confdefs.h <<\EOF
+#define PA_USE_JACK 1
+EOF
+
+ fi
+
+ if [ $with_oss != "no" ] ; then
+ OTHER_OBJS="$OTHER_OBJS pa_unix_oss/pa_unix_oss.o"
+ cat >>confdefs.h <<\EOF
+#define PA_USE_OSS 1
+EOF
+
+ fi
+ LIBS="$LIBS -lm -lpthread";
+ PADLL="libportaudio.so";
+ SHARED_FLAGS="-shared";
+
+ OTHER_OBJS="$OTHER_OBJS pa_unix/pa_unix_hostapis.o pa_unix/pa_unix_util.o"
+esac
+
+ac_config_files="$ac_config_files Makefile"
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overriden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if cmp -s $cache_file confcache; then :; else
+ if test -w $cache_file; then
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
+fi
+
+# Transform confdefs.h into DEFS.
+# Protect against shell expansion while executing Makefile rules.
+# Protect against Makefile macro expansion.
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then we branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+cat >confdef2opt.sed <<\EOF
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g
+t quote
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g
+t quote
+d
+: quote
+s,[ `~#$^&*(){}\\|;'"<>?],\\&,g
+s,\[,\\&,g
+s,\],\\&,g
+s,\$,$$,g
+p
+EOF
+# We use echo to avoid assuming a particular line-breaking character.
+# The extra dot is to prevent the shell from consuming trailing
+# line-breaks from the sub-command output. A line-break within
+# single-quotes doesn't work because, if this script is created in a
+# platform that uses two characters for line-breaks (e.g., DOS), tr
+# would break.
+ac_LF_and_DOT=`echo; echo .`
+DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
+rm -f confdef2opt.sed
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:2381: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+ac_cs_invocation="\$0 \$@"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# Name of the executable.
+as_me=`echo "$0" |sed 's,.*[\\/],,'`
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+as_executable_p="test -f"
+
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+# NLS nuisances.
+$as_unset LANG || test "${LANG+set}" != set || { LANG=C; export LANG; }
+$as_unset LC_ALL || test "${LC_ALL+set}" != set || { LC_ALL=C; export LC_ALL; }
+$as_unset LC_TIME || test "${LC_TIME+set}" != set || { LC_TIME=C; export LC_TIME; }
+$as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set || { LC_CTYPE=C; export LC_CTYPE; }
+$as_unset LANGUAGE || test "${LANGUAGE+set}" != set || { LANGUAGE=C; export LANGUAGE; }
+$as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set || { LC_COLLATE=C; export LC_COLLATE; }
+$as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set || { LC_NUMERIC=C; export LC_NUMERIC; }
+$as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set || { LC_MESSAGES=C; export LC_MESSAGES; }
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=:; export CDPATH; }
+
+exec 6>&1
+
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\EOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <bug-autoconf@gnu.org>."
+EOF
+
+cat >>$CONFIG_STATUS <<EOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.52,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ shift
+ set dummy "$ac_option" "$ac_optarg" ${1+"$@"}
+ shift
+ ;;
+ -*);;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_need_defaults=false;;
+ esac
+
+ case $1 in
+ # Handling of the options.
+EOF
+cat >>$CONFIG_STATUS <<EOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion"
+ exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;;
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:2549: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ shift
+ CONFIG_FILES="$CONFIG_FILES $1"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $1"
+ ac_need_defaults=false;;
+
+ # This is an error.
+ -*) { { echo "$as_me:2568: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
+
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+exec 5>>config.log
+cat >&5 << _ACEOF
+
+## ----------------------- ##
+## Running config.status. ##
+## ----------------------- ##
+
+This file was extended by $as_me 2.52, executed with
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ > $ac_cs_invocation
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+
+_ACEOF
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "Makefile" ) CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ *) { { echo "$as_me:2604: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+: ${TMPDIR=/tmp}
+{
+ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=$TMPDIR/cs$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in $TMPDIR" >&2
+ { (exit 1); exit 1; }
+}
+
+EOF
+
+cat >>$CONFIG_STATUS <<EOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@DEFS@,$DEFS,;t t
+s,@LIBS@,$LIBS,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@RANLIB@,$RANLIB,;t t
+s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@AR@,$AR,;t t
+s,@OTHER_OBJS@,$OTHER_OBJS,;t t
+s,@PADLL@,$PADLL,;t t
+s,@SHARED_FLAGS@,$SHARED_FLAGS,;t t
+s,@DLL_LIBS@,$DLL_LIBS,;t t
+s,@PKG_CONFIG@,$PKG_CONFIG,;t t
+s,@JACK_CFLAGS@,$JACK_CFLAGS,;t t
+s,@JACK_LIBS@,$JACK_LIBS,;t t
+CEOF
+
+EOF
+
+ cat >>$CONFIG_STATUS <<\EOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+ fi
+fi # test -n "$CONFIG_FILES"
+
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
+ esac
+
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ { case "$ac_dir" in
+ [\\/]* | ?:[\\/]* ) as_incr_dir=;;
+ *) as_incr_dir=.;;
+esac
+as_dummy="$ac_dir"
+for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
+ case $as_mkdir_dir in
+ # Skip DOS drivespec
+ ?:) as_incr_dir=$as_mkdir_dir ;;
+ *)
+ as_incr_dir=$as_incr_dir/$as_mkdir_dir
+ test -d "$as_incr_dir" || mkdir "$as_incr_dir"
+ ;;
+ esac
+done; }
+
+ ac_dir_suffix="/`echo $ac_dir|sed 's,^\./,,'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo "$ac_dir_suffix" | sed 's,/[^/]*,../,g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case $srcdir in
+ .) ac_srcdir=.
+ if test -z "$ac_dots"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_dots | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* )
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_dots$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_dots$srcdir ;;
+ esac
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_dots$INSTALL ;;
+ esac
+
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:2818: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated automatically by config.status. */
+ configure_input="Generated automatically from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:2836: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:2849: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+EOF
+cat >>$CONFIG_STATUS <<EOF
+ sed "$ac_vpsub
+$extrasub
+EOF
+cat >>$CONFIG_STATUS <<\EOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
+
+done
+EOF
+
+cat >>$CONFIG_STATUS <<\EOF
+
+{ (exit 0); exit 0; }
+EOF
+chmod +x $CONFIG_STATUS
+ac_clean_files=$ac_clean_files_save
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
+
diff --git a/pd/portaudio/configure.in b/pd/portaudio/configure.in
new file mode 100644
index 00000000..edb0fe11
--- /dev/null
+++ b/pd/portaudio/configure.in
@@ -0,0 +1,123 @@
+dnl
+dnl portaudio V19 configure.in script
+dnl
+dnl Dominic Mazzoni
+dnl
+
+dnl Require autoconf >= 2.13
+AC_PREREQ(2.13)
+
+dnl Init autoconf and make sure configure is being called
+dnl from the right directory
+AC_INIT([pa_common/portaudio.h])
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+AC_PATH_PROG(AR, ar, no)
+if [[ $AR = "no" ]] ; then
+ AC_MSG_ERROR("Could not find ar - needed to create a library");
+fi
+
+dnl This must be one of the first tests we do or it will fail...
+AC_C_BIGENDIAN
+
+dnl extra variables
+AC_SUBST(OTHER_OBJS)
+AC_SUBST(PADLL)
+AC_SUBST(SHARED_FLAGS)
+AC_SUBST(DLL_LIBS)
+
+dnl checks for various host APIs and arguments to configure that
+dnl turn them on or off
+
+AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no)
+
+PKG_CHECK_MODULES(JACK, jack, have_jack=yes, have_jack=no)
+
+AC_ARG_WITH(alsa,
+ [ --with-alsa (default=auto)],
+ with_alsa=$withval, with_alsa="yes")
+
+AC_ARG_WITH(jack,
+ [ --with-jack (default=auto)],
+ with_jack=$withval, with_jack="yes")
+
+AC_ARG_WITH(oss,
+ [ --with-oss (default=yes)],
+ with_oss=$withval, with_oss="yes")
+
+CFLAGS="-g -O2 -Wall"
+
+if [[ $ac_cv_c_bigendian = "yes" ]] ; then
+ CFLAGS="$CFLAGS -DPA_BIG_ENDIAN"
+else
+ CFLAGS="$CFLAGS -DPA_LITTLE_ENDIAN"
+fi
+
+case "${host_os}" in
+ darwin* )
+ dnl Mac OS X configuration
+
+ OTHER_OBJS="pa_mac_core/pa_mac_core.o";
+ LIBS="-framework AudioUnit -framework AudioToolbox -framework CoreAudio";
+ PADLL="libportaudio.dylib";
+ SHARED_FLAGS="-framework AudioUnit -framework AudioToolbox";
+ SHARED_FLAGS="$SHARED_FLAGS -framework CoreAudio -dynamiclib";
+ ;;
+
+ mingw* )
+ dnl MingW configuration
+
+ OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
+ LIBS="-lwinmm -lm";
+ PADLL="portaudio.dll";
+ SHARED_FLAGS="-shared -mthreads";
+ DLL_LIBS="-lwinmm";
+ ;;
+
+ cygwin* )
+ dnl Cygwin configuration
+
+ OTHER_OBJS="pa_win_wmme/pa_win_wmme.o";
+ LIBS="-lwinmm -lm";
+ PADLL="portaudio.dll";
+ SHARED_FLAGS="-shared -mthreads";
+ DLL_LIBS="-lwinmm";
+ ;;
+
+ *)
+ dnl Unix OSS configuration
+
+ AC_CHECK_LIB(pthread, pthread_create,
+ ,
+ AC_MSG_ERROR([libpthread not found!]))
+
+ if [[ $have_alsa = "yes" ] && [ $with_alsa != "no" ]] ; then
+ LIBS="$LIBS -lasound"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/pa_linux_alsa.o"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/callback_thread.o"
+ OTHER_OBJS="$OTHER_OBJS pa_linux_alsa/blocking_calls.o"
+ AC_DEFINE(PA_USE_ALSA)
+ fi
+
+ if [[ $have_jack = "yes" ] && [ $with_jack != "no" ]] ; then
+ LIBS="$LIBS $JACK_LIBS"
+ CFLAGS="$CFLAGS $JACK_CFLAGS"
+ OTHER_OBJS="$OTHER_OBJS pa_jack/pa_jack.o"
+ AC_DEFINE(PA_USE_JACK)
+ fi
+
+ if [[ $with_oss != "no" ]] ; then
+ OTHER_OBJS="$OTHER_OBJS pa_unix_oss/pa_unix_oss.o"
+ AC_DEFINE(PA_USE_OSS)
+ fi
+ LIBS="$LIBS -lm -lpthread";
+ PADLL="libportaudio.so";
+ SHARED_FLAGS="-shared";
+
+ OTHER_OBJS="$OTHER_OBJS pa_unix/pa_unix_hostapis.o pa_unix/pa_unix_util.o"
+esac
+
+AC_OUTPUT([Makefile])
diff --git a/pd/portaudio/docs/index.html b/pd/portaudio/docs/index.html
new file mode 100644
index 00000000..7d9b248d
--- /dev/null
+++ b/pd/portaudio/docs/index.html
@@ -0,0 +1,60 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="PortAudio Docs, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Docs</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Documentation</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>Copyright 2000 Phil Burk and Ross Bencina
+<br>&nbsp;
+<h3>
+<a href="portaudio_h.txt">API Reference</a></h3>
+
+<blockquote>The Application Programmer Interface is documented in "portaudio.h".</blockquote>
+
+<h3>
+<a href="pa_tutorial.html">Tutorial</a></h3>
+
+<blockquote>Describes how to write audio programs using the PortAudio API.</blockquote>
+
+<h3>
+<a href="pa_impl_guide.html">Implementation Guide</a></h3>
+
+<blockquote>Describes how to write an implementation of PortAudio for a
+new computer platform.</blockquote>
+
+<h3>
+<a href="portaudio_icmc2001.pdf">Paper Presented at ICMC2001</a> (PDF)</h3>
+
+<blockquote>Describes the PortAudio API and discusses implementation issues.
+Written July 2001.</blockquote>
+
+<h3>
+<a href="latency.html">Improving Latency</a></h3>
+
+<blockquote>How to tune your computer to achieve the lowest possible audio
+delay.</blockquote>
+
+<h3>
+<a href="proposals.html">Proposed Changes</a></h3>
+
+<blockquote>Describes API changes being considered by the developer community.
+Feedback welcome.</blockquote>
+<a href="http://www.portaudio.com/">Return to PortAudio Home Page</a>
+</body>
+</html>
diff --git a/pd/portaudio/docs/latency.html b/pd/portaudio/docs/latency.html
new file mode 100644
index 00000000..87f1d122
--- /dev/null
+++ b/pd/portaudio/docs/latency.html
@@ -0,0 +1,192 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Internal docs. How a stream is started or stopped.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Implementation - Start/Stop</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+<a href="http://www.portaudio.com">PortAudio</a> Latency</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>This page discusses the issues of audio latency for <a href="http://www.portaudio.com">PortAudio</a>
+. It offers suggestions on how to lower latency to improve the responsiveness
+of applications.
+<blockquote><b><a href="#what">What is Latency?</a></b>
+<br><b><a href="#portaudio">PortAudio and Latency</a></b>
+<br><b><a href="#macintosh">Macintosh</a></b>
+<br><b><a href="#unix">Unix</a></b>
+<br><b><a href="#windows">WIndows</a></b></blockquote>
+By Phil Burk, Copyright 2002 Phil Burk and Ross Bencina
+<h2>
+<a NAME="what"></a>What is Latency?</h2>
+Latency is basically longest time that you have to wait before you obtain
+a desired result. For digital audio output it is the time between making
+a sound in software and finally hearing it.
+<p>Consider the example of pressing a key on the ASCII keyboard to play
+a note. There are several stages in this process which each contribute
+their own latency. First the operating system must respond to the keypress.
+Then the audio signal generated must work its way through the PortAudio
+buffers. Then it must work its way through the audio card hardware. Then
+it must go through the audio amplifier which is very quick and then travel
+through the air. Sound travels at abous one foot per millisecond through
+air so placing speakers across the room can add 5-20 msec of delay.
+<p>The reverse process occurs when recording or responding to audio input.
+If you are processing audio, for example if you implement a software guitar
+fuzz box, then you have both the audio input and audio output latencies
+added together.
+<p>The audio buffers are used to prevent glitches in the audio stream.
+The user software writes audio into the output buffers. That audio is read
+by the low level audio driver or by DMA and sent to the DAC. If the computer
+gets busy doing something like reading the disk or redrawing the screen,
+then it may not have time to fill the audio buffer. The audio hardware
+then runs out of audio data, which causes a glitch. By using a large enough
+buffer we can ensure that there is always enough audio data for the audio
+hardware to play. But if the buffer is too large then the latency is high
+and the system feels sluggish. If you play notes on the keyboard then the
+"instrument" will feel unresponsive. So you want the buffers to be as small
+as possible without glitching.
+<h2>
+<a NAME="portaudio"></a>PortAudio and Latency</h2>
+The only delay that PortAudio can control is the total length of its buffers.
+The Pa_OpenStream() call takes two parameters: numBuffers and framesPerBuffer.
+The latency is also affected by the sample rate which we will call framesPerSecond.
+A frame is a set of samples that occur simultaneously. For a stereo stream,
+a frame is two samples.
+<p>The latency in milliseconds due to this buffering&nbsp; is:
+<blockquote><tt>latency_msec = 1000 * numBuffers * framesPerBuffer / framesPerSecond</tt></blockquote>
+This is not the total latency, as we have seen, but it is the part we can
+control.
+<p>If you call Pa_OpenStream() with numBuffers equal to zero, then PortAudio
+will select a conservative number that will prevent audio glitches. If
+you still get glitches, then you can pass a larger value for numBuffers
+until the glitching stops. if you try to pass a numBuffers value that is
+too small, then PortAudio will use its own idea of the minimum value.
+<p>PortAudio decides on the minimum number of buffers in a conservative
+way based on the frameRate, operating system and other variables. You can
+query the value that PortAudio will use by calling:
+<blockquote><tt>int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate
+);</tt></blockquote>
+On some systems you can override the PortAudio minimum if you know your
+system can handle a lower value. You do this by setting an environment
+variable called PA_MIN_LATENCY_MSEC which is read by PortAudio when it
+starts up. This is supported on the PortAudio implementations for Windows
+MME, Windows DirectSound, and Unix OSS.
+<h2>
+<a NAME="macintosh"></a>Macintosh</h2>
+The best thing you can do to improve latency on Mac OS 8 and 9 is to turn
+off Virtual Memory. PortAudio V18 will detect that Virtual Memory is turned
+off and use a very low latency.
+<p>For Mac OS X the latency is very low because Apple Core Audio is so
+well written. You can set the PA_MIN_LATENCY_MSEC variable using:
+<blockquote><tt>setenv PA_MIN_LATENCY_MSEC 4</tt></blockquote>
+
+<h2>
+<a NAME="unix"></a>Unix</h2>
+PortAudio under Unix currently uses a backgroud thread that reads and writes
+to OSS. This gives you decent but not great latency. But if you raise the
+priority of the background thread to a very priority then you can get under
+10 milliseconds latency. In order to raise your priority you must run the
+PortAudio program as root! You must also set PA_MIN_LATENCY_MSEC using
+the appropriate command for your shell.
+<h2>
+<a NAME="windows"></a>Windows</h2>
+Latency under Windows is a complex issue because of all the alternative
+operating system versions and device drivers. I have seen latency range
+from 8 milliseconds to 400 milliseconds. The worst case is when using Windows
+NT. Windows 98 is a little better, and Windows XP can be quite good if
+properly tuned.
+<p>The underlying audio API also makes a lot of difference. If the audio
+device has its own DirectSound driver then DirectSound can often provide
+better latency than WMME. But if a real DirectSound driver is not available
+for your device then it is emulated using WMME and the latency can be very
+high. That's where I saw the 400 millisecond latency. The ASIO implementation
+is generally very good and will give the lowest latency if available.
+<p>You can set the PA_MIN_LATENCY_MSEC variable to 50, for example, by
+entering in MS-DOS:
+<blockquote><tt>set PA_MIN_LATENCY_MSEC=50</tt></blockquote>
+If you enter this in a DOS window then you must run the PortAudio program
+from that same window for the variable to have an effect. You can add that
+line to your C:\AUTOEXEC.BAT file and reboot if you want it to affect any
+PortAudio based program.
+<p>For Windows XP, you can set environment variables as follows:
+<ol>
+<li>
+Select "Control Panel" from the "Start Menu".</li>
+
+<li>
+Launch the "System" Control Panel</li>
+
+<li>
+Click on the "Advanced" tab.</li>
+
+<li>
+Click on the "Environment Variables" button.</li>
+
+<li>
+Click "New" button under&nbsp; User Variables.</li>
+
+<li>
+Enter PA_MIN_LATENCY_MSEC for the name and some optimistic number for the
+value.</li>
+
+<li>
+Click OK, OK, OK.</li>
+</ol>
+
+<h3>
+Improving Latency on Windows</h3>
+There are several steps you can take to improve latency under windows.
+<ol>
+<li>
+Avoid reading or writng to disk when doing audio.</li>
+
+<li>
+Turn off all automated background tasks such as email clients, virus scanners,
+backup programs, FTP servers, web servers, etc. when doing audio.</li>
+
+<li>
+Disconnect from the network to prevent network traffic from interrupting
+your CPU.</li>
+</ol>
+<b>Important: </b>Windows XP users can also tune the OS to favor background
+tasks, such as audio, over foreground tasks, such as word processing. I
+lowered my latency from 40 to 10 milliseconds using this simple technique.
+<ol>
+<li>
+Select "Control Panel" from the "Start Menu".</li>
+
+<li>
+Launch the "System" Control Panel</li>
+
+<li>
+Click on the "Advanced" tab.</li>
+
+<li>
+Click on the "Settings" button in the Performance area.</li>
+
+<li>
+Click on the "Advanced" tab.</li>
+
+<li>
+Select "Background services" in the Processor Scheduling area.</li>
+
+<li>
+Click OK, OK.</li>
+</ol>
+Please let us know if you have others sugestions for lowering latency.
+<br>&nbsp;
+<br>&nbsp;
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_impl_guide.html b/pd/portaudio/docs/pa_impl_guide.html
new file mode 100644
index 00000000..50abc304
--- /dev/null
+++ b/pd/portaudio/docs/pa_impl_guide.html
@@ -0,0 +1,197 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Internal docs. How a stream is started or stopped.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Implementation - Start/Stop</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+<a href="http://www.portaudio.com">PortAudio</a> Implementation Guide</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>This document describes how to implement the PortAudio API on a new
+computer platform. Implementing PortAudio on a new platform, makes it possible
+to port many existing audio applications to that platform.
+<p>By Phil Burk
+<br>Copyright 2000 Phil Burk and Ross Bencina
+<p>Note that the license says: <b>"Any person wishing to distribute modifications
+to the Software is requested to send the modifications to the original
+developer so that they can be incorporated into the canonical version."</b>.
+So when you have finished a new implementation, please send it back to
+us at&nbsp; "<a href="http://www.portaudio.com">http://www.portaudio.com</a>"
+so that we can make it available for other users. Thank you!
+<h2>
+Download the Latest PortAudio Implementation</h2>
+Always start with the latest implementation available at "<a href="http://www.portaudio.com">http://www.portaudio.com</a>".
+Look for the nightly snapshot under the CVS section.
+<h2>
+Select an Existing Implementation as a Basis</h2>
+The fastest way to get started is to take an existing implementation and
+translate it for your new platform. Choose an implementation whose architecture
+is as close as possible to your target.
+<ul>
+<li>
+DirectSound Implementation - pa_win_ds - Uses a timer callback for the
+background "thread". Polls a circular buffer and writes blocks of data
+to keep it full.</li>
+
+<li>
+Windows MME - pa_win_wmme - Spawns an actual Win32 thread. Writes blocks
+of data to the HW device and waits for events that signal buffer completion.</li>
+
+<li>
+Linux OSS - pa_linux - Spawns a real thread that writes to the "/dev/dsp"
+stream using blocking I/O calls.</li>
+</ul>
+When you write a new implementation, you will be using some code that is
+in common with all implementations. This code is in the folder "pa_common".
+It provides various functions such as parameter checking, error code to
+text conversion, sample format conversion, clipping and dithering, etc.
+<p>The code that you write will go into a separate folder called "pa_{os}_{api}".
+For example, code specific to the DirectSound interface for Windows goes
+in "pa_win_ds".
+<h2>
+Read Docs and Code</h2>
+Famialiarize yourself with the system by reading the documentation provided.
+here is a suggested order:
+<ol>
+<li>
+User Programming <a href="pa_tutorial.html">Tutorial</a></li>
+
+<li>
+Header file "pa_common/portaudio.h" which defines API.</li>
+
+<li>
+Header file "pa_common/pa_host.h" for host dependant code. This definces
+the routine you will need to provide.</li>
+
+<li>
+Shared code in "pa_common/pa_lib.c".</li>
+
+<li>
+Docs on Implementation of <a href="pa_impl_startstop.html">Start/Stop</a>
+code.</li>
+</ol>
+
+<h2>
+Implement&nbsp; Output to Default Device</h2>
+Now we are ready to crank some code. For instant gratification, let's try
+to play a sine wave.
+<ol>
+<li>
+Link the test program "pa_tests/patest_sine.c" with the file "pa_lib.c"
+and the implementation specific file you are creating.</li>
+
+<li>
+For now, just stub out the device query code and the audio input code.</li>
+
+<li>
+Modify PaHost_OpenStream() to open your default target device and get everything
+setup.</li>
+
+<li>
+Modify PaHost_StartOutput() to start playing audio.</li>
+
+<li>
+Modify PaHost_StopOutput() to stop audio.</li>
+
+<li>
+Modify PaHost_CloseStream() to clean up. Free all memory that you allocated
+in PaHost_OpenStream().</li>
+
+<li>
+Keep cranking until you can play a sine wave using "patest_sine.c".</li>
+
+<li>
+Once that works, try "patest_pink.c", "patest_clip.c", "patest_sine8.c".</li>
+
+<li>
+To test your Open and Close code, try "patest_many.c".</li>
+
+<li>
+Now test to make sure that the three modes of stopping are properly supported
+by running "patest_stop.c".</li>
+
+<li>
+Test your implementation of time stamping with "patest_sync.c".</li>
+</ol>
+
+<h2>
+Implement Device Queries</h2>
+Now that output is working, lets implement the code for querying what devices
+are available to the user. Run "pa_tests/pa_devs.c". It should print all
+of the devices available and their characteristics.
+<h2>
+Implement Input</h2>
+Implement audio input and test it with:
+<ol>
+<li>
+patest_record.c - record in half duplex, play back as recorded.</li>
+
+<li>
+patest_wire.c - full duplex, copies input to output. Note that some HW
+may not support full duplex.</li>
+
+<li>
+patest_fuzz.c - plug in your guitar and get a feel for why latency is an
+important issue in computer music.</li>
+
+<li>
+paqa_devs.c - try to open every device and use it with every possible format</li>
+</ol>
+
+<h2>
+Debugging Tools</h2>
+You generally cannot use printf() calls to debug real-time processes because
+they disturb the timing. Also calling printf() from your background thread
+or interrupt could crash the machine. So PA includes a tool for capturing
+events and storing the information while it is running. It then prints
+the events when Pa_Terminate() is called.
+<ol>
+<li>
+To enable trace mode, change TRACE_REALTIME_EVENTS in "pa_common/pa_trace.h"
+from a (0) to a (1).</li>
+
+<li>
+Link with "pa_common/pa_trace.c".</li>
+
+<li>
+Add trace messages to your code by calling:</li>
+
+<br><tt>&nbsp;&nbsp; void AddTraceMessage( char *msg, int data );</tt>
+<br><tt>for example</tt>
+<br><tt>&nbsp;&nbsp; AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ",
+past->past_NumCallbacks );</tt>
+<li>
+Run your program. You will get a dump of events at the end.</li>
+
+<li>
+You can leave the trace messages in your code. They will turn to NOOPs
+when you change TRACE_REALTIME_EVENTS back to (0).</li>
+</ol>
+
+<h2>
+Delivery</h2>
+Please send your new code along with notes on the implementation back to
+us at "<a href="http://www.portaudio.com">http://www.portaudio.com</a>".
+We will review the implementation and post it with your name. If you had
+to make any modifications to the code in "pa_common" or "pa_tests" <b>please</b>
+send us those modifications and your notes. We will try to merge your changes
+so that the "pa_common" code works with <b>all</b> implementations.
+<p>If you have suggestions for how to make future implementations easier,
+please let us know.
+<br>THANKS!
+<br>&nbsp;
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_impl_startstop.html b/pd/portaudio/docs/pa_impl_startstop.html
new file mode 100644
index 00000000..0f2d0ce5
--- /dev/null
+++ b/pd/portaudio/docs/pa_impl_startstop.html
@@ -0,0 +1,190 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.75 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Internal docs. How a stream is started or stopped.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Implementation - Start/Stop</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Implementation</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Starting and Stopping Streams</h2>
+PortAudio is generally executed in two "threads". The foreground thread
+is the application thread. The background "thread" may be implemented as
+an actual thread, an interrupt handler, or a callback from a timer thread.
+<p>There are three ways that PortAudio can stop a stream. In each case
+we look at the sequence of events and the messages sent between the two
+threads. The following variables are contained in the internalPortAudioStream.
+<blockquote><tt>int&nbsp;&nbsp; past_IsActive;&nbsp;&nbsp;&nbsp;&nbsp;
+/* Background is still playing. */</tt>
+<br><tt>int&nbsp;&nbsp; past_StopSoon;&nbsp;&nbsp;&nbsp;&nbsp; /* Stop
+when last buffer done. */</tt>
+<br><tt>int&nbsp;&nbsp; past_StopNow;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*
+Stop IMMEDIATELY. */</tt></blockquote>
+
+<h3>
+Pa_AbortStream()</h3>
+This function causes the background thread to terminate as soon as possible
+and audio I/O to stop abruptly.
+<br>&nbsp;
+<table BORDER COLS=2 WIDTH="60%" >
+<tr>
+<td><b>Foreground Thread</b></td>
+
+<td><b>Background Thread</b></td>
+</tr>
+
+<tr>
+<td>sets <tt>StopNow</tt></td>
+
+<td></td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>sees <tt>StopNow</tt>,&nbsp;</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>clears IsActive, stops thread</td>
+</tr>
+
+<tr>
+<td>waits for thread to exit</td>
+
+<td></td>
+</tr>
+
+<tr>
+<td>turns off audio I/O</td>
+
+<td></td>
+</tr>
+</table>
+
+<h3>
+Pa_StopStream()</h3>
+This function stops the user callback function from being called and then
+waits for all audio data written to the output buffer to be played. In
+a system with very low latency, you may not hear any difference between
+<br>&nbsp;
+<table BORDER COLS=2 WIDTH="60%" >
+<tr>
+<td><b>Foreground Thread</b></td>
+
+<td><b>Background Thread</b></td>
+</tr>
+
+<tr>
+<td>sets StopSoon</td>
+
+<td></td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>stops calling user callback</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>continues until output buffer empty</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>clears IsActive, stops thread</td>
+</tr>
+
+<tr>
+<td>waits for thread to exit</td>
+
+<td></td>
+</tr>
+
+<tr>
+<td>turns off audio I/O</td>
+
+<td></td>
+</tr>
+</table>
+
+<h3>
+User callback returns one.</h3>
+If the user callback returns one then the user callback function will no
+longer be called. Audio output will continue until all audio data written
+to the output buffer has been played. Then the audio I/O is stopped, the
+background thread terminates, and the stream becomes inactive.
+<br>&nbsp;
+<table BORDER COLS=2 WIDTH="60%" >
+<tr>
+<td><b>Foreground Thread</b></td>
+
+<td><b>Background Thread</b></td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>callback returns 1</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>sets StopSoon</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>stops calling user callback</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>continues until output buffer empty</td>
+</tr>
+
+<tr>
+<td></td>
+
+<td>clears IsActive, stops thread</td>
+</tr>
+
+<tr>
+<td>waits for thread to exit</td>
+
+<td></td>
+</tr>
+
+<tr>
+<td>turns off audio I/O</td>
+
+<td></td>
+</tr>
+</table>
+
+<br>&nbsp;
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_asio.html b/pd/portaudio/docs/pa_tut_asio.html
new file mode 100644
index 00000000..1c3e5bfa
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_asio.html
@@ -0,0 +1,55 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Compiling for ASIO (Windows or Macintosh)</h2>
+
+<blockquote>ASIO is a low latency audio API from Steinberg. To compile
+an ASIO application, you must first <a href="http://www.steinberg.net/developers/ASIO2SDKAbout.phtml">download
+the ASIO SDK</a> from Steinberg. You also need to obtain ASIO drivers for
+your audio device.
+<p>Note: I am using '/' as a file separator below. On Macintosh replace
+'/' with ':'. On Windows, replace '/' with '\'.
+<p>&nbsp;To use ASIO with the PortAudio library add the following source
+files to your project:
+<blockquote>
+<pre>pa_asio/pa_asio.cpp</pre>
+</blockquote>
+and also these files from the ASIO SDK:
+<blockquote>
+<pre>common/asio.cpp
+host/asiodrivers.cpp
+host/asiolist.cpp</pre>
+</blockquote>
+and add these directories to the path for include files
+<blockquote>
+<pre>asiosdk2/host/pc&nbsp;&nbsp; (for Windows)
+asiosdk2/common
+asiosdk2/host</pre>
+</blockquote>
+You may try compiling the "pa_tests/patest_saw.c" file first because it
+is the simplest.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_over.html">previous</a> |&nbsp; <a href="pa_tut_callback.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_callback.html b/pd/portaudio/docs/pa_tut_callback.html
new file mode 100644
index 00000000..f5ccaf0f
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_callback.html
@@ -0,0 +1,91 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Writing a Callback Function</h2>
+
+<blockquote>To write a program using PortAudio, you must include the "portaudio.h"
+include file. You may wish to read "<a href="portaudio_h.txt">portaudio.h</a>"
+because it contains a complete description of the PortAudio functions and
+constants.
+<blockquote>
+<pre>#include "portaudio.h"</pre>
+</blockquote>
+The next task is to write your custom callback function. It is a function
+that is called by the PortAudio engine whenever it has captured audio data,
+or when it needs more audio data for output.
+<p>Your callback function is often called by an interrupt, or low level
+process so you should not do any complex system activities like allocating
+memory, or reading or writing files, or printf(). Just crunch numbers and
+generate audio signals. What is safe or not safe will vary from platform
+to platform. On the Macintosh, for example, you can only call "interrupt
+safe" routines. Also do not call any PortAudio functions in the callback
+except for Pa_StreamTime() and Pa_GetCPULoad().
+<p>Your callback function must return an int and accept the exact parameters
+specified in this typedef:
+<blockquote>
+<pre>typedef int (PortAudioCallback)(
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *inputBuffer, void *outputBuffer,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long framesPerBuffer,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PaTimestamp outTime, void *userData );</pre>
+</blockquote>
+Here is an example callback function from the test file "patests/patest_saw.c".
+It calculates a simple left and right sawtooth signal and writes it to
+the output buffer. Notice that in this example, the signals are of <tt>float</tt>
+data type. The signals must be between -1.0 and +1.0. You can also use
+16 bit integers or other formats which are specified during setup. You
+can pass a pointer to your data structure through PortAudio which will
+appear as <tt>userData</tt>.
+<blockquote>
+<pre>int patestCallback(&nbsp; void *inputBuffer, void *outputBuffer,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long framesPerBuffer,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; PaTimestamp outTime, void *userData )
+{
+&nbsp;&nbsp;&nbsp; unsigned int i;
+/* Cast data passed through stream to our structure type. */
+&nbsp;&nbsp;&nbsp; paTestData *data = (paTestData*)userData;
+&nbsp;&nbsp;&nbsp; float *out = (float*)outputBuffer;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+&nbsp;&nbsp;&nbsp; for( i=0; i&lt;framesPerBuffer; i++ )
+&nbsp;&nbsp;&nbsp; {
+&nbsp;&nbsp;&nbsp; /* Stereo channels are interleaved. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *out++ = data->left_phase;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* left */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *out++ = data->right_phase;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* right */
+
+&nbsp;&nbsp;&nbsp; /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data->left_phase += 0.01f;
+&nbsp;&nbsp;&nbsp; /* When signal reaches top, drop back down. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
+
+&nbsp;&nbsp;&nbsp; /* higher pitch so we can distinguish left and right. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; data->right_phase += 0.03f;&nbsp;
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
+&nbsp;&nbsp;&nbsp; }
+&nbsp;&nbsp;&nbsp; return 0;
+}</pre>
+</blockquote>
+</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_over.html">previous</a> |&nbsp; <a href="pa_tut_init.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_devs.html b/pd/portaudio/docs/pa_tut_devs.html
new file mode 100644
index 00000000..1756992c
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_devs.html
@@ -0,0 +1,65 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.75 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Querying for Available Devices</h2>
+
+<blockquote>There are often several different audio devices available in
+a computer with different capabilities. They can differ in the sample rates
+supported, bit widths, etc. PortAudio provides a simple way to query for
+the available devices, and then pass the selected device to Pa_OpenStream().
+For an example, see the file "pa_tests/pa_devs.c".
+<p>To determine the number of devices:
+<blockquote>
+<pre>numDevices = Pa_CountDevices();</pre>
+</blockquote>
+You can then query each device in turn by calling Pa_GetDeviceInfo() with
+an index.
+<blockquote>
+<pre>for( i=0; i&lt;numDevices; i++ ) {
+&nbsp;&nbsp;&nbsp;&nbsp; pdi = Pa_GetDeviceInfo( i );</pre>
+</blockquote>
+It will return a pointer to a <tt>PaDeviceInfo</tt> structure which is
+defined as:
+<blockquote>
+<pre>typedef struct{
+&nbsp;&nbsp;&nbsp; int structVersion;&nbsp;
+&nbsp;&nbsp;&nbsp; const char *name;
+&nbsp;&nbsp;&nbsp; int maxInputChannels;
+&nbsp;&nbsp;&nbsp; int maxOutputChannels;
+/* Number of discrete rates, or -1 if range supported. */
+&nbsp;&nbsp;&nbsp; int numSampleRates;
+/* Array of supported sample rates, or {min,max} if range supported. */
+&nbsp;&nbsp;&nbsp; const double *sampleRates;
+&nbsp;&nbsp;&nbsp; PaSampleFormat nativeSampleFormat;
+}PaDeviceInfo;</pre>
+</blockquote>
+If the device supports a continuous range of sample rates, then numSampleRates
+will equal -1, and the sampleRates array will have two values, the minimum&nbsp;
+and maximum rate.
+<p>The device information is allocated by Pa_Initialize() and freed by
+Pa_Terminate() so you do not have to free() the structure returned by Pa_GetDeviceInfo().</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_util.html">previous</a> |&nbsp; <a href="pa_tut_rw.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_explore.html b/pd/portaudio/docs/pa_tut_explore.html
new file mode 100644
index 00000000..91c08a5b
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_explore.html
@@ -0,0 +1,42 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Exploring PortAudio</h2>
+
+<blockquote>Now that you have a good idea of how PortAudio works, you can
+try out the test programs.
+<ul>
+<li>
+For an example of playing a sine wave, see "pa_tests/patest_sine.c".</li>
+
+<li>
+For an example of recording and playing back a sound, see&nbsp; "pa_tests/patest_record.c".</li>
+</ul>
+I also encourage you to examine the source for the PortAudio libraries.
+If you have suggestions on ways to improve them, please let us know. if
+you want to implement PortAudio on a new platform, please let us know as
+well so we can coordinate people's efforts.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_rw.html">previous</a> |&nbsp; next</font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_init.html b/pd/portaudio/docs/pa_tut_init.html
new file mode 100644
index 00000000..91bfa8d9
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_init.html
@@ -0,0 +1,43 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Initializing PortAudio</h2>
+
+<blockquote>Before making any other calls to PortAudio, you must call <tt>Pa_Initialize</tt>().
+This will trigger a scan of available devices which can be queried later.
+Like most PA functions, it will return a result of type <tt>paError</tt>.
+If the result is not <tt>paNoError</tt>, then an error has occurred.
+<blockquote>
+<pre>err = Pa_Initialize();
+if( err != paNoError ) goto error;</pre>
+</blockquote>
+You can get a text message that explains the error message by passing it
+to
+<blockquote>
+<pre>printf(&nbsp; "PortAudio error: %s\n", Pa_GetErrorText( err ) );</pre>
+</blockquote>
+</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_callback.html">previous</a> |&nbsp; <a href="pa_tut_open.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_mac.html b/pd/portaudio/docs/pa_tut_mac.html
new file mode 100644
index 00000000..bf3dafd1
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_mac.html
@@ -0,0 +1,41 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Compiling for Macintosh</h2>
+
+<blockquote>To compile a Macintosh application with the PortAudio library,
+add the following source files to your project:
+<blockquote>
+<pre>pa_mac:pa_mac.c
+pa_common:pa_lib.c
+pa_common:portaudio.h
+pa_common:pa_host.h</pre>
+</blockquote>
+Also add the Apple <b>SoundLib</b> to your project.
+<p>You may try compiling the "pa_tests:patest_saw.c" file first because
+it is the simplest.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_over.html">previous</a> |&nbsp; <a href="pa_tut_callback.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_mac_osx.html b/pd/portaudio/docs/pa_tut_mac_osx.html
new file mode 100644
index 00000000..3af8c140
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_mac_osx.html
@@ -0,0 +1,46 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Compiling for Macintosh OS X</h2>
+
+<blockquote>To compile a Macintosh OS X CoreAudio application with the
+PortAudio library:
+<p>Create a new ProjectBuilder project. You can use a "Tool" project to
+run the PortAudio examples.
+<p>Add the following source files to your Project:
+<blockquote>
+<pre>pa_mac_core/pa_mac_core.c
+pa_common/pa_lib.c
+pa_common/portaudio.h
+pa_common/pa_host.h
+pa_common/pa_convert.c</pre>
+</blockquote>
+Add the Apple CoreAudio.framework to your project by selecting "Add FrameWorks..."
+from the Project menu.
+<p>Compile and run the "pa_tests:patest_saw.c" file first because it is
+the simplest.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_over.html">previous</a> |&nbsp; <a href="pa_tut_callback.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_open.html b/pd/portaudio/docs/pa_tut_open.html
new file mode 100644
index 00000000..1621ef30
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_open.html
@@ -0,0 +1,52 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Opening a Stream using Defaults</h2>
+
+<blockquote>The next step is to open a stream which is similar to opening
+a file. You can specify whether you want audio input and/or output, how
+many channels, the data format, sample rate, etc. There are two calls for
+opening streams, <tt>Pa_OpenStream</tt>() and <tt>Pa_OpenDefaultStream</tt>().
+<p><tt>Pa_OpenStream()</tt> takes extra&nbsp; parameters which give you
+more control. You can normally just use <tt>Pa_OpenDefaultStream</tt>()
+which just calls <tt>Pa_OpenStream()</tt> <tt>with</tt> some reasonable
+default values.&nbsp; Let's open a stream for stereo output, using floating
+point data, at 44100 Hz.
+<blockquote>
+<pre>err = Pa_OpenDefaultStream(
+&nbsp;&nbsp;&nbsp; &amp;stream,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* passes back stream pointer */
+&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* no input channels */
+&nbsp;&nbsp;&nbsp; 2,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* stereo output */
+&nbsp;&nbsp;&nbsp; paFloat32,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* 32 bit floating point output */
+&nbsp;&nbsp;&nbsp; 44100,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* sample rate */
+&nbsp;&nbsp;&nbsp; 256,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* frames per buffer */
+&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* number of buffers, if zero then use default minimum */
+&nbsp;&nbsp;&nbsp; patestCallback, /* specify our custom callback */
+&nbsp;&nbsp;&nbsp; &amp;data );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* pass our data through to callback */</pre>
+</blockquote>
+If you want to use 16 bit integer data, pass <tt>paInt16</tt> instead of
+<tt>paFloat32</tt>.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_init.html">previous</a> |&nbsp; <a href="pa_tut_run.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_oss.html b/pd/portaudio/docs/pa_tut_oss.html
new file mode 100644
index 00000000..1bb76f25
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_oss.html
@@ -0,0 +1,46 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Compiling for Unix OSS</h2>
+
+<blockquote>[Skip this page if you are not using Unix and OSS]
+<p>We currently support the <a href="http://www.opensound.com/">OSS</a>
+audio drivers for Linux, Solaris, and FreeBSD. We hope to someday support
+the newer ALSA drivers.
+<ol>
+<li>
+cd to pa_unix_oss directory</li>
+
+<li>
+Edit the Makefile and uncomment one of the tests. You may try compiling
+the "patest_sine.c" file first because it is very simple.</li>
+
+<li>
+gmake run</li>
+</ol>
+</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_pc.html">previous</a> |&nbsp; <a href="pa_tut_callback.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_over.html b/pd/portaudio/docs/pa_tut_over.html
new file mode 100644
index 00000000..baa99205
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_over.html
@@ -0,0 +1,92 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Overview of PortAudio</h2>
+
+<blockquote>PortAudio is a library that provides streaming audio input
+and output. It is a cross-platform API (Application Programming Interface)
+that works on Windows, Macintosh, Unix running OSS, SGI, BeOS, and perhaps
+other platforms by the time you read this. This means that you can write
+a simple 'C' program to process or generate an audio signal, and that program
+can run on several different types of computer just by recompiling the
+source code.
+<p>Here are the steps to writing a PortAudio application:
+<ol>
+<li>
+Write a callback function that will be called by PortAudio when audio processing
+is needed.</li>
+
+<li>
+Initialize the PA library and open a stream for audio I/O.</li>
+
+<li>
+Start the stream. Your callback function will be now be called repeatedly
+by PA in the background.</li>
+
+<li>
+In your callback you can read audio data from the inputBuffer and/or write
+data to the outputBuffer.</li>
+
+<li>
+Stop the stream by returning 1 from your callback, or by calling a stop
+function.</li>
+
+<li>
+Close the stream and terminate the library.</li>
+</ol>
+</blockquote>
+
+<blockquote>There is also <a href="pa_tut_rw.html">another interface</a>
+provided that allows you to generate audio in the foreground. You then
+simply write data to the stream and the tool will not return until it is
+ready to accept more data. This interface is simpler to use but is usually
+not preferred for large applications because it requires that you launch
+a thread to perform the synthesis. Launching a thread may be difficult
+on non-multi-tasking systems such as the Macintosh prior to MacOS X.
+<p>Let's continue by building a simple application that will play a sawtooth
+wave.
+<p>Please select the page for the specific implementation you would like
+to use:
+<ul>
+<li>
+<a href="pa_tut_pc.html">Windows (WMME or DirectSound)</a></li>
+
+<li>
+<a href="pa_tut_mac.html">Macintosh SoundManager for OS 7,8,9</a></li>
+
+<li>
+<a href="pa_tut_mac_osx.html">Macintosh CoreAudio for OS X</a></li>
+
+<li>
+<a href="pa_tut_asio.html">ASIO on Windows or Macintosh</a></li>
+
+<li>
+<a href="pa_tut_oss.html">Unix OSS</a></li>
+</ul>
+or continue with the <a href="pa_tut_callback.html">next page of the programming
+tutorial</a>.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tutorial.html">previous</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_pc.html b/pd/portaudio/docs/pa_tut_pc.html
new file mode 100644
index 00000000..87e5f9a0
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_pc.html
@@ -0,0 +1,78 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Compiling for Windows (WMME or DirectSound)</h2>
+
+<blockquote>To compile PortAudio for Windows, you can choose between two
+options. One implementation uses the DirectSound API. The other uses the
+Windows MultiMedia Extensions API (aka WMME or WAVE).
+<p>Some advantages of using DirectSound are that DirectSound may have lower
+latency than WMME, and supports effects processing plugins. But one disadvantage
+is that DirectSound is not installed on all PCs, and is not well supported
+under Windows NT. So WMME is the best choice for most projects.
+<p>For either implementation add the following source files to your project:
+<blockquote>
+<pre><b>pa_common\pa_lib.c
+pa_common\portaudio.h
+pa_common\pa_host.h</b></pre>
+</blockquote>
+Link with the system library "<b>winmm.lib</b>". For Visual C++:
+<ol>
+<li>
+select "Settings..." from the "Project" menu,</li>
+
+<li>
+select the project name in the tree on the left,</li>
+
+<li>
+choose "All Configurations" in the popup menu above the tree,</li>
+
+<li>
+select the "Link" tab,</li>
+
+<li>
+enter "winmm.lib", without quotes, as the first item in the "Object/library
+modules:" field.</li>
+</ol>
+<b>WMME</b> - To use the WMME implementation, add the following source
+files to your project:
+<blockquote><b><tt>pa_win_wmme/pa_win_wmme.c</tt></b></blockquote>
+<b>DirectSound</b> - If you want to use the DirectSound implementation
+of PortAudio then you must have a recent copy of the free
+<a href="http://www.microsoft.com/directx/download.asp">DirectX</a>
+SDK for Developers from Microsoft installed on your computer. To compile
+an application add the following source files to your project:
+<blockquote>
+<pre><b>pa_win_ds\dsound_wrapper.c
+pa_win_ds\pa_dsound.c</b></pre>
+</blockquote>
+Link with the system library "<b>dsound.lib</b>" using the procedure described
+above for "winmm.lib".</blockquote>
+
+<blockquote>You might try compiling the "pa_tests\patest_saw.c" file first
+because it is the simplest.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_over.html">previous</a> |&nbsp; <a href="pa_tut_callback.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_run.html b/pd/portaudio/docs/pa_tut_run.html
new file mode 100644
index 00000000..5c70d089
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_run.html
@@ -0,0 +1,56 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Starting and Stopping a Stream</h2>
+
+<blockquote>The stream will not start running until you call Pa_StartStream().
+Then it will start calling your callback function to perform the audio
+processing.
+<blockquote>
+<pre>err = Pa_StartStream( stream );
+if( err != paNoError ) goto error;</pre>
+</blockquote>
+At this point, audio is being generated. You can communicate to your callback
+routine through the data structure you passed in on the open call, or through
+global variables, or using other interprocess communication techniques.
+Please be aware that your callback function may be called at interrupt
+time when your foreground process is least expecting it. So avoid sharing
+complex data structures that are easily corrupted like double linked lists.
+<p>In many of the tests we simply sleep for a few seconds so we can hear
+the sound. This is easy to do with Pa_Sleep() which will sleep for some
+number of milliseconds. Do not rely on this function for accurate scheduling.
+it is mostly for writing examples.
+<blockquote>
+<pre>/* Sleep for several seconds. */
+Pa_Sleep(NUM_SECONDS*1000);</pre>
+</blockquote>
+When you are through, you can stop the stream from the foreground.
+<blockquote>
+<pre>err = Pa_StopStream( stream );
+if( err != paNoError ) goto error;</pre>
+</blockquote>
+You can also stop the stream by returning 1 from your custom callback function.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_open.html">previous</a> |&nbsp; <a href="pa_tut_term.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_rw.html b/pd/portaudio/docs/pa_tut_rw.html
new file mode 100644
index 00000000..93c7b8bb
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_rw.html
@@ -0,0 +1,79 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.77 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Blocking Read/Write Functions</h2>
+
+<blockquote>[Note: These functions are not part of the official PortAudio
+API. They are simply built on top of PortAudio as an extra utility. Also
+note that they are under evaluation and their definition may change.]
+<p>There are two fundamentally different ways to design an audio API. One
+is to use callback functions the way we have already shown. The callback
+function operates under an interrupt or background thread This leaves the
+foreground application free to do other things while the audio just runs
+in the background. But this can sometimes be awkward.
+<p>So we have provided an alternative technique that lets a program generate
+audio in the foreground and then just write it to the audio stream as if
+it was a file. If there is not enough room in the audio buffer for more
+data, then the write function will just block until more room is available.
+This can make it very easy to write an audio example. To use this tool,
+you must add the files "pablio/pablio.c" and "pablio/ringbuffer.c" to your
+project. You must also:
+<blockquote>
+<pre>#include "pablio.h"</pre>
+</blockquote>
+Here is a short excerpt of a program that opens a stream for input and
+output. It then reads a block of samples from input, and writes them to
+output, in a loop.&nbsp; The complete example can be found in "pablio/test_rw.c".
+<blockquote>
+<pre>&nbsp;&nbsp;&nbsp; #define SAMPLES_PER_FRAME&nbsp;&nbsp;&nbsp;&nbsp; (2)
+&nbsp;&nbsp;&nbsp; #define FRAMES_PER_BLOCK&nbsp;&nbsp;&nbsp; (1024)
+&nbsp;&nbsp;&nbsp; SAMPLE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK];
+&nbsp;&nbsp;&nbsp; PaError&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; err;
+&nbsp;&nbsp;&nbsp; PABLIO_Stream&nbsp; *aStream;
+
+/* Open simplified blocking I/O layer on top of PortAudio. */
+&nbsp;&nbsp;&nbsp; err = OpenAudioStream( &amp;rwbl, SAMPLE_RATE, paFloat32,
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (PABLIO_READ_WRITE | PABLIO_STEREO) );
+&nbsp;&nbsp;&nbsp; if( err != paNoError ) goto error;
+
+/* Process samples in the foreground. */
+&nbsp;&nbsp;&nbsp; for( i=0; i&lt;(NUM_SECONDS * SAMPLE_RATE); i++ )
+&nbsp;&nbsp;&nbsp; {
+&nbsp;&nbsp;&nbsp; /* Read one block of data into sample array from audio input. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK );
+&nbsp;&nbsp;&nbsp; /*
+&nbsp;&nbsp;&nbsp; ** At this point you could process the data in samples array,
+&nbsp;&nbsp;&nbsp; ** and write the result back to the same samples array.
+&nbsp;&nbsp;&nbsp; */
+&nbsp;&nbsp;&nbsp; /* Write that same frame of data to output. */
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK );
+&nbsp;&nbsp;&nbsp; }
+
+&nbsp;&nbsp;&nbsp; CloseAudioStream( aStream );</pre>
+</blockquote>
+</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_devs.html">previous</a> |&nbsp; <a href="pa_tut_explore.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_term.html b/pd/portaudio/docs/pa_tut_term.html
new file mode 100644
index 00000000..1c72209f
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_term.html
@@ -0,0 +1,47 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.73 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Terminating PortAudio</h2>
+
+<blockquote>You can start and stop a stream as many times as you like.
+But when you are done using it, you should close it by calling:</blockquote>
+
+<blockquote>
+<blockquote>
+<pre>err = Pa_CloseStream( stream );
+if( err != paNoError ) goto error;</pre>
+</blockquote>
+Then when you are done using PortAudio, you should terminate the whole
+system by calling:
+<blockquote>
+<pre>Pa_Terminate();</pre>
+</blockquote>
+That's basically it. You can now write an audio program in 'C' that will
+run on multiple platforms, for example PCs and Macintosh.
+<p>In the rest of the tutorial we will look at some additional utility
+functions, and a different way of using PortAudio that does not require
+the use of a callback function.</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | <a href="pa_tutorial.html">contents</a>
+| <a href="pa_tut_run.html">previous</a> |&nbsp; <a href="pa_tut_util.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tut_util.html b/pd/portaudio/docs/pa_tut_util.html
new file mode 100644
index 00000000..f4b54750
--- /dev/null
+++ b/pd/portaudio/docs/pa_tut_util.html
@@ -0,0 +1,55 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.75 [en]C-gatewaynet (Win98; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<h2>
+Utility Functions</h2>
+
+<blockquote>Here are several more functions that are not critical, but
+may be handy when using PortAudio.
+<p>Pa_StreamActive() returns one when the stream in playing audio, zero
+when not playing, or a negative error number if the stream is invalid.
+The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
+but may also become inactive if the callback returns a non-zero value.
+In the latter case, the stream is considered inactive after the last buffer
+has finished playing.
+<blockquote>
+<pre>PaError Pa_StreamActive( PortAudioStream *stream );</pre>
+</blockquote>
+Pa_StreamTime() returns the number of samples that have been generated.
+PaTimeStamp is a double precision number which is a convenient way to pass
+big numbers around even though we only need integers.
+<blockquote>
+<pre>PaTimestamp Pa_StreamTime( PortAudioStream *stream );</pre>
+</blockquote>
+The "CPU Load" is a fraction of total CPU time consumed by the stream's
+audio processing. A value of 0.5 would imply that PortAudio and the sound
+generating callback was consuming roughly 50% of the available CPU time.
+This function may be called from the callback function or the application.
+<blockquote>
+<pre>double Pa_GetCPULoad( PortAudioStream* stream );</pre>
+</blockquote>
+</blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> |
+<a href="pa_tutorial.html">contents</a> | <a href="pa_tut_term.html">previous</a>
+|&nbsp; <a href="pa_tut_devs.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/pa_tutorial.html b/pd/portaudio/docs/pa_tutorial.html
new file mode 100644
index 00000000..1371c44f
--- /dev/null
+++ b/pd/portaudio/docs/pa_tutorial.html
@@ -0,0 +1,46 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="Tutorial for PortAudio, a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Tutorial</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio Tutorial</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>Copyright 2000 Phil Burk and Ross Bencina
+<h2>
+Table of Contents</h2>
+
+<blockquote><a href="pa_tut_over.html">Overview of PortAudio</a>
+<br><a href="pa_tut_mac.html">Compiling for Macintosh OS 7,8,9</a>
+<br><a href="pa_tut_mac_osx.html">Compiling for Macintosh OS X</a>
+<br><a href="pa_tut_pc.html">Compiling for Windows (DirectSound and WMME)</a>
+<br><a href="pa_tut_asio.html">Compiling for ASIO on Windows or Mac OS
+8,9</a>
+<br><a href="pa_tut_oss.html">Compiling for Unix OSS</a>
+<br><a href="pa_tut_callback.html">Writing a Callback Function</a>
+<br><a href="pa_tut_init.html">Initializing PortAudio</a>
+<br><a href="pa_tut_open.html">Opening a Stream using Defaults</a>
+<br><a href="pa_tut_run.html">Starting and Stopping a Stream</a>
+<br><a href="pa_tut_term.html">Cleaning Up</a>
+<br><a href="pa_tut_util.html">Utilities</a>
+<br><a href="pa_tut_devs.html">Querying for Devices</a>
+<br><a href="pa_tut_rw.html">Blocking Read/Write Functions</a>
+<br><a href="pa_tut_explore.html">Exploring the PortAudio Package</a></blockquote>
+<font size=+2><a href="http://www.portaudio.com/">home</a> | contents |
+previous |&nbsp; <a href="pa_tut_over.html">next</a></font>
+</body>
+</html>
diff --git a/pd/portaudio/docs/portaudio_h.txt b/pd/portaudio/docs/portaudio_h.txt
new file mode 100644
index 00000000..6d60086f
--- /dev/null
+++ b/pd/portaudio/docs/portaudio_h.txt
@@ -0,0 +1,425 @@
+#ifndef PORT_AUDIO_H
+#define PORT_AUDIO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio API Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+typedef int PaError;
+typedef enum {
+ paNoError = 0,
+
+ paHostError = -10000,
+ paInvalidChannelCount,
+ paInvalidSampleRate,
+ paInvalidDeviceId,
+ paInvalidFlag,
+ paSampleFormatNotSupported,
+ paBadIODeviceCombination,
+ paInsufficientMemory,
+ paBufferTooBig,
+ paBufferTooSmall,
+ paNullCallback,
+ paBadStreamPtr,
+ paTimedOut,
+ paInternalError
+} PaErrorNum;
+
+/*
+ Pa_Initialize() is the library initialisation function - call this before
+ using the library.
+*/
+
+PaError Pa_Initialize( void );
+
+/*
+ Pa_Terminate() is the library termination function - call this after
+ using the library.
+*/
+
+PaError Pa_Terminate( void );
+
+/*
+ Return host specific error.
+ This can be called after receiving a paHostError.
+*/
+long Pa_GetHostError( void );
+
+/*
+ Translate the error number into a human readable message.
+*/
+const char *Pa_GetErrorText( PaError errnum );
+
+/*
+ Sample formats
+
+ These are formats used to pass sound data between the callback and the
+ stream. Each device has a "native" format which may be used when optimum
+ efficiency or control over conversion is required.
+
+ Formats marked "always available" are supported (emulated) by all devices.
+
+ The floating point representation uses +1.0 and -1.0 as the respective
+ maximum and minimum.
+
+*/
+
+typedef unsigned long PaSampleFormat;
+#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
+#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
+#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
+#define paInt24 ((PaSampleFormat) (1<<3))
+#define paPackedInt24 ((PaSampleFormat) (1<<4))
+#define paInt8 ((PaSampleFormat) (1<<5))
+#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */
+#define paCustomFormat ((PaSampleFormat) (1<<16))
+
+/*
+ Device enumeration mechanism.
+
+ Device ids range from 0 to Pa_CountDevices()-1.
+
+ Devices may support input, output or both. Device 0 is always the "default"
+ device and should support at least stereo in and out if that is available
+ on the taget platform _even_ if this involves kludging an input/output
+ device on platforms that usually separate input from output. Other platform
+ specific devices are specified by positive device ids.
+*/
+
+typedef int PaDeviceID;
+#define paNoDevice -1
+
+typedef struct{
+ int structVersion;
+ const char *name;
+ int maxInputChannels;
+ int maxOutputChannels;
+/* Number of discrete rates, or -1 if range supported. */
+ int numSampleRates;
+/* Array of supported sample rates, or {min,max} if range supported. */
+ const double *sampleRates;
+ PaSampleFormat nativeSampleFormats;
+} PaDeviceInfo;
+
+
+int Pa_CountDevices();
+/*
+ Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID()
+
+ Return the default device ID or paNoDevice if there is no devices.
+ The result can be passed to Pa_OpenStream().
+
+ On the PC, the user can specify a default device by
+ setting an environment variable. For example, to use device #1.
+
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ID by using
+ the supplied application "pa_devs".
+*/
+PaDeviceID Pa_GetDefaultInputDeviceID( void );
+PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+
+/*
+ PaTimestamp is used to represent a continuous sample clock with arbitrary
+ start time useful for syncronisation. The type is used in the outTime
+ argument to the callback function and the result of Pa_StreamTime()
+*/
+
+typedef double PaTimestamp;
+
+/*
+ Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
+ referring to the device specified by id.
+ If id is out of range the function returns NULL.
+
+ The returned structure is owned by the PortAudio implementation and must
+ not be manipulated or freed. The pointer is guaranteed to be valid until
+ between calls to Pa_Initialize() and Pa_Terminate().
+*/
+
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID devID );
+
+/*
+ PortAudioCallback is implemented by clients of the portable audio api.
+
+ inputBuffer and outputBuffer are arrays of interleaved samples,
+ the format, packing and number of channels used by the buffers are
+ determined by parameters to Pa_OpenStream() (see below).
+
+ framesPerBuffer is the number of sample frames to be processed by the callback.
+
+ outTime is the time in samples when the buffer(s) processed by
+ this callback will begin being played at the audio output.
+ See also Pa_StreamTime()
+
+ userData is the value of a user supplied pointer passed to Pa_OpenStream()
+ intended for storing synthesis data etc.
+
+ return value:
+ The callback can return a nonzero value to stop the stream. This may be
+ useful in applications such as soundfile players where a specific duration
+ of output is required. However, it is not necessary to utilise this mechanism
+ as StopStream() will also terminate the stream. A callback returning a
+ nonzero value must fill the entire outputBuffer.
+
+ NOTE: None of the other stream functions may be called from within the
+ callback function except for Pa_GetCPULoad().
+
+*/
+
+typedef int (PortAudioCallback)(
+ void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+
+/*
+ Stream flags
+
+ These flags may be supplied (ored together) in the streamFlags argument to
+ the Pa_OpenStream() function.
+
+ [ suggestions? ]
+*/
+
+#define paNoFlag (0)
+#define paClipOff (1<<0) /* disable defult clipping of out of range samples */
+#define paDitherOff (1<<1) /* disable default dithering */
+#define paPlatformSpecificFlags (0x00010000)
+typedef unsigned long PaStreamFlags;
+
+/*
+ A single PortAudioStream provides multiple channels of real-time
+ input and output audio streaming to a client application.
+ Pointers to PortAudioStream objects are passed between PortAudio functions.
+*/
+
+typedef void PortAudioStream;
+#define PaStream PortAudioStream
+
+/*
+ Pa_OpenStream() opens a stream for either input, output or both.
+
+ stream is the address of a PortAudioStream pointer which will receive
+ a pointer to the newly opened stream.
+
+ inputDevice is the id of the device used for input (see PaDeviceID above.)
+ inputDevice may be paNoDevice to indicate that an input device is not required.
+
+ numInputChannels is the number of channels of sound to be delivered to the
+ callback. It can range from 1 to the value of maxInputChannels in the
+ device input record for the device specified in the inputDevice parameter.
+ If inputDevice is paNoDevice numInputChannels is ignored.
+
+ inputSampleFormat is the format of inputBuffer provided to the callback
+ function. inputSampleFormat may be any of the formats described by the
+ PaSampleFormat enumeration (see above). PortAudio guarantees support for
+ the sound devices native formats (nativeSampleFormats in the device info
+ record) and additionally 16 and 32 bit integer and 32 bit floating point
+ formats. Support for other formats is implementation defined.
+
+ inputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ inputDriverInfo is never required for correct operation. If not used
+ inputDriverInfo should be NULL.
+
+ outputDevice is the id of the device used for output (see PaDeviceID above.)
+ outputDevice may be paNoDevice to indicate that an output device is not required.
+
+ numOutputChannels is the number of channels of sound to be supplied by the
+ callback. See the definition of numInputChannels above for more details.
+
+ outputSampleFormat is the sample format of the outputBuffer filled by the
+ callback function. See the definition of inputSampleFormat above for more
+ details.
+
+ outputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ outputDriverInfo is never required for correct operation. If not used
+ outputDriverInfo should be NULL.
+
+ sampleRate is the desired sampleRate for input and output
+
+ framesPerBuffer is the length in sample frames of all internal sample buffers
+ used for communication with platform specific audio routines. Wherever
+ possible this corresponds to the framesPerBuffer parameter passed to the
+ callback function.
+
+ numberOfBuffers is the number of buffers used for multibuffered
+ communication with the platform specific audio routines. This parameter is
+ provided only as a guide - and does not imply that an implementation must
+ use multibuffered i/o when reliable double buffering is available (such as
+ SndPlayDoubleBuffer() on the Macintosh.)
+
+ streamFlags may contain a combination of flags ORed together.
+ These flags modify the behavior of the
+ streaming process. Some flags may only be relevant to certain buffer formats.
+
+ callback is a pointer to a client supplied function that is responsible
+ for processing and filling input and output buffers (see above for details.)
+
+ userData is a client supplied pointer which is passed to the callback
+ function. It could for example, contain a pointer to instance data necessary
+ for processing the audio buffers.
+
+ return value:
+ Apon success Pa_OpenStream() returns PaNoError and places a pointer to a
+ valid PortAudioStream in the stream argument. The stream is inactive (stopped).
+ If a call to Pa_OpenStream() fails a nonzero error code is returned (see
+ PAError above) and the value of stream is invalid.
+
+*/
+
+PaError Pa_OpenStream( PortAudioStream** stream,
+ PaDeviceID inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+/*
+ Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that
+ opens the default input and/or ouput devices. Most parameters have
+ identical meaning to their Pa_OpenStream() counterparts, with the following
+ exceptions:
+
+ If either numInputChannels or numOutputChannels is 0 the respective device
+ is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() )
+
+ sampleFormat applies to both the input and output buffers.
+*/
+
+PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+/*
+ Pa_CloseStream() closes an audio stream, flushing any pending buffers.
+*/
+
+PaError Pa_CloseStream( PortAudioStream* );
+
+/*
+ Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
+ Pa_StopStream() waits until all pending audio buffers have been played.
+ Pa_AbortStream() stops playing immediately without waiting for pending
+ buffers to complete.
+*/
+
+PaError Pa_StartStream( PortAudioStream *stream );
+
+PaError Pa_StopStream( PortAudioStream *stream );
+
+PaError Pa_AbortStream( PortAudioStream *stream );
+
+/*
+ Pa_StreamActive() returns one when the stream is playing audio,
+ zero when not playing, or a negative error number if the
+ stream is invalid.
+ The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
+ but may also become inactive if the callback returns a non-zero value.
+ In the latter case, the stream is considered inactive after the last
+ buffer has finished playing.
+*/
+
+PaError Pa_StreamActive( PortAudioStream *stream );
+
+/*
+ Pa_StreamTime() returns the current output time for the stream in samples.
+ This time may be used as a time reference (for example syncronising audio to
+ MIDI).
+*/
+
+PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+
+/*
+ The "CPU Load" is a fraction of total CPU time consumed by the
+ stream's audio processing.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ This function may be called from the callback function or the application.
+*/
+double Pa_GetCPULoad( PortAudioStream* stream );
+
+/*
+ Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for
+ the current host based on minimum latency.
+ On the PC, for the DirectSound implementation, latency can be optionally set
+ by user by setting an environment variable.
+ For example, to set latency to 200 msec, put:
+
+ set PA_MIN_LATENCY_MSEC=200
+
+ in the AUTOEXEC.BAT file and reboot.
+ If the environment variable is not set, then the latency will be determined
+ based on the OS. Windows NT has higher latency than Win95.
+*/
+
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
+
+/*
+ Sleep for at least 'msec' milliseconds.
+ You may sleep longer than the requested time so don't rely
+ on this for accurate musical timing.
+*/
+void Pa_Sleep( long msec );
+
+/*
+ Return size in bytes of a single sample in a given PaSampleFormat
+ or paSampleFormatNotSupported.
+*/
+PaError Pa_GetSampleSize( PaSampleFormat format );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PORT_AUDIO_H */
diff --git a/pd/portaudio/docs/portaudio_icmc2001.pdf b/pd/portaudio/docs/portaudio_icmc2001.pdf
new file mode 100644
index 00000000..dd074b7d
--- /dev/null
+++ b/pd/portaudio/docs/portaudio_icmc2001.pdf
Binary files differ
diff --git a/pd/portaudio/docs/proposals.html b/pd/portaudio/docs/proposals.html
new file mode 100644
index 00000000..0f9b8cb6
--- /dev/null
+++ b/pd/portaudio/docs/proposals.html
@@ -0,0 +1,36 @@
+<HTML>
+<HEAD>
+<TITLE>Proposed Changes to PortAudio API</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META content="Phil Burk, Ross Bencina" name=Author>
+<META content="Changes being discussed by the community of PortAudio deveopers."
+name=Description>
+<META
+content="audio, tutorial, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,"
+name=KeyWords>
+</HEAD>
+<BODY LINK="#0000ff" VLINK="#800080">&nbsp;
+<CENTER>
+<TABLE bgColor=#fada7a cols=1 width="100%">
+ <TBODY>
+ <TR>
+ <TD>
+ <CENTER>
+ <H1>Proposed Changes to PortAudio API</H1>
+ </CENTER>
+</TD></TR></TBODY></TABLE></CENTER>
+<P><A href="http://www.portaudio.com/">PortAudio Home Page</A></P>
+
+<P>Updated: July 27, 2002 </P>
+<H2>The Proposals Have Moved</H2>
+
+<p>
+All PortAudio Enhancement Proposal documentation has moved. On the web site, it is now located at:
+<A HREF="http://www.portaudio.com/docs/proposals">http://www.portaudio.com/docs/proposals</A>
+
+On the CVS server it is now located in a module named "pa_proposals".
+</p>
+
+
+</BODY>
+</HTML>
diff --git a/pd/portaudio/docs/releases.html b/pd/portaudio/docs/releases.html
new file mode 100644
index 00000000..aec80a1c
--- /dev/null
+++ b/pd/portaudio/docs/releases.html
@@ -0,0 +1,339 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="PortAudio is a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Release Notes</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio - Release Notes</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>Link to <a href="http://www.portaudio.com">PortAudio Home Page</a>
+<h2>
+<b>V18 - 5/6/02</b></h2>
+
+<blockquote>All source code and documentation now under <a href="http://www.portaudio.com/usingcvs.html">CVS</a>.
+<p>Ran most of the code through <a href="http://astyle.sourceforge.net/">AStyle</a>
+to cleanup ragged indentation caused by using different editors. Used this
+command:
+<br><tt>&nbsp;&nbsp; astyle --style=ansi -c -o --convert-tabs --indent-preprocessor
+*.c</tt></blockquote>
+
+<blockquote>Added "pa_common/pa_convert.c" for Mac OS X. Start of new conversion
+utilities.
+<p><b>ASIO</b>
+<ul>
+<li>
+New Pa_ASIO_Adaptor_Init function to init Callback adpatation variables,</li>
+
+<li>
+Cleanup of Pa_ASIO_Callback_Input</li>
+
+<li>
+Break apart device loading to debug random failure in Pa_ASIO_QueryDeviceInfo</li>
+
+<li>
+Deallocate all resources in PaHost_Term for cases where Pa_CloseStream
+is not called properly</li>
+
+<li>
+New Pa_ASIO_loadDriver that calls CoInitialize on each thread on Windows.
+Allows use by multiple threads.</li>
+
+<li>
+Correct error code management in PaHost_Term, removed various compiler
+warning</li>
+
+<li>
+Add Mac includes for &lt;Devices.h> and &lt;Timer.h></li>
+
+<li>
+Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better
+error handling</li>
+</ul>
+<b>Mac OS X</b>
+<ul>
+<li>
+Major cleanup and improvements.</li>
+
+<li>
+Fixed device queries for numChannels and sampleRates,</li>
+
+<li>
+Audio input works if using same CoreAudio device (some HW devices make
+separate CoreAudio devices).</li>
+
+<li>
+Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file.</li>
+
+<li>
+Return error if opened in mono mode cuz not supported.</li>
+
+<li>
+Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally.</li>
+
+<li>
+Use getrusage() instead of gettimeofday() for CPU Load calculation.</li>
+</ul>
+<b>Windows MME</b>
+<ul>
+<li>
+Fixed bug that caused TIMEOUT in Pa_StopStream(). Added check for past_StopSoon()
+in Pa_TimeSlice(). Thanks Julien Maillard.</li>
+
+<li>
+Detect Win XP versus NT, use lower latency.</li>
+
+<li>
+Fix DBUG typo;</li>
+
+<li>
+removed init of CurrentCount which was not compiling on Borland</li>
+
+<li>
+general cleanup, factored streamData alloc and cpu usage initialization</li>
+
+<li>
+stopped counting WAVE_MAPPER when there were no audio cards plugged in</li>
+</ul>
+<b>Windows DirectSound</b>
+<ul>
+<li>
+Detect Win XP and Win 2K properly when determining latency.</li>
+</ul>
+<b>Unix OSS</b>
+<ul>
+<li>
+Use high real-time priority if app is running with root priveledges. Lowers
+latency.</li>
+
+<li>
+Added watch dog thread that prevents real-time thread from hogging CPU
+and hanging the computer.</li>
+
+<li>
+Check error return from read() and write().</li>
+
+<li>
+Check CPU endianness instead of assuming Little Endian.</li>
+</ul>
+</blockquote>
+
+<h2>
+<b>V17 - 10/15/01</b></h2>
+
+<blockquote><b>Unix OSS</b>
+<ul>
+<li>
+Set num channels back to two after device query for ALSA. This fixed a
+bug in V16 that sometimes caused a failure when querying for the sample
+rates. Thanks Stweart Greenhill.</li>
+</ul>
+</blockquote>
+
+<blockquote>
+<h4>
+<b>Macintosh Sound Manager</b></h4>
+
+<ul>
+<li>
+Use NewSndCallBackUPP() for CARBON compatibility.</li>
+</ul>
+</blockquote>
+
+<h2>
+<b>V16 - 9/27/01</b></h2>
+
+<blockquote><b>Added Alpha implementations for ASIO, SGI, and BeOS!</b>
+<br>&nbsp;
+<li>
+CPULoad is now calculated based on the time spent to generate a known number
+of frames. This is more accurate than a simple percentage of real-time.
+Implemented in pa_unix_oss, pa_win_wmme and pa_win_ds.</li>
+
+<li>
+Fix dither and shift for recording PaUInt8 format data.</li>
+
+<li>
+Added "patest_maxsines.c" which tests <tt>Pa_GetCPULoad().</tt></li>
+</blockquote>
+
+<blockquote>
+<h4>
+Windows WMME</h4>
+
+<ul>
+<li>
+sDevicePtrs now allocated using <tt>GlobalAlloc()</tt>. This prevents a
+crash in Pa_Terminate() on Win2000. Thanks Mike Berry for finding this.
+Thanks Mike Berry.</li>
+
+<li>
+Pass process instead of thread to <tt>SetPriorityClass</tt>(). This fixes
+a bug that caused the priority to not be increased. Thanks to Alberto di
+Bene for spotting this.</li>
+</ul>
+
+<h4>
+Windows DirectSound</h4>
+
+<ul>
+<li>
+Casts for compiling with __MWERKS__ CodeWarrior.</li>
+</ul>
+
+<h4>
+UNIX OSS</h4>
+
+<ul>
+<li>
+Derived from Linux OSS implementation.</li>
+
+<li>
+Numerous patches from Heiko Purnhagen, Stephen Brandon, etc.</li>
+
+<li>
+Improved query mechanism which often bailed out unnecessarily.</li>
+
+<li>
+Removed sNumDevices and potential related bugs,</li>
+
+<li>
+Use <tt>getenv("PA_MIN_LATENCY_MSEC")</tt> in code to set desired latency.
+User can set by entering:</li>
+
+<br>&nbsp;&nbsp;&nbsp; <tt>export PA_MIN_LATENCY_MSEC=40</tt></ul>
+
+<h4>
+Macintosh Sound Manager</h4>
+
+<ul>
+<li>
+Pass unused event to WaitNextEvent instead of NULL to prevent Mac OSX crash.
+Thanks Dominic Mazzoni.</li>
+
+<li>
+Use requested number of input channels.</li>
+
+<br>&nbsp;</ul>
+</blockquote>
+
+<h2>
+<b>V15 - 5/29/01</b></h2>
+
+<blockquote>
+<ul>
+<li>
+<b>New Linux OSS Beta</b></li>
+</ul>
+
+<h4>
+Windows WMME</h4>
+
+<ul>
+<li>
+&nbsp;sDevicePtrs now allocated based on sizeof(pointer). Was allocating
+too much space.</li>
+
+<li>
+&nbsp;Check for excessive numbers of channels. Some drivers reported bogus
+numbers.</li>
+
+<li>
+Apply Mike Berry's changes for CodeWarrior on PC including condition including
+of memory.h, and explicit typecasting on memory allocation.</li>
+</ul>
+
+<h4>
+Macintosh Sound Manager</h4>
+
+<ul>
+<li>
+ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID.</li>
+
+<li>
+Device Scan was crashing for anything other than siBadSoundInDevice, but
+some Macs may return other errors! Caused failure to init on some G4s under
+OS9.</li>
+
+<li>
+Fix TIMEOUT in record mode.</li>
+
+<li>
+Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON</li>
+</ul>
+</blockquote>
+
+<h2>
+<b>V14 - 2/6/01</b></h2>
+
+<blockquote>
+<ul>
+<li>
+Added implementation for Windows MultiMedia Extensions (WMME) by Ross and
+Phil</li>
+
+<li>
+Changed Pa_StopStream() so that it waits for the buffers to drain.</li>
+
+<li>
+Added Pa_AbortStream() that stops immediately without waiting.</li>
+
+<li>
+Added new test: patest_stop.c to test above two mods.</li>
+
+<li>
+Fixed Pa_StreamTime() so that it returns current play position instead
+of the write position. Added "patest_sync.c" to demo audio/video sync.</li>
+
+<li>
+Improved stability of Macintosh implementation. Added timeouts to prevent
+hangs.</li>
+
+<li>
+Added Pa_GetSampleSize( PaSampleFormat format );</li>
+
+<li>
+Changes some "int"s to "long"s so that PA works properly on Macintosh which
+often compiles using 16 bit ints.</li>
+
+<li>
+Added Implementation Guide</li>
+</ul>
+</blockquote>
+
+<h2>
+<b>V12 - 1/9/01</b></h2>
+
+<blockquote>
+<ul>
+<li>
+Mac now scans for and queries all devices. But it does not yet support
+selecting any other than the default device.</li>
+
+<li>
+Blocking I/O calls renamed to separate them from the PortAudio API.</li>
+
+<li>
+Cleaned up indentation problems with tabs versus spaces.</li>
+
+<li>
+Now attempts to correct bogus sample rate info returned from DirectSound
+device queries.</li>
+</ul>
+</blockquote>
+
+</body>
+</html>
diff --git a/pd/portaudio/fixdir.bat b/pd/portaudio/fixdir.bat
new file mode 100755
index 00000000..92d6c747
--- /dev/null
+++ b/pd/portaudio/fixdir.bat
@@ -0,0 +1,19 @@
+rem Use Astyle to fix style in 'C' files
+cd %1%
+
+fixlines -p *.c
+fixlines -p *.cpp
+fixlines -p *.cc
+
+astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.c
+astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cpp
+astyle --style=ansi -c -o --convert-tabs --indent-preprocessor *.cc
+del *.orig
+@rem convert line terminators to Unix style LFs
+fixlines -u *.c
+fixlines -u *.cpp
+fixlines -u *.cc
+fixlines -u *.h
+del *.bak
+
+cd ..\
diff --git a/pd/portaudio/fixfile.bat b/pd/portaudio/fixfile.bat
new file mode 100755
index 00000000..48f6fbc2
--- /dev/null
+++ b/pd/portaudio/fixfile.bat
@@ -0,0 +1,7 @@
+rem Use Astyle to fix style in a file
+fixlines -p %1%
+astyle --style=ansi -c -o --convert-tabs --indent-preprocessor %1%
+del %1%.orig
+@rem convert line terminators to Unix style LFs
+fixlines -u %1%
+del %1%.bak
diff --git a/pd/portaudio/index.html b/pd/portaudio/index.html
new file mode 100644
index 00000000..91e5b4c3
--- /dev/null
+++ b/pd/portaudio/index.html
@@ -0,0 +1,89 @@
+<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <meta name="GENERATOR" content="Mozilla/4.79 [en] (Windows NT 5.0; U) [Netscape]">
+ <meta name="Author" content="Phil Burk">
+ <meta name="Description" content="PortAudio is a cross platform, open-source, audio I/O library.It provides a very simple API for recording and/or playing sound using a simple callback function.">
+ <meta name="KeyWords" content="audio, library, portable, open-source, DirectSound,sound, music, JSyn, synthesis,">
+ <title>PortAudio Implementations for DirectSound</title>
+</head>
+<body>
+&nbsp;
+<center><table COLS=1 WIDTH="100%" BGCOLOR="#FADA7A" >
+<tr>
+<td>
+<center>
+<h1>
+PortAudio - Portable Audio Library</h1></center>
+</td>
+</tr>
+</table></center>
+
+<p>Last updated 5/6/02.
+<p>PortAudio is a cross platform, <a href="#License">open-source</a>, audio
+I/O library proposed by <b>Ross Bencina</b> to the <a href="http://shoko.calarts.edu/~glmrboy/musicdsp/music-dsp.html">music-dsp</a>
+mailing list. It lets you write simple audio programs in 'C' that will
+compile and run on <b>Windows, Macintosh, Unix, BeOS</b>. PortAudio is
+intended to promote the exchange of audio synthesis software between developers
+on different platforms.
+<p>For complete information on PortAudio and to download the latest releases,
+please visit "<b><font size=+2><a href="http://www.portaudio.com">http://www.portaudio.com</a></font></b>".
+<br>&nbsp;
+<br>&nbsp;
+<center>
+<h2>
+<b><a href="docs/index.html">Click here for Documentation</a></b></h2></center>
+
+<h2>
+<b><font size=+2></font></b></h2>
+
+<h2>
+<b><font size=+2>Contacts and E-Mail List</font></b></h2>
+
+<ul>
+<li>
+If you are using or implementing PortAudio then please join the <b><font size=+1><a href="http://techweb.rfa.org/mailman/listinfo/portaudio">PortAudio
+mail list</a></font><font size=+2> </font></b>generously administered by
+<b>Bill
+Eldridge</b>.</li>
+
+<li>
+If you find bugs in one of these implementations, or have suggestions,
+please e-mail them to <a href="mailto:philburk@softsynth.com">Phil Burk</a>.</li>
+
+<li>
+If you make improvements to the library, please send them to us so we can
+incorporate the improvements.</li>
+</ul>
+
+<h2>
+<a NAME="License"></a>License</h2>
+PortAudio Portable Real-Time Audio Library
+<br>Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+<p>Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following conditions:
+<ul>
+<li>
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.</li>
+
+<li>
+Any person wishing to distribute modifications to the Software is requested
+to send the modifications to the original developer so that they can be
+incorporated into the canonical version.</li>
+</ul>
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND ON INFRINGEMENT.
+<br>IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+<br>&nbsp;
+</body>
+</html>
diff --git a/pd/portaudio/install-sh b/pd/portaudio/install-sh
new file mode 100755
index 00000000..e9de2384
--- /dev/null
+++ b/pd/portaudio/install-sh
@@ -0,0 +1,251 @@
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ chmodcmd=""
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
diff --git a/pd/portaudio/pa_asio/Callback_adaptation_.pdf b/pd/portaudio/pa_asio/Callback_adaptation_.pdf
new file mode 100644
index 00000000..76bf6786
--- /dev/null
+++ b/pd/portaudio/pa_asio/Callback_adaptation_.pdf
Binary files differ
diff --git a/pd/portaudio/pa_asio/Pa_ASIO.pdf b/pd/portaudio/pa_asio/Pa_ASIO.pdf
new file mode 100644
index 00000000..ac5ecadb
--- /dev/null
+++ b/pd/portaudio/pa_asio/Pa_ASIO.pdf
Binary files differ
diff --git a/pd/portaudio/pa_asio/borland_asio_readme.txt b/pd/portaudio/pa_asio/borland_asio_readme.txt
new file mode 100644
index 00000000..56e472b8
--- /dev/null
+++ b/pd/portaudio/pa_asio/borland_asio_readme.txt
@@ -0,0 +1,6 @@
+Steinberg's ASIO 2 SDK will compile but crash on
+initialization if compiled with a Borland compiler.
+
+The problem is described, and a solution provided on
+the following page:
+http://www.audiomulch.com/~rossb/code/calliasio \ No newline at end of file
diff --git a/pd/portaudio/pa_asio/pa_asio.cpp b/pd/portaudio/pa_asio/pa_asio.cpp
index baed8ed4..c8ba58f4 100644
--- a/pd/portaudio/pa_asio/pa_asio.cpp
+++ b/pd/portaudio/pa_asio/pa_asio.cpp
@@ -1,10 +1,10 @@
/*
- * $Id: pa_asio.cpp,v 1.7 2002/04/30 12:33:04 stephane Exp $
+ * $Id: pa_asio.cpp,v 1.7.2.30 2002/12/03 06:30:39 rossbencina Exp $
* Portable Audio I/O Library for ASIO Drivers
*
* Author: Stephane Letz
* Based on the Open Source API proposed by Ross Bencina
- * Copyright (c) 2000-2001 Stephane Letz, Phil Burk
+ * Copyright (c) 2000-2002 Stephane Letz, Phil Burk, Ross Bencina
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -57,2942 +57,2051 @@
12-04-02 Add Mac includes for <Devices.h> and <Timer.h> : Phil Burk
13-04-02 Removes another compiler warning : Stephane Letz
30-04-02 Pa_ASIO_QueryDeviceInfo bug correction, memory allocation checking, better error handling : D Viens, P Burk, S Letz
-
- TO DO :
-
- - Check Pa_StopSteam and Pa_AbortStream
- - Optimization for Input only or Ouput only (really necessary ??)
+ 12-06-02 Rehashed into new multi-api infrastructure, added support for all ASIO sample formats : Ross Bencina
+ 18-06-02 Added pa_asio.h, PaAsio_GetAvailableLatencyValues() : Ross B.
+ 21-06-02 Added SelectHostBufferSize() which selects host buffer size based on user latency parameters : Ross Bencina
+ ** NOTE maintanance history is now stored in CVS **
*/
+/** @file
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
+ @todo implement underflow/overflow streamCallback statusFlags, paNeverDropInput.
-#include "portaudio.h"
-#include "pa_host.h"
-#include "pa_trace.h"
+ @todo implement host api specific extension to set i/o buffer sizes in frames
-#include "asiosys.h"
-#include "asio.h"
-#include "asiodrivers.h"
+ @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.)
+ @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
-#if MAC
-#include <Devices.h>
-#include <Timer.h>
-#include <Math64.h>
-#else
-#include <math.h>
-#include <windows.h>
-#include <mmsystem.h>
-#endif
+ @todo implement IsFormatSupported
-enum {
- // number of input and outputs supported by the host application
- // you can change these to higher or lower values
- kMaxInputChannels = 32,
- kMaxOutputChannels = 32
-};
+ @todo work out how to implement stream stoppage from callback and
+ implement IsStreamActive properly
-/* ASIO specific device information. */
-typedef struct internalPortAudioDevice
-{
- PaDeviceInfo pad_Info;
-} internalPortAudioDevice;
+ @todo rigorously check asio return codes and convert to pa error codes
+ @todo Different channels of a multichannel stream can have different sample
+ formats, but we assume that all are the same as the first channel for now.
+ Fixing this will require the block processor to maintain per-channel
+ conversion functions - could get nasty.
-/* ASIO driver internal data storage */
-typedef struct PaHostSoundControl
-{
- // ASIOInit()
- ASIODriverInfo pahsc_driverInfo;
+ @todo investigate whether the asio processNow flag needs to be honoured
- // ASIOGetChannels()
- int32 pahsc_NumInputChannels;
- int32 pahsc_NumOutputChannels;
+ @todo handle asioMessages() callbacks in a useful way, or at least document
+ what cases we don't handle.
- // ASIOGetBufferSize() - sizes in frames per buffer
- int32 pahsc_minSize;
- int32 pahsc_maxSize;
- int32 pahsc_preferredSize;
- int32 pahsc_granularity;
+ @todo miscellaneous other FIXMEs
- // ASIOGetSampleRate()
- ASIOSampleRate pahsc_sampleRate;
+ @todo implement the following somewhere:
- // ASIOOutputReady()
- bool pahsc_postOutput;
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+*/
- // ASIOGetLatencies ()
- int32 pahsc_inputLatency;
- int32 pahsc_outputLatency;
- // ASIOCreateBuffers ()
- ASIOBufferInfo bufferInfos[kMaxInputChannels + kMaxOutputChannels]; // buffer info's
- // ASIOGetChannelInfo()
- ASIOChannelInfo pahsc_channelInfos[kMaxInputChannels + kMaxOutputChannels]; // channel info's
- // The above two arrays share the same indexing, as the data in them are linked together
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+//#include <values.h>
- // Information from ASIOGetSamplePosition()
- // data is converted to double floats for easier use, however 64 bit integer can be used, too
- double nanoSeconds;
- double samples;
- double tcSamples; // time code samples
+#include "portaudio.h"
+#include "pa_asio.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"
- // bufferSwitchTimeInfo()
- ASIOTime tInfo; // time info state
- unsigned long sysRefTime; // system reference time, when bufferSwitch() was called
+#include "asiosys.h"
+#include "asio.h"
+#include "asiodrivers.h"
- // Signal the end of processing in this example
- bool stopped;
-
- ASIOCallbacks pahsc_asioCallbacks;
-
-
- int32 pahsc_userInputBufferFrameOffset; // Position in Input user buffer
- int32 pahsc_userOutputBufferFrameOffset; // Position in Output user buffer
- int32 pahsc_hostOutputBufferFrameOffset; // Position in Output ASIO buffer
-
- int32 past_FramesPerHostBuffer; // Number of frames in ASIO buffer
-
- int32 pahsc_InputBufferOffset; // Number of null frames for input buffer alignement
- int32 pahsc_OutputBufferOffset; // Number of null frames for ouput buffer alignement
-
+/*
#if MAC
- UInt64 pahsc_EntryCount;
- UInt64 pahsc_LastExitCount;
-#elif WINDOWS
- LARGE_INTEGER pahsc_EntryCount;
- LARGE_INTEGER pahsc_LastExitCount;
-#endif
-
- PaTimestamp pahsc_NumFramesDone;
-
- internalPortAudioStream *past;
-
-} PaHostSoundControl;
-
+#include <Devices.h>
+#include <Timer.h>
+#include <Math64.h>
+#else
+*/
+/*
+#include <math.h>
+#include <windows.h>
+#include <mmsystem.h>
+*/
+/*
+#endif
+*/
-//----------------------------------------------------------
-#define PRINT(x) { printf x; fflush(stdout); }
-#define ERR_RPT(x) PRINT(x)
+/* external references */
+extern AsioDrivers* asioDrivers ;
+bool loadAsioDriver(char *name);
-#define DBUG(x) /* PRINT(x) */
-#define DBUGX(x) /* PRINT(x) /**/
/* We are trying to be compatible with CARBON but this has not been thoroughly tested. */
+/* not tested at all since new code was introduced. */
#define CARBON_COMPATIBLE (0)
-#define PA_MAX_DEVICE_INFO (32)
-
-#define MIN_INT8 (-0x80)
-#define MAX_INT8 (0x7F)
-
-#define MIN_INT8_FP ((float)-0x80)
-#define MAX_INT8_FP ((float)0x7F)
-#define MIN_INT16_FP ((float)-0x8000)
-#define MAX_INT16_FP ((float)0x7FFF)
-#define MIN_INT16 (-0x8000)
-#define MAX_INT16 (0x7FFF)
-#define MAX_INT32_FP (2147483520.0f) /* 0x0x7FFFFF80 - seems safe */
-/************************************************************************************/
-/****************** Data ************************************************************/
-/************************************************************************************/
-static int sNumDevices = 0;
-static internalPortAudioDevice sDevices[PA_MAX_DEVICE_INFO] = { 0 };
-static int32 sPaHostError = 0;
-static int sDefaultOutputDeviceID = 0;
-static int sDefaultInputDeviceID = 0;
+/* prototypes for functions declared in this file */
+
+extern "C" PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+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 CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+static signed long GetStreamReadAvailable( PaStream* stream );
+static signed long GetStreamWriteAvailable( PaStream* stream );
+
+/* our ASIO callback functions */
-PaHostSoundControl asioDriverInfo = {0};
-
-#ifdef MAC
-static bool swap = true;
-#elif WINDOWS
-static bool swap = false;
-#endif
-
-// Prototypes
static void bufferSwitch(long index, ASIOBool processNow);
static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow);
static void sampleRateChanged(ASIOSampleRate sRate);
static long asioMessages(long selector, long value, void* message, double* opt);
-static void Pa_StartUsageCalculation( internalPortAudioStream *past );
-static void Pa_EndUsageCalculation( internalPortAudioStream *past );
-
-static void Pa_ASIO_Convert_Inter_Input(
- ASIOBufferInfo* nativeBuffer,
- void* inputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
- ASIOSampleType nativeFormat,
- PaSampleFormat paFormat,
- PaStreamFlags flags,
- long index);
-
-static void Pa_ASIO_Convert_Inter_Output(
- ASIOBufferInfo* nativeBuffer,
- void* outputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
- ASIOSampleType nativeFormat,
- PaSampleFormat paFormat,
- PaStreamFlags flags,
- long index);
-
-static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer,
- ASIOSampleType nativeFormat,
- long NumInputChannels,
- long NumOuputChannels,
- long index,
- long hostFrameOffset,
- long frames);
-
-static void Pa_ASIO_Callback_Input(long index);
-static void Pa_ASIO_Callback_Output(long index, long framePerBuffer);
-static void Pa_ASIO_Callback_End();
-static void Pa_ASIO_Clear_User_Buffers();
-
-// Some external references
-extern AsioDrivers* asioDrivers ;
-bool loadAsioDriver(char *name);
-unsigned long get_sys_reference_time();
-
-/************************************************************************************/
-/****************** Macro ************************************************************/
-/************************************************************************************/
+static ASIOCallbacks asioCallbacks_ =
+ { bufferSwitch, sampleRateChanged, asioMessages, bufferSwitchTimeInfo };
-#define SwapLong(v) ((((v)>>24)&0xFF)|(((v)>>8)&0xFF00)|(((v)&0xFF00)<<8)|(((v)&0xFF)<<24)) ;
-#define SwapShort(v) ((((v)>>8)&0xFF)|(((v)&0xFF)<<8)) ;
-
-#define ClipShort(v) (((v)<MIN_INT16)?MIN_INT16:(((v)>MAX_INT16)?MAX_INT16:(v)))
-#define ClipChar(v) (((v)<MIN_INT8)?MIN_INT8:(((v)>MAX_INT8)?MAX_INT8:(v)))
-#define ClipFloat(v) (((v)<-1.0f)?-1.0f:(((v)>1.0f)?1.0f:(v)))
-
-#ifndef min
-#define min(a,b) ((a)<(b)?(a):(b))
-#endif
-
-#ifndef max
-#define max(a,b) ((a)>=(b)?(a):(b))
-#endif
+#define PA_ASIO_SET_LAST_HOST_ERROR( errorCode, errorText ) \
+ PaUtil_SetLastHostErrorInfo( paASIO, errorCode, errorText )
-static bool Pa_ASIO_loadAsioDriver(char *name)
+static const char* PaAsio_GetAsioErrorText( ASIOError asioError )
{
- #ifdef WINDOWS
- CoInitialize(0);
- #endif
- return loadAsioDriver(name);
+ const char *result;
+
+ switch( asioError ){
+ case ASE_OK:
+ case ASE_SUCCESS: result = "Success"; break;
+ case ASE_NotPresent: result = "Hardware input or output is not present or available"; break;
+ case ASE_HWMalfunction: result = "Hardware is malfunctioning"; break;
+ case ASE_InvalidParameter: result = "Input parameter invalid"; break;
+ case ASE_InvalidMode: result = "Hardware is in a bad mode or used in a bad mode"; break;
+ case ASE_SPNotAdvancing: result = "Hardware is not running when sample position is inquired"; break;
+ case ASE_NoClock: result = "Sample clock or rate cannot be determined or is not present"; break;
+ case ASE_NoMemory: result = "Not enough memory for completing the request"; break;
+ default: result = "Unknown ASIO error"; break;
+ }
+
+ return result;
}
-
-// Utilities for alignement buffer size computation
-static int PGCD (int a, int b) {return (b == 0) ? a : PGCD (b,a%b);}
-static int PPCM (int a, int b) {return (a*b) / PGCD (a,b);}
+#define PA_ASIO_SET_LAST_ASIO_ERROR( asioError ) \
+ PaUtil_SetLastHostErrorInfo( paASIO, asioError, PaAsio_GetAsioErrorText( asioError ) )
+
-// Takes the size of host buffer and user buffer : returns the number of frames needed for buffer alignement
-static int Pa_ASIO_CalcFrameShift (int M, int N)
-{
- int res = 0;
- for (int i = M; i < PPCM (M,N) ; i+=M) { res = max (res, i%N); }
- return res;
-}
+/* PaAsioHostApiRepresentation - host api datastructure specific to this implementation */
-// We have the following relation :
-// Pa_ASIO_CalcFrameShift (M,N) + M = Pa_ASIO_CalcFrameShift (N,M) + N
-
-/* ASIO sample type to PortAudio sample type conversion */
-static PaSampleFormat Pa_ASIO_Convert_SampleFormat(ASIOSampleType type)
+typedef struct
{
- switch (type) {
-
- case ASIOSTInt16MSB:
- case ASIOSTInt16LSB:
- case ASIOSTInt32MSB16:
- case ASIOSTInt32LSB16:
- return paInt16;
-
- case ASIOSTFloat32MSB:
- case ASIOSTFloat32LSB:
- case ASIOSTFloat64MSB:
- case ASIOSTFloat64LSB:
- return paFloat32;
-
- case ASIOSTInt32MSB:
- case ASIOSTInt32LSB:
- case ASIOSTInt32MSB18:
- case ASIOSTInt32MSB20:
- case ASIOSTInt32MSB24:
- case ASIOSTInt32LSB18:
- case ASIOSTInt32LSB20:
- case ASIOSTInt32LSB24:
- return paInt32;
-
- case ASIOSTInt24MSB:
- case ASIOSTInt24LSB:
- return paInt24;
-
- default:
- return paCustomFormat;
- }
-}
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
-/* Allocate ASIO buffers, initialise channels */
-static ASIOError Pa_ASIO_CreateBuffers (PaHostSoundControl *asioDriverInfo, long InputChannels,
- long OutputChannels, long framesPerBuffer)
-{
- ASIOError err;
- int i;
-
- ASIOBufferInfo *info = asioDriverInfo->bufferInfos;
-
- // Check parameters
- if ((InputChannels > kMaxInputChannels) || (OutputChannels > kMaxInputChannels)) return ASE_InvalidParameter;
-
- for(i = 0; i < InputChannels; i++, info++){
- info->isInput = ASIOTrue;
- info->channelNum = i;
- info->buffers[0] = info->buffers[1] = 0;
- }
-
- for(i = 0; i < OutputChannels; i++, info++){
- info->isInput = ASIOFalse;
- info->channelNum = i;
- info->buffers[0] = info->buffers[1] = 0;
- }
-
- // Set up the asioCallback structure and create the ASIO data buffer
- asioDriverInfo->pahsc_asioCallbacks.bufferSwitch = &bufferSwitch;
- asioDriverInfo->pahsc_asioCallbacks.sampleRateDidChange = &sampleRateChanged;
- asioDriverInfo->pahsc_asioCallbacks.asioMessage = &asioMessages;
- asioDriverInfo->pahsc_asioCallbacks.bufferSwitchTimeInfo = &bufferSwitchTimeInfo;
-
- DBUG(("PortAudio : ASIOCreateBuffers with size = %ld \n", framesPerBuffer));
-
- err = ASIOCreateBuffers( asioDriverInfo->bufferInfos, InputChannels+OutputChannels,
- framesPerBuffer, &asioDriverInfo->pahsc_asioCallbacks);
- if (err != ASE_OK) return err;
-
- // Initialise buffers
- for (i = 0; i < InputChannels + OutputChannels; i++)
- {
- asioDriverInfo->pahsc_channelInfos[i].channel = asioDriverInfo->bufferInfos[i].channelNum;
- asioDriverInfo->pahsc_channelInfos[i].isInput = asioDriverInfo->bufferInfos[i].isInput;
- err = ASIOGetChannelInfo(&asioDriverInfo->pahsc_channelInfos[i]);
- if (err != ASE_OK) break;
- }
+ PaUtilAllocationGroup *allocations;
- err = ASIOGetLatencies(&asioDriverInfo->pahsc_inputLatency, &asioDriverInfo->pahsc_outputLatency);
-
- DBUG(("PortAudio : InputLatency = %ld latency = %ld msec \n",
- asioDriverInfo->pahsc_inputLatency,
- (long)((asioDriverInfo->pahsc_inputLatency*1000)/ asioDriverInfo->past->past_SampleRate)));
- DBUG(("PortAudio : OuputLatency = %ld latency = %ld msec \n",
- asioDriverInfo->pahsc_outputLatency,
- (long)((asioDriverInfo->pahsc_outputLatency*1000)/ asioDriverInfo->past->past_SampleRate)));
-
- return err;
+ /* the ASIO C API only allows one ASIO driver to be open at a time,
+ so we kee track of whether we have the driver open here, and
+ use this information to return errors from OpenStream if the
+ driver is already open.
+ */
+ int driverOpen;
}
+PaAsioHostApiRepresentation;
/*
- Query ASIO driver info :
-
- First we get all available ASIO drivers located in the ASIO folder,
- then try to load each one. For each loaded driver, get all needed informations.
+ Retrieve <driverCount> driver names from ASIO, returned in a char**
+ allocated in <group>.
*/
-static PaError Pa_ASIO_QueryDeviceInfo( internalPortAudioDevice * ipad )
+static char **GetAsioDriverNames( PaUtilAllocationGroup *group, long driverCount )
{
+ char **result = 0;
+ int i;
+
+ result =(char**)PaUtil_GroupAllocateMemory(
+ group, sizeof(char*) * driverCount );
+ if( !result )
+ goto error;
-#define NUM_STANDARDSAMPLINGRATES 3 /* 11.025, 22.05, 44.1 */
-#define NUM_CUSTOMSAMPLINGRATES 9 /* must be the same number of elements as in the array below */
-#define MAX_NUMSAMPLINGRATES (NUM_STANDARDSAMPLINGRATES+NUM_CUSTOMSAMPLINGRATES)
+ result[0] = (char*)PaUtil_GroupAllocateMemory(
+ group, 32 * driverCount );
+ if( !result[0] )
+ goto error;
- ASIOSampleRate possibleSampleRates[]
- = {8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0};
-
- ASIOChannelInfo channelInfos;
- long InputChannels,OutputChannels;
- double *sampleRates;
- char* names[PA_MAX_DEVICE_INFO] ;
- PaDeviceInfo *dev;
- int i;
- int numDrivers;
- ASIOError asioError;
-
- /* Allocate names */
- for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) {
- names[i] = (char*)PaHost_AllocateFastMemory(32);
- /* check memory */
- if(!names[i]) return paInsufficientMemory;
- }
-
- /* MUST BE CHECKED : to force fragments loading on Mac */
- Pa_ASIO_loadAsioDriver("dummy");
-
- /* Get names of all available ASIO drivers */
- asioDrivers->getDriverNames(names,PA_MAX_DEVICE_INFO);
-
- /* Check all available ASIO drivers */
-#if MAC
- numDrivers = asioDrivers->getNumFragments();
-#elif WINDOWS
- numDrivers = asioDrivers->asioGetNumDev();
-#endif
- DBUG(("PaASIO_QueryDeviceInfo: numDrivers = %d\n", numDrivers ));
+ for( i=0; i<driverCount; ++i )
+ result[i] = result[0] + (32 * i);
- for (int driver = 0 ; driver < numDrivers ; driver++)
- {
+ asioDrivers->getDriverNames( result, driverCount );
- #if WINDOWS
- asioDriverInfo.pahsc_driverInfo.asioVersion = 2; // FIXME - is this right? PLB
- asioDriverInfo.pahsc_driverInfo.sysRef = GetDesktopWindow(); // FIXME - is this right? PLB
- #endif
-
- /* If the driver can be loaded : */
- if ( !Pa_ASIO_loadAsioDriver(names[driver]) )
- {
- DBUG(("PaASIO_QueryDeviceInfo could not loadAsioDriver %s\n", names[driver]));
- }
- else if( (asioError = ASIOInit(&asioDriverInfo.pahsc_driverInfo)) != ASE_OK )
- {
- DBUG(("PaASIO_QueryDeviceInfo: ASIOInit returned %d for %s\n", asioError, names[driver]));
- }
- else if( (ASIOGetChannels(&InputChannels, &OutputChannels) != ASE_OK))
- {
- DBUG(("PaASIO_QueryDeviceInfo could not ASIOGetChannels for %s\n", names[driver]));
- }
- else
- {
- /* Gets the name */
- dev = &(ipad[sNumDevices].pad_Info);
- dev->name = names[driver];
- names[driver] = 0;
-
- /* Gets Input and Output channels number */
- dev->maxInputChannels = InputChannels;
- dev->maxOutputChannels = OutputChannels;
-
- DBUG(("PaASIO_QueryDeviceInfo: InputChannels = %d\n", InputChannels ));
- DBUG(("PaASIO_QueryDeviceInfo: OutputChannels = %d\n", OutputChannels ));
-
- /* Make room in case device supports all rates. */
- sampleRates = (double*)PaHost_AllocateFastMemory(MAX_NUMSAMPLINGRATES * sizeof(double));
- /* check memory */
- if (!sampleRates) {
- ASIOExit();
- return paInsufficientMemory;
- }
- dev->sampleRates = sampleRates;
- dev->numSampleRates = 0;
-
- /* Loop through the possible sampling rates and check each to see if the device supports it. */
- for (int index = 0; index < MAX_NUMSAMPLINGRATES; index++) {
- if (ASIOCanSampleRate(possibleSampleRates[index]) != ASE_NoClock) {
- DBUG(("PortAudio : possible sample rate = %d\n", (long)possibleSampleRates[index]));
- dev->numSampleRates += 1;
- *sampleRates = possibleSampleRates[index];
- sampleRates++;
- }
- }
-
- /* We assume that all channels have the same SampleType, so check the first */
- channelInfos.channel = 0;
- channelInfos.isInput = 1;
- ASIOGetChannelInfo(&channelInfos);
-
- dev->nativeSampleFormats = Pa_ASIO_Convert_SampleFormat(channelInfos.type);
-
- /* unload the driver */
- ASIOExit();
- sNumDevices++;
- }
- }
-
- /* free only unused names */
- for (i = 0 ; i < PA_MAX_DEVICE_INFO ; i++) if (names[i]) PaHost_FreeFastMemory(names[i],32);
-
- return paNoError;
+error:
+ return result;
}
-//----------------------------------------------------------------------------------
-// TAKEN FROM THE ASIO SDK:
-static void sampleRateChanged(ASIOSampleRate sRate)
-{
- // do whatever you need to do if the sample rate changed
- // usually this only happens during external sync.
- // Audio processing is not stopped by the driver, actual sample rate
- // might not have even changed, maybe only the sample rate status of an
- // AES/EBU or S/PDIF digital input at the audio device.
- // You might have to update time/sample related conversion routines, etc.
-}
-//----------------------------------------------------------------------------------
-// TAKEN FROM THE ASIO SDK:
-long asioMessages(long selector, long value, void* message, double* opt)
+static PaSampleFormat AsioSampleTypeToPaNativeSampleFormat(ASIOSampleType type)
{
- // currently the parameters "value", "message" and "opt" are not used.
- long ret = 0;
- switch(selector)
- {
- case kAsioSelectorSupported:
- if(value == kAsioResetRequest
- || value == kAsioEngineVersion
- || value == kAsioResyncRequest
- || value == kAsioLatenciesChanged
- // the following three were added for ASIO 2.0, you don't necessarily have to support them
- || value == kAsioSupportsTimeInfo
- || value == kAsioSupportsTimeCode
- || value == kAsioSupportsInputMonitor)
- ret = 1L;
- break;
-
- case kAsioBufferSizeChange:
- //printf("kAsioBufferSizeChange \n");
- break;
-
- case kAsioResetRequest:
- // defer the task and perform the reset of the driver during the next "safe" situation
- // You cannot reset the driver right now, as this code is called from the driver.
- // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
- // Afterwards you initialize the driver again.
- asioDriverInfo.stopped; // In this sample the processing will just stop
- ret = 1L;
- break;
- case kAsioResyncRequest:
- // This informs the application, that the driver encountered some non fatal data loss.
- // It is used for synchronization purposes of different media.
- // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
- // Windows Multimedia system, which could loose data because the Mutex was hold too long
- // by another thread.
- // However a driver can issue it in other situations, too.
- ret = 1L;
- break;
- case kAsioLatenciesChanged:
- // This will inform the host application that the drivers were latencies changed.
- // Beware, it this does not mean that the buffer sizes have changed!
- // You might need to update internal delay data.
- ret = 1L;
- //printf("kAsioLatenciesChanged \n");
- break;
- case kAsioEngineVersion:
- // return the supported ASIO version of the host application
- // If a host applications does not implement this selector, ASIO 1.0 is assumed
- // by the driver
- ret = 2L;
- break;
- case kAsioSupportsTimeInfo:
- // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
- // is supported.
- // For compatibility with ASIO 1.0 drivers the host application should always support
- // the "old" bufferSwitch method, too.
- ret = 1;
- break;
- case kAsioSupportsTimeCode:
- // informs the driver wether application is interested in time code info.
- // If an application does not need to know about time code, the driver has less work
- // to do.
- ret = 0;
- break;
- }
- return ret;
-}
+ switch (type) {
+ case ASIOSTInt16MSB:
+ case ASIOSTInt16LSB:
+ return paInt16;
+ case ASIOSTFloat32MSB:
+ case ASIOSTFloat32LSB:
+ case ASIOSTFloat64MSB:
+ case ASIOSTFloat64LSB:
+ return paFloat32;
-//----------------------------------------------------------------------------------
-// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
-#if NATIVE_INT64
- #define ASIO64toDouble(a) (a)
-#else
- const double twoRaisedTo32 = 4294967296.;
- #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
-#endif
+ case ASIOSTInt32MSB:
+ case ASIOSTInt32LSB:
+ case ASIOSTInt32MSB16:
+ case ASIOSTInt32LSB16:
+ case ASIOSTInt32MSB18:
+ case ASIOSTInt32MSB20:
+ case ASIOSTInt32MSB24:
+ case ASIOSTInt32LSB18:
+ case ASIOSTInt32LSB20:
+ case ASIOSTInt32LSB24:
+ return paInt32;
+ case ASIOSTInt24MSB:
+ case ASIOSTInt24LSB:
+ return paInt24;
-static ASIOTime *bufferSwitchTimeInfo(ASIOTime *timeInfo, long index, ASIOBool processNow)
-{
- // the actual processing callback.
- // Beware that this is normally in a seperate thread, hence be sure that you take care
- // about thread synchronization. This is omitted here for simplicity.
-
- // static processedSamples = 0;
- int result = 0;
-
- // store the timeInfo for later use
- asioDriverInfo.tInfo = *timeInfo;
-
- // get the time stamp of the buffer, not necessary if no
- // synchronization to other media is required
-
- if (timeInfo->timeInfo.flags & kSystemTimeValid)
- asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
- else
- asioDriverInfo.nanoSeconds = 0;
-
- if (timeInfo->timeInfo.flags & kSamplePositionValid)
- asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
- else
- asioDriverInfo.samples = 0;
+ default:
+ return paCustomFormat;
+ }
+}
- if (timeInfo->timeCode.flags & kTcValid)
- asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
- else
- asioDriverInfo.tcSamples = 0;
- // get the system reference time
- asioDriverInfo.sysRefTime = get_sys_reference_time();
+static int BytesPerAsioSample( ASIOSampleType sampleType )
+{
+ switch (sampleType) {
+ case ASIOSTInt16MSB:
+ case ASIOSTInt16LSB:
+ return 2;
-#if 0
- // a few debug messages for the Windows device driver developer
- // tells you the time when driver got its interrupt and the delay until the app receives
- // the event notification.
- static double last_samples = 0;
- char tmp[128];
- sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples));
- OutputDebugString (tmp);
- last_samples = asioDriverInfo.samples;
-#endif
+ case ASIOSTFloat64MSB:
+ case ASIOSTFloat64LSB:
+ return 8;
- // To avoid the callback accessing a desallocated stream
- if( asioDriverInfo.past == NULL) return 0L;
+ case ASIOSTFloat32MSB:
+ case ASIOSTFloat32LSB:
+ case ASIOSTInt32MSB:
+ case ASIOSTInt32LSB:
+ case ASIOSTInt32MSB16:
+ case ASIOSTInt32LSB16:
+ case ASIOSTInt32MSB18:
+ case ASIOSTInt32MSB20:
+ case ASIOSTInt32MSB24:
+ case ASIOSTInt32LSB18:
+ case ASIOSTInt32LSB20:
+ case ASIOSTInt32LSB24:
+ return 4;
- // Keep sample position
- asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo;
+ case ASIOSTInt24MSB:
+ case ASIOSTInt24LSB:
+ return 3;
- /* Has a user callback returned '1' to indicate finished at the last ASIO callback? */
- if( asioDriverInfo.past->past_StopSoon ) {
-
- Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos,
- asioDriverInfo.pahsc_channelInfos[0].type,
- asioDriverInfo.pahsc_NumInputChannels ,
- asioDriverInfo.pahsc_NumOutputChannels,
- index,
- 0,
- asioDriverInfo.past_FramesPerHostBuffer);
-
- asioDriverInfo.past->past_IsActive = 0;
-
- // Finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
- if (asioDriverInfo.pahsc_postOutput) ASIOOutputReady();
-
- }else {
-
- /* CPU usage */
- Pa_StartUsageCalculation(asioDriverInfo.past);
-
- Pa_ASIO_Callback_Input(index);
-
- // Finally if the driver supports the ASIOOutputReady() optimization, do it here, all data are in place
- if (asioDriverInfo.pahsc_postOutput) ASIOOutputReady();
-
- Pa_ASIO_Callback_End();
-
- /* CPU usage */
- Pa_EndUsageCalculation(asioDriverInfo.past);
- }
-
- return 0L;
+ default:
+ return 0;
+ }
}
-//----------------------------------------------------------------------------------
-void bufferSwitch(long index, ASIOBool processNow)
-{
- // the actual processing callback.
- // Beware that this is normally in a seperate thread, hence be sure that you take care
- // about thread synchronization. This is omitted here for simplicity.
-
- // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs to be created
- // though it will only set the timeInfo.samplePosition and timeInfo.systemTime fields and the according flags
-
- ASIOTime timeInfo;
- memset (&timeInfo, 0, sizeof (timeInfo));
+static void Swap16( void *buffer, long shift, long count )
+{
+ unsigned short *p = (unsigned short*)buffer;
+ unsigned short temp;
+ (void) shift; /* unused parameter */
- // get the time stamp of the buffer, not necessary if no
- // synchronization to other media is required
- if(ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
- timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
-
- // Call the real callback
- bufferSwitchTimeInfo (&timeInfo, index, processNow);
+ while( count-- )
+ {
+ temp = *p;
+ *p++ = (unsigned short)((temp<<8) | (temp>>8));
+ }
}
-//----------------------------------------------------------------------------------
-unsigned long get_sys_reference_time()
-{
- // get the system reference time
- #if WINDOWS
- return timeGetTime();
- #elif MAC
- static const double twoRaisedTo32 = 4294967296.;
- UnsignedWide ys;
- Microseconds(&ys);
- double r = ((double)ys.hi * twoRaisedTo32 + (double)ys.lo);
- return (unsigned long)(r / 1000.);
- #endif
+static void Swap24( void *buffer, long shift, long count )
+{
+ unsigned char *p = (unsigned char*)buffer;
+ unsigned char temp;
+ (void) shift; /* unused parameter */
+
+ while( count-- )
+ {
+ temp = *p;
+ *p = *(p+2);
+ *(p+2) = temp;
+ p += 3;
+ }
}
+#define PA_SWAP32_( x ) ((x>>24) | ((x>>8)&0xFF00) | ((x<<8)&0xFF0000) | (x<<24));
-/*************************************************************
-** Calculate 2 LSB dither signal with a triangular distribution.
-** Ranged properly for adding to a 32 bit integer prior to >>15.
-*/
-#define DITHER_BITS (15)
-#define DITHER_SCALE (1.0f / ((1<<DITHER_BITS)-1))
-inline static long Pa_TriangularDither( void )
+static void Swap32( void *buffer, long shift, long count )
{
- static unsigned long previous = 0;
- static unsigned long randSeed1 = 22222;
- static unsigned long randSeed2 = 5555555;
- long current, highPass;
-/* Generate two random numbers. */
- randSeed1 = (randSeed1 * 196314165) + 907633515;
- randSeed2 = (randSeed2 * 196314165) + 907633515;
-/* Generate triangular distribution about 0. */
- current = (((long)randSeed1)>>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS));
- /* High pass filter to reduce audibility. */
- highPass = current - previous;
- previous = current;
- return highPass;
-}
+ unsigned long *p = (unsigned long*)buffer;
+ unsigned long temp;
+ (void) shift; /* unused parameter */
-// TO BE COMPLETED WITH ALL SUPPORTED PA SAMPLE TYPES
+ while( count-- )
+ {
+ temp = *p;
+ *p++ = PA_SWAP32_( temp);
+ }
+}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+static void SwapShiftLeft32( void *buffer, long shift, long count )
{
- long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- float *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- *userBufPtr = (1.0f / MAX_INT16_FP) * temp;
- userBufPtr += NumInputChannels;
- }
- }
-
+ unsigned long *p = (unsigned long*)buffer;
+ unsigned long temp;
+
+ while( count-- )
+ {
+ temp = *p;
+ temp = PA_SWAP32_( temp);
+ *p++ = temp << shift;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+static void ShiftRightSwap32( void *buffer, long shift, long count )
{
- long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- float *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (1.0f / MAX_INT32_FP) * temp;
- userBufPtr += NumInputChannels;
- }
- }
+ unsigned long *p = (unsigned long*)buffer;
+ unsigned long temp;
+
+ while( count-- )
+ {
+ temp = *p >> shift;
+ *p++ = PA_SWAP32_( temp);
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
-static void Input_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+static void ShiftLeft32( void *buffer, long shift, long count )
{
- unsigned long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- float *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (float)temp;
- userBufPtr += NumInputChannels;
- }
- }
+ unsigned long *p = (unsigned long*)buffer;
+ unsigned long temp;
+
+ while( count-- )
+ {
+ temp = *p;
+ *p++ = temp << shift;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+static void ShiftRight32( void *buffer, long shift, long count )
{
- long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- long *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- *userBufPtr = temp<<16;
- userBufPtr += NumInputChannels;
- }
- }
+ unsigned long *p = (unsigned long*)buffer;
+ unsigned long temp;
+
+ while( count-- )
+ {
+ temp = *p;
+ *p++ = temp >> shift;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+#define PA_SWAP_( x, y ) temp=x; x = y; y = temp;
+
+static void Swap64ConvertFloat64ToFloat32( void *buffer, long shift, long count )
{
- long temp;
- int i,j;
+ double *in = (double*)buffer;
+ float *out = (float*)buffer;
+ unsigned char *p;
+ unsigned char temp;
+ (void) shift; /* unused parameter */
+
+ while( count-- )
+ {
+ p = (unsigned char*)in;
+ PA_SWAP_( p[0], p[7] );
+ PA_SWAP_( p[1], p[6] );
+ PA_SWAP_( p[2], p[5] );
+ PA_SWAP_( p[3], p[4] );
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- long *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = temp;
- userBufPtr += NumInputChannels;
- }
- }
+ *out++ = (float) (*in++);
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
-static void Input_Float32_Int32 (ASIOBufferInfo* nativeBuffer, long *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
+static void ConvertFloat64ToFloat32( void *buffer, long shift, long count )
{
- unsigned long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- long *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (long)((float)temp * MAX_INT32_FP); // Is temp a value between -1.0 and 1.0 ??
- userBufPtr += NumInputChannels;
- }
- }
-}
-
+ double *in = (double*)buffer;
+ float *out = (float*)buffer;
+ (void) shift; /* unused parameter */
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,bool swap)
-{
- long temp;
- int i,j;
-
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- *userBufPtr = (short)temp;
- userBufPtr += NumInputChannels;
- }
- }
+ while( count-- )
+ *out++ = (float) (*in++);
}
-
- //-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
+
+static void ConvertFloat32ToFloat64Swap64( void *buffer, long shift, long count )
{
- long temp;
- int i,j;
+ float *in = ((float*)buffer) + (count-1);
+ double *out = ((double*)buffer) + (count-1);
+ unsigned char *p;
+ unsigned char temp;
+ (void) shift; /* unused parameter */
+
+ while( count-- )
+ {
+ *out = *in--;
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (short)(temp>>16);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = (temp >> 1) + Pa_TriangularDither();
- temp = temp >> 15;
- temp = (short) ClipShort(temp);
- *userBufPtr = (short)temp;
- userBufPtr += NumInputChannels;
- }
- }
+ p = (unsigned char*)out;
+ PA_SWAP_( p[0], p[7] );
+ PA_SWAP_( p[1], p[6] );
+ PA_SWAP_( p[2], p[5] );
+ PA_SWAP_( p[3], p[4] );
- }
+ out--;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
-static void Input_Float32_Int16 (ASIOBufferInfo* nativeBuffer, short *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
+static void ConvertFloat32ToFloat64( void *buffer, long shift, long count )
{
- unsigned long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (short)((float)temp * MAX_INT16_FP); // Is temp a value between -1.0 and 1.0 ??
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- short *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = (short)(((float)temp * MAX_INT16_FP) + dither);
- temp = ClipShort(temp);
- *userBufPtr = (short)temp;
- userBufPtr += NumInputChannels;
- }
- }
- }
+ float *in = ((float*)buffer) + (count-1);
+ double *out = ((double*)buffer) + (count-1);
+ (void) shift; /* unused parameter */
+
+ while( count-- )
+ *out-- = *in--;
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+#ifdef MAC
+#define PA_MSB_IS_NATIVE_
+#undef PA_LSB_IS_NATIVE_
+#endif
+
+#ifdef WINDOWS
+#undef PA_MSB_IS_NATIVE_
+#define PA_LSB_IS_NATIVE_
+#endif
+
+typedef void PaAsioBufferConverter( void *, long, long );
+
+static void SelectAsioToPaConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
{
- long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- *userBufPtr = (char)(temp>>8);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- temp += Pa_TriangularDither() >> 8;
- temp = ClipShort(temp);
- *userBufPtr = (char)(temp>>8);
- userBufPtr += NumInputChannels;
- }
- }
- }
+ *shift = 0;
+ *converter = 0;
+
+ switch (type) {
+ case ASIOSTInt16MSB:
+ /* dest: paInt16, no conversion necessary, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap16;
+ #endif
+ break;
+ case ASIOSTInt16LSB:
+ /* dest: paInt16, no conversion necessary, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap16;
+ #endif
+ break;
+ case ASIOSTFloat32MSB:
+ /* dest: paFloat32, no conversion necessary, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTFloat32LSB:
+ /* dest: paFloat32, no conversion necessary, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTFloat64MSB:
+ /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap64ConvertFloat64ToFloat32;
+ #else
+ *converter = ConvertFloat64ToFloat32;
+ #endif
+ break;
+ case ASIOSTFloat64LSB:
+ /* dest: paFloat32, in-place conversion to/from float32, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap64ConvertFloat64ToFloat32;
+ #else
+ *converter = ConvertFloat64ToFloat32;
+ #endif
+ break;
+ case ASIOSTInt32MSB:
+ /* dest: paInt32, no conversion necessary, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTInt32LSB:
+ /* dest: paInt32, no conversion necessary, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTInt32MSB16:
+ /* dest: paInt32, 16 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 16;
+ break;
+ case ASIOSTInt32MSB18:
+ /* dest: paInt32, 14 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 14;
+ break;
+ case ASIOSTInt32MSB20:
+ /* dest: paInt32, 12 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 12;
+ break;
+ case ASIOSTInt32MSB24:
+ /* dest: paInt32, 8 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 8;
+ break;
+ case ASIOSTInt32LSB16:
+ /* dest: paInt32, 16 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 16;
+ break;
+ case ASIOSTInt32LSB18:
+ /* dest: paInt32, 14 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 14;
+ break;
+ case ASIOSTInt32LSB20:
+ /* dest: paInt32, 12 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 12;
+ break;
+ case ASIOSTInt32LSB24:
+ /* dest: paInt32, 8 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = SwapShiftLeft32;
+ #else
+ *converter = ShiftLeft32;
+ #endif
+ *shift = 8;
+ break;
+ case ASIOSTInt24MSB:
+ /* dest: paInt24, no conversion necessary, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap24;
+ #endif
+ break;
+ case ASIOSTInt24LSB:
+ /* dest: paInt24, no conversion necessary, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap24;
+ #endif
+ break;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset, uint32 flags,bool swap)
+
+static void SelectPaToAsioConverter( ASIOSampleType type, PaAsioBufferConverter **converter, long *shift )
{
- long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (char)(temp>>24);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = temp>>16; // Shift to get a 16 bit value, then use the 16 bits to 8 bits code (MUST BE CHECHED)
- temp += Pa_TriangularDither() >> 8;
- temp = ClipShort(temp);
- *userBufPtr = (char)(temp >> 8);
- userBufPtr += NumInputChannels;
- }
- }
- }
+ *shift = 0;
+ *converter = 0;
+
+ switch (type) {
+ case ASIOSTInt16MSB:
+ /* src: paInt16, no conversion necessary, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap16;
+ #endif
+ break;
+ case ASIOSTInt16LSB:
+ /* src: paInt16, no conversion necessary, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap16;
+ #endif
+ break;
+ case ASIOSTFloat32MSB:
+ /* src: paFloat32, no conversion necessary, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTFloat32LSB:
+ /* src: paFloat32, no conversion necessary, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTFloat64MSB:
+ /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = ConvertFloat32ToFloat64Swap64;
+ #else
+ *converter = ConvertFloat32ToFloat64;
+ #endif
+ break;
+ case ASIOSTFloat64LSB:
+ /* src: paFloat32, in-place conversion to/from float32, possible byte swap*/
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = ConvertFloat32ToFloat64Swap64;
+ #else
+ *converter = ConvertFloat32ToFloat64;
+ #endif
+ break;
+ case ASIOSTInt32MSB:
+ /* src: paInt32, no conversion necessary, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTInt32LSB:
+ /* src: paInt32, no conversion necessary, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap32;
+ #endif
+ break;
+ case ASIOSTInt32MSB16:
+ /* src: paInt32, 16 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 16;
+ break;
+ case ASIOSTInt32MSB18:
+ /* src: paInt32, 14 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 14;
+ break;
+ case ASIOSTInt32MSB20:
+ /* src: paInt32, 12 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 12;
+ break;
+ case ASIOSTInt32MSB24:
+ /* src: paInt32, 8 bit shift, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 8;
+ break;
+ case ASIOSTInt32LSB16:
+ /* src: paInt32, 16 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 16;
+ break;
+ case ASIOSTInt32LSB18:
+ /* src: paInt32, 14 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 14;
+ break;
+ case ASIOSTInt32LSB20:
+ /* src: paInt32, 12 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 12;
+ break;
+ case ASIOSTInt32LSB24:
+ /* src: paInt32, 8 bit shift, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = ShiftRightSwap32;
+ #else
+ *converter = ShiftRight32;
+ #endif
+ *shift = 8;
+ break;
+ case ASIOSTInt24MSB:
+ /* src: paInt24, no conversion necessary, possible byte swap */
+ #ifdef PA_LSB_IS_NATIVE_
+ *converter = Swap24;
+ #endif
+ break;
+ case ASIOSTInt24LSB:
+ /* src: paInt24, no conversion necessary, possible byte swap */
+ #ifdef PA_MSB_IS_NATIVE_
+ *converter = Swap24;
+ #endif
+ break;
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
-static void Input_Float32_Int8 (ASIOBufferInfo* nativeBuffer, char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+typedef struct PaAsioDeviceInfo
{
- unsigned long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (char)((float)temp*MAX_INT8_FP); // Is temp a value between -1.0 and 1.0 ??
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = (char)(((float)temp * MAX_INT8_FP) + dither);
- temp = ClipChar(temp);
- *userBufPtr = (char)temp;
- userBufPtr += NumInputChannels;
- }
- }
- }
+ PaDeviceInfo commonDeviceInfo;
+ long minBufferSize;
+ long maxBufferSize;
+ long preferredBufferSize;
+ long bufferGranularity;
}
+PaAsioDeviceInfo;
+
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int16_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
+PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device,
+ long *minLatency, long *maxLatency, long *preferredLatency, long *granularity )
{
- long temp;
- int i,j;
+ PaError result;
+ PaUtilHostApiRepresentation *hostApi;
+ PaDeviceIndex hostApiDevice;
+
+ result = PaUtil_GetHostApiRepresentation( &hostApi, paASIO );
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- *userBufPtr = (unsigned char)((temp>>8) + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapShort(temp);
- temp += Pa_TriangularDither() >> 8;
- temp = ClipShort(temp);
- *userBufPtr = (unsigned char)((temp>>8) + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
- }
-}
+ if( result == paNoError )
+ {
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice, device, hostApi );
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Input_Int32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
-{
- long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (unsigned char)((temp>>24) + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
+ if( result == paNoError )
{
- for( j=0; j<NumInputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = temp>>16; // Shift to get a 16 bit value, then use the 16 bits to 8 bits code (MUST BE CHECHED)
- temp += Pa_TriangularDither() >> 8;
- temp = ClipShort(temp);
- *userBufPtr = (unsigned char)((temp>>8) + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
+ PaAsioDeviceInfo *asioDeviceInfo =
+ (PaAsioDeviceInfo*)hostApi->deviceInfos[hostApiDevice];
+
+ *minLatency = asioDeviceInfo->minBufferSize;
+ *maxLatency = asioDeviceInfo->maxBufferSize;
+ *preferredLatency = asioDeviceInfo->preferredBufferSize;
+ *granularity = asioDeviceInfo->bufferGranularity;
}
+ }
+
+ return result;
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
-static void Input_Float32_IntU8 (ASIOBufferInfo* nativeBuffer, unsigned char *inBufPtr, int framePerBuffer, int NumInputChannels, int index, int hostFrameOffset,int userFrameOffset, uint32 flags,bool swap)
-{
- unsigned long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- *userBufPtr = (unsigned char)(((float)temp*MAX_INT8_FP) + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
- }
- else
- {
- for( j=0; j<NumInputChannels; j++ ) {
- unsigned long *asioBufPtr = &((unsigned long*)nativeBuffer[j].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &inBufPtr[j+(userFrameOffset*NumInputChannels)];
- for (i= 0; i < framePerBuffer; i++)
- {
- float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = asioBufPtr[i];
- if (swap) temp = SwapLong(temp);
- temp = (char)(((float)temp * MAX_INT8_FP) + dither);
- temp = ClipChar(temp);
- *userBufPtr = (unsigned char)(temp + 0x80);
- userBufPtr += NumInputChannels;
- }
- }
- }
-}
-
-// OUPUT
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Float32_Int16 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags, bool swap)
+typedef struct PaAsioDriverInfo
{
- long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- if( flags & paClipOff ) /* NOTHING */
- {
- for( j=0; j<NumOuputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
-
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = (short) (*userBufPtr * MAX_INT16_FP);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
- else /* CLIP */
- {
- for( j=0; j<NumOuputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
-
- for (i= 0; i < framePerBuffer; i++)
- {
- temp = (long) (*userBufPtr * MAX_INT16_FP);
- temp = ClipShort(temp);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
- }
- else
- {
- /* If you dither then you have to clip because dithering could push the signal out of range! */
- for( j=0; j<NumOuputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
-
- for (i= 0; i < framePerBuffer; i++)
- {
- float dither = Pa_TriangularDither()*DITHER_SCALE;
- temp = (long) ((*userBufPtr * MAX_INT16_FP) + dither);
- temp = ClipShort(temp);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
+ ASIODriverInfo asioDriverInfo;
+ long numInputChannels, numOutputChannels;
+ long bufferMinSize, bufferMaxSize, bufferPreferredSize, bufferGranularity;
+ bool postOutput;
}
+PaAsioDriverInfo;
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Float32_Int32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
+/*
+ load the asio driver named by <driverName> and return statistics about
+ the driver in info. If no error occurred, the driver will remain open
+ and must be closed by the called by calling ASIOExit() - if an error
+ is returned the driver will already be closed.
+*/
+static PaError LoadAsioDriver( const char *driverName, PaAsioDriverInfo *info )
{
- long temp;
- int i,j;
-
- if( flags & paClipOff )
- {
- for (j= 0; j < NumOuputChannels; j++)
- {
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (long) (*userBufPtr * MAX_INT32_FP);
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
- else // CLIP *
- {
- for (j= 0; j < NumOuputChannels; j++)
- {
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- float temp1 = *userBufPtr;
- temp1 = ClipFloat(temp1);
- temp = (long) (temp1*MAX_INT32_FP);
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
+ PaError result = paNoError;
+ ASIOError asioError;
+ int asioIsInitialized = 0;
+
+ if( !loadAsioDriver( const_cast<char*>(driverName) ) )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_HOST_ERROR( 0, "Failed to load ASIO driver" );
+ goto error;
+ }
+
+ if( (asioError = ASIOInit( &info->asioDriverInfo )) != ASE_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ goto error;
+ }
+ else
+ {
+ asioIsInitialized = 1;
+ }
+
+ if( (asioError = ASIOGetChannels(&info->numInputChannels,
+ &info->numOutputChannels)) != ASE_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ goto error;
+ }
+
+ if( (asioError = ASIOGetBufferSize(&info->bufferMinSize,
+ &info->bufferMaxSize, &info->bufferPreferredSize,
+ &info->bufferGranularity)) != ASE_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ goto error;
+ }
+
+ if( ASIOOutputReady() == ASE_OK )
+ info->postOutput = true;
+ else
+ info->postOutput = false;
+
+ return result;
+
+error:
+ if( asioIsInitialized )
+ ASIOExit();
+ return result;
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE TESTED
+#define PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_ 13 /* must be the same number of elements as in the array below */
+static ASIOSampleRate defaultSampleRateSearchOrder_[]
+ = {44100.0, 48000.0, 32000.0, 24000.0, 22050.0, 88200.0, 96000.0,
+ 192000.0, 16000.0, 12000.0, 11025.0, 96000.0, 8000.0 };
+
- static void Output_Float32_Float32 (ASIOBufferInfo* nativeBuffer, float *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,uint32 flags,bool swap)
+PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
{
- long temp;
- int i,j;
-
- if( flags & paClipOff )
- {
- for (j= 0; j < NumOuputChannels; j++)
- {
- float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (long) *userBufPtr;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = (float)temp;
- userBufPtr += NumOuputChannels;
- }
- }
-
- }
- else /* CLIP */
+ PaError result = paNoError;
+ int i, j, driverCount;
+ PaAsioHostApiRepresentation *asioHostApi;
+ PaAsioDeviceInfo *deviceInfoArray;
+ char **names;
+ PaAsioDriverInfo paAsioDriverInfo;
+ ASIOError asioError;
+ ASIODriverInfo asioDriverInfo;
+ ASIOChannelInfo asioChannelInfo;
+ double *sampleRates;
+
+
+ asioHostApi = (PaAsioHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaAsioHostApiRepresentation) );
+ if( !asioHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ asioHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !asioHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ asioHostApi->driverOpen = 0;
+
+ *hostApi = &asioHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+
+ (*hostApi)->info.type = paASIO;
+ (*hostApi)->info.name = "ASIO";
+ (*hostApi)->info.deviceCount = 0;
+
+ #ifdef WINDOWS
+ CoInitialize(0);
+ #endif
+
+ /* MUST BE CHECKED : to force fragments loading on Mac */
+ loadAsioDriver( "dummy" );
+
+
+ /* driverCount is the number of installed drivers - not necessarily
+ the number of installed physical devices. */
+ #if MAC
+ driverCount = asioDrivers->getNumFragments();
+ #elif WINDOWS
+ driverCount = asioDrivers->asioGetNumDev();
+ #endif
+
+ if( driverCount > 0 )
+ {
+ names = GetAsioDriverNames( asioHostApi->allocations, driverCount );
+ if( !names )
{
- for (j= 0; j < NumOuputChannels; j++)
- {
- float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- float *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- float temp1 = *userBufPtr;
- temp1 = ClipFloat(temp1); // Is is necessary??
- temp = (long) temp1;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = (float)temp;
- userBufPtr += NumOuputChannels;
- }
- }
+ result = paInsufficientMemory;
+ goto error;
}
-}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int32_Int16(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
-{
- long temp;
- int i,j;
-
- if( flags & paDitherOff )
- {
- for (j= 0; j < NumOuputChannels; j++)
- {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (short) ((*userBufPtr) >> 16);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
- }
- else
+ /* allocate enough space for all drivers, even if some aren't installed */
+
+ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ asioHostApi->allocations, sizeof(PaDeviceInfo*) * driverCount );
+ if( !(*hostApi)->deviceInfos )
{
- for (j= 0; j < NumOuputChannels; j++)
- {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (*userBufPtr >> 1) + Pa_TriangularDither();
- temp = temp >> 15;
- temp = (short) ClipShort(temp);
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
+ result = paInsufficientMemory;
+ goto error;
}
-}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int32_Int32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
-{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
+ /* allocate all device info structs in a contiguous block */
+ deviceInfoArray = (PaAsioDeviceInfo*)PaUtil_GroupAllocateMemory(
+ asioHostApi->allocations, sizeof(PaAsioDeviceInfo) * driverCount );
+ if( !deviceInfoArray )
{
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = *userBufPtr;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
+ result = paInsufficientMemory;
+ goto error;
}
-}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE CHECKED
-static void Output_Int32_Float32(ASIOBufferInfo* nativeBuffer, long *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset,uint32 flags,bool swap)
-{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
+ #if WINDOWS
+ asioDriverInfo.asioVersion = 2; /* FIXME - is this right? PLB */
+ asioDriverInfo.sysRef = GetDesktopWindow(); /* FIXME - is this right? PLB */
+ #elif MAC
+ /* REVIEW: is anything needed here?? RDB */
+ #endif
+
+ for( i=0; i < driverCount; ++i )
{
- float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- long *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
+ /* Attempt to load the asio driver... */
+ if( LoadAsioDriver( names[i], &paAsioDriverInfo ) == paNoError )
+ {
+ PaAsioDeviceInfo *asioDeviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
+ PaDeviceInfo *deviceInfo = &asioDeviceInfo->commonDeviceInfo;
+
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+
+ deviceInfo->name = names[i];
+
+ deviceInfo->maxInputChannels = paAsioDriverInfo.numInputChannels;
+ deviceInfo->maxOutputChannels = paAsioDriverInfo.numOutputChannels;
+
+ PA_DEBUG(("PaAsio_Initialize: inputChannels = %d\n", inputChannels ));
+ PA_DEBUG(("PaAsio_Initialize: outputChannels = %d\n", outputChannels ));
+
+
+ deviceInfo->defaultLowInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultLowOutputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighOutputLatency = 0.; /* @todo IMPLEMENT ME */
+
+ deviceInfo->defaultSampleRate = 0.;
+ for( int j=0; j < PA_DEFAULTSAMPLERATESEARCHORDER_COUNT_; ++j )
{
- temp = *userBufPtr;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = ((float)temp) * (1.0f / MAX_INT32_FP);
- userBufPtr += NumOuputChannels;
+ ASIOError asioError = ASIOCanSampleRate( defaultSampleRateSearchOrder_[j] );
+ if( asioError != ASE_NoClock && asioError != ASE_NotPresent ){
+ deviceInfo->defaultSampleRate = defaultSampleRateSearchOrder_[j];
+ break;
+ }
}
+
+ asioDeviceInfo->minBufferSize = paAsioDriverInfo.bufferMinSize;
+ asioDeviceInfo->maxBufferSize = paAsioDriverInfo.bufferMaxSize;
+ asioDeviceInfo->preferredBufferSize = paAsioDriverInfo.bufferPreferredSize;
+ asioDeviceInfo->bufferGranularity = paAsioDriverInfo.bufferGranularity;
+
+
+ /* We assume that all channels have the same SampleType, so check the first, FIXME, probably shouldn't assume that */
+ asioChannelInfo.channel = 0;
+ asioChannelInfo.isInput = 1;
+ ASIOGetChannelInfo( &asioChannelInfo ); /* FIXME, check return code */
+
+
+ /* unload the driver */
+ ASIOExit();
+
+ (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
+ ++(*hostApi)->info.deviceCount;
+ }
}
-}
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int16_Int16(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset, int userFrameOffset,bool swap)
-{
- long temp;
- int i,j;
+ if( (*hostApi)->info.deviceCount > 0 )
+ {
+ (*hostApi)->info.defaultInputDevice = 0;
+ (*hostApi)->info.defaultOutputDevice = 0;
+ }
+ else
+ {
+ (*hostApi)->info.defaultInputDevice = paNoDevice;
+ (*hostApi)->info.defaultOutputDevice = paNoDevice;
+ }
+
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &asioHostApi->callbackStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &asioHostApi->blockingStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
- for (j= 0; j < NumOuputChannels; j++)
+ return result;
+
+error:
+ if( asioHostApi )
+ {
+ if( asioHostApi->allocations )
{
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- short *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = *userBufPtr;
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
+ PaUtil_FreeAllAllocations( asioHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
}
+
+ PaUtil_FreeMemory( asioHostApi );
+ }
+ return result;
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int16_Int32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
- {
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- short *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (*userBufPtr)<<16;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
- }
+ PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
+
+ /*
+ IMPLEMENT ME:
+ - clean up any resources not handled by the allocation group
+ */
+
+ if( asioHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( asioHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( asioHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( asioHostApi );
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE CHECKED
-static void Output_Int16_Float32(ASIOBufferInfo* nativeBuffer, short *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
- {
- float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- short *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = *userBufPtr;
- asioBufPtr[i] = ((float)temp) * (1.0f / MAX_INT16_FP);
- userBufPtr += NumOuputChannels;
- }
- }
+ int numInputChannels, numOutputChannels;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ if( inputParameters )
+ {
+ numInputChannels = 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 numInputChannels */
+ if( numInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numInputChannels = 0;
+ }
+
+ if( outputParameters )
+ {
+ numOutputChannels = 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 numInputChannels */
+ if( numOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numOutputChannels = 0;
+ }
+
+ /*
+ IMPLEMENT ME:
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+ */
+
+ return paFormatIsSupported;
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int8_Int16(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
-{
- long temp;
- int i,j;
- for (j= 0; j < NumOuputChannels; j++)
- {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (short)(*userBufPtr)<<8;
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
- }
+
+
+/* PaAsioStream - a stream data structure specifically for this implementation */
+
+typedef struct PaAsioStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ PaAsioHostApiRepresentation *asioHostApi;
+ unsigned long framesPerHostCallback;
+
+ /* ASIO driver info - these may not be needed for the life of the stream,
+ but store them here until we work out how format conversion is going
+ to work. */
+
+ ASIOBufferInfo *asioBufferInfos;
+ ASIOChannelInfo *asioChannelInfos;
+ long inputLatency, outputLatency; // actual latencies returned by asio
+
+ long numInputChannels, numOutputChannels;
+ bool postOutput;
+
+ void **bufferPtrs; /* this is carved up for inputBufferPtrs and outputBufferPtrs */
+ void **inputBufferPtrs[2];
+ void **outputBufferPtrs[2];
+
+ PaAsioBufferConverter *inputBufferConverter;
+ long inputShift;
+ PaAsioBufferConverter *outputBufferConverter;
+ long outputShift;
+
+ volatile int stopProcessing; /* stop thread once existing buffers have been returned */
+ volatile int abortProcessing; /* stop thread immediately */
}
+PaAsioStream;
+
+static PaAsioStream *theAsioStream = 0; /* due to ASIO sdk limitations there can be only one stream */
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_Int8_Int32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+
+static void ZeroOutputBuffers( PaAsioStream *stream, long index )
{
- long temp;
- int i,j;
+ int i;
+
+ for( i=0; i < stream->numOutputChannels; ++i )
+ {
+ void *buffer = stream->asioBufferInfos[ i + stream->numInputChannels ].buffers[index];
- for (j= 0; j < NumOuputChannels; j++)
- {
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = (short)(*userBufPtr)<<24;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
- }
+ int bytesPerSample = BytesPerAsioSample( stream->asioChannelInfos[ i + stream->numInputChannels ].type );
+
+ memset( buffer, 0, stream->framesPerHostCallback * bytesPerSample );
+ }
}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE CHECKED
-static void Output_Int8_Float32(ASIOBufferInfo* nativeBuffer, char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
+static unsigned long SelectHostBufferSize( unsigned long suggestedLatencyFrames,
+ PaAsioDriverInfo *driverInfo )
{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
+ unsigned long result;
+
+ if( suggestedLatencyFrames == 0 )
+ {
+ result = driverInfo->bufferPreferredSize;
+ }
+ else{
+ if( suggestedLatencyFrames <= (unsigned long)driverInfo->bufferMinSize )
{
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = *userBufPtr;
- asioBufPtr[i] = (long)(((float)temp) * (1.0f / MAX_INT8_FP));
- userBufPtr += NumOuputChannels;
- }
+ result = driverInfo->bufferMinSize;
}
-}
+ else if( suggestedLatencyFrames >= (unsigned long)driverInfo->bufferMaxSize )
+ {
+ result = driverInfo->bufferMaxSize;
+ }
+ else
+ {
+ if( driverInfo->bufferGranularity == -1 )
+ {
+ /* power-of-two */
+ result = 2;
+
+ while( result < suggestedLatencyFrames )
+ result *= result;
+
+ if( result < (unsigned long)driverInfo->bufferMinSize )
+ result = driverInfo->bufferMinSize;
+
+ if( result > (unsigned long)driverInfo->bufferMaxSize )
+ result = driverInfo->bufferMaxSize;
+ }
+ else if( driverInfo->bufferGranularity == 0 )
+ {
+ result = driverInfo->bufferPreferredSize;
+ }
+ else
+ {
+ /* modulo granularity */
+
+ result = suggestedLatencyFrames +
+ (driverInfo->bufferGranularity -
+ (suggestedLatencyFrames % driverInfo->bufferGranularity));
+ if( result > (unsigned long)driverInfo->bufferMaxSize )
+ result = driverInfo->bufferMaxSize;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaAsioHostApiRepresentation *asioHostApi = (PaAsioHostApiRepresentation*)hostApi;
+ PaAsioStream *stream = 0;
+ unsigned long framesPerHostBuffer;
+ int numInputChannels, numOutputChannels;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+ PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
+ unsigned long suggestedInputLatencyFrames;
+ unsigned long suggestedOutputLatencyFrames;
+ const char *driverName;
+ ASIOError asioError;
+ int asioIsInitialized = 0;
+ int asioBuffersCreated = 0;
+ PaAsioDriverInfo driverInfo;
+ int i;
+
+ /* unless we move to using lower level ASIO calls, we can only have
+ one device open at a time */
+ if( asioHostApi->driverOpen )
+ return paDeviceUnavailable;
+
+
+
+ if( inputParameters )
+ {
+ numInputChannels = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+ suggestedInputLatencyFrames = inputParameters->suggestedLatency * sampleRate;
+
+ driverName = asioHostApi->inheritedHostApiRep.deviceInfos[ inputParameters->device ]->name;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* validate hostApiSpecificStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numInputChannels = 0;
+ suggestedInputLatencyFrames = 0;
+ }
+
+ if( outputParameters )
+ {
+ numOutputChannels = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+ suggestedOutputLatencyFrames = outputParameters->suggestedLatency;
+
+ driverName = asioHostApi->inheritedHostApiRep.deviceInfos[ outputParameters->device ]->name;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* validate hostApiSpecificStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numOutputChannels = 0;
+ suggestedOutputLatencyFrames = 0;
+ }
+
+
+ if( inputParameters && outputParameters )
+ {
+ /* full duplex ASIO stream must use the same device for input and output */
+
+ if( inputParameters->device != outputParameters->device )
+ return paBadIODeviceCombination;
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_IntU8_Int16(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
-{
- long temp;
- int i,j;
+
- for (j= 0; j < NumOuputChannels; j++)
+ /* NOTE: we load the driver and use its current settings
+ rather than the ones in our device info structure which may be stale */
+
+ result = LoadAsioDriver( driverName, &driverInfo );
+ if( result == paNoError )
+ asioIsInitialized = 1;
+ else
+ goto error;
+
+ /* check that input device can support numInputChannels */
+ if( numInputChannels > 0 )
+ {
+ if( numInputChannels > driverInfo.numInputChannels )
{
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = ((short)((*userBufPtr) - 0x80)) << 8;
- if (swap) temp = SwapShort(temp);
- asioBufPtr[i] = (short)temp;
- userBufPtr += NumOuputChannels;
- }
+ result = paInvalidChannelCount;
+ goto error;
}
-}
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Output_IntU8_Int32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
-{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
+ /* check that output device can support numOutputChannels */
+ if( numOutputChannels )
+ {
+ if( numOutputChannels > driverInfo.numOutputChannels )
{
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = ((short)((*userBufPtr) - 0x80)) << 24;
- if (swap) temp = SwapLong(temp);
- asioBufPtr[i] = temp;
- userBufPtr += NumOuputChannels;
- }
- }
-}
+ result = paInvalidChannelCount;
+ goto error;
+ }
+ }
+
+ /* Set sample rate */
+ if( ASIOSetSampleRate( sampleRate ) != ASE_OK )
+ {
+ result = paInvalidSampleRate;
+ goto error;
+ }
+
+ framesPerHostBuffer = SelectHostBufferSize(
+ (( suggestedInputLatencyFrames > suggestedOutputLatencyFrames )
+ ? suggestedInputLatencyFrames : suggestedOutputLatencyFrames),
+ &driverInfo );
+
+ /*
+ IMPLEMENT ME:
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+ */
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// MUST BE CHECKED
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
-static void Output_IntU8_Float32(ASIOBufferInfo* nativeBuffer, unsigned char *outBufPtr, int framePerBuffer, int NumInputChannels, int NumOuputChannels, int index, int hostFrameOffset,int userFrameOffset, bool swap)
-{
- long temp;
- int i,j;
-
- for (j= 0; j < NumOuputChannels; j++)
+
+ stream = (PaAsioStream*)PaUtil_AllocateMemory( sizeof(PaAsioStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ stream->asioBufferInfos = 0; /* for deallocation in error */
+ stream->asioChannelInfos = 0; /* for deallocation in error */
+ stream->bufferPtrs = 0; /* for deallocation in error */
+
+ if( streamCallback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &asioHostApi->callbackStreamInterface, streamCallback, userData );
+ }
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &asioHostApi->blockingStreamInterface, streamCallback, userData );
+ }
+
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+
+ stream->asioBufferInfos = (ASIOBufferInfo*)PaUtil_AllocateMemory(
+ sizeof(ASIOBufferInfo) * (numInputChannels + numOutputChannels) );
+ if( !stream->asioBufferInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+
+ for( i=0; i < numInputChannels; ++i )
+ {
+ ASIOBufferInfo *info = &stream->asioBufferInfos[i];
+
+ info->isInput = ASIOTrue;
+ info->channelNum = i;
+ info->buffers[0] = info->buffers[1] = 0;
+ }
+
+ for( i=0; i < numOutputChannels; ++i ){
+ ASIOBufferInfo *info = &stream->asioBufferInfos[numInputChannels+i];
+
+ info->isInput = ASIOFalse;
+ info->channelNum = i;
+ info->buffers[0] = info->buffers[1] = 0;
+ }
+
+ asioError = ASIOCreateBuffers( stream->asioBufferInfos, numInputChannels+numOutputChannels,
+ framesPerHostBuffer, &asioCallbacks_ );
+ if( asioError != ASE_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ goto error;
+ }
+
+ asioBuffersCreated = 1;
+
+ stream->asioChannelInfos = (ASIOChannelInfo*)PaUtil_AllocateMemory(
+ sizeof(ASIOChannelInfo) * (numInputChannels + numOutputChannels) );
+ if( !stream->asioChannelInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i=0; i < numInputChannels + numOutputChannels; ++i )
+ {
+ stream->asioChannelInfos[i].channel = stream->asioBufferInfos[i].channelNum;
+ stream->asioChannelInfos[i].isInput = stream->asioBufferInfos[i].isInput;
+ asioError = ASIOGetChannelInfo( &stream->asioChannelInfos[i] );
+ if( asioError != ASE_OK )
{
- float *asioBufPtr = &((float*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- unsigned char *userBufPtr = &outBufPtr[j+(userFrameOffset*NumOuputChannels)];
- for( i=0; i<framePerBuffer; i++ )
- {
- temp = ((short)((*userBufPtr) - 0x80)) << 24;
- asioBufPtr[i] = ((float)temp) * (1.0f / MAX_INT32_FP);
- userBufPtr += NumOuputChannels;
- }
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ goto error;
+ }
+ }
+
+ stream->bufferPtrs = (void**)PaUtil_AllocateMemory(
+ 2 * sizeof(void*) * (numInputChannels + numOutputChannels) );
+ if( !stream->bufferPtrs )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( numInputChannels > 0 )
+ {
+ stream->inputBufferPtrs[0] = stream-> bufferPtrs;
+ stream->inputBufferPtrs[1] = &stream->bufferPtrs[numInputChannels];
+
+ for( i=0; i<numInputChannels; ++i )
+ {
+ stream->inputBufferPtrs[0][i] = stream->asioBufferInfos[i].buffers[0];
+ stream->inputBufferPtrs[1][i] = stream->asioBufferInfos[i].buffers[1];
+ }
+ }
+ else
+ {
+ stream->inputBufferPtrs[0] = 0;
+ stream->inputBufferPtrs[1] = 0;
+ }
+
+ if( numOutputChannels > 0 )
+ {
+ stream->outputBufferPtrs[0] = &stream->bufferPtrs[numInputChannels*2];
+ stream->outputBufferPtrs[1] = &stream->bufferPtrs[numInputChannels*2 + numOutputChannels];
+
+ for( i=0; i<numOutputChannels; ++i )
+ {
+ stream->outputBufferPtrs[0][i] = stream->asioBufferInfos[numInputChannels+i].buffers[0];
+ stream->outputBufferPtrs[1][i] = stream->asioBufferInfos[numInputChannels+i].buffers[1];
}
-}
+ }
+ else
+ {
+ stream->outputBufferPtrs[0] = 0;
+ stream->outputBufferPtrs[1] = 0;
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Clear_Output_16 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset)
-{
- int i,j;
- for( j=0; j<NumOuputChannels; j++ ) {
- short *asioBufPtr = &((short*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- for (i= 0; i < frames; i++) {asioBufPtr[i] = 0; }
- }
-}
+ ASIOGetLatencies( &stream->inputLatency, &stream->outputLatency );
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Clear_Output_32 (ASIOBufferInfo* nativeBuffer, long frames, long NumInputChannels, long NumOuputChannels, long index, long hostFrameOffset)
-{
- int i,j;
+ stream->streamRepresentation.streamInfo.inputLatency = (double)stream->inputLatency / sampleRate; // seconds
+ stream->streamRepresentation.streamInfo.outputLatency = (double)stream->outputLatency / sampleRate; // seconds
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
- for( j=0; j<NumOuputChannels; j++ ) {
- long *asioBufPtr = &((long*)nativeBuffer[j+NumInputChannels].buffers[index])[hostFrameOffset];
- for (i= 0; i < frames; i++) {asioBufPtr[i] = 0; }
- }
-}
+ PA_DEBUG(("PaAsio : InputLatency = %ld latency = %ld msec \n",
+ stream->inputLatency,
+ (long)((stream->inputLatency*1000)/ sampleRate)));
+ PA_DEBUG(("PaAsio : OuputLatency = %ld latency = %ld msec \n",
+ stream->outputLatency,
+ (long)((stream->outputLatency*1000)/ sampleRate)));
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Adaptor_Init()
-{
- if (asioDriverInfo.past->past_FramesPerUserBuffer <= asioDriverInfo.past_FramesPerHostBuffer) {
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset = asioDriverInfo.pahsc_OutputBufferOffset;
- asioDriverInfo.pahsc_userInputBufferFrameOffset = 0; // empty
- asioDriverInfo.pahsc_userOutputBufferFrameOffset = asioDriverInfo.past->past_FramesPerUserBuffer; // empty
- }else {
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0; // empty
- asioDriverInfo.pahsc_userInputBufferFrameOffset = asioDriverInfo.pahsc_InputBufferOffset;
- asioDriverInfo.pahsc_userOutputBufferFrameOffset = asioDriverInfo.past->past_FramesPerUserBuffer; // empty
- }
-}
+ if( numInputChannels > 0 )
+ {
+ /* FIXME: assume all channels use the same type for now */
+ ASIOSampleType inputType = stream->asioChannelInfos[0].type;
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-// FIXME : optimization for Input only or output only modes (really necessary ??)
-static void Pa_ASIO_Callback_Input( long index)
-{
- internalPortAudioStream *past = asioDriverInfo.past;
- long framesInputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer; // number of frames available into the host input buffer
- long framesInputUserBuffer; // number of frames needed to complete the user input buffer
- long framesOutputHostBuffer; // number of frames needed to complete the host output buffer
- long framesOuputUserBuffer; // number of frames available into the user output buffer
- long userResult;
- long tmp;
-
- /* Fill host ASIO output with remaining frames in user output */
- framesOutputHostBuffer = asioDriverInfo.past_FramesPerHostBuffer;
- framesOuputUserBuffer = asioDriverInfo.past->past_FramesPerUserBuffer - asioDriverInfo.pahsc_userOutputBufferFrameOffset;
- tmp = min(framesOutputHostBuffer, framesOuputUserBuffer);
- framesOutputHostBuffer -= tmp;
- Pa_ASIO_Callback_Output(index,tmp);
-
- /* Available frames in hostInputBuffer */
- while (framesInputHostBuffer > 0) {
-
- /* Number of frames needed to complete an user input buffer */
- framesInputUserBuffer = asioDriverInfo.past->past_FramesPerUserBuffer - asioDriverInfo.pahsc_userInputBufferFrameOffset;
-
- if (framesInputHostBuffer >= framesInputUserBuffer) {
-
- /* Convert ASIO input to user input */
- Pa_ASIO_Convert_Inter_Input (asioDriverInfo.bufferInfos,
- past->past_InputBuffer,
- asioDriverInfo.pahsc_NumInputChannels ,
- asioDriverInfo.pahsc_NumOutputChannels,
- framesInputUserBuffer,
- asioDriverInfo.past_FramesPerHostBuffer - framesInputHostBuffer,
- asioDriverInfo.pahsc_userInputBufferFrameOffset,
- asioDriverInfo.pahsc_channelInfos[0].type,
- past->past_InputSampleFormat,
- past->past_Flags,
- index);
-
- /* Call PortAudio callback */
- userResult = asioDriverInfo.past->past_Callback(past->past_InputBuffer, past->past_OutputBuffer,
- past->past_FramesPerUserBuffer,past->past_FrameCount,past->past_UserData );
-
- /* User callback has asked us to stop in the middle of the host buffer */
- if( userResult != 0) {
-
- /* Put 0 in the end of the output buffer */
- Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos,
- asioDriverInfo.pahsc_channelInfos[0].type,
- asioDriverInfo.pahsc_NumInputChannels ,
- asioDriverInfo.pahsc_NumOutputChannels,
- index,
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset,
- asioDriverInfo.past_FramesPerHostBuffer - asioDriverInfo.pahsc_hostOutputBufferFrameOffset);
-
- past->past_StopSoon = 1;
- return;
- }
-
-
- /* Full user ouput buffer : write offset */
- asioDriverInfo.pahsc_userOutputBufferFrameOffset = 0;
-
- /* Empty user input buffer : read offset */
- asioDriverInfo.pahsc_userInputBufferFrameOffset = 0;
-
- /* Fill host ASIO output */
- tmp = min (past->past_FramesPerUserBuffer,framesOutputHostBuffer);
- Pa_ASIO_Callback_Output(index,tmp);
-
- framesOutputHostBuffer -= tmp;
- framesInputHostBuffer -= framesInputUserBuffer;
-
- }else {
-
- /* Convert ASIO input to user input */
- Pa_ASIO_Convert_Inter_Input (asioDriverInfo.bufferInfos,
- past->past_InputBuffer,
- asioDriverInfo.pahsc_NumInputChannels ,
- asioDriverInfo.pahsc_NumOutputChannels,
- framesInputHostBuffer,
- asioDriverInfo.past_FramesPerHostBuffer - framesInputHostBuffer,
- asioDriverInfo.pahsc_userInputBufferFrameOffset,
- asioDriverInfo.pahsc_channelInfos[0].type,
- past->past_InputSampleFormat,
- past->past_Flags,
- index);
-
- /* Update pahsc_userInputBufferFrameOffset */
- asioDriverInfo.pahsc_userInputBufferFrameOffset += framesInputHostBuffer;
-
- /* Update framesInputHostBuffer */
- framesInputHostBuffer = 0;
- }
- }
+ hostInputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( inputType );
-}
+ SelectAsioToPaConverter( inputType, &stream->inputBufferConverter, &stream->inputShift );
+ }
+ else
+ {
+ stream->inputBufferConverter = 0;
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Callback_Output(long index, long framePerBuffer)
-{
- internalPortAudioStream *past = asioDriverInfo.past;
+ if( numOutputChannels > 0 )
+ {
+ /* FIXME: assume all channels use the same type for now */
+ ASIOSampleType outputType = stream->asioChannelInfos[numInputChannels].type;
- if (framePerBuffer > 0) {
-
- /* Convert user output to ASIO ouput */
- Pa_ASIO_Convert_Inter_Output (asioDriverInfo.bufferInfos,
- past->past_OutputBuffer,
- asioDriverInfo.pahsc_NumInputChannels,
- asioDriverInfo.pahsc_NumOutputChannels,
- framePerBuffer,
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset,
- asioDriverInfo.pahsc_userOutputBufferFrameOffset,
- asioDriverInfo.pahsc_channelInfos[0].type,
- past->past_InputSampleFormat,
- past->past_Flags,
- index);
-
- /* Update hostOuputFrameOffset */
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset += framePerBuffer;
+ hostOutputSampleFormat = AsioSampleTypeToPaNativeSampleFormat( outputType );
- /* Update userOutputFrameOffset */
- asioDriverInfo.pahsc_userOutputBufferFrameOffset += framePerBuffer;
- }
-}
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Callback_End()
- {
- /* Empty ASIO ouput : write offset */
- asioDriverInfo.pahsc_hostOutputBufferFrameOffset = 0;
- }
-
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
-static void Pa_ASIO_Clear_User_Buffers()
-{
- if( asioDriverInfo.past->past_InputBuffer != NULL )
- {
- memset( asioDriverInfo.past->past_InputBuffer, 0, asioDriverInfo.past->past_InputBufferSize );
- }
- if( asioDriverInfo.past->past_OutputBuffer != NULL )
- {
- memset( asioDriverInfo.past->past_OutputBuffer, 0, asioDriverInfo.past->past_OutputBufferSize );
- }
-}
+ SelectPaToAsioConverter( outputType, &stream->outputBufferConverter, &stream->outputShift );
+ }
+ else
+ {
+ stream->outputBufferConverter = 0;
+ }
-//-------------------------------------------------------------------------------------------------------------------------------------------------------
- static void Pa_ASIO_Clear_Output(ASIOBufferInfo* nativeBuffer,
- ASIOSampleType nativeFormat,
- long NumInputChannels,
- long NumOuputChannels,
- long index,
- long hostFrameOffset,
- long frames)
-{
-
- switch (nativeFormat) {
-
- case ASIOSTInt16MSB:
- case ASIOSTInt16LSB:
- case ASIOSTInt32MSB16:
- case ASIOSTInt32LSB16:
- Pa_ASIO_Clear_Output_16(nativeBuffer, frames, NumInputChannels, NumOuputChannels, index, hostFrameOffset);
- break;
-
- case ASIOSTFloat64MSB:
- case ASIOSTFloat64LSB:
- break;
-
- case ASIOSTFloat32MSB:
- case ASIOSTFloat32LSB:
- case ASIOSTInt32MSB:
- case ASIOSTInt32LSB:
- case ASIOSTInt32MSB18:
- case ASIOSTInt32MSB20:
- case ASIOSTInt32MSB24:
- case ASIOSTInt32LSB18:
- case ASIOSTInt32LSB20:
- case ASIOSTInt32LSB24:
- Pa_ASIO_Clear_Output_32(nativeBuffer, frames, NumInputChannels, NumOuputChannels, index, hostFrameOffset);
- break;
-
- case ASIOSTInt24MSB:
- case ASIOSTInt24LSB:
- break;
-
- default:
- break;
- }
-}
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ numInputChannels, inputSampleFormat, hostInputSampleFormat,
+ numOutputChannels, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer,
+ framesPerHostBuffer, paUtilFixedHostBufferSize,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+ stream->asioHostApi = asioHostApi;
+ stream->framesPerHostCallback = framesPerHostBuffer;
-//---------------------------------------------------------------------------------------
-static void Pa_ASIO_Convert_Inter_Input(
- ASIOBufferInfo* nativeBuffer,
- void* inputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
- ASIOSampleType nativeFormat,
- PaSampleFormat paFormat,
- PaStreamFlags flags,
- long index)
-{
-
- if((NumInputChannels > 0) && (nativeBuffer != NULL))
- {
- /* Convert from native format to PA format. */
- switch(paFormat)
- {
- case paFloat32:
- {
- float *inBufPtr = (float *) inputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Input_Int16_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
- break;
- case ASIOSTInt32LSB:
- Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap);
- break;
- case ASIOSTInt32MSB:
- Input_Int32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
- break;
- case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,swap);
- break;
- case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Float32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset, userFrameOffset,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
-
- break;
- }
-
- case paInt32:
- {
- long *inBufPtr = (long *)inputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Input_Int16_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Input_Int16_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTInt32LSB:
- Input_Int32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt32MSB:
- Input_Int32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int32(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
-
- }
- break;
- }
-
- case paInt16:
- {
- short *inBufPtr = (short *) inputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Input_Int16_Int16(nativeBuffer, inBufPtr, framePerBuffer , NumInputChannels, index , hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Input_Int16_Int16(nativeBuffer, inBufPtr, framePerBuffer , NumInputChannels, index , hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTInt32LSB:
- Input_Int32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTInt32MSB:
- Input_Int32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int16(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
-
- }
- break;
- }
-
- case paInt8:
- {
- /* Convert 16 bit data to 8 bit chars */
-
- char *inBufPtr = (char *) inputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Input_Int16_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap);
- break;
- case ASIOSTInt16MSB:
- Input_Int16_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTInt32LSB:
- Input_Int32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTInt32MSB:
- Input_Int32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_Int8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
- break;
- }
-
- case paUInt8:
- {
- /* Convert 16 bit data to 8 bit unsigned chars */
-
- unsigned char *inBufPtr = (unsigned char *)inputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Input_Int16_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTInt16MSB:
- Input_Int16_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTInt32LSB:
- Input_Int32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap);
- break;
- case ASIOSTInt32MSB:
- Input_Int32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTFloat32LSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,swap);
- break;
- case ASIOSTFloat32MSB: // IEEE 754 32 bit float, as found on Intel x86 architecture
- Input_Float32_IntU8(nativeBuffer, inBufPtr, framePerBuffer, NumInputChannels, index, hostFrameOffset,userFrameOffset,flags,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
-
- }
- break;
- }
-
- default:
- break;
- }
- }
-}
+ stream->numInputChannels = numInputChannels;
+ stream->numOutputChannels = numOutputChannels;
+ stream->postOutput = driverInfo.postOutput;
+ asioHostApi->driverOpen = 1;
-//---------------------------------------------------------------------------------------
-static void Pa_ASIO_Convert_Inter_Output(ASIOBufferInfo* nativeBuffer,
- void* outputBuffer,
- long NumInputChannels,
- long NumOuputChannels,
- long framePerBuffer,
- long hostFrameOffset,
- long userFrameOffset,
- ASIOSampleType nativeFormat,
- PaSampleFormat paFormat,
- PaStreamFlags flags,
- long index)
-{
-
- if((NumOuputChannels > 0) && (nativeBuffer != NULL))
- {
- /* Convert from PA format to native format */
-
- switch(paFormat)
- {
- case paFloat32:
- {
- float *outBufPtr = (float *) outputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Output_Float32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags, swap);
- break;
- case ASIOSTInt16MSB:
- Output_Float32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags,!swap);
- break;
- case ASIOSTInt32LSB:
- Output_Float32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset, userFrameOffset, flags,swap);
- break;
- case ASIOSTInt32MSB:
- Output_Float32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTFloat32LSB:
- Output_Float32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset,flags,swap);
- break;
- case ASIOSTFloat32MSB:
- Output_Float32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
- break;
- }
-
- case paInt32:
- {
- long *outBufPtr = (long *) outputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Output_Int32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTInt16MSB:
- Output_Int32_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTInt32LSB:
- Output_Int32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTInt32MSB:
- Output_Int32_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
- case ASIOSTFloat32LSB:
- Output_Int32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,swap);
- break;
- case ASIOSTFloat32MSB:
- Output_Int32_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, flags,!swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
- break;
- }
-
- case paInt16:
- {
- short *outBufPtr = (short *) outputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Output_Int16_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Output_Int16_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTInt32LSB:
- Output_Int16_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt32MSB:
- Output_Int16_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTFloat32LSB:
- Output_Int16_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTFloat32MSB:
- Output_Int16_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
-
- }
- break;
- }
-
-
- case paInt8:
- {
- char *outBufPtr = (char *) outputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Output_Int8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Output_Int8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTInt32LSB:
- Output_Int8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt32MSB:
- Output_Int8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTFloat32LSB:
- Output_Int8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTFloat32MSB:
- Output_Int8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
- break;
- }
-
- case paUInt8:
- {
- unsigned char *outBufPtr = (unsigned char *) outputBuffer;
-
- switch (nativeFormat) {
- case ASIOSTInt16LSB:
- Output_IntU8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt16MSB:
- Output_IntU8_Int16(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTInt32LSB:
- Output_IntU8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTInt32MSB:
- Output_IntU8_Int32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
- case ASIOSTFloat32LSB:
- Output_IntU8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, swap);
- break;
- case ASIOSTFloat32MSB:
- Output_IntU8_Float32(nativeBuffer, outBufPtr, framePerBuffer, NumInputChannels, NumOuputChannels, index, hostFrameOffset,userFrameOffset, !swap);
- break;
-
- case ASIOSTInt24LSB: // used for 20 bits as well
- case ASIOSTInt24MSB: // used for 20 bits as well
-
- case ASIOSTFloat64LSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
- case ASIOSTFloat64MSB: // IEEE 754 64 bit double float, as found on Intel x86 architecture
-
- // these are used for 32 bit data buffer, with different alignment of the data inside
- // 32 bit PCI bus systems can more easily used with these
-
- case ASIOSTInt32LSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32LSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32LSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32LSB24: // 32 bit data with 24 bit alignment
-
-
- case ASIOSTInt32MSB16: // 32 bit data with 16 bit alignment
- case ASIOSTInt32MSB18: // 32 bit data with 18 bit alignment
- case ASIOSTInt32MSB20: // 32 bit data with 20 bit alignment
- case ASIOSTInt32MSB24: // 32 bit data with 24 bit alignment
- DBUG(("Not yet implemented : please report the problem\n"));
- break;
- }
- break;
- }
-
- default:
- break;
- }
- }
+ *s = (PaStream*)stream;
-}
+ return result;
+error:
+ if( stream )
+ {
+ if( stream->asioBufferInfos )
+ PaUtil_FreeMemory( stream->asioBufferInfos );
+ if( stream->asioChannelInfos )
+ PaUtil_FreeMemory( stream->asioChannelInfos );
-/* Load a ASIO driver corresponding to the required device */
-static PaError Pa_ASIO_loadDevice (long device)
-{
- PaDeviceInfo * dev = &(sDevices[device].pad_Info);
+ if( stream->bufferPtrs )
+ PaUtil_FreeMemory( stream->bufferPtrs );
- if (!Pa_ASIO_loadAsioDriver((char *) dev->name)) return paHostError;
- if (ASIOInit(&asioDriverInfo.pahsc_driverInfo) != ASE_OK) return paHostError;
- if (ASIOGetChannels(&asioDriverInfo.pahsc_NumInputChannels, &asioDriverInfo.pahsc_NumOutputChannels) != ASE_OK) return paHostError;
- if (ASIOGetBufferSize(&asioDriverInfo.pahsc_minSize, &asioDriverInfo.pahsc_maxSize, &asioDriverInfo.pahsc_preferredSize, &asioDriverInfo.pahsc_granularity) != ASE_OK) return paHostError;
-
- if(ASIOOutputReady() == ASE_OK)
- asioDriverInfo.pahsc_postOutput = true;
- else
- asioDriverInfo.pahsc_postOutput = false;
-
- return paNoError;
+ PaUtil_FreeMemory( stream );
+ }
+
+ if( asioBuffersCreated )
+ ASIODisposeBuffers();
+
+ if( asioIsInitialized )
+ ASIOExit();
+
+ return result;
}
-//---------------------------------------------------
-static int GetHighestBitPosition (unsigned long n)
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
{
- int pos = -1;
- while( n != 0 )
- {
- pos++;
- n = n >> 1;
- }
- return pos;
-}
+ PaError result = paNoError;
+ PaAsioStream *stream = (PaAsioStream*)s;
-//------------------------------------------------------------------------------------------
-static int GetFirstMultiple(long min, long val ){ return ((min + val - 1) / val) * val; }
+ /*
+ IMPLEMENT ME:
+ - additional stream closing + cleanup
+ */
-//------------------------------------------------------------------------------------------
-static int GetFirstPossibleDivisor(long max, long val )
-{
- for (int i = 2; i < 20; i++) {if (((val%i) == 0) && ((val/i) <= max)) return (val/i); }
- return val;
-}
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
-//------------------------------------------------------------------------
-static int IsPowerOfTwo( unsigned long n ) { return ((n & (n-1)) == 0); }
+ stream->asioHostApi->driverOpen = 0;
+ PaUtil_FreeMemory( stream->asioBufferInfos );
+ PaUtil_FreeMemory( stream->asioChannelInfos );
+ PaUtil_FreeMemory( stream->bufferPtrs );
+ PaUtil_FreeMemory( stream );
-/*******************************************************************
-* Determine size of native ASIO audio buffer size
-* Input parameters : FramesPerUserBuffer, NumUserBuffers
-* Output values : FramesPerHostBuffer, OutputBufferOffset or InputtBufferOffset
-*/
+ ASIODisposeBuffers();
+ ASIOExit();
+
+ return result;
+}
-static PaError PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
+
+static void bufferSwitch(long index, ASIOBool processNow)
{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- long requestedBufferSize;
- long firstMultiple, firstDivisor;
-
- // Compute requestedBufferSize
- if( past->past_NumUserBuffers < 1 ){
- requestedBufferSize = past->past_FramesPerUserBuffer;
- }else{
- requestedBufferSize = past->past_NumUserBuffers * past->past_FramesPerUserBuffer;
- }
-
- // Adjust FramesPerHostBuffer using requestedBufferSize, ASIO minSize and maxSize,
- if (requestedBufferSize < asioDriverInfo.pahsc_minSize){
-
- firstMultiple = GetFirstMultiple(asioDriverInfo.pahsc_minSize, requestedBufferSize);
-
- if (firstMultiple <= asioDriverInfo.pahsc_maxSize)
- asioDriverInfo.past_FramesPerHostBuffer = firstMultiple;
- else
- asioDriverInfo.past_FramesPerHostBuffer = asioDriverInfo.pahsc_minSize;
-
- }else if (requestedBufferSize > asioDriverInfo.pahsc_maxSize){
-
- firstDivisor = GetFirstPossibleDivisor(asioDriverInfo.pahsc_maxSize, requestedBufferSize);
-
- if ((firstDivisor >= asioDriverInfo.pahsc_minSize) && (firstDivisor <= asioDriverInfo.pahsc_maxSize))
- asioDriverInfo.past_FramesPerHostBuffer = firstDivisor;
- else
- asioDriverInfo.past_FramesPerHostBuffer = asioDriverInfo.pahsc_maxSize;
- }else{
- asioDriverInfo.past_FramesPerHostBuffer = requestedBufferSize;
- }
+//TAKEN FROM THE ASIO SDK
+
+ // the actual processing callback.
+ // Beware that this is normally in a seperate thread, hence be sure that
+ // you take care about thread synchronization. This is omitted here for
+ // simplicity.
+
+ // as this is a "back door" into the bufferSwitchTimeInfo a timeInfo needs
+ // to be created though it will only set the timeInfo.samplePosition and
+ // timeInfo.systemTime fields and the according flags
- // If ASIO buffer size needs to be a power of two
- if( asioDriverInfo.pahsc_granularity < 0 ){
- // Needs to be a power of two.
+ ASIOTime timeInfo;
+ memset( &timeInfo, 0, sizeof (timeInfo) );
+
+ // get the time stamp of the buffer, not necessary if no
+ // synchronization to other media is required
+ if( ASIOGetSamplePosition(&timeInfo.timeInfo.samplePosition, &timeInfo.timeInfo.systemTime) == ASE_OK)
+ timeInfo.timeInfo.flags = kSystemTimeValid | kSamplePositionValid;
- if( !IsPowerOfTwo( asioDriverInfo.past_FramesPerHostBuffer ) )
- {
- int highestBit = GetHighestBitPosition(asioDriverInfo.past_FramesPerHostBuffer);
- asioDriverInfo.past_FramesPerHostBuffer = 1 << (highestBit + 1);
- }
- }
-
- DBUG(("----------------------------------\n"));
- DBUG(("PortAudio : minSize = %ld \n",asioDriverInfo.pahsc_minSize));
- DBUG(("PortAudio : preferredSize = %ld \n",asioDriverInfo.pahsc_preferredSize));
- DBUG(("PortAudio : maxSize = %ld \n",asioDriverInfo.pahsc_maxSize));
- DBUG(("PortAudio : granularity = %ld \n",asioDriverInfo.pahsc_granularity));
- DBUG(("PortAudio : User buffer size = %d\n", asioDriverInfo.past->past_FramesPerUserBuffer ));
- DBUG(("PortAudio : ASIO buffer size = %d\n", asioDriverInfo.past_FramesPerHostBuffer ));
-
- if (asioDriverInfo.past_FramesPerHostBuffer > past->past_FramesPerUserBuffer){
-
- // Computes the MINIMUM value of null frames shift for the output buffer alignement
- asioDriverInfo.pahsc_OutputBufferOffset = Pa_ASIO_CalcFrameShift (asioDriverInfo.past_FramesPerHostBuffer,past->past_FramesPerUserBuffer);
- asioDriverInfo.pahsc_InputBufferOffset = 0;
- DBUG(("PortAudio : Minimum BufferOffset for Output = %d\n", asioDriverInfo.pahsc_OutputBufferOffset));
- }else{
-
- //Computes the MINIMUM value of null frames shift for the input buffer alignement
- asioDriverInfo.pahsc_InputBufferOffset = Pa_ASIO_CalcFrameShift (asioDriverInfo.past_FramesPerHostBuffer,past->past_FramesPerUserBuffer);
- asioDriverInfo.pahsc_OutputBufferOffset = 0;
- DBUG(("PortAudio : Minimum BufferOffset for Input = %d\n", asioDriverInfo.pahsc_InputBufferOffset));
- }
-
- return paNoError;
+ // Call the real callback
+ bufferSwitchTimeInfo( &timeInfo, index, processNow );
}
-/***********************************************************************/
-int Pa_CountDevices()
+// conversion from 64 bit ASIOSample/ASIOTimeStamp to double float
+#if NATIVE_INT64
+ #define ASIO64toDouble(a) (a)
+#else
+ const double twoRaisedTo32 = 4294967296.;
+ #define ASIO64toDouble(a) ((a).lo + (a).hi * twoRaisedTo32)
+#endif
+
+static ASIOTime *bufferSwitchTimeInfo( ASIOTime *timeInfo, long index, ASIOBool processNow )
{
- PaError err ;
-
- if( sNumDevices <= 0 )
- {
- /* Force loading of ASIO drivers */
- err = Pa_ASIO_QueryDeviceInfo(sDevices);
- if( err != paNoError ) goto error;
- }
-
- return sNumDevices;
+ // the actual processing callback.
+ // Beware that this is normally in a seperate thread, hence be sure that
+ // you take care about thread synchronization. This is omitted here for simplicity.
+
+
+ (void) processNow; /* unused parameter: FIXME: the sdk implies that we shouldn't process now if this parameter is false */
+
+#if 0
+ // store the timeInfo for later use
+ asioDriverInfo.tInfo = *timeInfo;
+
+ // get the time stamp of the buffer, not necessary if no
+ // synchronization to other media is required
-error:
- PaHost_Term();
- DBUG(("Pa_CountDevices: returns %d\n", err ));
- return err;
-}
+ if (timeInfo->timeInfo.flags & kSystemTimeValid)
+ asioDriverInfo.nanoSeconds = ASIO64toDouble(timeInfo->timeInfo.systemTime);
+ else
+ asioDriverInfo.nanoSeconds = 0;
-/***********************************************************************/
-PaError PaHost_Init( void )
-{
- /* Have we already initialized the device info? */
- PaError err = (PaError) Pa_CountDevices();
- return ( err < 0 ) ? err : paNoError;
-}
+ if (timeInfo->timeInfo.flags & kSamplePositionValid)
+ asioDriverInfo.samples = ASIO64toDouble(timeInfo->timeInfo.samplePosition);
+ else
+ asioDriverInfo.samples = 0;
-/***********************************************************************/
-PaError PaHost_Term( void )
-{
- int i;
- PaDeviceInfo *dev;
- double *rates;
- PaError result = paNoError;
-
- if (sNumDevices > 0) {
-
- /* Free allocated sample rate arrays and names*/
- for( i=0; i<sNumDevices; i++ ){
- dev = &sDevices[i].pad_Info;
- rates = (double *) dev->sampleRates;
- if ((rates != NULL)) PaHost_FreeFastMemory(rates, MAX_NUMSAMPLINGRATES * sizeof(double));
- dev->sampleRates = NULL;
- if(dev->name != NULL) PaHost_FreeFastMemory((void *) dev->name, 32);
- dev->name = NULL;
-
- }
-
- sNumDevices = 0;
-
- /* Dispose : if not done by Pa_CloseStream */
- if(ASIODisposeBuffers() != ASE_OK) result = paHostError;
- if(ASIOExit() != ASE_OK) result = paHostError;
-
- /* remove the loaded ASIO driver */
- asioDrivers->removeCurrentDriver();
- }
-
- return result;
-}
+ if (timeInfo->timeCode.flags & kTcValid)
+ asioDriverInfo.tcSamples = ASIO64toDouble(timeInfo->timeCode.timeCodeSamples);
+ else
+ asioDriverInfo.tcSamples = 0;
-/***********************************************************************/
-PaError PaHost_OpenStream( internalPortAudioStream *past )
-{
- PaError result = paNoError;
- ASIOError err;
- int32 device;
+ // get the system reference time
+ asioDriverInfo.sysRefTime = get_sys_reference_time();
+#endif
+
+#if 0
+ // a few debug messages for the Windows device driver developer
+ // tells you the time when driver got its interrupt and the delay until the app receives
+ // the event notification.
+ static double last_samples = 0;
+ char tmp[128];
+ sprintf (tmp, "diff: %d / %d ms / %d ms / %d samples \n", asioDriverInfo.sysRefTime - (long)(asioDriverInfo.nanoSeconds / 1000000.0), asioDriverInfo.sysRefTime, (long)(asioDriverInfo.nanoSeconds / 1000000.0), (long)(asioDriverInfo.samples - last_samples));
+ OutputDebugString (tmp);
+ last_samples = asioDriverInfo.samples;
+#endif
+
+ // Keep sample position
+ // FIXME: asioDriverInfo.pahsc_NumFramesDone = timeInfo->timeInfo.samplePosition.lo;
+
+ if( theAsioStream->stopProcessing || theAsioStream->abortProcessing ) {
+
+ ZeroOutputBuffers( theAsioStream, index );
+
+ // Finally if the driver supports the ASIOOutputReady() optimization,
+ // do it here, all data are in place
+ if( theAsioStream->postOutput )
+ ASIOOutputReady();
+
+ }
+ else
+ {
+ int i;
- /* Check if a stream already runs */
- if (asioDriverInfo.past != NULL) return paHostError;
-
- /* Check the device number */
- if ((past->past_InputDeviceID != paNoDevice)
- &&(past->past_OutputDeviceID != paNoDevice)
- &&(past->past_InputDeviceID != past->past_OutputDeviceID))
+ PaUtil_BeginCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer );
+
+ PaStreamCallbackTimeInfo paTimeInfo;
+
+ // asio systemTime is supposed to be measured according to the same
+ // clock as timeGetTime
+ paTimeInfo.currentTime = (ASIO64toDouble( timeInfo->timeInfo.systemTime ) * .000000001);
+ paTimeInfo.inputBufferAdcTime = paTimeInfo.currentTime - theAsioStream->streamRepresentation.streamInfo.inputLatency;
+ paTimeInfo.outputBufferDacTime = paTimeInfo.currentTime + theAsioStream->streamRepresentation.streamInfo.outputLatency;
+
+
+ if( theAsioStream->inputBufferConverter )
{
- return paInvalidDeviceId;
+ for( i=0; i<theAsioStream->numInputChannels; i++ )
+ {
+ theAsioStream->inputBufferConverter( theAsioStream->inputBufferPtrs[index][i],
+ theAsioStream->inputShift, theAsioStream->framesPerHostCallback );
+ }
}
- /* Allocation */
- memset(&asioDriverInfo, 0, sizeof(PaHostSoundControl));
- past->past_DeviceData = (void*) &asioDriverInfo;
-
+ PaUtil_BeginBufferProcessing( &theAsioStream->bufferProcessor, &paTimeInfo );
- /* FIXME */
- asioDriverInfo.past = past;
-
- /* load the ASIO device */
- device = (past->past_InputDeviceID < 0) ? past->past_OutputDeviceID : past->past_InputDeviceID;
- result = Pa_ASIO_loadDevice(device);
- if (result != paNoError) goto error;
-
- /* Check ASIO parameters and input parameters */
- if ((past->past_NumInputChannels > asioDriverInfo.pahsc_NumInputChannels)
- || (past->past_NumOutputChannels > asioDriverInfo.pahsc_NumOutputChannels)) {
- result = paInvalidChannelCount;
- goto error;
- }
+ PaUtil_SetInputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
+ for( i=0; i<theAsioStream->numInputChannels; ++i )
+ PaUtil_SetNonInterleavedInputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->inputBufferPtrs[index][i] );
+
+ PaUtil_SetOutputFrameCount( &theAsioStream->bufferProcessor, 0 /* default to host buffer size */ );
+ for( i=0; i<theAsioStream->numOutputChannels; ++i )
+ PaUtil_SetNonInterleavedOutputChannel( &theAsioStream->bufferProcessor, i, theAsioStream->outputBufferPtrs[index][i] );
+
+ int callbackResult;
+ unsigned long framesProcessed = PaUtil_EndBufferProcessing( &theAsioStream->bufferProcessor, &callbackResult );
- /* Set sample rate */
- if (ASIOSetSampleRate(past->past_SampleRate) != ASE_OK) {
- result = paInvalidSampleRate;
- goto error;
+ if( theAsioStream->outputBufferConverter )
+ {
+ for( i=0; i<theAsioStream->numOutputChannels; i++ )
+ {
+ theAsioStream->outputBufferConverter( theAsioStream->outputBufferPtrs[index][i],
+ theAsioStream->outputShift, theAsioStream->framesPerHostCallback );
+ }
}
-
- /* if OK calc buffer size */
- result = PaHost_CalcNumHostBuffers( past );
- if (result != paNoError) goto error;
-
-
- /*
- Allocating input and output buffers number for the real past_NumInputChannels and past_NumOutputChannels
- optimize the data transfer.
- */
-
- asioDriverInfo.pahsc_NumInputChannels = past->past_NumInputChannels;
- asioDriverInfo.pahsc_NumOutputChannels = past->past_NumOutputChannels;
-
- /* Allocate ASIO buffers and callback*/
- err = Pa_ASIO_CreateBuffers(&asioDriverInfo,
- asioDriverInfo.pahsc_NumInputChannels,
- asioDriverInfo.pahsc_NumOutputChannels,
- asioDriverInfo.past_FramesPerHostBuffer);
-
- if (err == ASE_OK)
- return paNoError;
- else if (err == ASE_NoMemory)
- result = paInsufficientMemory;
- else if (err == ASE_InvalidParameter)
- result = paInvalidChannelCount;
- else if (err == ASE_InvalidMode)
- result = paBufferTooBig;
- else
- result = paHostError;
-
-error:
- ASIOExit();
- return result;
-}
+ PaUtil_EndCpuLoadMeasurement( &theAsioStream->cpuLoadMeasurer, framesProcessed );
-/***********************************************************************/
-PaError PaHost_CloseStream( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc;
- PaError result = paNoError;
+ // Finally if the driver supports the ASIOOutputReady() optimization,
+ // do it here, all data are in place
+ if( theAsioStream->postOutput )
+ ASIOOutputReady();
- if( past == NULL ) return paBadStreamPtr;
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return paNoError;
+ if( callbackResult == paContinue )
+ {
+ /* nothing special to do */
+ }
+ else if( callbackResult == paAbort )
+ {
+ /* IMPLEMENT ME - finish playback immediately */
+ }
+ else
+ {
+ /* User callback has asked us to stop with paComplete or other non-zero value */
- #if PA_TRACE_START_STOP
- AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
- #endif
-
- /* Dispose */
- if(ASIODisposeBuffers() != ASE_OK) result = paHostError;
- if(ASIOExit() != ASE_OK) result = paHostError;
-
- /* Free data and device for output. */
- past->past_DeviceData = NULL;
- asioDriverInfo.past = NULL;
-
- return result;
+ /* IMPLEMENT ME - finish playback once currently queued audio has completed */
+ }
+ }
+
+ return 0L;
}
-/***********************************************************************/
-PaError PaHost_StartOutput( internalPortAudioStream *past )
+
+static void sampleRateChanged(ASIOSampleRate sRate)
{
- /* Clear the index 0 host output buffer */
- Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos,
- asioDriverInfo.pahsc_channelInfos[0].type,
- asioDriverInfo.pahsc_NumInputChannels,
- asioDriverInfo.pahsc_NumOutputChannels,
- 0,
- 0,
- asioDriverInfo.past_FramesPerHostBuffer);
-
- /* Clear the index 1 host output buffer */
- Pa_ASIO_Clear_Output(asioDriverInfo.bufferInfos,
- asioDriverInfo.pahsc_channelInfos[0].type,
- asioDriverInfo.pahsc_NumInputChannels,
- asioDriverInfo.pahsc_NumOutputChannels,
- 1,
- 0,
- asioDriverInfo.past_FramesPerHostBuffer);
-
- Pa_ASIO_Clear_User_Buffers();
-
- Pa_ASIO_Adaptor_Init();
+ // TAKEN FROM THE ASIO SDK
+ // do whatever you need to do if the sample rate changed
+ // usually this only happens during external sync.
+ // Audio processing is not stopped by the driver, actual sample rate
+ // might not have even changed, maybe only the sample rate status of an
+ // AES/EBU or S/PDIF digital input at the audio device.
+ // You might have to update time/sample related conversion routines, etc.
- return paNoError;
+ (void) sRate; /* unused parameter */
}
-/***********************************************************************/
-PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+static long asioMessages(long selector, long value, void* message, double* opt)
{
- /* Nothing to do ?? */
- return paNoError;
-}
+// TAKEN FROM THE ASIO SDK
+ // currently the parameters "value", "message" and "opt" are not used.
+ long ret = 0;
-/***********************************************************************/
-PaError PaHost_StartInput( internalPortAudioStream *past )
-{
- /* Nothing to do ?? */
- return paNoError;
-}
+ (void) message; /* unused parameters */
+ (void) opt;
+
+ switch(selector)
+ {
+ case kAsioSelectorSupported:
+ if(value == kAsioResetRequest
+ || value == kAsioEngineVersion
+ || value == kAsioResyncRequest
+ || value == kAsioLatenciesChanged
+ // the following three were added for ASIO 2.0, you don't necessarily have to support them
+ || value == kAsioSupportsTimeInfo
+ || value == kAsioSupportsTimeCode
+ || value == kAsioSupportsInputMonitor)
+ ret = 1L;
+ break;
+
+ case kAsioBufferSizeChange:
+ //printf("kAsioBufferSizeChange \n");
+ break;
+
+ case kAsioResetRequest:
+ // defer the task and perform the reset of the driver during the next "safe" situation
+ // You cannot reset the driver right now, as this code is called from the driver.
+ // Reset the driver is done by completely destruct is. I.e. ASIOStop(), ASIODisposeBuffers(), Destruction
+ // Afterwards you initialize the driver again.
+
+ /*FIXME: commented the next line out */
+ //asioDriverInfo.stopped; // In this sample the processing will just stop
+ ret = 1L;
+ break;
+
+ case kAsioResyncRequest:
+ // This informs the application, that the driver encountered some non fatal data loss.
+ // It is used for synchronization purposes of different media.
+ // Added mainly to work around the Win16Mutex problems in Windows 95/98 with the
+ // Windows Multimedia system, which could loose data because the Mutex was hold too long
+ // by another thread.
+ // However a driver can issue it in other situations, too.
+ ret = 1L;
+ break;
+
+ case kAsioLatenciesChanged:
+ // This will inform the host application that the drivers were latencies changed.
+ // Beware, it this does not mean that the buffer sizes have changed!
+ // You might need to update internal delay data.
+ ret = 1L;
+ //printf("kAsioLatenciesChanged \n");
+ break;
+
+ case kAsioEngineVersion:
+ // return the supported ASIO version of the host application
+ // If a host applications does not implement this selector, ASIO 1.0 is assumed
+ // by the driver
+ ret = 2L;
+ break;
+
+ case kAsioSupportsTimeInfo:
+ // informs the driver wether the asioCallbacks.bufferSwitchTimeInfo() callback
+ // is supported.
+ // For compatibility with ASIO 1.0 drivers the host application should always support
+ // the "old" bufferSwitch method, too.
+ ret = 1;
+ break;
+
+ case kAsioSupportsTimeCode:
+ // informs the driver wether application is interested in time code info.
+ // If an application does not need to know about time code, the driver has less work
+ // to do.
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaAsioStream *stream = (PaAsioStream*)s;
+ ASIOError asioError;
+
+ if( stream->numOutputChannels > 0 )
+ {
+ ZeroOutputBuffers( stream, 0 );
+ ZeroOutputBuffers( stream, 1 );
+ }
+
+ stream->stopProcessing = 0;
+ stream->abortProcessing = 0;
+
+ theAsioStream = stream;
+ asioError = ASIOStart();
+ if( asioError != ASE_OK )
+ {
+ theAsioStream = 0;
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ }
-/***********************************************************************/
-PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
-{
- /* Nothing to do */
- return paNoError;
+ return result;
}
-/***********************************************************************/
-PaError PaHost_StartEngine( internalPortAudioStream *past )
-{
- // TO DO : count of samples
- past->past_IsActive = 1;
- return (ASIOStart() == ASE_OK) ? paNoError : paHostError;
-}
-/***********************************************************************/
-PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+static PaError StopStream( PaStream *s )
{
- // TO DO : count of samples
- past->past_IsActive = 0;
- return (ASIOStop() == ASE_OK) ? paNoError : paHostError;
-}
+ PaError result = paNoError;
+ PaAsioStream *stream = (PaAsioStream*)s;
+ ASIOError asioError;
-/***********************************************************************/
-// TO BE CHECKED
-PaError PaHost_StreamActive( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc;
- if( past == NULL ) return paBadStreamPtr;
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return paInternalError;
- return (PaError) past->past_IsActive;
+ stream->stopProcessing = 1;
+ stream->abortProcessing = 1;
+
+ asioError = ASIOStop();
+ if( asioError != ASE_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_ASIO_SET_LAST_ASIO_ERROR( asioError );
+ }
+
+ theAsioStream = 0;
+
+ return result;
}
-/*************************************************************************/
-PaTimestamp Pa_StreamTime( PortAudioStream *stream )
-{
- PaHostSoundControl *pahsc;
- internalPortAudioStream *past = (internalPortAudioStream *) stream;
- if( past == NULL ) return paBadStreamPtr;
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
- return pahsc->pahsc_NumFramesDone;
-}
-/*************************************************************************
- * Allocate memory that can be accessed in real-time.
- * This may need to be held in physical memory so that it is not
- * paged to virtual memory.
- * This call MUST be balanced with a call to PaHost_FreeFastMemory().
- */
-void *PaHost_AllocateFastMemory( long numBytes )
+static PaError AbortStream( PaStream *s )
{
- #if MAC
- void *addr = NewPtrClear( numBytes );
- if( (addr == NULL) || (MemError () != 0) ) return NULL;
-
- #if (CARBON_COMPATIBLE == 0)
- if( HoldMemory( addr, numBytes ) != noErr )
- {
- DisposePtr( (Ptr) addr );
- return NULL;
- }
- #endif
- return addr;
- #elif WINDOWS
- void *addr = malloc( numBytes ); /* FIXME - do we need physical memory? */
- if( addr != NULL ) memset( addr, 0, numBytes );
- return addr;
- #endif
+ /* ASIO doesn't provide Abort behavior, so just stop instead */
+ return StopStream( s );
}
-/*************************************************************************
- * Free memory that could be accessed in real-time.
- * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
- */
-void PaHost_FreeFastMemory( void *addr, long numBytes )
+
+static PaError IsStreamStopped( PaStream *s )
{
- #if MAC
- if( addr == NULL ) return;
- #if CARBON_COMPATIBLE
- (void) numBytes;
- #else
- UnholdMemory( addr, numBytes );
- #endif
- DisposePtr( (Ptr) addr );
- #elif WINDOWS
- if( addr != NULL ) free( addr );
- #endif
+ //PaAsioStream *stream = (PaAsioStream*)s;
+ (void) s; /* unused parameter */
+ return theAsioStream == 0;
}
-/*************************************************************************/
-void Pa_Sleep( long msec )
+static PaError IsStreamActive( PaStream *s )
{
- #if MAC
- int32 sleepTime, endTime;
- /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */
- sleepTime = ((msec * 60) + 999) / 1000;
- if( sleepTime < 1 ) sleepTime = 1;
- endTime = TickCount() + sleepTime;
- do{
- DBUGX(("Sleep for %d ticks.\n", sleepTime ));
- WaitNextEvent( 0, NULL, sleepTime, NULL ); /* Use this just to sleep without getting events. */
- sleepTime = endTime - TickCount();
- } while( sleepTime > 0 );
- #elif WINDOWS
- Sleep( msec );
- #endif
+ //PaAsioStream *stream = (PaAsioStream*)s;
+ (void) s; /* unused parameter */
+ return theAsioStream != 0; /* FIXME: currently there is no way to stop the stream from the callback */
}
-/*************************************************************************/
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
-{
- if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
- return &sDevices[id].pad_Info;
-}
-/*************************************************************************/
-PaDeviceID Pa_GetDefaultInputDeviceID( void )
+static PaTime GetStreamTime( PaStream *s )
{
- return sDefaultInputDeviceID;
+ (void) s; /* unused parameter */
+ return (double)timeGetTime() * .001;
}
-/*************************************************************************/
-PaDeviceID Pa_GetDefaultOutputDeviceID( void )
-{
- return sDefaultOutputDeviceID;
-}
-/*************************************************************************/
-int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate )
+static double GetStreamCpuLoad( PaStream* s )
{
- // TO BE IMPLEMENTED : using the ASIOGetLatency call??
- return 2;
-}
+ PaAsioStream *stream = (PaAsioStream*)s;
-/*************************************************************************/
-int32 Pa_GetHostError( void )
-{
- int32 err = sPaHostError;
- sPaHostError = 0;
- return err;
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
}
-#ifdef MAC
+/*
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
-/**************************************************************************/
-static void Pa_StartUsageCalculation( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- UnsignedWide widePad;
- if( pahsc == NULL ) return;
-/* Query system timer for usage analysis and to prevent overuse of CPU. */
- Microseconds( &widePad );
- pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad );
-}
-/**************************************************************************/
-static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+static PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
{
- UnsignedWide widePad;
- UInt64 CurrentCount;
- long InsideCount;
- long TotalCount;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return;
-/* Measure CPU utilization during this callback. Note that this calculation
-** assumes that we had the processor the whole time.
-*/
-#define LOWPASS_COEFFICIENT_0 (0.9)
-#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
- Microseconds( &widePad );
- CurrentCount = UnsignedWideToUInt64( widePad );
- if( past->past_IfLastExitValid )
- {
- InsideCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_EntryCount);
- TotalCount = (long) U64Subtract(CurrentCount, pahsc->pahsc_LastExitCount);
-/* Low pass filter the result because sometimes we get called several times in a row.
-* That can cause the TotalCount to be very low which can cause the usage to appear
-* unnaturally high. So we must filter numerator and denominator separately!!!
-*/
- past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
- (LOWPASS_COEFFICIENT_1 * InsideCount));
- past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
- (LOWPASS_COEFFICIENT_1 * TotalCount));
- past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
- }
- pahsc->pahsc_LastExitCount = CurrentCount;
- past->past_IfLastExitValid = 1;
+ PaAsioStream *stream = (PaAsioStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameters */
+ (void) buffer;
+ (void) frames;
+
+ return paNoError;
}
-#elif WINDOWS
-/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
-static void Pa_StartUsageCalculation( internalPortAudioStream *past )
+static PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return;
-/* Query system timer for usage analysis and to prevent overuse of CPU. */
- QueryPerformanceCounter( &pahsc->pahsc_EntryCount );
+ PaAsioStream *stream = (PaAsioStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameters */
+ (void) buffer;
+ (void) frames;
+
+ return paNoError;
}
-static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+
+static signed long GetStreamReadAvailable( PaStream* s )
{
- LARGE_INTEGER CurrentCount = { 0, 0 };
- LONGLONG InsideCount;
- LONGLONG TotalCount;
-/*
-** Measure CPU utilization during this callback. Note that this calculation
-** assumes that we had the processor the whole time.
-*/
-#define LOWPASS_COEFFICIENT_0 (0.9)
-#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+ PaAsioStream *stream = (PaAsioStream*)s;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- if( pahsc == NULL ) return;
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameter */
- if( QueryPerformanceCounter( &CurrentCount ) )
- {
- if( past->past_IfLastExitValid )
- {
- InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart;
- TotalCount = CurrentCount.QuadPart - pahsc->pahsc_LastExitCount.QuadPart;
-/* Low pass filter the result because sometimes we get called several times in a row.
- * That can cause the TotalCount to be very low which can cause the usage to appear
- * unnaturally high. So we must filter numerator and denominator separately!!!
- */
- past->past_AverageInsideCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
- (LOWPASS_COEFFICIENT_1 * InsideCount));
- past->past_AverageTotalCount = (( LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
- (LOWPASS_COEFFICIENT_1 * TotalCount));
- past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
- }
- pahsc->pahsc_LastExitCount = CurrentCount;
- past->past_IfLastExitValid = 1;
- }
+ return 0;
}
-#endif
-
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+ PaAsioStream *stream = (PaAsioStream*)s;
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameter */
+
+ return 0;
+}
diff --git a/pd/portaudio/pa_asio/pa_asio.h b/pd/portaudio/pa_asio/pa_asio.h
new file mode 100644
index 00000000..c2775928
--- /dev/null
+++ b/pd/portaudio/pa_asio/pa_asio.h
@@ -0,0 +1,68 @@
+#ifndef PA_ASIO_H
+#define PA_ASIO_H
+/*
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * ASIO specific extensions
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+#include "portaudio.h"
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+/** Retrieve legal latency settings for the specificed device, in samples.
+
+ @param device The global index of the device about which the query is being made.
+ @param minLatency A pointer to the location which will recieve the minimum latency value.
+ @param maxLatency A pointer to the location which will recieve the maximum latency value.
+ @param minLatency A pointer to the location which will recieve the preferred latency value.
+ @param granularity A pointer to the location which will recieve the granularity. This value
+ determines which values between minLatency and maxLatency are available. ie the step size,
+ if granularity is -1 then available latency settings are powers of two.
+
+ @see ASIOGetBufferSize in the ASIO SDK.
+
+ @todo This function should have a better name, any suggestions?
+*/
+PaError PaAsio_GetAvailableLatencyValues( PaDeviceIndex device,
+ long *minLatency, long *maxLatency, long *preferredLatency, long *granularity );
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PA_ASIO_H */
diff --git a/pd/portaudio/pa_asio/readme_asio_sdk_patch.txt b/pd/portaudio/pa_asio/readme_asio_sdk_patch.txt
new file mode 100755
index 00000000..c0fdca7f
--- /dev/null
+++ b/pd/portaudio/pa_asio/readme_asio_sdk_patch.txt
@@ -0,0 +1,25 @@
+There is a bug in the ASIO SDK that causes the Macintosh version to often fail during initialization. Here is a patch that you can apply.
+
+In codefragments.cpp replace getFrontProcessDirectory function with
+the following one (GetFrontProcess replaced by GetCurrentProcess)
+
+
+bool CodeFragments::getFrontProcessDirectory(void *specs)
+{
+ FSSpec *fss = (FSSpec *)specs;
+ ProcessInfoRec pif;
+ ProcessSerialNumber psn;
+
+ memset(&psn,0,(long)sizeof(ProcessSerialNumber));
+ // if(GetFrontProcess(&psn) == noErr) // wrong !!!
+ if(GetCurrentProcess(&psn) == noErr) // correct !!!
+ {
+ pif.processName = 0;
+ pif.processAppSpec = fss;
+ pif.processInfoLength = sizeof(ProcessInfoRec);
+ if(GetProcessInformation(&psn, &pif) == noErr)
+ return true;
+ }
+ return false;
+}
+
diff --git a/pd/portaudio/pa_beos/PlaybackNode.cc b/pd/portaudio/pa_beos/PlaybackNode.cc
new file mode 100644
index 00000000..41cbae34
--- /dev/null
+++ b/pd/portaudio/pa_beos/PlaybackNode.cc
@@ -0,0 +1,538 @@
+/*
+ * $Id: PlaybackNode.cc,v 1.1.1.1 2003-05-09 16:03:53 ggeiger Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * BeOS Media Kit Implementation by Joshua Haberman
+ *
+ * Copyright (c) 2001 Joshua Haberman <joshua@haberman.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ---
+ *
+ * Significant portions of this file are based on sample code from Be. The
+ * Be Sample Code Licence follows:
+ *
+ * Copyright 1991-1999, Be Incorporated.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions, and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+#include <be/media/BufferGroup.h>
+#include <be/media/Buffer.h>
+#include <be/media/TimeSource.h>
+
+#include "PlaybackNode.h"
+
+#define PRINT(x) { printf x; fflush(stdout); }
+
+#ifdef DEBUG
+#define DBUG(x) PRINT(x)
+#else
+#define DBUG(x)
+#endif
+
+
+PaPlaybackNode::PaPlaybackNode(uint32 channels, float frame_rate, uint32 frames_per_buffer,
+ PortAudioCallback* callback, void *user_data) :
+ BMediaNode("PortAudio input node"),
+ BBufferProducer(B_MEDIA_RAW_AUDIO),
+ BMediaEventLooper(),
+ mAborted(false),
+ mRunning(false),
+ mBufferGroup(NULL),
+ mDownstreamLatency(0),
+ mStartTime(0),
+ mCallback(callback),
+ mUserData(user_data),
+ mFramesPerBuffer(frames_per_buffer)
+{
+ DBUG(("Constructor called.\n"));
+
+ mPreferredFormat.type = B_MEDIA_RAW_AUDIO;
+ mPreferredFormat.u.raw_audio.channel_count = channels;
+ mPreferredFormat.u.raw_audio.frame_rate = frame_rate;
+ mPreferredFormat.u.raw_audio.byte_order =
+ (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN;
+ mPreferredFormat.u.raw_audio.buffer_size =
+ media_raw_audio_format::wildcard.buffer_size;
+
+ mOutput.destination = media_destination::null;
+ mOutput.format = mPreferredFormat;
+
+ /* The amount of time it takes for this node to produce a buffer when
+ * asked. Essentially, it is how long the user's callback takes to run.
+ * We set this to be the length of the sound data each buffer of the
+ * requested size can hold. */
+ //mInternalLatency = (bigtime_t)(1000000 * frames_per_buffer / frame_rate);
+
+ /* ACK! it seems that the mixer (at least on my machine) demands that IT
+ * specify the buffer size, so for now I'll just make a generic guess here */
+ mInternalLatency = 1000000 / 20;
+}
+
+
+
+PaPlaybackNode::~PaPlaybackNode()
+{
+ DBUG(("Destructor called.\n"));
+ Quit(); /* Stop the BMediaEventLooper thread */
+}
+
+
+/*************************
+ *
+ * Local methods
+ *
+ */
+
+bool PaPlaybackNode::IsRunning()
+{
+ return mRunning;
+}
+
+
+PaTimestamp PaPlaybackNode::GetStreamTime()
+{
+ BTimeSource *timeSource = TimeSource();
+ PaTimestamp time = (timeSource->Now() - mStartTime) *
+ mPreferredFormat.u.raw_audio.frame_rate / 1000000;
+ return time;
+}
+
+
+void PaPlaybackNode::SetSampleFormat(PaSampleFormat inFormat,
+ PaSampleFormat outFormat)
+{
+ uint32 beOutFormat;
+
+ switch(outFormat)
+ {
+ case paFloat32:
+ beOutFormat = media_raw_audio_format::B_AUDIO_FLOAT;
+ mOutputSampleWidth = 4;
+ break;
+
+ case paInt16:
+ beOutFormat = media_raw_audio_format::B_AUDIO_SHORT;
+ mOutputSampleWidth = 2;
+ break;
+
+ case paInt32:
+ beOutFormat = media_raw_audio_format::B_AUDIO_INT;
+ mOutputSampleWidth = 4;
+ break;
+
+ case paInt8:
+ beOutFormat = media_raw_audio_format::B_AUDIO_CHAR;
+ mOutputSampleWidth = 1;
+ break;
+
+ case paUInt8:
+ beOutFormat = media_raw_audio_format::B_AUDIO_UCHAR;
+ mOutputSampleWidth = 1;
+ break;
+
+ case paInt24:
+ case paPackedInt24:
+ case paCustomFormat:
+ DBUG(("Unsupported output format: %x\n", outFormat));
+ break;
+
+ default:
+ DBUG(("Unknown output format: %x\n", outFormat));
+ }
+
+ mPreferredFormat.u.raw_audio.format = beOutFormat;
+ mFramesPerBuffer * mPreferredFormat.u.raw_audio.channel_count * mOutputSampleWidth;
+}
+
+BBuffer *PaPlaybackNode::FillNextBuffer(bigtime_t time)
+{
+ /* Get a buffer from the buffer group */
+ BBuffer *buf = mBufferGroup->RequestBuffer(
+ mOutput.format.u.raw_audio.buffer_size, BufferDuration());
+ unsigned long frames = mOutput.format.u.raw_audio.buffer_size /
+ mOutputSampleWidth / mOutput.format.u.raw_audio.channel_count;
+ bigtime_t start_time;
+ int ret;
+
+ if( !buf )
+ {
+ DBUG(("Unable to allocate a buffer\n"));
+ return NULL;
+ }
+
+ start_time = mStartTime +
+ (bigtime_t)((double)mSamplesSent /
+ (double)mOutput.format.u.raw_audio.frame_rate /
+ (double)mOutput.format.u.raw_audio.channel_count *
+ 1000000.0);
+
+ /* Now call the user callback to get the data */
+ ret = mCallback(NULL, /* Input buffer */
+ buf->Data(), /* Output buffer */
+ frames, /* Frames per buffer */
+ mSamplesSent / mOutput.format.u.raw_audio.channel_count, /* timestamp */
+ mUserData);
+
+ if( ret )
+ mAborted = true;
+
+ media_header *hdr = buf->Header();
+
+ hdr->type = B_MEDIA_RAW_AUDIO;
+ hdr->size_used = mOutput.format.u.raw_audio.buffer_size;
+ hdr->time_source = TimeSource()->ID();
+ hdr->start_time = start_time;
+
+ return buf;
+}
+
+
+
+
+/*************************
+ *
+ * BMediaNode methods
+ *
+ */
+
+BMediaAddOn *PaPlaybackNode::AddOn( int32 * ) const
+{
+ DBUG(("AddOn() called.\n"));
+ return NULL; /* we don't provide service to outside applications */
+}
+
+
+status_t PaPlaybackNode::HandleMessage( int32 message, const void *data,
+ size_t size )
+{
+ DBUG(("HandleMessage() called.\n"));
+ return B_ERROR; /* we don't define any custom messages */
+}
+
+
+
+
+/*************************
+ *
+ * BMediaEventLooper methods
+ *
+ */
+
+void PaPlaybackNode::NodeRegistered()
+{
+ DBUG(("NodeRegistered() called.\n"));
+
+ /* Start the BMediaEventLooper thread */
+ SetPriority(B_REAL_TIME_PRIORITY);
+ Run();
+
+ /* set up as much information about our output as we can */
+ mOutput.source.port = ControlPort();
+ mOutput.source.id = 0;
+ mOutput.node = Node();
+ ::strcpy(mOutput.name, "PortAudio Playback");
+}
+
+
+void PaPlaybackNode::HandleEvent( const media_timed_event *event,
+ bigtime_t lateness, bool realTimeEvent )
+{
+ // DBUG(("HandleEvent() called.\n"));
+ status_t err;
+
+ switch(event->type)
+ {
+ case BTimedEventQueue::B_START:
+ DBUG((" Handling a B_START event\n"));
+ if( RunState() != B_STARTED )
+ {
+ mStartTime = event->event_time + EventLatency();
+ mSamplesSent = 0;
+ mAborted = false;
+ mRunning = true;
+ media_timed_event firstEvent( mStartTime,
+ BTimedEventQueue::B_HANDLE_BUFFER );
+ EventQueue()->AddEvent( firstEvent );
+ }
+ break;
+
+ case BTimedEventQueue::B_STOP:
+ DBUG((" Handling a B_STOP event\n"));
+ mRunning = false;
+ EventQueue()->FlushEvents( 0, BTimedEventQueue::B_ALWAYS, true,
+ BTimedEventQueue::B_HANDLE_BUFFER );
+ break;
+
+ case BTimedEventQueue::B_HANDLE_BUFFER:
+ //DBUG((" Handling a B_HANDLE_BUFFER event\n"));
+
+ /* make sure we're started and connected */
+ if( RunState() != BMediaEventLooper::B_STARTED ||
+ mOutput.destination == media_destination::null )
+ break;
+
+ BBuffer *buffer = FillNextBuffer(event->event_time);
+
+ /* make sure we weren't aborted while this routine was running.
+ * this can happen in one of two ways: either the callback returned
+ * nonzero (in which case mAborted is set in FillNextBuffer() ) or
+ * the client called AbortStream */
+ if( mAborted )
+ {
+ if( buffer )
+ buffer->Recycle();
+ Stop(0, true);
+ break;
+ }
+
+ if( buffer )
+ {
+ err = SendBuffer(buffer, mOutput.destination);
+ if( err != B_OK )
+ buffer->Recycle();
+ }
+
+ mSamplesSent += mOutput.format.u.raw_audio.buffer_size / mOutputSampleWidth;
+
+ /* Now schedule the next buffer event, so we can send another
+ * buffer when this one runs out. We calculate when it should
+ * happen by calculating when the data we just sent will finish
+ * playing.
+ *
+ * NOTE, however, that the event will actually get generated
+ * earlier than we specify, to account for the latency it will
+ * take to produce the buffer. It uses the latency value we
+ * specified in SetEventLatency() to determine just how early
+ * to generate it. */
+
+ /* totalPerformanceTime includes the time represented by the buffer
+ * we just sent */
+ bigtime_t totalPerformanceTime = (bigtime_t)((double)mSamplesSent /
+ (double)mOutput.format.u.raw_audio.channel_count /
+ (double)mOutput.format.u.raw_audio.frame_rate * 1000000.0);
+
+ bigtime_t nextEventTime = mStartTime + totalPerformanceTime;
+
+ media_timed_event nextBufferEvent(nextEventTime,
+ BTimedEventQueue::B_HANDLE_BUFFER);
+ EventQueue()->AddEvent(nextBufferEvent);
+
+ break;
+
+ }
+}
+
+
+
+
+/*************************
+ *
+ * BBufferProducer methods
+ *
+ */
+
+status_t PaPlaybackNode::FormatSuggestionRequested( media_type type,
+ int32 /*quality*/, media_format* format )
+{
+ /* the caller wants to know this node's preferred format and provides
+ * a suggestion, asking if we support it */
+ DBUG(("FormatSuggestionRequested() called.\n"));
+
+ if(!format)
+ return B_BAD_VALUE;
+
+ *format = mPreferredFormat;
+
+ /* we only support raw audio (a wildcard is okay too) */
+ if ( type == B_MEDIA_UNKNOWN_TYPE || type == B_MEDIA_RAW_AUDIO )
+ return B_OK;
+ else
+ return B_MEDIA_BAD_FORMAT;
+}
+
+
+status_t PaPlaybackNode::FormatProposal( const media_source& output,
+ media_format* format )
+{
+ /* This is similar to FormatSuggestionRequested(), but it is actually part
+ * of the negotiation process. We're given the opportunity to specify any
+ * properties that are wildcards (ie. properties that the other node doesn't
+ * care one way or another about) */
+ DBUG(("FormatProposal() called.\n"));
+
+ /* Make sure this proposal really applies to our output */
+ if( output != mOutput.source )
+ return B_MEDIA_BAD_SOURCE;
+
+ /* We return two things: whether we support the proposed format, and our own
+ * preferred format */
+ *format = mPreferredFormat;
+
+ if( format->type == B_MEDIA_UNKNOWN_TYPE || format->type == B_MEDIA_RAW_AUDIO )
+ return B_OK;
+ else
+ return B_MEDIA_BAD_FORMAT;
+}
+
+
+status_t PaPlaybackNode::FormatChangeRequested( const media_source& source,
+ const media_destination& destination, media_format* io_format, int32* )
+{
+ /* we refuse to change formats, supporting only 1 */
+ DBUG(("FormatChangeRequested() called.\n"));
+
+ return B_ERROR;
+}
+
+
+status_t PaPlaybackNode::GetNextOutput( int32* cookie, media_output* out_output )
+{
+ /* this is where we allow other to enumerate our outputs -- the cookie is
+ * an integer we can use to keep track of where we are in enumeration. */
+ DBUG(("GetNextOutput() called.\n"));
+
+ if( *cookie == 0 )
+ {
+ *out_output = mOutput;
+ *cookie = 1;
+ return B_OK;
+ }
+
+ return B_BAD_INDEX;
+}
+
+
+status_t PaPlaybackNode::DisposeOutputCookie( int32 cookie )
+{
+ DBUG(("DisposeOutputCookie() called.\n"));
+ return B_OK;
+}
+
+
+void PaPlaybackNode::LateNoticeReceived( const media_source& what,
+ bigtime_t how_much, bigtime_t performance_time )
+{
+ /* This function is called as notification that a buffer we sent wasn't
+ * received by the time we stamped it with -- it got there late. Basically,
+ * it means we underestimated our own latency, so we should increase it */
+ DBUG(("LateNoticeReceived() called.\n"));
+
+ if( what != mOutput.source )
+ return;
+
+ if( RunMode() == B_INCREASE_LATENCY )
+ {
+ mInternalLatency += how_much;
+ SetEventLatency( mDownstreamLatency + mInternalLatency );
+ DBUG(("Increasing latency to %Ld\n", mDownstreamLatency + mInternalLatency));
+ }
+ else
+ DBUG(("I don't know what to do with this notice!"));
+}
+
+
+void PaPlaybackNode::EnableOutput( const media_source& what, bool enabled,
+ int32* )
+{
+ DBUG(("EnableOutput() called.\n"));
+ /* stub -- we don't support this yet */
+}
+
+
+status_t PaPlaybackNode::PrepareToConnect( const media_source& what,
+ const media_destination& where, media_format* format,
+ media_source* out_source, char* out_name )
+{
+ /* the final stage of format negotiations. here we _must_ make specific any
+ * remaining wildcards */
+ DBUG(("PrepareToConnect() called.\n"));
+
+ /* make sure this really refers to our source */
+ if( what != mOutput.source )
+ return B_MEDIA_BAD_SOURCE;
+
+ /* make sure we're not already connected */
+ if( mOutput.destination != media_destination::null )
+ return B_MEDIA_ALREADY_CONNECTED;
+
+ if( format->type != B_MEDIA_RAW_AUDIO )
+ return B_MEDIA_BAD_FORMAT;
+
+ if( format->u.raw_audio.format != mPreferredFormat.u.raw_audio.format )
+ return B_MEDIA_BAD_FORMAT;
+
+ if( format->u.raw_audio.buffer_size ==
+ media_raw_audio_format::wildcard.buffer_size )
+ {
+ DBUG(("We were left to decide buffer size: choosing 2048"));
+ format->u.raw_audio.buffer_size = 2048;
+ }
+ else
+ DBUG(("Using consumer specified buffer size of %lu.\n",
+ format->u.raw_audio.buffer_size));
+
+ /* Reserve the connection, return the information */
+ mOutput.destination = where;
+ mOutput.format = *format;
+ *out_source = mOutput.source;
+ strncpy( out_name, mOutput.name, B_MEDIA_NAME_LENGTH );
+
+ return B_OK;
+}
+
+
+void PaPlaybackNode::Connect(status_t error, const media_source& source,
+ const media_destination& destination, const media_format& format, char* io_name)
+{
+ DBUG(("Connect() called.\n"));
+
diff --git a/pd/portaudio/pa_beos/PlaybackNode.h b/pd/portaudio/pa_beos/PlaybackNode.h
new file mode 100644
index 00000000..db978a59
--- /dev/null
+++ b/pd/portaudio/pa_beos/PlaybackNode.h
@@ -0,0 +1,108 @@
+/*
+ * $Id: PlaybackNode.h,v 1.1.1.1 2003-05-09 16:03:53 ggeiger Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * BeOS Media Kit Implementation by Joshua Haberman
+ *
+ * Copyright (c) 2001 Joshua Haberman <joshua@haberman.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <be/media/MediaRoster.h>
+#include <be/media/MediaEventLooper.h>
+#include <be/media/BufferProducer.h>
+
+#include "portaudio.h"
+
+class PaPlaybackNode :
+ public BBufferProducer,
+ public BMediaEventLooper
+{
+
+public:
+ PaPlaybackNode( uint32 channels, float frame_rate, uint32 frames_per_buffer,
+ PortAudioCallback *callback, void *user_data );
+ ~PaPlaybackNode();
+
+
+ /* Local methods ******************************************/
+
+ BBuffer *FillNextBuffer(bigtime_t time);
+ void SetSampleFormat(PaSampleFormat inFormat, PaSampleFormat outFormat);
+ bool IsRunning();
+ PaTimestamp GetStreamTime();
+
+ /* BMediaNode methods *************************************/
+
+ BMediaAddOn* AddOn( int32 * ) const;
+ status_t HandleMessage( int32 message, const void *data, size_t size );
+
+ /* BMediaEventLooper methods ******************************/
+
+ void HandleEvent( const media_timed_event *event, bigtime_t lateness,
+ bool realTimeEvent );
+ void NodeRegistered();
+
+ /* BBufferProducer methods ********************************/
+
+ status_t FormatSuggestionRequested( media_type type, int32 quality,
+ media_format* format );
+ status_t FormatProposal( const media_source& output, media_format* format );
+ status_t FormatChangeRequested( const media_source& source,
+ const media_destination& destination, media_format* io_format, int32* );
+
+ status_t GetNextOutput( int32* cookie, media_output* out_output );
+ status_t DisposeOutputCookie( int32 cookie );
+
+ void LateNoticeReceived( const media_source& what, bigtime_t how_much,
+ bigtime_t performance_time );
+ void EnableOutput( const media_source& what, bool enabled, int32* _deprecated_ );
+
+ status_t PrepareToConnect( const media_source& what,
+ const media_destination& where, media_format* format,
+ media_source* out_source, char* out_name );
+ void Connect(status_t error, const media_source& source,
+ const media_destination& destination, const media_format& format,
+ char* io_name);
+ void Disconnect(const media_source& what, const media_destination& where);
+
+ status_t SetBufferGroup(const media_source& for_source, BBufferGroup* newGroup);
+
+ bool mAborted;
+
+private:
+ media_output mOutput;
+ media_format mPreferredFormat;
+ uint32 mOutputSampleWidth, mFramesPerBuffer;
+ BBufferGroup *mBufferGroup;
+ bigtime_t mDownstreamLatency, mInternalLatency, mStartTime;
+ uint64 mSamplesSent;
+ PortAudioCallback *mCallback;
+ void *mUserData;
+ bool mRunning;
+
+};
+
diff --git a/pd/portaudio/pa_beos/pa_beos_mk.cc b/pd/portaudio/pa_beos/pa_beos_mk.cc
new file mode 100644
index 00000000..3307a2ff
--- /dev/null
+++ b/pd/portaudio/pa_beos/pa_beos_mk.cc
@@ -0,0 +1,441 @@
+/*
+ * $Id: pa_beos_mk.cc,v 1.1.1.1 2003-05-09 16:03:53 ggeiger Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * BeOS Media Kit Implementation by Joshua Haberman
+ *
+ * Copyright (c) 2001 Joshua Haberman <joshua@haberman.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <be/app/Application.h>
+#include <be/kernel/OS.h>
+#include <be/media/RealtimeAlloc.h>
+#include <be/media/MediaRoster.h>
+#include <be/media/TimeSource.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+
+#include "PlaybackNode.h"
+
+#define PRINT(x) { printf x; fflush(stdout); }
+
+#ifdef DEBUG
+#define DBUG(x) PRINT(x)
+#else
+#define DBUG(x)
+#endif
+
+typedef struct PaHostSoundControl
+{
+ /* These members are common to all modes of operation */
+ media_node pahsc_TimeSource; /* the sound card's DAC. */
+ media_format pahsc_Format;
+
+ /* These methods are specific to playing mode */
+ media_node pahsc_OutputNode; /* output to the mixer */
+ media_node pahsc_InputNode; /* reads data from user callback -- PA specific */
+
+ media_input pahsc_MixerInput; /* input jack on the soundcard's mixer. */
+ media_output pahsc_PaOutput; /* output jack from the PA node */
+
+ PaPlaybackNode *pahsc_InputNodeInstance;
+
+}
+PaHostSoundControl;
+
+/*************************************************************************/
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
+{
+ /* stub */
+ return 0;
+}
+
+/*************************************************************************/
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
+{
+ /* stub */
+ return 0;
+}
+
+/*************************************************************************/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ /* stub */
+ return NULL;
+}
+
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ /* stub */
+ return 1;
+}
+
+/*************************************************************************/
+PaError PaHost_Init( void )
+{
+ /* we have to create this in order to use BMediaRoster. I hope it doesn't
+ * cause problems */
+ be_app = new BApplication("application/x-vnd.portaudio-app");
+
+ return paNoError;
+}
+
+PaError PaHost_Term( void )
+{
+ delete be_app;
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+ DBUG(("IsRunning returning: %s\n",
+ pahsc->pahsc_InputNodeInstance->IsRunning() ? "true" : "false"));
+
+ return (PaError)pahsc->pahsc_InputNodeInstance->IsRunning();
+}
+
+PaError PaHost_StartOutput( internalPortAudioStream *past )
+{
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StartInput( internalPortAudioStream *past )
+{
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+
+/*************************************************************************/
+PaError PaHost_StartEngine( internalPortAudioStream *past )
+{
+ bigtime_t very_soon, start_latency;
+ status_t err;
+ BMediaRoster *roster = BMediaRoster::Roster(&err);
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+
+ /* for some reason, err indicates an error (though nothing it wrong)
+ * when the DBUG macro in pa_lib.c is enabled. It's reproducably
+ * linked. Weird. */
+ if( !roster /* || err != B_OK */ )
+ {
+ DBUG(("No media server! err=%d, roster=%x\n", err, roster));
+ return paHostError;
+ }
+
+ /* tell the node when to start -- since there aren't any other nodes
+ * starting that we have to wait for, just tell it to start now
+ */
+
+ BTimeSource *timeSource = roster->MakeTimeSourceFor(pahsc->pahsc_TimeSource);
+ very_soon = timeSource->PerformanceTimeFor( BTimeSource::RealTime() );
+ timeSource->Release();
+
+ /* Add the latency of starting the network of nodes */
+ err = roster->GetStartLatencyFor( pahsc->pahsc_TimeSource, &start_latency );
+ very_soon += start_latency;
+
+ err = roster->StartNode( pahsc->pahsc_InputNode, very_soon );
+ /* No need to start the mixer -- it's always running */
+
+ return paNoError;
+}
+
+
+/*************************************************************************/
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+ BMediaRoster *roster = BMediaRoster::Roster();
+
+ if( !roster )
+ {
+ DBUG(("No media roster!\n"));
+ return paHostError;
+ }
+
+ if( !pahsc )
+ return paHostError;
+
+ /* this crashes, and I don't know why yet */
+ // if( abort )
+ // pahsc->pahsc_InputNodeInstance->mAborted = true;
+
+ roster->StopNode(pahsc->pahsc_InputNode, 0, /* immediate = */ true);
+
+ return paNoError;
+}
+
+
+/*************************************************************************/
+PaError PaHost_OpenStream( internalPortAudioStream *past )
+{
+ status_t err;
+ BMediaRoster *roster = BMediaRoster::Roster(&err);
+ PaHostSoundControl *pahsc;
+
+ /* Allocate and initialize host data. */
+ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
+ if( pahsc == NULL )
+ {
+ goto error;
+ }
+ memset( pahsc, 0, sizeof(PaHostSoundControl) );
+ past->past_DeviceData = (void *) pahsc;
+
+ if( !roster /* || err != B_OK */ )
+ {
+ /* no media server! */
+ DBUG(("No media server.\n"));
+ goto error;
+ }
+
+ if ( past->past_NumInputChannels > 0 && past->past_NumOutputChannels > 0 )
+ {
+ /* filter -- not implemented yet */
+ goto error;
+ }
+ else if ( past->past_NumInputChannels > 0 )
+ {
+ /* recorder -- not implemented yet */
+ goto error;
+ }
+ else
+ {
+ /* player ****************************************************************/
+
+ status_t err;
+ int32 num;
+
+ /* First we need to create the three components (like components in a stereo
+ * system). The mixer component is our interface to the sound card, data
+ * we write there will get played. The BePA_InputNode component is the node
+ * which represents communication with the PA client (it is what calls the
+ * client's callbacks). The time source component is the sound card's DAC,
+ * which allows us to slave the other components to it instead of the system
+ * clock. */
+ err = roster->GetAudioMixer( &pahsc->pahsc_OutputNode );
+ if( err != B_OK )
+ {
+ DBUG(("Couldn't get default mixer.\n"));
+ goto error;
+ }
+
+ err = roster->GetTimeSource( &pahsc->pahsc_TimeSource );
+ if( err != B_OK )
+ {
+ DBUG(("Couldn't get time source.\n"));
+ goto error;
+ }
+
+ pahsc->pahsc_InputNodeInstance = new PaPlaybackNode(2, 44100,
+ past->past_FramesPerUserBuffer, past->past_Callback, past->past_UserData );
+ pahsc->pahsc_InputNodeInstance->SetSampleFormat(0,
+ past->past_OutputSampleFormat);
+ err = roster->RegisterNode( pahsc->pahsc_InputNodeInstance );
+ if( err != B_OK )
+ {
+ DBUG(("Unable to register node.\n"));
+ goto error;
+ }
+
+ roster->GetNodeFor( pahsc->pahsc_InputNodeInstance->Node().node,
+ &pahsc->pahsc_InputNode );
+ if( err != B_OK )
+ {
+ DBUG(("Unable to get input node.\n"));
+ goto error;
+ }
+
+ /* Now we have three components (nodes) sitting next to each other. The
+ * next step is to look at them and find their inputs and outputs so we can
+ * wire them together. */
+ err = roster->GetFreeInputsFor( pahsc->pahsc_OutputNode,
+ &pahsc->pahsc_MixerInput, 1, &num, B_MEDIA_RAW_AUDIO );
+ if( err != B_OK || num < 1 )
+ {
+ DBUG(("Couldn't get the mixer input.\n"));
+ goto error;
+ }
+
+ err = roster->GetFreeOutputsFor( pahsc->pahsc_InputNode,
+ &pahsc->pahsc_PaOutput, 1, &num, B_MEDIA_RAW_AUDIO );
+ if( err != B_OK || num < 1 )
+ {
+ DBUG(("Couldn't get PortAudio output.\n"));
+ goto error;
+ }
+
+
+ /* We've found the input and output -- the final step is to run a wire
+ * between them so they are connected. */
+
+ /* try to make the mixer input adapt to what PA sends it */
+ pahsc->pahsc_Format = pahsc->pahsc_PaOutput.format;
+ roster->Connect( pahsc->pahsc_PaOutput.source,
+ pahsc->pahsc_MixerInput.destination, &pahsc->pahsc_Format,
+ &pahsc->pahsc_PaOutput, &pahsc->pahsc_MixerInput );
+
+
+ /* Actually, there's one final step -- tell them all to sync to the
+ * sound card's DAC */
+ roster->SetTimeSourceFor( pahsc->pahsc_InputNode.node,
+ pahsc->pahsc_TimeSource.node );
+ roster->SetTimeSourceFor( pahsc->pahsc_OutputNode.node,
+ pahsc->pahsc_TimeSource.node );
+
+ }
+
+ return paNoError;
+
+error:
+ PaHost_CloseStream( past );
+ return paHostError;
+}
+
+/*************************************************************************/
+PaError PaHost_CloseStream( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+ status_t err;
+ BMediaRoster *roster = BMediaRoster::Roster(&err);
+
+ if( !roster )
+ {
+ DBUG(("Couldn't get media roster\n"));
+ return paHostError;
+ }
+
+ if( !pahsc )
+ return paHostError;
+
+ /* Disconnect all the connections we made when opening the stream */
+
+ roster->Disconnect(pahsc->pahsc_InputNode.node, pahsc->pahsc_PaOutput.source,
+ pahsc->pahsc_OutputNode.node, pahsc->pahsc_MixerInput.destination);
+
+ DBUG(("Calling ReleaseNode()"));
+ roster->ReleaseNode(pahsc->pahsc_InputNode);
+
+ /* deleting the node shouldn't be necessary -- it is reference counted, and will
+ * delete itself when its references drop to zero. the call to ReleaseNode()
+ * above should decrease its reference count */
+ pahsc->pahsc_InputNodeInstance = NULL;
+
+ return paNoError;
+}
+
+/*************************************************************************/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *)past->past_DeviceData;
+
+ return pahsc->pahsc_InputNodeInstance->GetStreamTime();
+}
+
+/*************************************************************************/
+void Pa_Sleep( long msec )
+{
+ /* snooze() takes microseconds */
+ snooze( msec * 1000 );
+}
+
+/*************************************************************************
+ * Allocate memory that can be accessed in real-time.
+ * This may need to be held in physical memory so that it is not
+ * paged to virtual memory.
+ * This call MUST be balanced with a call to PaHost_FreeFastMemory().
+ * Memory will be set to zero.
+ */
+void *PaHost_AllocateFastMemory( long numBytes )
+{
+ /* BeOS supports non-pagable memory through pools -- a pool is an area
+ * of physical memory that is locked. It would be best to pre-allocate
+ * that pool and then hand out memory from it, but we don't know in
+ * advance how much we'll need. So for now, we'll allocate a pool
+ * for every request we get, storing a pointer to the pool at the
+ * beginning of the allocated memory */
+ rtm_pool *pool;
+ void *addr;
+ long size = numBytes + sizeof(rtm_pool *);
+ static int counter = 0;
+ char pool_name[100];
+
+ /* Every pool needs a unique name. */
+ sprintf(pool_name, "PaPoolNumber%d", counter++);
+
+ if( rtm_create_pool( &pool, size, pool_name ) != B_OK )
+ return 0;
+
+ addr = rtm_alloc( pool, size );
+ if( addr == NULL )
+ return 0;
+
+ memset( addr, 0, numBytes );
+ *((rtm_pool **)addr) = pool; // store the pointer to the pool
+ addr = (rtm_pool **)addr + 1; // and return the next location in memory
+
+ return addr;
+}
+
+/*************************************************************************
+ * Free memory that could be accessed in real-time.
+ * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
+ */
+void PaHost_FreeFastMemory( void *addr, long numBytes )
+{
+ rtm_pool *pool;
+
+ if( addr == NULL )
+ return;
+
+ addr = (rtm_pool **)addr - 1;
+ pool = *((rtm_pool **)addr);
+
+ rtm_free( addr );
+ rtm_delete_pool( pool );
+}
diff --git a/pd/portaudio/pa_common/pa_allocation.c b/pd/portaudio/pa_common/pa_allocation.c
new file mode 100644
index 00000000..5eefeabb
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_allocation.c
@@ -0,0 +1,217 @@
+/*
+ * Id:
+ * Portable Audio I/O Library allocation group implementation
+ * memory allocation group for tracking allocation groups
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "pa_allocation.h"
+#include "pa_util.h"
+
+/*
+ Maintain 3 singly linked lists...
+ linkBlocks: the buffers used to allocate the links
+ spareLinks: links available for use in the allocations list
+ allocations: the buffers currently allocated using PaUtil_ContextAllocateMemory()
+
+ Link block size is doubled every time new links are allocated.
+*/
+
+
+#define PA_INITIAL_LINK_COUNT_ 16
+
+struct PaUtilAllocationGroupLink
+{
+ struct PaUtilAllocationGroupLink *next;
+ void *buffer;
+};
+
+/*
+ Allocate a block of links. The first link will have it's buffer member
+ pointing to the block, and it's next member set to <nextBlock>. The remaining
+ links will have NULL buffer members, and each link will point to
+ the next link except the last, which will point to <nextSpare>
+*/
+static struct PaUtilAllocationGroupLink *AllocateLinks( long count,
+ struct PaUtilAllocationGroupLink *nextBlock,
+ struct PaUtilAllocationGroupLink *nextSpare )
+{
+ struct PaUtilAllocationGroupLink *result;
+ int i;
+
+ result = PaUtil_AllocateMemory( sizeof(struct PaUtilAllocationGroupLink) * count );
+ if( result )
+ {
+ /* the block link */
+ result[0].buffer = result;
+ result[0].next = nextBlock;
+
+ /* the spare links */
+ for( i=1; i<count; ++i )
+ {
+ result[i].buffer = 0;
+ result[i].next = &result[i+1];
+ }
+ result[count-1].next = nextSpare;
+ }
+
+ return result;
+}
+
+
+PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void )
+{
+ PaUtilAllocationGroup* result = 0;
+ struct PaUtilAllocationGroupLink *links;
+
+
+ links = AllocateLinks( PA_INITIAL_LINK_COUNT_, 0, 0 );
+ if( links != 0 )
+ {
+ result = (PaUtilAllocationGroup*)PaUtil_AllocateMemory( sizeof(PaUtilAllocationGroup) );
+ if( result )
+ {
+ result->linkCount = PA_INITIAL_LINK_COUNT_;
+ result->linkBlocks = &links[0];
+ result->spareLinks = &links[1];
+ result->allocations = 0;
+ }
+ else
+ {
+ PaUtil_FreeMemory( links );
+ }
+ }
+
+ return result;
+}
+
+
+void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group )
+{
+ struct PaUtilAllocationGroupLink *current = group->linkBlocks;
+ struct PaUtilAllocationGroupLink *next;
+
+ while( current )
+ {
+ next = current->next;
+ PaUtil_FreeMemory( current->buffer );
+ current = next;
+ }
+
+ PaUtil_FreeMemory( group );
+}
+
+
+void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size )
+{
+ struct PaUtilAllocationGroupLink *links, *link;
+ void *result = 0;
+
+ /* allocate more links if necessary */
+ if( !group->spareLinks )
+ {
+ /* double the link count on each block allocation */
+ links = AllocateLinks( group->linkCount, group->linkBlocks, group->spareLinks );
+ if( links )
+ {
+ group->linkCount += group->linkCount;
+ group->linkBlocks = &links[0];
+ group->spareLinks = &links[1];
+ }
+ }
+
+ if( group->spareLinks )
+ {
+ result = PaUtil_AllocateMemory( size );
+ if( result )
+ {
+ link = group->spareLinks;
+ group->spareLinks = link->next;
+
+ link->buffer = result;
+ link->next = group->allocations;
+
+ group->allocations = link;
+ }
+ }
+
+ return result;
+}
+
+
+void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer )
+{
+ struct PaUtilAllocationGroupLink *current = group->allocations;
+ struct PaUtilAllocationGroupLink *previous = 0;
+
+ if( buffer == 0 )
+ return;
+
+ /* find the right link and remove it */
+ while( current )
+ {
+ if( current->buffer == buffer )
+ {
+ previous->next = current->next;
+
+ current->buffer = 0;
+ current->next = group->spareLinks;
+ group->spareLinks = current;
+ }
+ previous = current;
+ current = current->next;
+ }
+
+ PaUtil_FreeMemory( buffer ); /* free the memory whether we found it in the list or not */
+}
+
+
+void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group )
+{
+ struct PaUtilAllocationGroupLink *current = group->allocations;
+ struct PaUtilAllocationGroupLink *previous = 0;
+
+ /* free all buffers in the allocations list */
+ while( current )
+ {
+ PaUtil_FreeMemory( current->buffer );
+ current->buffer = 0;
+
+ previous = current;
+ current = current->next;
+ }
+
+ /* link the former allocations list onto the front of the spareLinks list */
+ if( previous )
+ {
+ previous->next = group->spareLinks;
+ group->spareLinks = group->allocations;
+ group->allocations = 0;
+ }
+}
+
diff --git a/pd/portaudio/pa_common/pa_allocation.h b/pd/portaudio/pa_common/pa_allocation.h
new file mode 100644
index 00000000..b906c14b
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_allocation.h
@@ -0,0 +1,92 @@
+#ifndef PA_ALLOCATION_H
+#define PA_ALLOCATION_H
+/*
+ * Id:
+ * Portable Audio I/O Library allocation context header
+ * memory allocation context for tracking allocation groups
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/** @file
+ An allocation group is useful for keeping track of multiple blocks
+ of memory which are allocated at the same time (such as during initialization)
+ and need to be deallocated at the same time. The allocation group maintains
+ a list of allocated blocks, and can deallocate them all simultaneously which
+ can be usefull for cleaning up after a partially initialized object fails.
+
+ The allocation group implementation is built on top of the lower
+ level allocation functions defined in pa_util.h
+*/
+
+
+
+typedef struct
+{
+ long linkCount;
+ struct PaUtilAllocationGroupLink *linkBlocks;
+ struct PaUtilAllocationGroupLink *spareLinks;
+ struct PaUtilAllocationGroupLink *allocations;
+}PaUtilAllocationGroup;
+
+
+
+/** Create an allocation group.
+*/
+PaUtilAllocationGroup* PaUtil_CreateAllocationGroup( void );
+
+/** Destroy an allocation group, but not the memory allocated through the group.
+*/
+void PaUtil_DestroyAllocationGroup( PaUtilAllocationGroup* group );
+
+/** Allocate a block of memory though an allocation group.
+*/
+void* PaUtil_GroupAllocateMemory( PaUtilAllocationGroup* group, long size );
+
+/** Free a block of memory that was previously allocated though an allocation
+ group. Calling this function is a relatively time consuming operation.
+ Under normal circumstances clients should call PaUtil_FreeAllAllocations to
+ free all allocated blocks simultaneously.
+ @see PaUtil_FreeAllAllocations
+*/
+void PaUtil_GroupFreeMemory( PaUtilAllocationGroup* group, void *buffer );
+
+/** Free all blocks of memory which have been allocated through the allocation
+ group. This function doesn't destroy the group itself.
+*/
+void PaUtil_FreeAllAllocations( PaUtilAllocationGroup* group );
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_ALLOCATION_H */
diff --git a/pd/portaudio/pa_common/pa_allocation.o b/pd/portaudio/pa_common/pa_allocation.o
new file mode 100644
index 00000000..43ac4148
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_allocation.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_converters.c b/pd/portaudio/pa_common/pa_converters.c
new file mode 100644
index 00000000..39e5e47f
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_converters.c
@@ -0,0 +1,1653 @@
+/*
+ * $Id: pa_converters.c,v 1.1.2.13 2003/02/28 01:49:59 rossbencina Exp $
+ * Portable Audio I/O Library sample conversion mechanism
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/** @file
+
+ @todo implement the converters marked IMPLEMENT ME: Float32_To_UInt8_Dither,
+ Float32_To_UInt8_Clip, Float32_To_UInt8_DitherClip, Int32_To_Int24,
+ Int32_To_Int24_Dither, Int32_To_Int16, Int32_To_Int16_Dither, Int32_To_Int8,
+ Int32_To_Int8_Dither, Int32_To_UInt8, Int32_To_UInt8_Dither, Int24_To_Int32,
+ Int24_To_Int16, Int24_To_Int16_Dither, Int24_To_Int8, Int24_To_Int8_Dither,
+ Int24_To_UInt8, Int24_To_UInt8_Dither, Int16_To_Int32, Int16_To_Int24,
+ Int16_To_Int8, Int16_To_Int8_Dither, Int16_To_UInt8, Int16_To_UInt8_Dither,
+ Int8_To_Int32, Int8_To_Int24, Int8_To_Int16, Int8_To_UInt8, UInt8_To_Int32,
+ UInt8_To_Int24, UInt8_To_Int16, UInt8_To_Int8
+
+ @todo review the converters marked REVIEW: Float32_To_Int32,
+ Float32_To_Int32_Dither, Float32_To_Int32_Clip, Float32_To_Int32_DitherClip
+*/
+
+
+#include "pa_converters.h"
+#include "pa_dither.h"
+#include "pa_endianness.h"
+
+
+PaSampleFormat PaUtil_SelectClosestAvailableFormat(
+ PaSampleFormat availableFormats, PaSampleFormat format )
+{
+ PaSampleFormat result;
+
+ format &= ~paNonInterleaved;
+ availableFormats &= ~paNonInterleaved;
+
+ if( (format & availableFormats) == 0 )
+ {
+ /* NOTE: this code depends on the sample format constants being in
+ descending order of quality - ie best quality is 0
+ FIXME: should write an assert which checks that all of the
+ known constants conform to that requirement.
+ */
+
+ if( format != 0x01 )
+ {
+ /* scan for better formats */
+ result = format;
+ do
+ {
+ result >>= 1;
+ }
+ while( (result & availableFormats) == 0 && result != 0 );
+ }
+ else
+ {
+ result = 0;
+ }
+
+ if( result == 0 ){
+ /* scan for worse formats */
+ result = format;
+ do
+ {
+ result <<= 1;
+ }
+ while( (result & availableFormats) == 0 && result != paCustomFormat );
+
+ if( (result & availableFormats) == 0 )
+ result = paSampleFormatNotSupported;
+ }
+
+ }else{
+ result = format;
+ }
+
+ return result;
+}
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_SELECT_FORMAT_( format, float32, int32, int24, int16, int8, uint8 ) \
+ switch( format & ~paNonInterleaved ){ \
+ case paFloat32: \
+ float32 \
+ case paInt32: \
+ int32 \
+ case paInt24: \
+ int24 \
+ case paInt16: \
+ int16 \
+ case paInt8: \
+ int8 \
+ case paUInt8: \
+ uint8 \
+ default: return 0; \
+ }
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_SELECT_CONVERTER_DITHER_CLIP_( flags, source, destination ) \
+ if( flags & paClipOff ){ /* no clip */ \
+ if( flags & paDitherOff ){ /* no dither */ \
+ return paConverters. source ## _To_ ## destination; \
+ }else{ /* dither */ \
+ return paConverters. source ## _To_ ## destination ## _Dither; \
+ } \
+ }else{ /* clip */ \
+ if( flags & paDitherOff ){ /* no dither */ \
+ return paConverters. source ## _To_ ## destination ## _Clip; \
+ }else{ /* dither */ \
+ return paConverters. source ## _To_ ## destination ## _DitherClip;\
+ } \
+ }
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_SELECT_CONVERTER_DITHER_( flags, source, destination ) \
+ if( flags & paDitherOff ){ /* no dither */ \
+ return paConverters. source ## _To_ ## destination; \
+ }else{ /* dither */ \
+ return paConverters. source ## _To_ ## destination ## _Dither; \
+ }
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_USE_CONVERTER_( source, destination )\
+ return paConverters. source ## _To_ ## destination;
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_UNITY_CONVERSION_( wordlength )\
+ return paConverters.Copy_ ## wordlength ## _To_ ## wordlength;
+
+/* -------------------------------------------------------------------------- */
+
+PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat,
+ PaSampleFormat destinationFormat, PaStreamFlags flags )
+{
+ PA_SELECT_FORMAT_( sourceFormat,
+ /* paFloat32: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_UNITY_CONVERSION_( 32 ),
+ /* paInt32: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int32 ),
+ /* paInt24: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int24 ),
+ /* paInt16: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int16 ),
+ /* paInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, Int8 ),
+ /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_CLIP_( flags, Float32, UInt8 )
+ ),
+ /* paInt32: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_USE_CONVERTER_( Int32, Float32 ),
+ /* paInt32: */ PA_UNITY_CONVERSION_( 32 ),
+ /* paInt24: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int24 ),
+ /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int16 ),
+ /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, Int8 ),
+ /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int32, UInt8 )
+ ),
+ /* paInt24: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_USE_CONVERTER_( Int24, Float32 ),
+ /* paInt32: */ PA_USE_CONVERTER_( Int24, Int32 ),
+ /* paInt24: */ PA_UNITY_CONVERSION_( 24 ),
+ /* paInt16: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int16 ),
+ /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, Int8 ),
+ /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int24, UInt8 )
+ ),
+ /* paInt16: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_USE_CONVERTER_( Int16, Float32 ),
+ /* paInt32: */ PA_USE_CONVERTER_( Int16, Int32 ),
+ /* paInt24: */ PA_USE_CONVERTER_( Int16, Int24 ),
+ /* paInt16: */ PA_UNITY_CONVERSION_( 16 ),
+ /* paInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, Int8 ),
+ /* paUInt8: */ PA_SELECT_CONVERTER_DITHER_( flags, Int16, UInt8 )
+ ),
+ /* paInt8: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_USE_CONVERTER_( Int8, Float32 ),
+ /* paInt32: */ PA_USE_CONVERTER_( Int8, Int32 ),
+ /* paInt24: */ PA_USE_CONVERTER_( Int8, Int24 ),
+ /* paInt16: */ PA_USE_CONVERTER_( Int8, Int16 ),
+ /* paInt8: */ PA_UNITY_CONVERSION_( 8 ),
+ /* paUInt8: */ PA_USE_CONVERTER_( Int8, UInt8 )
+ ),
+ /* paUInt8: */
+ PA_SELECT_FORMAT_( destinationFormat,
+ /* paFloat32: */ PA_USE_CONVERTER_( UInt8, Float32 ),
+ /* paInt32: */ PA_USE_CONVERTER_( UInt8, Int32 ),
+ /* paInt24: */ PA_USE_CONVERTER_( UInt8, Int24 ),
+ /* paInt16: */ PA_USE_CONVERTER_( UInt8, Int16 ),
+ /* paInt8: */ PA_USE_CONVERTER_( UInt8, Int8 ),
+ /* paUInt8: */ PA_UNITY_CONVERSION_( 8 )
+ )
+ )
+}
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef PA_NO_STANDARD_CONVERTERS
+
+/* -------------------------------------------------------------------------- */
+
+PaUtilConverterTable paConverters = {
+ 0, /* PaUtilConverter *Float32_To_Int32; */
+ 0, /* PaUtilConverter *Float32_To_Int32_Dither; */
+ 0, /* PaUtilConverter *Float32_To_Int32_Clip; */
+ 0, /* PaUtilConverter *Float32_To_Int32_DitherClip; */
+
+ 0, /* PaUtilConverter *Float32_To_Int24; */
+ 0, /* PaUtilConverter *Float32_To_Int24_Dither; */
+ 0, /* PaUtilConverter *Float32_To_Int24_Clip; */
+ 0, /* PaUtilConverter *Float32_To_Int24_DitherClip; */
+
+ 0, /* PaUtilConverter *Float32_To_Int16; */
+ 0, /* PaUtilConverter *Float32_To_Int16_Dither; */
+ 0, /* PaUtilConverter *Float32_To_Int16_Clip; */
+ 0, /* PaUtilConverter *Float32_To_Int16_DitherClip; */
+
+ 0, /* PaUtilConverter *Float32_To_Int8; */
+ 0, /* PaUtilConverter *Float32_To_Int8_Dither; */
+ 0, /* PaUtilConverter *Float32_To_Int8_Clip; */
+ 0, /* PaUtilConverter *Float32_To_Int8_DitherClip; */
+
+ 0, /* PaUtilConverter *Float32_To_UInt8; */
+ 0, /* PaUtilConverter *Float32_To_UInt8_Dither; */
+ 0, /* PaUtilConverter *Float32_To_UInt8_Clip; */
+ 0, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */
+
+ 0, /* PaUtilConverter *Int32_To_Float32; */
+ 0, /* PaUtilConverter *Int32_To_Int24; */
+ 0, /* PaUtilConverter *Int32_To_Int24_Dither; */
+ 0, /* PaUtilConverter *Int32_To_Int16; */
+ 0, /* PaUtilConverter *Int32_To_Int16_Dither; */
+ 0, /* PaUtilConverter *Int32_To_Int8; */
+ 0, /* PaUtilConverter *Int32_To_Int8_Dither; */
+ 0, /* PaUtilConverter *Int32_To_UInt8; */
+ 0, /* PaUtilConverter *Int32_To_UInt8_Dither; */
+
+ 0, /* PaUtilConverter *Int24_To_Float32; */
+ 0, /* PaUtilConverter *Int24_To_Int32; */
+ 0, /* PaUtilConverter *Int24_To_Int16; */
+ 0, /* PaUtilConverter *Int24_To_Int16_Dither; */
+ 0, /* PaUtilConverter *Int24_To_Int8; */
+ 0, /* PaUtilConverter *Int24_To_Int8_Dither; */
+ 0, /* PaUtilConverter *Int24_To_UInt8; */
+ 0, /* PaUtilConverter *Int24_To_UInt8_Dither; */
+
+ 0, /* PaUtilConverter *Int16_To_Float32; */
+ 0, /* PaUtilConverter *Int16_To_Int32; */
+ 0, /* PaUtilConverter *Int16_To_Int24; */
+ 0, /* PaUtilConverter *Int16_To_Int8; */
+ 0, /* PaUtilConverter *Int16_To_Int8_Dither; */
+ 0, /* PaUtilConverter *Int16_To_UInt8; */
+ 0, /* PaUtilConverter *Int16_To_UInt8_Dither; */
+
+ 0, /* PaUtilConverter *Int8_To_Float32; */
+ 0, /* PaUtilConverter *Int8_To_Int32; */
+ 0, /* PaUtilConverter *Int8_To_Int24 */
+ 0, /* PaUtilConverter *Int8_To_Int16; */
+ 0, /* PaUtilConverter *Int8_To_UInt8; */
+
+ 0, /* PaUtilConverter *UInt8_To_Float32; */
+ 0, /* PaUtilConverter *UInt8_To_Int32; */
+ 0, /* PaUtilConverter *UInt8_To_Int24; */
+ 0, /* PaUtilConverter *UInt8_To_Int16; */
+ 0, /* PaUtilConverter *UInt8_To_Int8; */
+
+ 0, /* PaUtilConverter *Copy_8_To_8; */
+ 0, /* PaUtilConverter *Copy_16_To_16; */
+ 0, /* PaUtilConverter *Copy_24_To_24; */
+ 0 /* PaUtilConverter *Copy_32_To_32; */
+};
+
+/* -------------------------------------------------------------------------- */
+
+#else /* PA_NO_STANDARD_CONVERTERS is not defined */
+
+/* -------------------------------------------------------------------------- */
+
+#define PA_CLIP_( val, min, max )\
+ { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
+
+
+static const float const_1_div_128_ = 1.0f / 128.0f; /* 8 bit multiplier */
+
+static const float const_1_div_32768_ = 1.0f / 32768.f; /* 16 bit multiplier */
+
+static const double const_1_div_2147483648_ = 1.0 / 2147483648.0; /* 32 bit multiplier */
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ /* REVIEW */
+ double scaled = *src * 0x7FFFFFFF;
+ *dest = (signed long) scaled;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+
+ while( count-- )
+ {
+ /* REVIEW */
+ 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;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ /* REVIEW */
+ double scaled = *src * 0x7FFFFFFF;
+ PA_CLIP_( scaled, -2147483648., 2147483647. );
+ *dest = (signed long) scaled;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+
+ while( count-- )
+ {
+ /* REVIEW */
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* 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;
+
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ /* convert to 32 bit and drop the low 8 bits */
+ double scaled = *src * 0x7FFFFFFF;
+ temp = (signed long) scaled;
+
+#if defined(PA_LITTLE_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+#elif defined(PA_BIG_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 24);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 8);
+#endif
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ while( count-- )
+ {
+ /* convert to 32 bit and drop the low 8 bits */
+
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ double dithered = ((double)*src * (2147483646.0)) + dither;
+
+ temp = (signed long) dithered;
+
+#if defined(PA_LITTLE_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+#elif defined(PA_BIG_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 24);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 8);
+#endif
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ /* convert to 32 bit and drop the low 8 bits */
+ double scaled = *src * 0x7FFFFFFF;
+ PA_CLIP_( scaled, -2147483648., 2147483647. );
+ temp = (signed long) scaled;
+
+#if defined(PA_LITTLE_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+#elif defined(PA_BIG_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 24);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 8);
+#endif
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ while( count-- )
+ {
+ /* convert to 32 bit and drop the low 8 bits */
+
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ double dithered = ((double)*src * (2147483646.0)) + dither;
+ PA_CLIP_( dithered, -2147483648., 2147483647. );
+
+ temp = (signed long) dithered;
+
+#if defined(PA_LITTLE_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+#elif defined(PA_BIG_ENDIAN)
+ dest[0] = (unsigned char)(temp >> 24);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 8);
+#endif
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ short samp = (short) (*src * (32767.0f));
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+
+ while( count-- )
+ {
+
+ float dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ /* use smaller scaler to prevent overflow when we add the dither */
+ float dithered = (*src * (32766.0f)) + dither;
+ *dest = (signed short) dithered;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ long samp = (signed long) (*src * (32767.0f));
+ PA_CLIP_( samp, -0x8000, 0x7FFF );
+ *dest = (signed short) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ 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;
+ PA_CLIP_( samp, -0x8000, 0x7FFF );
+ *dest = (signed short) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ signed char samp = (signed char) (*src * (127.0f));
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ 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;
+ *dest = (signed char) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int8_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ signed long samp = (signed long)(*src * (127.0f));
+ PA_CLIP_( samp, -0x80, 0x7F );
+ *dest = (signed char) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int8_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ 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;
+ PA_CLIP_( samp, -0x80, 0x7F );
+ *dest = (signed char) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_UInt8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ unsigned char samp = (unsigned char)(128 + ((unsigned char) (*src * (127.0f))));
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_UInt8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_UInt8_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_UInt8_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Float32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ *dest = (double)*src * const_1_div_2147483648_;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int24_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int16_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_Int8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_UInt8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int32_To_UInt8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed long *src = (signed long*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Float32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ signed long temp;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+#if defined(PA_LITTLE_ENDIAN)
+ temp = (((long)src[0]) << 8);
+ temp = temp | (((long)src[1]) << 16);
+ temp = temp | (((long)src[2]) << 24);
+#elif defined(PA_BIG_ENDIAN)
+ temp = (((long)src[0]) << 24);
+ temp = temp | (((long)src[1]) << 16);
+ temp = temp | (((long)src[2]) << 8);
+#endif
+
+ *dest = (double)temp * const_1_div_2147483648_;
+
+ src += sourceStride * 3;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Int16_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Int8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_Int8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_UInt8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int24_To_UInt8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_Float32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ float samp = *src * const_1_div_32768_; /* FIXME: i'm concerned about this being asymetrical with float->int16 -rb */
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_Int8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_Int8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ signed char *dest = (signed char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_UInt8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int16_To_UInt8_Dither(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed short *src = (signed short*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int8_To_Float32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed char *src = (signed char*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ float samp = *src * const_1_div_128_;
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int8_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed char *src = (signed char*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int8_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed char *src = (signed char*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int8_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed char *src = (signed char*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Int8_To_UInt8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ signed char *src = (signed char*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void UInt8_To_Float32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ float samp = (*src - 128) * const_1_div_128_;
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void UInt8_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void UInt8_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ (void) destinationBuffer; /* unused parameters */
+ (void) destinationStride; /* unused parameters */
+ (void) sourceBuffer; /* unused parameters */
+ (void) sourceStride; /* unused parameters */
+ (void) count; /* unused parameters */
+ (void) ditherGenerator; /* unused parameters */
+ /* IMPLEMENT ME */
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void UInt8_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void UInt8_To_Int8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ float *dest = (float*)destinationBuffer;
+ (void)ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+
+ /* IMPLEMENT ME */
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Copy_8_To_8(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ *dest = *src;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Copy_16_To_16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned short *src = (unsigned short*)sourceBuffer;
+ unsigned short *dest = (unsigned short*)destinationBuffer;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ *dest = *src;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Copy_24_To_24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned char *src = (unsigned char*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+
+ src += sourceStride * 3;
+ dest += destinationStride * 3;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Copy_32_To_32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ unsigned long *dest = (unsigned long*)destinationBuffer;
+ unsigned long *src = (unsigned long*)sourceBuffer;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ while( count-- )
+ {
+ *dest = *src;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+PaUtilConverterTable paConverters = {
+ Float32_To_Int32, /* PaUtilConverter *Float32_To_Int32; */
+ Float32_To_Int32_Dither, /* PaUtilConverter *Float32_To_Int32_Dither; */
+ Float32_To_Int32_Clip, /* PaUtilConverter *Float32_To_Int32_Clip; */
+ Float32_To_Int32_DitherClip, /* PaUtilConverter *Float32_To_Int32_DitherClip; */
+
+ Float32_To_Int24, /* PaUtilConverter *Float32_To_Int24; */
+ Float32_To_Int24_Dither, /* PaUtilConverter *Float32_To_Int24_Dither; */
+ Float32_To_Int24_Clip, /* PaUtilConverter *Float32_To_Int24_Clip; */
+ Float32_To_Int24_DitherClip, /* PaUtilConverter *Float32_To_Int24_DitherClip; */
+
+ Float32_To_Int16, /* PaUtilConverter *Float32_To_Int16; */
+ Float32_To_Int16_Dither, /* PaUtilConverter *Float32_To_Int16_Dither; */
+ Float32_To_Int16_Clip, /* PaUtilConverter *Float32_To_Int16_Clip; */
+ Float32_To_Int16_DitherClip, /* PaUtilConverter *Float32_To_Int16_DitherClip; */
+
+ Float32_To_Int8, /* PaUtilConverter *Float32_To_Int8; */
+ Float32_To_Int8_Dither, /* PaUtilConverter *Float32_To_Int8_Dither; */
+ Float32_To_Int8_Clip, /* PaUtilConverter *Float32_To_Int8_Clip; */
+ Float32_To_Int8_DitherClip, /* PaUtilConverter *Float32_To_Int8_DitherClip; */
+
+ Float32_To_UInt8, /* PaUtilConverter *Float32_To_UInt8; */
+ Float32_To_UInt8_Dither, /* PaUtilConverter *Float32_To_UInt8_Dither; */
+ Float32_To_UInt8_Clip, /* PaUtilConverter *Float32_To_UInt8_Clip; */
+ Float32_To_UInt8_DitherClip, /* PaUtilConverter *Float32_To_UInt8_DitherClip; */
+
+ Int32_To_Float32, /* PaUtilConverter *Int32_To_Float32; */
+ Int32_To_Int24, /* PaUtilConverter *Int32_To_Int24; */
+ Int32_To_Int24_Dither, /* PaUtilConverter *Int32_To_Int24_Dither; */
+ Int32_To_Int16, /* PaUtilConverter *Int32_To_Int16; */
+ Int32_To_Int16_Dither, /* PaUtilConverter *Int32_To_Int16_Dither; */
+ Int32_To_Int8, /* PaUtilConverter *Int32_To_Int8; */
+ Int32_To_Int8_Dither, /* PaUtilConverter *Int32_To_Int8_Dither; */
+ Int32_To_UInt8, /* PaUtilConverter *Int32_To_UInt8; */
+ Int32_To_UInt8_Dither, /* PaUtilConverter *Int32_To_UInt8_Dither; */
+
+ Int24_To_Float32, /* PaUtilConverter *Int24_To_Float32; */
+ Int24_To_Int32, /* PaUtilConverter *Int24_To_Int32; */
+ Int24_To_Int16, /* PaUtilConverter *Int24_To_Int16; */
+ Int24_To_Int16_Dither, /* PaUtilConverter *Int24_To_Int16_Dither; */
+ Int24_To_Int8, /* PaUtilConverter *Int24_To_Int8; */
+ Int24_To_Int8_Dither, /* PaUtilConverter *Int24_To_Int8_Dither; */
+ Int24_To_UInt8, /* PaUtilConverter *Int24_To_UInt8; */
+ Int24_To_UInt8_Dither, /* PaUtilConverter *Int24_To_UInt8_Dither; */
+
+ Int16_To_Float32, /* PaUtilConverter *Int16_To_Float32; */
+ Int16_To_Int32, /* PaUtilConverter *Int16_To_Int32; */
+ Int16_To_Int24, /* PaUtilConverter *Int16_To_Int24; */
+ Int16_To_Int8, /* PaUtilConverter *Int16_To_Int8; */
+ Int16_To_Int8_Dither, /* PaUtilConverter *Int16_To_Int8_Dither; */
+ Int16_To_UInt8, /* PaUtilConverter *Int16_To_UInt8; */
+ Int16_To_UInt8_Dither, /* PaUtilConverter *Int16_To_UInt8_Dither; */
+
+ Int8_To_Float32, /* PaUtilConverter *Int8_To_Float32; */
+ Int8_To_Int32, /* PaUtilConverter *Int8_To_Int32; */
+ Int8_To_Int24, /* PaUtilConverter *Int8_To_Int24 */
+ Int8_To_Int16, /* PaUtilConverter *Int8_To_Int16; */
+ Int8_To_UInt8, /* PaUtilConverter *Int8_To_UInt8; */
+
+ UInt8_To_Float32, /* PaUtilConverter *UInt8_To_Float32; */
+ UInt8_To_Int32, /* PaUtilConverter *UInt8_To_Int32; */
+ UInt8_To_Int24, /* PaUtilConverter *UInt8_To_Int24; */
+ UInt8_To_Int16, /* PaUtilConverter *UInt8_To_Int16; */
+ UInt8_To_Int8, /* PaUtilConverter *UInt8_To_Int8; */
+
+ Copy_8_To_8, /* PaUtilConverter *Copy_8_To_8; */
+ Copy_16_To_16, /* PaUtilConverter *Copy_16_To_16; */
+ Copy_24_To_24, /* PaUtilConverter *Copy_24_To_24; */
+ Copy_32_To_32 /* PaUtilConverter *Copy_32_To_32; */
+};
+
+/* -------------------------------------------------------------------------- */
+
+#endif /* PA_NO_STANDARD_CONVERTERS */
diff --git a/pd/portaudio/pa_common/pa_converters.h b/pd/portaudio/pa_common/pa_converters.h
new file mode 100644
index 00000000..8fa0fda7
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_converters.h
@@ -0,0 +1,197 @@
+#ifndef PA_CONVERTERS_H
+#define PA_CONVERTERS_H
+/*
+ * $Id: pa_converters.h,v 1.1.2.7 2002/10/22 08:58:17 rossbencina Exp $
+ * Portable Audio I/O Library sample conversion mechanism
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "portaudio.h" /* for PaSampleFormat */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+struct PaUtilTriangularDitherGenerator;
+
+
+/** Choose an available sample format which is most appropriate for
+ representing the requested format. If the requested format is not available
+ higher quality formats are considered before lower quality formates.
+ @param availableFormats A variable containing the logical OR of all available
+ formats.
+ @param format The desired format.
+ @return The most appropriate available format for representing the requested
+ format.
+*/
+PaSampleFormat PaUtil_SelectClosestAvailableFormat(
+ PaSampleFormat availableFormats, PaSampleFormat format );
+
+
+/* high level conversions functions for use by implementations */
+
+
+/** The generic sample converter prototype. Sample converters convert count
+ samples from sourceBuffer to destinationBuffer. The actual type of the data
+ pointed to by these parameters varys for different converter functions.
+ @param destinationBuffer A pointer to the first sample of the destination.
+ @param destinationStride An offset between successive destination samples
+ expressed in samples (not bytes.) It may be negative.
+ @param sourceBuffer A pointer to the first sample of the source.
+ @param sourceStride An offset between successive source samples
+ expressed in samples (not bytes.) It may be negative.
+ @param count The number of samples to convert.
+ @param ditherState State information used to calculate dither. Converters
+ that do not perform dithering will ignore this parameter, in which case
+ NULL or invalid dither state may be passed.
+*/
+typedef void PaUtilConverter(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, struct PaUtilTriangularDitherGenerator *ditherGenerator );
+
+
+/** Find a sample converter function for the given source and destinations
+ formats and flags (clip and dither.)
+ @return
+ A pointer to a PaUtil_Converter which will perform the requested
+ conversion, or NULL if the given format conversion is not supported.
+ For conversions where clipping or dithering is not necessary, the
+ clip and dither flags are ignored and a non-clipping or dithering
+ version is returned.
+ If the source and destination formats are the same, a function which
+ copies data of the appropriate size will be returned.
+*/
+PaUtilConverter* PaUtil_SelectConverter( PaSampleFormat sourceFormat,
+ PaSampleFormat destinationFormat, PaStreamFlags flags );
+
+
+/* low level functions and data structures which may be used for
+ substituting additional conversion functions */
+
+
+/** The type used to store all sample conversion functions.
+ @see paConverters;
+*/
+typedef struct{
+ PaUtilConverter *Float32_To_Int32;
+ PaUtilConverter *Float32_To_Int32_Dither;
+ PaUtilConverter *Float32_To_Int32_Clip;
+ PaUtilConverter *Float32_To_Int32_DitherClip;
+
+ PaUtilConverter *Float32_To_Int24;
+ PaUtilConverter *Float32_To_Int24_Dither;
+ PaUtilConverter *Float32_To_Int24_Clip;
+ PaUtilConverter *Float32_To_Int24_DitherClip;
+
+ PaUtilConverter *Float32_To_Int16;
+ PaUtilConverter *Float32_To_Int16_Dither;
+ PaUtilConverter *Float32_To_Int16_Clip;
+ PaUtilConverter *Float32_To_Int16_DitherClip;
+
+ PaUtilConverter *Float32_To_Int8;
+ PaUtilConverter *Float32_To_Int8_Dither;
+ PaUtilConverter *Float32_To_Int8_Clip;
+ PaUtilConverter *Float32_To_Int8_DitherClip;
+
+ PaUtilConverter *Float32_To_UInt8;
+ PaUtilConverter *Float32_To_UInt8_Dither;
+ PaUtilConverter *Float32_To_UInt8_Clip;
+ PaUtilConverter *Float32_To_UInt8_DitherClip;
+
+ PaUtilConverter *Int32_To_Float32;
+ PaUtilConverter *Int32_To_Int24;
+ PaUtilConverter *Int32_To_Int24_Dither;
+ PaUtilConverter *Int32_To_Int16;
+ PaUtilConverter *Int32_To_Int16_Dither;
+ PaUtilConverter *Int32_To_Int8;
+ PaUtilConverter *Int32_To_Int8_Dither;
+ PaUtilConverter *Int32_To_UInt8;
+ PaUtilConverter *Int32_To_UInt8_Dither;
+
+ PaUtilConverter *Int24_To_Float32;
+ PaUtilConverter *Int24_To_Int32;
+ PaUtilConverter *Int24_To_Int16;
+ PaUtilConverter *Int24_To_Int16_Dither;
+ PaUtilConverter *Int24_To_Int8;
+ PaUtilConverter *Int24_To_Int8_Dither;
+ PaUtilConverter *Int24_To_UInt8;
+ PaUtilConverter *Int24_To_UInt8_Dither;
+
+ PaUtilConverter *Int16_To_Float32;
+ PaUtilConverter *Int16_To_Int32;
+ PaUtilConverter *Int16_To_Int24;
+ PaUtilConverter *Int16_To_Int8;
+ PaUtilConverter *Int16_To_Int8_Dither;
+ PaUtilConverter *Int16_To_UInt8;
+ PaUtilConverter *Int16_To_UInt8_Dither;
+
+ PaUtilConverter *Int8_To_Float32;
+ PaUtilConverter *Int8_To_Int32;
+ PaUtilConverter *Int8_To_Int24;
+ PaUtilConverter *Int8_To_Int16;
+ PaUtilConverter *Int8_To_UInt8;
+
+ PaUtilConverter *UInt8_To_Float32;
+ PaUtilConverter *UInt8_To_Int32;
+ PaUtilConverter *UInt8_To_Int24;
+ PaUtilConverter *UInt8_To_Int16;
+ PaUtilConverter *UInt8_To_Int8;
+
+ PaUtilConverter *Copy_8_To_8; /* copy without any conversion */
+ PaUtilConverter *Copy_16_To_16; /* copy without any conversion */
+ PaUtilConverter *Copy_24_To_24; /* copy without any conversion */
+ PaUtilConverter *Copy_32_To_32; /* copy without any conversion */
+} PaUtilConverterTable;
+
+
+/** A table of pointers to all required converter functions.
+ PaUtil_SelectConverter() uses this table to lookup the appropriate
+ conversion functions. The fields of this structure are initialized
+ with default conversion functions. Fields may be NULL, indicating that
+ no conversion function is available. User code may substitue optimised
+ conversion functions by assigning different function pointers to
+ these fields.
+
+ @note
+ If the PA_NO_STANDARD_CONVERTERS preprocessor variable is defined,
+ PortAudio's standard converters will not be compiled, and all fields
+ of this structure will be initialized to NULL. In such cases, users
+ should supply their own conversion functions if the require PortAudio
+ to open a stream that requires sample conversion.
+
+ @see PaUtilConverterTable, PaUtilConverter, PaUtil_SelectConverter
+*/
+extern PaUtilConverterTable paConverters;
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_CONVERTERS_H */
diff --git a/pd/portaudio/pa_common/pa_converters.o b/pd/portaudio/pa_common/pa_converters.o
new file mode 100644
index 00000000..3baede8e
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_converters.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_cpuload.c b/pd/portaudio/pa_common/pa_cpuload.c
new file mode 100644
index 00000000..bce82aff
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_cpuload.c
@@ -0,0 +1,79 @@
+/*
+ * $Id: pa_cpuload.c,v 1.1.2.9 2002/10/22 08:58:17 rossbencina Exp $
+ * Portable Audio I/O Library CPU Load measurement functions
+ * Portable CPU load measurement facility.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 2002 Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "pa_cpuload.h"
+
+#include <assert.h>
+
+#include "pa_util.h" /* for PaUtil_GetTime() */
+
+
+void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate )
+{
+ assert( sampleRate > 0 );
+
+ measurer->samplingPeriod = 1. / sampleRate;
+}
+
+
+void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer )
+{
+ measurer->measurementStartTime = PaUtil_GetTime();
+}
+
+
+void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed )
+{
+ double measurementEndTime, secondsFor100Percent, measuredLoad;
+
+ if( framesProcessed > 0 ){
+ measurementEndTime = PaUtil_GetTime();
+
+ assert( framesProcessed > 0 );
+ secondsFor100Percent = framesProcessed * measurer->samplingPeriod;
+
+ measuredLoad = (measurementEndTime - measurer->measurementStartTime) / secondsFor100Percent;
+
+ /* Low pass filter the calculated CPU load to reduce jitter using a simple IIR low pass filter. */
+#define LOWPASS_COEFFICIENT_0 (0.9)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+
+ measurer->averageLoad = (LOWPASS_COEFFICIENT_0 * measurer->averageLoad) +
+ (LOWPASS_COEFFICIENT_1 * measuredLoad);
+ }
+}
+
+
+double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer )
+{
+ return measurer->averageLoad;
+}
diff --git a/pd/portaudio/pa_common/pa_cpuload.h b/pd/portaudio/pa_common/pa_cpuload.h
new file mode 100644
index 00000000..28c4c29a
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_cpuload.h
@@ -0,0 +1,56 @@
+#ifndef PA_CPULOAD_H
+#define PA_CPULOAD_H
+/*
+ * $Id: pa_cpuload.h,v 1.1.2.8 2002/10/22 08:58:17 rossbencina Exp $
+ * Portable Audio I/O Library CPU Load measurement functions
+ * Portable CPU load measurement facility.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 2002 Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+typedef struct {
+ double samplingPeriod;
+ double measurementStartTime;
+ double averageLoad;
+} PaUtilCpuLoadMeasurer; /** @todo need better name than measurer */
+
+void PaUtil_InitializeCpuLoadMeasurer( PaUtilCpuLoadMeasurer* measurer, double sampleRate );
+void PaUtil_BeginCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer );
+void PaUtil_EndCpuLoadMeasurement( PaUtilCpuLoadMeasurer* measurer, unsigned long framesProcessed );
+double PaUtil_GetCpuLoad( PaUtilCpuLoadMeasurer* measurer );
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_CPULOAD_H */
diff --git a/pd/portaudio/pa_common/pa_cpuload.o b/pd/portaudio/pa_common/pa_cpuload.o
new file mode 100644
index 00000000..bc599f45
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_cpuload.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_dither.c b/pd/portaudio/pa_common/pa_dither.c
new file mode 100644
index 00000000..10f43e69
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_dither.c
@@ -0,0 +1,91 @@
+/*
+ * $Id: pa_dither.c,v 1.1.2.3 2002/06/16 13:11:02 rossbencina Exp $
+ * Portable Audio I/O Library triangular dither generator
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "pa_dither.h"
+
+#define PA_DITHER_BITS_ (15)
+
+
+void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *state )
+{
+ state->previous = 0;
+ state->randSeed1 = 22222;
+ state->randSeed2 = 5555555;
+}
+
+
+signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *state )
+{
+ signed long current, highPass;
+
+ /* Generate two random numbers. */
+ state->randSeed1 = (state->randSeed1 * 196314165) + 907633515;
+ state->randSeed2 = (state->randSeed2 * 196314165) + 907633515;
+
+ /* Generate triangular distribution about 0.
+ * Shift before adding to prevent overflow which would skew the distribution.
+ * Also shift an extra bit for the high pass filter.
+ */
+#define DITHER_SHIFT_ ((32 - PA_DITHER_BITS_) + 1)
+ current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
+ (((signed long)state->randSeed2)>>DITHER_SHIFT_);
+
+ /* High pass filter to reduce audibility. */
+ highPass = current - state->previous;
+ state->previous = current;
+ return highPass;
+}
+
+/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */
+#define PA_FLOAT_DITHER_SCALE_ (1.0f / ((1<<PA_DITHER_BITS_)-1))
+static const float const_float_dither_scale_ = PA_FLOAT_DITHER_SCALE_;
+
+float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *state )
+{
+ signed long current, highPass;
+
+ /* Generate two random numbers. */
+ state->randSeed1 = (state->randSeed1 * 196314165) + 907633515;
+ state->randSeed2 = (state->randSeed2 * 196314165) + 907633515;
+
+ /* Generate triangular distribution about 0.
+ * Shift before adding to prevent overflow which would skew the distribution.
+ * Also shift an extra bit for the high pass filter.
+ */
+#define DITHER_SHIFT_ ((32 - PA_DITHER_BITS_) + 1)
+ current = (((signed long)state->randSeed1)>>DITHER_SHIFT_) +
+ (((signed long)state->randSeed2)>>DITHER_SHIFT_);
+
+ /* High pass filter to reduce audibility. */
+ highPass = current - state->previous;
+ state->previous = current;
+ return ((float)highPass) * const_float_dither_scale_;
+}
diff --git a/pd/portaudio/pa_common/pa_dither.h b/pd/portaudio/pa_common/pa_dither.h
new file mode 100644
index 00000000..97116f0f
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_dither.h
@@ -0,0 +1,189 @@
+#ifndef PA_DITHER_H
+#define PA_DITHER_H
+/*
+ * $Id: pa_dither.h,v 1.1.2.2 2002/06/05 22:37:03 rossb Exp $
+ * Portable Audio I/O Library triangular dither generator
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+typedef struct PaUtilTriangularDitherGenerator{
+ unsigned long previous;
+ unsigned long randSeed1;
+ unsigned long randSeed2;
+} PaUtilTriangularDitherGenerator;
+/**< State needed to generate a dither signal */
+
+
+void PaUtil_InitializeTriangularDitherState( PaUtilTriangularDitherGenerator *ditherState );
+/**< Initialize dither state */
+
+signed long PaUtil_Generate16BitTriangularDither( PaUtilTriangularDitherGenerator *ditherState );
+/**<
+ Calculate 2 LSB dither signal with a triangular distribution.
+ Ranged for adding to a 1 bit right-shifted 32 bit integer
+ prior to >>15. eg:
+<pre>
+ signed long in = *
+ signed long dither = PaUtil_Generate16BitTriangularDither( ditherState );
+ signed short out = (signed short)(((in>>1) + dither) >> 15);
+</pre>
+ @return
+ A signed long with a range of +32767 to -32768
+*/
+
+
+float PaUtil_GenerateFloatTriangularDither( PaUtilTriangularDitherGenerator *ditherState );
+/**<
+ Calculate 2 LSB dither signal with a triangular distribution.
+ Ranged for adding to a pre-scaled float.
+<pre>
+ float in = *
+ float dither = PaUtil_GenerateFloatTriangularDither( ditherState );
+ // use smaller scaler to prevent overflow when we add the dither
+ signed short out = (signed short)(in*(32766.0f) + dither );
+</pre>
+ @return
+ A float with a range of -2.0 to +1.99999.
+*/
+
+
+
+/*
+The following alternate dither algorithms are known...
+*/
+
+/*Noise shaped dither (March 2000)
+-------------------
+
+This is a simple implementation of highpass triangular-PDF dither with
+2nd-order noise shaping, for use when truncating floating point audio
+data to fixed point.
+
+The noise shaping lowers the noise floor by 11dB below 5kHz (@ 44100Hz
+sample rate) compared to triangular-PDF dither. The code below assumes
+input data is in the range +1 to -1 and doesn't check for overloads!
+
+To save time when generating dither for multiple channels you can do
+things like this: r3=(r1 & 0x7F)<<8; instead of calling rand() again.
+
+
+
+ int r1, r2; //rectangular-PDF random numbers
+ float s1, s2; //error feedback buffers
+ float s = 0.5f; //set to 0.0f for no noise shaping
+ float w = pow(2.0,bits-1); //word length (usually bits=16)
+ float wi= 1.0f/w;
+ float d = wi / RAND_MAX; //dither amplitude (2 lsb)
+ float o = wi * 0.5f; //remove dc offset
+ float in, tmp;
+ int out;
+
+
+//for each sample...
+
+ r2=r1; //can make HP-TRI dither by
+ r1=rand(); //subtracting previous rand()
+
+ in += s * (s1 + s1 - s2); //error feedback
+ tmp = in + o + d * (float)(r1 - r2); //dc offset and dither
+
+ out = (int)(w * tmp); //truncate downwards
+ if(tmp<0.0f) out--; //this is faster than floor()
+
+ s2 = s1;
+ s1 = in - wi * (float)out; //error
+
+
+
+--
+paul.kellett@maxim.abel.co.uk
+http://www.maxim.abel.co.uk
+*/
+
+
+/*
+16-to-8-bit first-order dither
+
+Type : First order error feedforward dithering code
+References : Posted by Jon Watte
+
+Notes :
+This is about as simple a dithering algorithm as you can implement, but it's
+likely to sound better than just truncating to N bits.
+
+Note that you might not want to carry forward the full difference for infinity.
+It's probably likely that the worst performance hit comes from the saturation
+conditionals, which can be avoided with appropriate instructions on many DSPs
+and integer SIMD type instructions, or CMOV.
+
+Last, if sound quality is paramount (such as when going from > 16 bits to 16
+bits) you probably want to use a higher-order dither function found elsewhere
+on this site.
+
+
+Code :
+// This code will down-convert and dither a 16-bit signed short
+// mono signal into an 8-bit unsigned char signal, using a first
+// order forward-feeding error term dither.
+
+#define uchar unsigned char
+
+void dither_one_channel_16_to_8( short * input, uchar * output, int count, int * memory )
+{
+ int m = *memory;
+ while( count-- > 0 ) {
+ int i = *input++;
+ i += m;
+ int j = i + 32768 - 128;
+ uchar o;
+ if( j < 0 ) {
+ o = 0;
+ }
+ else if( j > 65535 ) {
+ o = 255;
+ }
+ else {
+ o = (uchar)((j>>8)&0xff);
+ }
+ m = ((j-32768+128)-i);
+ *output++ = o;
+ }
+ *memory = m;
+}
+*/
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_DITHER_H */
diff --git a/pd/portaudio/pa_common/pa_dither.o b/pd/portaudio/pa_common/pa_dither.o
new file mode 100644
index 00000000..fc7a4bb4
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_dither.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_endianness.h b/pd/portaudio/pa_common/pa_endianness.h
new file mode 100644
index 00000000..aaccaf75
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_endianness.h
@@ -0,0 +1,108 @@
+#ifndef PA_ENDIANNESS_H
+#define PA_ENDIANNESS_H
+/*
+ * $Id: pa_endianness.h,v 1.1.2.1 2003/02/28 01:49:59 rossbencina Exp $
+ * Portable Audio I/O Library current platform endianness macros
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/** @file
+ Arrange for either the PA_LITTLE_ENDIAN or PA_BIG_ENDIAN preprocessor symbols
+ to be defined. The one that is defined reflects the endianness of the target
+ platform and may be used to implement conditional compilation of byte-order
+ dependent code.
+
+ If either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN is defined already, then no attempt
+ is made to override that setting. This may be useful if you have a better way
+ of determining the platform's endianness. The autoconf mechanism uses this for
+ example.
+
+ A PA_VALIDATE_ENDIANNESS macro is provided to compare the compile time
+ and runtime endiannes and raise an assertion if they don't match.
+*/
+
+
+#if defined(PA_LITTLE_ENDIAN) || defined(PA_BIG_ENDIAN)
+ /* endianness define has been set externally, such as by autoconf */
+
+ #if defined(PA_LITTLE_ENDIAN) && defined(PA_BIG_ENDIAN)
+ #error both PA_LITTLE_ENDIAN and PA_BIG_ENDIAN have been defined externally to pa_endianness.h - only one endianness at a time please
+ #endif
+
+#else
+ /* endianness define has not been set externally */
+
+ /* set PA_LITTLE_ENDIAN or PA_BIG_ENDIAN by testing well known platform specific defines */
+
+ #ifdef WIN32
+
+ #define PA_LITTLE_ENDIAN /* win32, assume intel byte order */
+
+ #else
+
+#endif
+
+ #if !defined(PA_LITTLE_ENDIAN) && !defined(PA_BIG_ENDIAN)
+ /*
+ If the following error is raised, you either need to modify the code above
+ to automatically determine the endianness from other symbols defined on your
+ platform, or define either PA_LITTLE_ENDIAN or PA_BIG_ENDIAN externally.
+ */
+ #error pa_endianness.h was unable to automatically determine the endianness of the target platform
+ #endif
+
+#endif
+
+/* PA_VALIDATE_ENDIANNESS compares the compile time and runtime endianness,
+ and raises an assertion if they don't match. <assert.h> must be included in
+ the context in which this macro is used.
+*/
+#if defined(PA_LITTLE_ENDIAN)
+ #define PA_VALIDATE_ENDIANNESS \
+ { \
+ const long nativeOne = 1; \
+ assert( "compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 1 ); \
+ }
+#elif defined(PA_BIG_ENDIAN)
+ #define PA_VALIDATE_ENDIANNESS \
+ { \
+ const long nativeOne = 1; \
+ assert( "compile time and runtime endianness don't match" && (((char *)&nativeOne)[0]) == 0 ); \
+ }
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_ENDIANNESS_H */
diff --git a/pd/portaudio/pa_common/pa_front.c b/pd/portaudio/pa_common/pa_front.c
new file mode 100644
index 00000000..27293b20
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_front.c
@@ -0,0 +1,1884 @@
+/*
+ * $Id: pa_front.c,v 1.1.2.36 2003/02/28 01:49:59 rossbencina Exp $
+ * Portable Audio I/O Library Multi-Host API front end
+ * Validate function parameters and manage multiple host APIs.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* doxygen index page */
+/** @mainpage
+
+PortAudio is an open-source cross-platform ‘C’ library for audio input
+and output. It is designed to simplify the porting of audio applications
+between various platforms, and also to simplify the development of audio
+software in general by hiding the complexities of device interfacing.
+
+See the PortAudio website for further information http://www.portaudio.com/
+
+This documentation pertains to PortAudio V19, API version 2.0 which is
+currently under development. API version 2.0 differs in a number of ways from
+previous versions, please consult the enhancement proposals for further details:
+http://www.portaudio.com/docs/proposals/index.html
+
+This documentation is under construction. Things you might be interested in
+include:
+
+- The PortAudio API 2.0 documented in portaudio.h
+
+- The possibly incomplete and totally unorganised <a href="todo.html">Todo List</a>
+*/
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <memory.h>
+#include <string.h>
+#include <assert.h> /* needed by PA_VALIDATE_ENDIANNESS */
+
+#include "portaudio.h"
+#include "pa_util.h"
+#include "pa_endianness.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+
+#include "pa_trace.h"
+
+
+#define PA_VERSION_ 1899
+#define PA_VERSION_TEXT_ "PortAudio V19-devel"
+
+
+
+/* #define PA_LOG_API_CALLS */
+
+/*
+ The basic format for log messages is as follows:
+
+ - entry (void function):
+
+ "FunctionName called.\n"
+
+ - entry (non void function):
+
+ "FunctionName called:\n"
+ "\tParam1Type param1: param1Value\n"
+ "\tParam2Type param2: param2Value\n" (etc...)
+
+
+ - exit (no return value)
+
+ "FunctionName returned.\n"
+
+ - exit (simple return value)
+
+ "FunctionName returned:\n"
+ "\tReturnType: returnValue\n\n"
+
+ if the return type is an error code, the error text is displayed in ()
+
+ if the return type is not an error code, but has taken a special value
+ because an error occurred, then the reason for the error is shown in []
+
+ if the return type is a struct ptr, the struct is dumped.
+
+ see the code for more detailed examples
+*/
+
+int Pa_GetVersion( void )
+{
+ return PA_VERSION_;
+}
+
+
+const char* Pa_GetVersionText( void )
+{
+ return PA_VERSION_TEXT_;
+}
+
+
+
+#define PA_LAST_HOST_ERROR_TEXT_LENGTH_ 1024
+
+static char lastHostErrorText_[ PA_LAST_HOST_ERROR_TEXT_LENGTH_ + 1 ] = {0};
+
+static PaHostErrorInfo lastHostErrorInfo_ = { -1, 0, lastHostErrorText_ };
+
+
+void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
+ const char *errorText )
+{
+ lastHostErrorInfo_.hostApiType = hostApiType;
+ lastHostErrorInfo_.errorCode = errorCode;
+
+ strncpy( lastHostErrorText_, errorText, PA_LAST_HOST_ERROR_TEXT_LENGTH_ );
+}
+
+
+void PaUtil_DebugPrint( const char *format, ... )
+{
+ va_list ap;
+
+ va_start( ap, format );
+ vfprintf( stderr, format, ap );
+ va_end( ap );
+
+ fflush( stderr );
+}
+
+
+static PaUtilHostApiRepresentation **hostApis_ = 0;
+static int hostApisCount_ = 0;
+static int initializationCount_ = 0;
+static int deviceCount_ = 0;
+
+PaUtilStreamRepresentation *firstOpenStream_ = NULL;
+
+
+#define PA_IS_INITIALISED_ (initializationCount_ != 0)
+
+
+static int CountHostApiInitializers( void )
+{
+ int result = 0;
+
+ while( paHostApiInitializers[ result ] != 0 )
+ ++result;
+ return result;
+}
+
+
+static void TerminateHostApis( void )
+{
+ /* terminate in reverse order from initialization */
+
+ while( hostApisCount_ > 0 )
+ {
+ --hostApisCount_;
+ hostApis_[hostApisCount_]->Terminate( hostApis_[hostApisCount_] );
+ }
+ hostApisCount_ = 0;
+ deviceCount_ = 0;
+
+ if( hostApis_ != 0 )
+ PaUtil_FreeMemory( hostApis_ );
+ hostApis_ = 0;
+}
+
+
+static PaError InitializeHostApis( void )
+{
+ PaError result = paNoError;
+ int i, initializerCount, baseDeviceIndex;
+
+ initializerCount = CountHostApiInitializers();
+
+ hostApis_ = PaUtil_AllocateMemory( sizeof(PaUtilHostApiRepresentation*) * initializerCount );
+ if( !hostApis_ )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ hostApisCount_ = 0;
+ deviceCount_ = 0;
+ baseDeviceIndex = 0;
+
+ for( i=0; i< initializerCount; ++i )
+ {
+ hostApis_[hostApisCount_] = NULL;
+ result = paHostApiInitializers[i]( &hostApis_[hostApisCount_], hostApisCount_ );
+ if( result != paNoError )
+ goto error;
+
+ if( hostApis_[hostApisCount_] )
+ {
+
+ hostApis_[hostApisCount_]->privatePaFrontInfo.baseDeviceIndex = baseDeviceIndex;
+
+ if( hostApis_[hostApisCount_]->info.defaultInputDevice != paNoDevice )
+ hostApis_[hostApisCount_]->info.defaultInputDevice += baseDeviceIndex;
+
+ if( hostApis_[hostApisCount_]->info.defaultOutputDevice != paNoDevice )
+ hostApis_[hostApisCount_]->info.defaultOutputDevice += baseDeviceIndex;
+
+ baseDeviceIndex += hostApis_[hostApisCount_]->info.deviceCount;
+ deviceCount_ += hostApis_[hostApisCount_]->info.deviceCount;
+
+ ++hostApisCount_;
+ }
+ }
+
+ return result;
+
+error:
+ TerminateHostApis();
+ return result;
+}
+
+
+/*
+ FindHostApi() finds the index of the host api to which
+ <device> belongs and returns it. if <hostSpecificDeviceIndex> is
+ non-null, the host specific device index is returned in it.
+ returns -1 if <device> is out of range.
+
+*/
+static int FindHostApi( PaDeviceIndex device, int *hostSpecificDeviceIndex )
+{
+ int i=0;
+
+ if( !PA_IS_INITIALISED_ )
+ return -1;
+
+ if( device < 0 )
+ return -1;
+
+ while( i < hostApisCount_
+ && device >= hostApis_[i]->info.deviceCount )
+ {
+
+ device -= hostApis_[i]->info.deviceCount;
+ ++i;
+ }
+
+ if( i >= hostApisCount_ )
+ return -1;
+
+ if( hostSpecificDeviceIndex )
+ *hostSpecificDeviceIndex = device;
+
+ return i;
+}
+
+
+static void AddOpenStream( PaStream* stream )
+{
+ ((PaUtilStreamRepresentation*)stream)->nextOpenStream = firstOpenStream_;
+ firstOpenStream_ = (PaUtilStreamRepresentation*)stream;
+}
+
+
+static void RemoveOpenStream( PaStream* stream )
+{
+ PaUtilStreamRepresentation *previous = NULL;
+ PaUtilStreamRepresentation *current = firstOpenStream_;
+
+ while( current != NULL )
+ {
+ if( ((PaStream*)current) == stream )
+ {
+ if( previous == NULL )
+ {
+ firstOpenStream_ = current->nextOpenStream;
+ }
+ else
+ {
+ previous->nextOpenStream = current->nextOpenStream;
+ }
+ return;
+ }
+ else
+ {
+ previous = current;
+ current = current->nextOpenStream;
+ }
+ }
+}
+
+
+static void CloseOpenStreams( void )
+{
+ /* we call Pa_CloseStream() here to ensure that the same destruction
+ logic is used for automatically closed streams */
+
+ while( firstOpenStream_ != NULL )
+ Pa_CloseStream( firstOpenStream_ );
+}
+
+
+PaError Pa_Initialize( void )
+{
+ PaError result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint( "Pa_Initialize called.\n" );
+#endif
+
+ if( PA_IS_INITIALISED_ )
+ {
+ ++initializationCount_;
+ result = paNoError;
+ }
+ else
+ {
+ PA_VALIDATE_ENDIANNESS;
+
+ PaUtil_InitializeClock();
+ PaUtil_ResetTraceMessages();
+
+ result = InitializeHostApis();
+ if( result == paNoError )
+ ++initializationCount_;
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint( "Pa_Initialize returned:\n" );
+ PaUtil_DebugPrint( "\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_Terminate( void )
+{
+ PaError result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_Terminate called.\n" );
+#endif
+
+ if( PA_IS_INITIALISED_ )
+ {
+ if( --initializationCount_ == 0 )
+ {
+ CloseOpenStreams();
+
+ TerminateHostApis();
+
+ PaUtil_DumpTraceMessages();
+ }
+ result = paNoError;
+ }
+ else
+ {
+ result= paNotInitialized;
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_Terminate returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void )
+{
+ return &lastHostErrorInfo_;
+}
+
+
+const char *Pa_GetErrorText( PaError errorNumber )
+{
+ const char *result;
+
+ switch( errorNumber )
+ {
+ case paNoError: result = "Success"; break;
+ case paNotInitialized: result = "PortAudio not initialized"; break;
+ /** @todo could catenate the last host error text to result in the case of paUnanticipatedHostError */
+ case paUnanticipatedHostError: result = "Unanticipated host error"; break;
+ case paInvalidChannelCount: result = "Invalid number of channels"; break;
+ case paInvalidSampleRate: result = "Invalid sample rate"; break;
+ case paInvalidDevice: result = "Invalid device"; break;
+ case paInvalidFlag: result = "Invalid flag"; break;
+ case paSampleFormatNotSupported: result = "Sample format not supported"; break;
+ case paBadIODeviceCombination: result = "Illegal combination of I/O devices"; break;
+ case paInsufficientMemory: result = "Insufficient memory"; break;
+ case paBufferTooBig: result = "Buffer too big"; break;
+ case paBufferTooSmall: result = "Buffer too small"; break;
+ case paNullCallback: result = "No callback routine specified"; break;
+ case paBadStreamPtr: result = "Invalid stream pointer"; break;
+ case paTimedOut: result = "Wait timed out"; break;
+ case paInternalError: result = "Internal PortAudio error"; break;
+ case paDeviceUnavailable: result = "Device unavailable"; break;
+ case paIncompatibleHostApiSpecificStreamInfo: result = "Incompatible host API specific stream info"; break;
+ case paStreamIsStopped: result = "Stream is stopped"; break;
+ case paStreamIsNotStopped: result = "Stream is not stopped"; break;
+ default: result = "Illegal error number"; break;
+ }
+ return result;
+}
+
+
+PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type )
+{
+ PaHostApiIndex result;
+ int i;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex called:\n" );
+ PaUtil_DebugPrint("\PaHostApiTypeId type: %d\n", type );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+
+ result = -1;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex: -1 [ PortAudio not initialized ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ result = -1;
+
+ for( i=0; i < hostApisCount_; ++i )
+ {
+ if( hostApis_[i]->info.type == type )
+ {
+ result = i;
+ break;
+ }
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiTypeIdToHostApiIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex: %d\n\n", result );
+#endif
+ }
+
+ return result;
+}
+
+
+PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,
+ PaHostApiTypeId type )
+{
+ PaError result;
+ int i;
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNotInitialized;
+ }
+ else
+ {
+ result = paInternalError; /* @todo should return host API not found */
+
+ for( i=0; i < hostApisCount_; ++i )
+ {
+ if( hostApis_[i]->info.type == type )
+ {
+ *hostApi = hostApis_[i];
+ result = paNoError;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+PaError PaUtil_DeviceIndexToHostApiDeviceIndex(
+ PaDeviceIndex *hostApiDevice, PaDeviceIndex device, struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaError result;
+ PaDeviceIndex x;
+
+ x = device - hostApi->privatePaFrontInfo.baseDeviceIndex;
+
+ if( x < 0 || x >= hostApi->info.deviceCount )
+ {
+ result = paInvalidDevice;
+ }
+ else
+ {
+ *hostApiDevice = x;
+ result = paNoError;
+ }
+
+ return result;
+}
+
+
+PaHostApiIndex Pa_CountHostApis( void )
+{
+ int result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountHostApis called.\n" );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNotInitialized;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountHostApis returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+ }
+ else
+ {
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountHostApis returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", hostApisCount_ );
+#endif
+
+ return hostApisCount_;
+ }
+}
+
+
+PaHostApiIndex Pa_GetDefaultHostApi( void )
+{
+ int result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultHostApi called.\n" );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNotInitialized;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+ }
+ else
+ {
+ result = paDefaultHostApiIndex;
+
+ /* internal consistency check: make sure that the default host api
+ index is within range */
+
+ if( result < 0 || result >= hostApisCount_ )
+ {
+ result = paInternalError;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ }
+ else
+ {
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultHostApi returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex %d\n\n", result );
+#endif
+ }
+
+ return result;
+ }
+}
+
+
+const PaHostApiInfo* Pa_GetHostApiInfo( PaHostApiIndex hostApi )
+{
+ PaHostApiInfo *info;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetHostApiInfo called:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ info = NULL;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ PortAudio not initialized ]\n\n" );
+#endif
+
+ }
+ else if( hostApi < 0 || hostApi >= hostApisCount_ )
+ {
+ info = NULL;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiInfo*: NULL [ hostApi out of range ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ info = &hostApis_[hostApi]->info;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetHostApiInfo returned:\n" );
+ PaUtil_DebugPrint("\tPaHostApiInfo*: 0x%p\n", info );
+ PaUtil_DebugPrint("\t{" );
+ PaUtil_DebugPrint("\t\tint structVersion: %d\n", info->structVersion );
+ PaUtil_DebugPrint("\t\tPaHostApiTypeId type: %d\n", info->type );
+ PaUtil_DebugPrint("\t\tconst char *name: %s\n\n", info->name );
+ PaUtil_DebugPrint("\t}\n\n" );
+#endif
+
+ }
+
+ return info;
+}
+
+
+PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, int hostApiDeviceIndex )
+{
+ PaDeviceIndex result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex called:\n" );
+ PaUtil_DebugPrint("\tPaHostApiIndex hostApi: %d\n", hostApi );
+ PaUtil_DebugPrint("\tint hostApiDeviceIndex: %d\n", hostApiDeviceIndex );
+#endif
+
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNoDevice;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: paNoDevice [ PortAudio not initialized ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ if( hostApi < 0 || hostApi >= hostApisCount_ )
+ {
+ result = paNoDevice;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: paNoDevice [ hostApi out of range ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ if( hostApiDeviceIndex < 0 ||
+ hostApiDeviceIndex >= hostApis_[hostApi]->info.deviceCount )
+ {
+ result = paNoDevice;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: paNoDevice [ hostApiDeviceIndex out of range ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ result = hostApis_[hostApi]->privatePaFrontInfo.baseDeviceIndex + hostApiDeviceIndex;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_HostApiDeviceIndexToPaDeviceIndex returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
+#endif
+ }
+ }
+ }
+
+ return result;
+}
+
+
+PaDeviceIndex Pa_CountDevices( void )
+{
+ PaDeviceIndex result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountDevices called.\n" );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = 0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountDevices returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: 0 [ PortAudio not initialized ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ result = deviceCount_;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CountDevices returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
+#endif
+
+ }
+
+ return result;
+}
+
+
+PaDeviceIndex Pa_GetDefaultInputDevice( void )
+{
+ PaHostApiIndex hostApi;
+ PaDeviceIndex result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultInputDevice called.\n" );
+#endif
+
+ hostApi = Pa_GetDefaultHostApi();
+ if( hostApi < 0 )
+ {
+ result = paNoDevice;
+ }
+ else
+ {
+ result = hostApis_[hostApi]->info.defaultInputDevice;
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultInputDevice returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
+#endif
+
+ return result;
+}
+
+
+PaDeviceIndex Pa_GetDefaultOutputDevice( void )
+{
+ PaHostApiIndex hostApi;
+ PaDeviceIndex result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultOutputDevice called.\n" );
+#endif
+
+ hostApi = Pa_GetDefaultHostApi();
+ if( hostApi < 0 )
+ {
+ result = paNoDevice;
+ }
+ else
+ {
+ result = hostApis_[hostApi]->info.defaultOutputDevice;
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDefaultOutputDevice returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex: %d\n\n", result );
+#endif
+
+ return result;
+}
+
+
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device )
+{
+ int hostSpecificDeviceIndex;
+ int hostApiIndex = FindHostApi( device, &hostSpecificDeviceIndex );
+ PaDeviceInfo *result;
+
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDeviceInfo called:\n" );
+ PaUtil_DebugPrint("\tPaDeviceIndex device: %d\n", device );
+#endif
+
+ if( hostApiIndex < 0 )
+ {
+ result = NULL;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceInfo* NULL [ invalid device index ]\n\n" );
+#endif
+
+ }
+ else
+ {
+ result = hostApis_[hostApiIndex]->deviceInfos[ hostSpecificDeviceIndex ];
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetDeviceInfo returned:\n" );
+ PaUtil_DebugPrint("\tPaDeviceInfo*: 0x%p:\n", result );
+ PaUtil_DebugPrint("\t{" );
+
+ PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion );
+ PaUtil_DebugPrint("\t\tconst char *name: %s\n", result->name );
+ PaUtil_DebugPrint("\t\tPaHostApiIndex hostApi: %d\n", result->hostApi );
+ PaUtil_DebugPrint("\t\tint maxInputChannels: %d\n", result->maxInputChannels );
+ PaUtil_DebugPrint("\t\tint maxOutputChannels: %d\n", result->maxOutputChannels );
+ PaUtil_DebugPrint("\t}\n\n" );
+#endif
+
+ }
+
+ return result;
+}
+
+
+/*
+ SampleFormatIsValid() returns 1 if sampleFormat is a sample format
+ defined in portaudio.h, or 0 otherwise.
+*/
+static int SampleFormatIsValid( PaSampleFormat format )
+{
+ switch( format & ~paNonInterleaved )
+ {
+ case paFloat32: return 1;
+ case paInt16: return 1;
+ case paInt32: return 1;
+ case paInt24: return 1;
+ case paInt8: return 1;
+ case paUInt8: return 1;
+ case paCustomFormat: return 1;
+ default: return 0;
+ }
+}
+
+/*
+ NOTE: make sure this validation list is kept syncronised with the one in
+ pa_hostapi.h
+
+ ValidateOpenStreamParameters() checks that parameters to Pa_OpenStream()
+ conform to the expected values as described below. This function is
+ also designed to be used with the proposed Pa_IsFormatSupported() function.
+
+ There are basically two types of validation that could be performed:
+ Generic conformance validation, and device capability mismatch
+ validation. This function performs only generic conformance validation.
+ Validation that would require knowledge of device capabilities is
+ not performed because of potentially complex relationships between
+ combinations of parameters - for example, even if the sampleRate
+ seems ok, it might not be for a duplex stream - we have no way of
+ checking this in an API-neutral way, so we don't try.
+
+ On success the function returns PaNoError and fills in hostApi,
+ hostApiInputDeviceID, and hostApiOutputDeviceID fields. On failure
+ the function returns an error code indicating the first encountered
+ parameter error.
+
+
+ If ValidateOpenStreamParameters() returns paNoError, the following
+ assertions are guaranteed to be true.
+
+ - at least one of inputParameters & outputParmeters is valid (not NULL)
+
+ - if inputParameters & outputParmeters are both valid, that
+ inputParameters->device & outputParmeters->device both use the same host api
+
+ PaDeviceIndex inputParameters->device
+ - is within range (0 to Pa_CountDevices-1) Or:
+ - is paUseHostApiSpecificDeviceSpecification and
+ inputParameters->hostApiSpecificStreamInfo is non-NULL and refers
+ to a valid host api
+
+ int inputParameters->channelCount
+ - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, channelCount is > 0
+ - upper bound is NOT validated against device capabilities
+
+ PaSampleFormat inputParameters->sampleFormat
+ - is one of the sample formats defined in portaudio.h
+
+ void *inputParameters->hostApiSpecificStreamInfo
+ - if supplied its hostApi field matches the input device's host Api
+
+ PaDeviceIndex outputParmeters->device
+ - is within range (0 to Pa_CountDevices-1)
+
+ int outputParmeters->channelCount
+ - if inputDevice is valid, channelCount is > 0
+ - upper bound is NOT validated against device capabilities
+
+ PaSampleFormat outputParmeters->sampleFormat
+ - is one of the sample formats defined in portaudio.h
+
+ void *outputParmeters->hostApiSpecificStreamInfo
+ - if supplied its hostApi field matches the output device's host Api
+
+ double sampleRate
+ - is not an 'absurd' rate (less than 1000. or greater than 200000.)
+ - sampleRate is NOT validated against device capabilities
+
+ PaStreamFlags streamFlags
+ - unused platform neutral flags are zero
+*/
+static PaError ValidateOpenStreamParameters(
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ PaStreamFlags streamFlags,
+ PaUtilHostApiRepresentation **hostApi,
+ PaDeviceIndex *hostApiInputDevice,
+ PaDeviceIndex *hostApiOutputDevice )
+{
+ int inputHostApiIndex=0, outputHostApiIndex=0;
+
+ if( (inputParameters == NULL) && (outputParameters == NULL) )
+ {
+
+ return paInvalidDevice; /* @todo should be a new error code "invalid device parameters" or something */
+
+ }
+ else
+ {
+ if( inputParameters == NULL )
+ {
+ *hostApiInputDevice = paNoDevice;
+ }
+ else if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ {
+ if( inputParameters->hostApiSpecificStreamInfo )
+ {
+ inputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(
+ ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType );
+
+ if( inputHostApiIndex != -1 )
+ {
+ *hostApiInputDevice = paUseHostApiSpecificDeviceSpecification;
+ *hostApi = hostApis_[inputHostApiIndex];
+ }
+ else
+ {
+ return paInvalidDevice;
+ }
+ }
+ else
+ {
+ return paInvalidDevice;
+ }
+ }
+ else
+ {
+ if( inputParameters->device < 0 || inputParameters->device >= deviceCount_ )
+ return paInvalidDevice;
+
+ inputHostApiIndex = FindHostApi( inputParameters->device, hostApiInputDevice );
+ if( inputHostApiIndex < 0 )
+ return paInternalError;
+
+ *hostApi = hostApis_[inputHostApiIndex];
+
+ if( inputParameters->channelCount <= 0 )
+ return paInvalidChannelCount;
+
+ if( !SampleFormatIsValid( inputParameters->sampleFormat ) )
+ return paSampleFormatNotSupported;
+
+ if( inputParameters->hostApiSpecificStreamInfo != NULL )
+ {
+ if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType
+ != (*hostApi)->info.type )
+ return paIncompatibleHostApiSpecificStreamInfo;
+ }
+ }
+
+ if( outputParameters == NULL )
+ {
+ *hostApiOutputDevice = paNoDevice;
+ }
+ else if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ {
+ if( outputParameters->hostApiSpecificStreamInfo )
+ {
+ outputHostApiIndex = Pa_HostApiTypeIdToHostApiIndex(
+ ((PaUtilHostApiSpecificStreamInfoHeader*)outputParameters->hostApiSpecificStreamInfo)->hostApiType );
+
+ if( outputHostApiIndex != -1 )
+ {
+ *hostApiOutputDevice = paUseHostApiSpecificDeviceSpecification;
+ *hostApi = hostApis_[outputHostApiIndex];
+ }
+ else
+ {
+ return paInvalidDevice;
+ }
+ }
+ else
+ {
+ return paInvalidDevice;
+ }
+ }
+ else
+ {
+ if( outputParameters->device < 0 || outputParameters->device >= deviceCount_ )
+ return paInvalidDevice;
+
+ outputHostApiIndex = FindHostApi( outputParameters->device, hostApiOutputDevice );
+ if( outputHostApiIndex < 0 )
+ return paInternalError;
+
+ *hostApi = hostApis_[outputHostApiIndex];
+
+ if( outputParameters->channelCount <= 0 )
+ return paInvalidChannelCount;
+
+ if( !SampleFormatIsValid( outputParameters->sampleFormat ) )
+ return paSampleFormatNotSupported;
+
+ if( outputParameters->hostApiSpecificStreamInfo != NULL )
+ {
+ if( ((PaUtilHostApiSpecificStreamInfoHeader*)inputParameters->hostApiSpecificStreamInfo)->hostApiType
+ != (*hostApi)->info.type )
+ return paIncompatibleHostApiSpecificStreamInfo;
+ }
+ }
+
+ if( (inputParameters != NULL) && (outputParameters != NULL) )
+ {
+ /* ensure that both devices use the same API */
+ if( inputHostApiIndex != outputHostApiIndex )
+ return paBadIODeviceCombination;
+ }
+ }
+
+
+ /* Check for absurd sample rates. */
+ if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
+ return paInvalidSampleRate;
+
+ if( ((streamFlags & ~paPlatformSpecificFlags) & ~(paClipOff | paDitherOff | paNeverDropInput | paPrimeOutputBuffersUsingStreamCallback ) ) != 0 )
+ return paInvalidFlag;
+
+ return paNoError;
+}
+
+
+PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
+{
+ PaError result;
+ PaUtilHostApiRepresentation *hostApi;
+ PaDeviceIndex hostApiInputDevice, hostApiOutputDevice;
+ PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
+ PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
+
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsFormatSupported called:\n" );
+
+ if( inputParameters == NULL ){
+ PaUtil_DebugPrint("\PaStreamParameters *inputParameters: NULL\n" );
+ }else{
+ PaUtil_DebugPrint("\PaStreamParameters *inputParameters: 0x%p\n", inputParameters );
+ PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device );
+ PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount );
+ PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat );
+ PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency );
+ PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo );
+ }
+
+ if( outputParameters == NULL ){
+ PaUtil_DebugPrint("\PaStreamParameters *outputParameters: NULL\n" );
+ }else{
+ PaUtil_DebugPrint("\PaStreamParameters *outputParameters: 0x%p\n", outputParameters );
+ PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device );
+ PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount );
+ PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat );
+ PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency );
+ PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo );
+ }
+
+ PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNotInitialized;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ return result;
+ }
+
+ result = ValidateOpenStreamParameters( inputParameters,
+ outputParameters,
+ sampleRate, paNoFlag,
+ &hostApi,
+ &hostApiInputDevice,
+ &hostApiOutputDevice );
+ if( result != paNoError )
+ {
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsFormatSupported returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ return result;
+ }
+
+
+ if( inputParameters )
+ {
+ hostApiInputParameters.device = hostApiInputDevice;
+ hostApiInputParameters.channelCount = inputParameters->channelCount;
+ hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;
+ hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;
+ hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;
+ hostApiInputParametersPtr = &hostApiInputParameters;
+ }
+ else
+ {
+ hostApiInputParametersPtr = NULL;
+ }
+
+ if( outputParameters )
+ {
+ hostApiOutputParameters.device = hostApiOutputDevice;
+ hostApiOutputParameters.channelCount = outputParameters->channelCount;
+ hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;
+ hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;
+ hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;
+ hostApiOutputParametersPtr = &hostApiOutputParameters;
+ }
+ else
+ {
+ hostApiOutputParametersPtr = NULL;
+ }
+
+ result = hostApi->IsFormatSupported( hostApi,
+ hostApiInputParametersPtr, hostApiOutputParametersPtr,
+ sampleRate );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
+ if( result == paFormatIsSupported )
+ PaUtil_DebugPrint("\tPaError: 0 [ paFormatIsSupported ]\n\n" );
+ else
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_OpenStream( PaStream** stream,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result;
+ PaUtilHostApiRepresentation *hostApi;
+ PaDeviceIndex hostApiInputDevice, hostApiOutputDevice;
+ PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
+ PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
+
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream );
+
+ if( inputParameters == NULL ){
+ PaUtil_DebugPrint("\PaStreamParameters *inputParameters: NULL\n" );
+ }else{
+ PaUtil_DebugPrint("\PaStreamParameters *inputParameters: 0x%p\n", inputParameters );
+ PaUtil_DebugPrint("\tPaDeviceIndex inputParameters->device: %d\n", inputParameters->device );
+ PaUtil_DebugPrint("\tint inputParameters->channelCount: %d\n", inputParameters->channelCount );
+ PaUtil_DebugPrint("\tPaSampleFormat inputParameters->sampleFormat: %d\n", inputParameters->sampleFormat );
+ PaUtil_DebugPrint("\tPaTime inputParameters->suggestedLatency: %f\n", inputParameters->suggestedLatency );
+ PaUtil_DebugPrint("\tvoid *inputParameters->hostApiSpecificStreamInfo: 0x%p\n", inputParameters->hostApiSpecificStreamInfo );
+ }
+
+ if( outputParameters == NULL ){
+ PaUtil_DebugPrint("\PaStreamParameters *outputParameters: NULL\n" );
+ }else{
+ PaUtil_DebugPrint("\PaStreamParameters *outputParameters: 0x%p\n", outputParameters );
+ PaUtil_DebugPrint("\tPaDeviceIndex outputParameters->device: %d\n", outputParameters->device );
+ PaUtil_DebugPrint("\tint outputParameters->channelCount: %d\n", outputParameters->channelCount );
+ PaUtil_DebugPrint("\tPaSampleFormat outputParameters->sampleFormat: %d\n", outputParameters->sampleFormat );
+ PaUtil_DebugPrint("\tPaTime outputParameters->suggestedLatency: %f\n", outputParameters->suggestedLatency );
+ PaUtil_DebugPrint("\tvoid *outputParameters->hostApiSpecificStreamInfo: 0x%p\n", outputParameters->hostApiSpecificStreamInfo );
+ }
+
+ PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
+ PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer );
+ PaUtil_DebugPrint("\tPaStreamFlags streamFlags: 0x%x\n", streamFlags );
+ PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback );
+ PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData );
+#endif
+
+ if( !PA_IS_INITIALISED_ )
+ {
+ result = paNotInitialized;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
+ PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ return result;
+ }
+
+ /* Check for parameter errors. */
+
+ if( stream == NULL )
+ {
+ result = paBadStreamPtr;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
+ PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ return result;
+ }
+
+ result = ValidateOpenStreamParameters( inputParameters,
+ outputParameters,
+ sampleRate, streamFlags,
+ &hostApi,
+ &hostApiInputDevice,
+ &hostApiOutputDevice );
+ if( result != paNoError )
+ {
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
+ PaUtil_DebugPrint("\t*(PaStream** stream): undefined\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+ return result;
+ }
+
+
+ if( inputParameters )
+ {
+ hostApiInputParameters.device = hostApiInputDevice;
+ hostApiInputParameters.channelCount = inputParameters->channelCount;
+ hostApiInputParameters.sampleFormat = inputParameters->sampleFormat;
+ hostApiInputParameters.suggestedLatency = inputParameters->suggestedLatency;
+ hostApiInputParameters.hostApiSpecificStreamInfo = inputParameters->hostApiSpecificStreamInfo;
+ hostApiInputParametersPtr = &hostApiInputParameters;
+ }
+ else
+ {
+ hostApiInputParametersPtr = NULL;
+ }
+
+ if( outputParameters )
+ {
+ hostApiOutputParameters.device = hostApiOutputDevice;
+ hostApiOutputParameters.channelCount = outputParameters->channelCount;
+ hostApiOutputParameters.sampleFormat = outputParameters->sampleFormat;
+ hostApiOutputParameters.suggestedLatency = outputParameters->suggestedLatency;
+ hostApiOutputParameters.hostApiSpecificStreamInfo = outputParameters->hostApiSpecificStreamInfo;
+ hostApiOutputParametersPtr = &hostApiOutputParameters;
+ }
+ else
+ {
+ hostApiOutputParametersPtr = NULL;
+ }
+
+ result = hostApi->OpenStream( hostApi, stream,
+ hostApiInputParametersPtr, hostApiOutputParametersPtr,
+ sampleRate, framesPerBuffer, streamFlags, streamCallback, userData );
+
+ if( result == paNoError )
+ AddOpenStream( *stream );
+
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenStream returned:\n" );
+ PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p\n", *stream );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_OpenDefaultStream( PaStream** stream,
+ int inputChannelCount,
+ int outputChannelCount,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result;
+ PaStreamParameters hostApiInputParameters, hostApiOutputParameters;
+ PaStreamParameters *hostApiInputParametersPtr, *hostApiOutputParametersPtr;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenDefaultStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream** stream: 0x%p\n", stream );
+ PaUtil_DebugPrint("\tint inputChannelCount: %d\n", inputChannelCount );
+ PaUtil_DebugPrint("\tint outputChannelCount: %d\n", outputChannelCount );
+ PaUtil_DebugPrint("\tPaSampleFormat sampleFormat: %d\n", sampleFormat );
+ PaUtil_DebugPrint("\tdouble sampleRate: %g\n", sampleRate );
+ PaUtil_DebugPrint("\tunsigned long framesPerBuffer: %d\n", framesPerBuffer );
+ PaUtil_DebugPrint("\tPaStreamCallback *streamCallback: 0x%p\n", streamCallback );
+ PaUtil_DebugPrint("\tvoid *userData: 0x%p\n", userData );
+#endif
+
+
+ if( inputChannelCount > 0 )
+ {
+ hostApiInputParameters.device = Pa_GetDefaultInputDevice();
+ hostApiInputParameters.channelCount = inputChannelCount;
+ hostApiInputParameters.sampleFormat = sampleFormat;
+ hostApiInputParameters.suggestedLatency = /* REVIEW: should we be using high input latency here? */
+ Pa_GetDeviceInfo( hostApiInputParameters.device )->defaultHighInputLatency;
+ hostApiInputParameters.hostApiSpecificStreamInfo = NULL;
+ hostApiInputParametersPtr = &hostApiInputParameters;
+ }
+ else
+ {
+ hostApiInputParametersPtr = NULL;
+ }
+
+ if( outputChannelCount > 0 )
+ {
+ hostApiOutputParameters.device = Pa_GetDefaultOutputDevice();
+ hostApiOutputParameters.channelCount = outputChannelCount;
+ hostApiOutputParameters.sampleFormat = sampleFormat;
+ hostApiOutputParameters.suggestedLatency = /* REVIEW: should we be using high input latency here? */
+ Pa_GetDeviceInfo( hostApiOutputParameters.device )->defaultHighOutputLatency;
+ hostApiOutputParameters.hostApiSpecificStreamInfo = NULL;
+ hostApiOutputParametersPtr = &hostApiOutputParameters;
+ }
+ else
+ {
+ hostApiOutputParametersPtr = NULL;
+ }
+
+
+ result = Pa_OpenStream(
+ stream, hostApiInputParametersPtr, hostApiOutputParametersPtr,
+ sampleRate, framesPerBuffer, paNoFlag, streamCallback, userData );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_OpenDefaultStream returned:\n" );
+ PaUtil_DebugPrint("\t*(PaStream** stream): 0x%p", *stream );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+static PaError ValidateStream( PaStream* stream )
+{
+ if( !PA_IS_INITIALISED_ ) return paNotInitialized;
+
+ if( stream == NULL ) return paBadStreamPtr;
+
+ if( ((PaUtilStreamRepresentation*)stream)->magic != PA_STREAM_MAGIC )
+ return paBadStreamPtr;
+
+ return paNoError;
+}
+
+
+PaError Pa_CloseStream( PaStream* stream )
+{
+ PaUtilStreamInterface *interface;
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CloseStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ /* always remove the open stream from our list, even if this function
+ eventually returns an error. Otherwise CloseOpenStreams() will
+ get stuck in an infinite loop */
+ RemoveOpenStream( stream ); /* be sure to call this _before_ closing the stream */
+
+ if( result == paNoError )
+ {
+ interface = PA_STREAM_INTERFACE(stream);
+ if( !interface->IsStopped( stream ) )
+ {
+ result = interface->Abort( stream );
+ }
+
+ if( result == paNoError ) /* REVIEW: shouldn't we close anyway? */
+ result = interface->Close( stream );
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_CloseStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_SetStreamFinishedCallback called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+ PaUtil_DebugPrint("\tPaStreamFinishedCallback* streamFinishedCallback: 0x%p\n", streamFinishedCallback );
+#endif
+
+ if( result == paNoError )
+ {
+ if( !PA_STREAM_INTERFACE(stream)->IsStopped( stream ) )
+ {
+ result = paStreamIsNotStopped ;
+ }
+ else
+ {
+ PA_STREAM_REP( stream )->streamFinishedCallback = streamFinishedCallback;
+ }
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_SetStreamFinishedCallback returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+
+}
+
+
+PaError Pa_StartStream( PaStream *stream )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_StartStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( result == paNoError )
+ {
+ if( !PA_STREAM_INTERFACE(stream)->IsStopped( stream ) )
+ {
+ result = paStreamIsNotStopped ;
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->Start( stream );
+ }
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_StartStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_StopStream( PaStream *stream )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_StopStream called\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( result == paNoError )
+ {
+ if( PA_STREAM_INTERFACE(stream)->IsStopped( stream ) )
+ {
+ result = paStreamIsStopped;
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->Stop( stream );
+ }
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_StopStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_AbortStream( PaStream *stream )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_AbortStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( result == paNoError )
+ {
+ if( PA_STREAM_INTERFACE(stream)->IsStopped( stream ) )
+ {
+ result = paStreamIsStopped;
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->Abort( stream );
+ }
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_AbortStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_IsStreamStopped( PaStream *stream )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsStreamStopped called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( result == paNoError )
+ result = PA_STREAM_INTERFACE(stream)->IsStopped( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsStreamStopped returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_IsStreamActive( PaStream *stream )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsStreamActive called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( result == paNoError )
+ result = PA_STREAM_INTERFACE(stream)->IsActive( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_IsStreamActive returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream )
+{
+ PaError error = ValidateStream( stream );
+ const PaStreamInfo *result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamInfo called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( error != paNoError )
+ {
+ result = 0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" );
+ PaUtil_DebugPrint("\const PaStreamInfo*: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) );
+#endif
+
+ }
+ else
+ {
+ result = &PA_STREAM_REP( stream )->streamInfo;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamInfo returned:\n" );
+ PaUtil_DebugPrint("\tconst PaStreamInfo*: 0x%p:\n", result );
+ PaUtil_DebugPrint("\t{" );
+
+ PaUtil_DebugPrint("\t\tint structVersion: %d\n", result->structVersion );
+ PaUtil_DebugPrint("\t\tPaTime inputLatency: %f\n", result->inputLatency );
+ PaUtil_DebugPrint("\t\tPaTime outputLatency: %f\n", result->outputLatency );
+ PaUtil_DebugPrint("\t\tdouble sampleRate: %f\n", result->sampleRate );
+ PaUtil_DebugPrint("\t}\n\n" );
+#endif
+
+ }
+
+ return result;
+}
+
+
+PaTime Pa_GetStreamTime( PaStream *stream )
+{
+ PaError error = ValidateStream( stream );
+ PaTime result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamTime called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( error != paNoError )
+ {
+ result = 0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" );
+ PaUtil_DebugPrint("\tPaTime: 0 [PaError error:%d ( %s )]\n\n", result, error, Pa_GetErrorText( error ) );
+#endif
+
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->GetTime( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamTime returned:\n" );
+ PaUtil_DebugPrint("\tPaTime: %g\n\n", result );
+#endif
+
+ }
+
+ return result;
+}
+
+
+double Pa_GetStreamCpuLoad( PaStream* stream )
+{
+ PaError error = ValidateStream( stream );
+ double result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamCpuLoad called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( error != paNoError )
+ {
+
+ result = 0.0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" );
+ PaUtil_DebugPrint("\tdouble: 0.0 [PaError error: %d ( %s )]\n\n", error, Pa_GetErrorText( error ) );
+#endif
+
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->GetCpuLoad( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamCpuLoad returned:\n" );
+ PaUtil_DebugPrint("\tdouble: %g\n\n", result );
+#endif
+
+ }
+
+ return result;
+}
+
+
+PaError Pa_ReadStream( PaStream* stream,
+ void *buffer,
+ unsigned long frames )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_ReadStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ /* @todo should return an error if buffer is zero or frames <= 0 */
+ if( frames > 0 && buffer != 0 )
+ result = PA_STREAM_INTERFACE(stream)->Read( stream, buffer, frames );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_ReadStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+
+PaError Pa_WriteStream( PaStream* stream,
+ void *buffer,
+ unsigned long frames )
+{
+ PaError result = ValidateStream( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_WriteStream called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ /* @todo should return an error if buffer is zero or frames <= 0 */
+ if( frames > 0 && buffer != 0 )
+ result = PA_STREAM_INTERFACE(stream)->Write( stream, buffer, frames );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_WriteStream returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return result;
+}
+
+signed long Pa_GetStreamReadAvailable( PaStream* stream )
+{
+ PaError error = ValidateStream( stream );
+ signed long result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamReadAvailable called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( error != paNoError )
+ {
+ result = 0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" );
+ PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) );
+#endif
+
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->GetReadAvailable( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamReadAvailable returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ }
+
+ return result;
+}
+
+
+signed long Pa_GetStreamWriteAvailable( PaStream* stream )
+{
+ PaError error = ValidateStream( stream );
+ signed long result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamWriteAvailable called:\n" );
+ PaUtil_DebugPrint("\tPaStream* stream: 0x%p\n", stream );
+#endif
+
+ if( error != paNoError )
+ {
+ result = 0;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" );
+ PaUtil_DebugPrint("\tunsigned long: 0 [ PaError error: %d ( %s ) ]\n\n", error, Pa_GetErrorText( error ) );
+#endif
+
+ }
+ else
+ {
+ result = PA_STREAM_INTERFACE(stream)->GetWriteAvailable( stream );
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetStreamWriteAvailable returned:\n" );
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ }
+
+ return result;
+}
+
+
+PaError Pa_GetSampleSize( PaSampleFormat format )
+{
+ int result;
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetSampleSize called:\n" );
+ PaUtil_DebugPrint("\tPaSampleFormat format: %d\n", format );
+#endif
+
+ switch( format & ~paNonInterleaved )
+ {
+
+ case paUInt8:
+ case paInt8:
+ result = 1;
+ break;
+
+ case paInt16:
+ result = 2;
+ break;
+
+ case paInt24:
+ result = 3;
+ break;
+
+ case paFloat32:
+ case paInt32:
+ result = 4;
+ break;
+
+ default:
+ result = paSampleFormatNotSupported;
+ break;
+ }
+
+#ifdef PA_LOG_API_CALLS
+ PaUtil_DebugPrint("Pa_GetSampleSize returned:\n" );
+ if( result > 0 )
+ PaUtil_DebugPrint("\tint: %d\n\n", result );
+ else
+ PaUtil_DebugPrint("\tPaError: %d ( %s )\n\n", result, Pa_GetErrorText( result ) );
+#endif
+
+ return (PaError) result;
+}
+
diff --git a/pd/portaudio/pa_common/pa_front.o b/pd/portaudio/pa_common/pa_front.o
new file mode 100644
index 00000000..0ce74a68
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_front.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_hostapi.h b/pd/portaudio/pa_common/pa_hostapi.h
new file mode 100644
index 00000000..f1f7a7ea
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_hostapi.h
@@ -0,0 +1,238 @@
+#ifndef PA_HOSTAPI_H
+#define PA_HOSTAPI_H
+/*
+ *
+ * Portable Audio I/O Library
+ * host api representation
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/** @file
+ Virtualised host api mechanism used by pa_front.
+*/
+
+#include "portaudio.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+typedef struct PaUtilPrivatePaFrontHostApiInfo {
+/* **for the use of pa_front.c only**
+ don't use fields in this structure, they my change at any time
+ use functions defined in pa_util.h if you think you need functionality
+ which can be derived from here
+*/
+
+ unsigned long baseDeviceIndex;
+}PaUtilPrivatePaFrontHostApiInfo;
+
+
+/** The common header for all data structures whose pointers are passed through
+ the hostApiSpecificStreamInfo field of the PaStreamParameters structure.
+ Note that in order to keep the public PortAudio interface clean, this structure
+ is not used explicitly when declaring hostApiSpecificStreamInfo data structures
+ however some code in pa_front depends on the first 3 members being equivalent
+ with this structure.
+ @see PaStreamParameters
+*/
+typedef struct PaUtilHostApiSpecificStreamInfoHeader
+{
+ unsigned long size; /**< size of whole structure including this header */
+ PaHostApiTypeId hostApiType; /**< host API for which this data is intended */
+ unsigned long version; /**< structure version */
+} PaUtilHostApiSpecificStreamInfoHeader;
+
+
+
+/*
+ PaUtilHostApiRepresentation must be implemented by each host api implementation.
+
+*/
+
+typedef struct PaUtilHostApiRepresentation {
+ PaUtilPrivatePaFrontHostApiInfo privatePaFrontInfo;
+
+ /**
+ The host api implementation should populate the info field. In the
+ case of info.defaultInputDevice and info.defaultOutputDevice the
+ values stored should be 0 based indicies within the host api's own
+ device index range (0 to deviceCount). These values will be converted
+ to global device indicies after PaUtilHostApiInitializer() returns.
+ */
+ PaHostApiInfo info;
+
+ PaDeviceInfo** deviceInfos;
+
+ /**
+ (*Terminate)() is guaranteed to be called with a valid <hostApi>
+ parameter, which was previously returned from the same implementation's
+ initializer.
+ */
+ void (*Terminate)( struct PaUtilHostApiRepresentation *hostApi );
+
+ /**
+ The inputParameters and outputParameters pointers should not be saved
+ as they will not remain valid after OpenStream is called.
+
+
+ The following guarantees are made about parameters to (*OpenStream)():
+
+ [NOTE: the following list up to *END PA FRONT VALIDATIONS* should be
+ kept in sync with the one for ValidateOpenStreamParameters and
+ Pa_OpenStream in pa_front.c]
+
+ PaHostApiRepresentation *hostApi
+ - is valid for this implementation
+
+ PaStream** stream
+ - is non-null
+
+ - at least one of inputParameters & outputParmeters is valid (not NULL)
+
+ - if inputParameters & outputParmeters are both valid, that
+ inputParameters->device & outputParmeters->device both use the same host api
+
+ PaDeviceIndex inputParameters->device
+ - is within range (0 to Pa_CountDevices-1) Or:
+ - is paUseHostApiSpecificDeviceSpecification and
+ inputParameters->hostApiSpecificStreamInfo is non-NULL and refers
+ to a valid host api
+
+ int inputParameters->numChannels
+ - if inputParameters->device is not paUseHostApiSpecificDeviceSpecification, numInputChannels is > 0
+ - upper bound is NOT validated against device capabilities
+
+ PaSampleFormat inputParameters->sampleFormat
+ - is one of the sample formats defined in portaudio.h
+
+ void *inputParameters->hostApiSpecificStreamInfo
+ - if supplied its hostApi field matches the input device's host Api
+
+ PaDeviceIndex outputParmeters->device
+ - is within range (0 to Pa_CountDevices-1)
+
+ int outputParmeters->numChannels
+ - if inputDevice is valid, numInputChannels is > 0
+ - upper bound is NOT validated against device capabilities
+
+ PaSampleFormat outputParmeters->sampleFormat
+ - is one of the sample formats defined in portaudio.h
+
+ void *outputParmeters->hostApiSpecificStreamInfo
+ - if supplied its hostApi field matches the output device's host Api
+
+ double sampleRate
+ - is not an 'absurd' rate (less than 1000. or greater than 200000.)
+ - sampleRate is NOT validated against device capabilities
+
+ PaStreamFlags streamFlags
+ - unused platform neutral flags are zero
+
+ [*END PA FRONT VALIDATIONS*]
+
+
+ The following validations MUST be performed by (*OpenStream)():
+
+ - check that input device can support numInputChannels
+
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if inputStreamInfo is supplied, validate its contents,
+ or return an error if no inputStreamInfo is expected
+
+ - check that output device can support numOutputChannels
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if outputStreamInfo is supplied, validate its contents,
+ or return an error if no outputStreamInfo is expected
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+
+ - alter sampleRate to a close allowable rate if necessary
+
+ - validate inputLatency and outputLatency
+
+ - validate any platform specific flags, if flags are supplied they
+ must be valid.
+ */
+ PaError (*OpenStream)( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** stream,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerCallback,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData );
+
+
+ PaError (*IsFormatSupported)( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate );
+} PaUtilHostApiRepresentation;
+
+
+/**
+ every host api implementation must supply a host api initializer in the
+ following form.
+*/
+typedef PaError PaUtilHostApiInitializer( PaUtilHostApiRepresentation**, PaHostApiIndex );
+
+
+/**
+ paHostApiInitializers is a NULL-terminated array of host api initializers
+ for the host apis which will be initialized when Pa_Initialize() is called.
+ each platform has a file which defines paHostApiInitializers for that platform.
+ see pa_win_init.c for example.
+*/
+extern PaUtilHostApiInitializer *paHostApiInitializers[];
+
+
+/** index of the default host API in the paHostApiInitializers array. Each
+ platform has a file which defines paDefaultHostApiIndex for that platform.
+ see pa_win_init.c for example.
+*/
+extern int paDefaultHostApiIndex;
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_HOSTAPI_H */
diff --git a/pd/portaudio/pa_common/pa_process.c b/pd/portaudio/pa_common/pa_process.c
new file mode 100644
index 00000000..2fbeb277
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_process.c
@@ -0,0 +1,1355 @@
+/*
+ * $Id: pa_process.c,v 1.1.2.28 2002/10/26 05:33:29 rossbencina Exp $
+ * Portable Audio I/O Library
+ * streamCallback <-> host buffer processing adapter
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <string.h> /* memset() */
+
+#include "pa_process.h"
+#include "pa_util.h"
+
+/** @file
+ The code in this file is not optimised yet. there may appear to be redundancies
+ that could be factored into common functions, but the redundanceis are left
+ intentionally as each appearance may have different optimisation possibilities.
+
+ The optimisations which are planned involve only converting data in-place
+ where possible, rather than copying to the temp buffer(s).
+
+ Note that in the extreme case of being able to convert in-place, and there
+ being no conversion necessary there should be some code which short-circuits
+ the operation.
+
+ Cache tilings for intereave<->deinterleave also need to be considered.
+
+ @todo The abort flag from the streamCallback is currently not honoured properly
+ in this file, see fixmes.
+
+ @todo see FIXMEs
+
+ @todo implement the streamFlags callback parameter, currently it is
+ always zero. It needs to be passed from the host layer somehow.
+*/
+
+#define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_ 1024
+
+
+/* greatest common divisor - PGCD in french */
+static unsigned long GCD( unsigned long a, unsigned long b )
+{
+ return (b==0) ? a : GCD( b, a%b);
+}
+
+/* least common multiple - PPCM in french */
+static unsigned long LCM( unsigned long a, unsigned long b )
+{
+ return (a*b) / GCD(a,b);
+}
+
+#define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b))
+
+static unsigned long CalculateFrameShift( unsigned long M, unsigned long N )
+{
+ unsigned long result = 0;
+ unsigned long i;
+ unsigned long lcm;
+ lcm = LCM( M, N );
+ for( i = M; i < lcm; i += M )
+ result = PA_MAX_( result, i % N );
+
+ return result;
+}
+
+
+PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
+ int inputChannelCount, PaSampleFormat userInputSampleFormat,
+ PaSampleFormat hostInputSampleFormat,
+ int outputChannelCount, PaSampleFormat userOutputSampleFormat,
+ PaSampleFormat hostOutputSampleFormat,
+ double sampleRate,
+ PaStreamFlags streamFlags,
+ unsigned long framesPerUserBuffer,
+ unsigned long framesPerHostBuffer,
+ PaUtilHostBufferSizeMode hostBufferSizeMode,
+ PaStreamCallback *streamCallback, void *userData )
+{
+ PaError result = paNoError;
+ PaError bytesPerSample;
+ unsigned long tempInputBufferSize, tempOutputBufferSize;
+
+ /* initialize buffer ptrs to zero so they can be freed if necessary in error */
+ bp->tempInputBuffer = 0;
+ bp->tempInputBufferPtrs = 0;
+ bp->tempOutputBuffer = 0;
+ bp->tempOutputBufferPtrs = 0;
+
+ bp->framesPerUserBuffer = framesPerUserBuffer;
+ bp->framesPerHostBuffer = framesPerHostBuffer;
+
+ bp->inputChannelCount = inputChannelCount;
+ bp->outputChannelCount = outputChannelCount;
+
+ bp->hostBufferSizeMode = hostBufferSizeMode;
+
+ bp->hostInputChannels[0] = 0;
+ bp->hostOutputChannels[0] = 0;
+
+ if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */
+ {
+ bp->useNonAdaptingProcess = 1;
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = 0;
+
+ if( hostBufferSizeMode == paUtilFixedHostBufferSize
+ || hostBufferSizeMode == paUtilBoundedHostBufferSize )
+ {
+ bp->framesPerTempBuffer = framesPerHostBuffer;
+ }
+ else /* unknown host buffer size */
+ {
+ bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_;
+ }
+ }
+ else
+ {
+ bp->framesPerTempBuffer = framesPerUserBuffer;
+
+ if( hostBufferSizeMode == paUtilFixedHostBufferSize
+ && framesPerHostBuffer % framesPerUserBuffer == 0 )
+ {
+ bp->useNonAdaptingProcess = 1;
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = 0;
+ }
+ else
+ {
+ bp->useNonAdaptingProcess = 0;
+
+ if( inputChannelCount > 0 && outputChannelCount > 0 )
+ {
+ /* full duplex */
+ if( hostBufferSizeMode == paUtilFixedHostBufferSize )
+ {
+ unsigned long frameShift =
+ CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer );
+
+ if( framesPerUserBuffer > framesPerHostBuffer )
+ {
+ bp->framesInTempInputBuffer = frameShift;
+ bp->framesInTempOutputBuffer = 0;
+ }
+ else
+ {
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = frameShift;
+ }
+ }
+ else /* variable host buffer size, add framesPerUserBuffer latency */
+ {
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = framesPerUserBuffer;
+ }
+ }
+ else
+ {
+ /* half duplex */
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = 0;
+ }
+ }
+ }
+
+
+
+ if( inputChannelCount > 0 )
+ {
+ bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat );
+ if( bytesPerSample > 0 )
+ {
+ bp->bytesPerHostInputSample = bytesPerSample;
+ }
+ else
+ {
+ result = bytesPerSample;
+ goto error;
+ }
+
+ bytesPerSample = Pa_GetSampleSize( userInputSampleFormat );
+ if( bytesPerSample > 0 )
+ {
+ bp->bytesPerUserInputSample = bytesPerSample;
+ }
+ else
+ {
+ result = bytesPerSample;
+ goto error;
+ }
+
+ bp->inputConverter =
+ PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, streamFlags );
+
+
+ bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
+
+
+ tempInputBufferSize =
+ bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
+
+ bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize );
+ if( bp->tempInputBuffer == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( bp->framesInTempInputBuffer > 0 )
+ memset( bp->tempInputBuffer, 0, tempInputBufferSize );
+
+ if( userInputSampleFormat & paNonInterleaved )
+ {
+ bp->tempInputBufferPtrs =
+ PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount );
+ if( bp->tempInputBufferPtrs == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ }
+
+ bp->hostInputChannels[0] = (PaUtilChannelDescriptor*)
+ PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2);
+ if( bp->hostInputChannels[0] == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount];
+ }
+
+ if( outputChannelCount > 0 )
+ {
+ bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat );
+ if( bytesPerSample > 0 )
+ {
+ bp->bytesPerHostOutputSample = bytesPerSample;
+ }
+ else
+ {
+ result = bytesPerSample;
+ goto error;
+ }
+
+ bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat );
+ if( bytesPerSample > 0 )
+ {
+ bp->bytesPerUserOutputSample = bytesPerSample;
+ }
+ else
+ {
+ result = bytesPerSample;
+ goto error;
+ }
+
+ bp->outputConverter =
+ PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags );
+
+
+ bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
+
+ tempOutputBufferSize =
+ bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
+
+ bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize );
+ if( bp->tempOutputBuffer == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( bp->framesInTempOutputBuffer > 0 )
+ memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
+
+ if( userOutputSampleFormat & paNonInterleaved )
+ {
+ bp->tempOutputBufferPtrs =
+ PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount );
+ if( bp->tempOutputBufferPtrs == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ }
+
+ bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*)
+ PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 );
+ if( bp->hostOutputChannels[0] == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount];
+ }
+
+ PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator );
+
+ bp->samplePeriod = 1. / sampleRate;
+
+ bp->streamCallback = streamCallback;
+ bp->userData = userData;
+
+ return result;
+
+error:
+ if( bp->tempInputBuffer )
+ PaUtil_FreeMemory( bp->tempInputBuffer );
+
+ if( bp->tempInputBufferPtrs )
+ PaUtil_FreeMemory( bp->tempInputBufferPtrs );
+
+ if( bp->hostInputChannels[0] )
+ PaUtil_FreeMemory( bp->hostInputChannels[0] );
+
+ if( bp->tempOutputBuffer )
+ PaUtil_FreeMemory( bp->tempOutputBuffer );
+
+ if( bp->tempOutputBufferPtrs )
+ PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
+
+ if( bp->hostOutputChannels[0] )
+ PaUtil_FreeMemory( bp->hostOutputChannels[0] );
+
+ return result;
+}
+
+
+void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp )
+{
+ if( bp->tempInputBuffer )
+ PaUtil_FreeMemory( bp->tempInputBuffer );
+
+ if( bp->tempInputBufferPtrs )
+ PaUtil_FreeMemory( bp->tempInputBufferPtrs );
+
+ if( bp->hostInputChannels[0] )
+ PaUtil_FreeMemory( bp->hostInputChannels[0] );
+
+ if( bp->tempOutputBuffer )
+ PaUtil_FreeMemory( bp->tempOutputBuffer );
+
+ if( bp->tempOutputBufferPtrs )
+ PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
+
+ if( bp->hostOutputChannels[0] )
+ PaUtil_FreeMemory( bp->hostOutputChannels[0] );
+}
+
+
+void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp, PaStreamCallbackTimeInfo* timeInfo )
+{
+ bp->timeInfo = timeInfo;
+
+ /* the first streamCallback will be called to process samples which are
+ currently in the input buffer before the ones starting at the timeInfo time */
+
+ bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod;
+
+ (void)bp->timeInfo->currentTime; /* FIXME: @todo time info currentTime not implemented */
+
+ /* the first streamCallback will be called to generate samples which will be
+ outputted after the frames currently in the output buffer have been
+ outputted. */
+ bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod;
+
+ bp->hostInputFrameCount[1] = 0;
+ bp->hostOutputFrameCount[1] = 0;
+}
+
+
+static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostInputChannels,
+ PaUtilChannelDescriptor *hostOutputChannels,
+ unsigned long frameCount );
+
+static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostInputChannels,
+ unsigned long frameCount );
+
+static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostOutputChannels,
+ unsigned long framesToProcess );
+
+static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult, int processPartialUserBuffers );
+
+#define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) )
+
+unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult )
+{
+ unsigned long framesToProcess, framesToGo;
+ unsigned long framesProcessed = 0;
+
+ if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
+ {
+ assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) ==
+ (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) );
+ }
+
+
+ if( bp->useNonAdaptingProcess )
+ {
+ if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
+ {
+ /* full duplex non-adapting process, splice buffers if they are
+ different lengths */
+
+ framesToGo = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]; /* relies on assert above for input/output equivalence */
+
+ do{
+ unsigned long *hostInputFrameCount;
+ PaUtilChannelDescriptor *hostInputChannels;
+ unsigned long *hostOutputFrameCount;
+ PaUtilChannelDescriptor *hostOutputChannels;
+ unsigned long framesProcessedThisIteration;
+
+ if( bp->hostInputFrameCount[0] != 0 )
+ {
+ hostInputFrameCount = &bp->hostInputFrameCount[0];
+ hostInputChannels = bp->hostInputChannels[0];
+ }
+ else
+ {
+ hostInputFrameCount = &bp->hostInputFrameCount[1];
+ hostInputChannels = bp->hostInputChannels[1];
+ }
+
+ if( bp->hostOutputFrameCount[0] != 0 )
+ {
+ hostOutputFrameCount = &bp->hostOutputFrameCount[0];
+ hostOutputChannels = bp->hostOutputChannels[0];
+ }
+ else
+ {
+ hostOutputFrameCount = &bp->hostOutputFrameCount[1];
+ hostOutputChannels = bp->hostOutputChannels[1];
+ }
+
+ framesToProcess = PA_MIN_( *hostInputFrameCount,
+ *hostOutputFrameCount );
+
+ assert( framesToProcess != 0 );
+
+ framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult,
+ hostInputChannels, hostOutputChannels,
+ framesToProcess );
+
+ *hostInputFrameCount -= framesProcessedThisIteration;
+ *hostOutputFrameCount -= framesProcessedThisIteration;
+
+ framesProcessed += framesProcessedThisIteration;
+ framesToGo -= framesProcessedThisIteration;
+
+ }while( framesToGo > 0 );
+ }
+ else
+ {
+ /* half duplex non-adapting process, just process 1st and 2nd buffer */
+ /* process first buffer */
+
+ framesToProcess = (bp->inputChannelCount != 0)
+ ? bp->hostInputFrameCount[0]
+ : bp->hostOutputFrameCount[0];
+
+ framesProcessed = NonAdaptingProcess( bp, streamCallbackResult,
+ bp->hostInputChannels[0], bp->hostOutputChannels[0],
+ framesToProcess );
+
+ /* process second buffer if provided */
+
+ framesToProcess = (bp->inputChannelCount != 0)
+ ? bp->hostInputFrameCount[1]
+ : bp->hostOutputFrameCount[1];
+ if( framesToProcess > 0 )
+ {
+ framesProcessed += NonAdaptingProcess( bp, streamCallbackResult,
+ bp->hostInputChannels[1], bp->hostOutputChannels[1],
+ framesToProcess );
+ }
+ }
+ }
+ else /* block adaption necessary*/
+ {
+
+ if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
+ {
+ /* full duplex */
+
+ if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed )
+ {
+ framesProcessed = AdaptingProcess( bp, streamCallbackResult,
+ 0 /* dont process partial user buffers */ );
+ }
+ else
+ {
+ framesProcessed = AdaptingProcess( bp, streamCallbackResult,
+ 1 /* process partial user buffers */ );
+ }
+ }
+ else if( bp->inputChannelCount != 0 )
+ {
+ /* input only */
+ framesToProcess = bp->hostInputFrameCount[0];
+
+ framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult,
+ bp->hostInputChannels[0], framesToProcess );
+
+ framesToProcess = bp->hostInputFrameCount[1];
+ if( framesToProcess > 0 )
+ {
+ framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult,
+ bp->hostInputChannels[1], framesToProcess );
+ }
+ }
+ else
+ {
+ /* output only */
+ framesToProcess = bp->hostOutputFrameCount[0];
+
+ framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult,
+ bp->hostOutputChannels[0], framesToProcess );
+
+ framesToProcess = bp->hostOutputFrameCount[1];
+ if( framesToProcess > 0 )
+ {
+ framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult,
+ bp->hostOutputChannels[1], framesToProcess );
+ }
+ }
+ }
+
+ return framesProcessed;
+}
+
+
+void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp,
+ unsigned long frameCount )
+{
+ if( frameCount == 0 )
+ bp->hostInputFrameCount[0] = bp->framesPerHostBuffer;
+ else
+ bp->hostInputFrameCount[0] = frameCount;
+}
+
+
+void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data, unsigned int stride )
+{
+ assert( channel < bp->inputChannelCount );
+
+ bp->hostInputChannels[0][channel].data = data;
+ bp->hostInputChannels[0][channel].stride = stride;
+}
+
+
+void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
+ unsigned int firstChannel, void *data, unsigned int channelCount )
+{
+ unsigned int i;
+ unsigned int channel = firstChannel;
+ unsigned char *p = (unsigned char*)data;
+
+ if( channelCount == 0 )
+ channelCount = bp->inputChannelCount;
+
+ assert( firstChannel < bp->inputChannelCount );
+ assert( firstChannel + channelCount <= bp->inputChannelCount );
+
+ for( i=0; i< channelCount; ++i )
+ {
+ bp->hostInputChannels[0][channel+i].data = p;
+ p += bp->bytesPerHostInputSample;
+ bp->hostInputChannels[0][channel+i].stride = channelCount;
+ }
+}
+
+
+void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data )
+{
+ assert( channel < bp->inputChannelCount );
+
+ bp->hostInputChannels[0][channel].data = data;
+ bp->hostInputChannels[0][channel].stride = 1;
+}
+
+
+void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp,
+ unsigned long frameCount )
+{
+ bp->hostInputFrameCount[1] = frameCount;
+}
+
+
+void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data, unsigned int stride )
+{
+ assert( channel < bp->inputChannelCount );
+
+ bp->hostInputChannels[1][channel].data = data;
+ bp->hostInputChannels[1][channel].stride = stride;
+}
+
+
+void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
+ unsigned int firstChannel, void *data, unsigned int channelCount )
+{
+ unsigned int i;
+ unsigned int channel = firstChannel;
+ unsigned char *p = (unsigned char*)data;
+
+ if( channelCount == 0 )
+ channelCount = bp->inputChannelCount;
+
+ assert( firstChannel < bp->inputChannelCount );
+ assert( firstChannel + channelCount <= bp->inputChannelCount );
+
+ for( i=0; i< channelCount; ++i )
+ {
+ bp->hostInputChannels[1][channel+i].data = p;
+ p += bp->bytesPerHostInputSample;
+ bp->hostInputChannels[1][channel+i].stride = channelCount;
+ }
+}
+
+
+void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data )
+{
+ assert( channel < bp->inputChannelCount );
+
+ bp->hostInputChannels[1][channel].data = data;
+ bp->hostInputChannels[1][channel].stride = 1;
+}
+
+
+void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp,
+ unsigned long frameCount )
+{
+ if( frameCount == 0 )
+ bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer;
+ else
+ bp->hostOutputFrameCount[0] = frameCount;
+}
+
+
+void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data, unsigned int stride )
+{
+ assert( channel < bp->outputChannelCount );
+
+ bp->hostOutputChannels[0][channel].data = data;
+ bp->hostOutputChannels[0][channel].stride = stride;
+}
+
+
+void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
+ unsigned int firstChannel, void *data, unsigned int channelCount )
+{
+ unsigned int i;
+ unsigned int channel = firstChannel;
+ unsigned char *p = (unsigned char*)data;
+
+ if( channelCount == 0 )
+ channelCount = bp->outputChannelCount;
+
+ assert( firstChannel < bp->outputChannelCount );
+ assert( firstChannel + channelCount <= bp->outputChannelCount );
+
+ for( i=0; i< channelCount; ++i )
+ {
+ bp->hostOutputChannels[0][channel+i].data = p;
+ p += bp->bytesPerHostOutputSample;
+ bp->hostOutputChannels[0][channel+i].stride = channelCount;
+ }
+}
+
+
+void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data )
+{
+ assert( channel < bp->outputChannelCount );
+
+ bp->hostOutputChannels[0][channel].data = data;
+ bp->hostOutputChannels[0][channel].stride = 1;
+}
+
+
+void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp,
+ unsigned long frameCount )
+{
+ bp->hostOutputFrameCount[1] = frameCount;
+}
+
+
+void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data, unsigned int stride )
+{
+ assert( channel < bp->outputChannelCount );
+
+ bp->hostOutputChannels[1][channel].data = data;
+ bp->hostOutputChannels[1][channel].stride = stride;
+}
+
+
+void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
+ unsigned int firstChannel, void *data, unsigned int channelCount )
+{
+ unsigned int i;
+ unsigned int channel = firstChannel;
+ unsigned char *p = (unsigned char*)data;
+
+ if( channelCount == 0 )
+ channelCount = bp->outputChannelCount;
+
+ assert( firstChannel < bp->outputChannelCount );
+ assert( firstChannel + channelCount <= bp->outputChannelCount );
+
+ for( i=0; i< channelCount; ++i )
+ {
+ bp->hostOutputChannels[1][channel+i].data = p;
+ p += bp->bytesPerHostOutputSample;
+ bp->hostOutputChannels[1][channel+i].stride = channelCount;
+ }
+}
+
+
+void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
+ unsigned int channel, void *data )
+{
+ assert( channel < bp->outputChannelCount );
+
+ bp->hostOutputChannels[1][channel].data = data;
+ bp->hostOutputChannels[1][channel].stride = 1;
+}
+
+
+/*
+ NonAdaptingProcess() is a simple buffer copying adaptor that can handle
+ both full and half duplex copies. It processes framesToProcess frames,
+ broken into blocks bp->framesPerTempBuffer long.
+ This routine can be used when the streamCallback doesn't care what length the
+ buffers are, or when framesToProcess is an integer multiple of
+ bp->framesPerTempBuffer, in which case streamCallback will always be called
+ with bp->framesPerTempBuffer samples.
+*/
+static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostInputChannels,
+ PaUtilChannelDescriptor *hostOutputChannels,
+ unsigned long framesToProcess )
+{
+ void *userInput, *userOutput;
+ unsigned char *srcBytePtr, *destBytePtr;
+ unsigned int srcStride, srcBytePtrStride;
+ unsigned int destStride, destBytePtrStride;
+ unsigned int i;
+ unsigned long frameCount;
+ unsigned long framesToGo = framesToProcess;
+ unsigned long framesProcessed = 0;
+ unsigned long statusFlags = 0; // FIXME: implement this
+
+ do
+ {
+ frameCount = ( bp->framesPerTempBuffer < framesToGo )
+ ? bp->framesPerTempBuffer
+ : framesToGo;
+
+ /* configure user input buffer and convert input data (host -> user) */
+ if( bp->inputChannelCount == 0 )
+ {
+ /* no input */
+ userInput = 0;
+ }
+ else /* there are input channels */
+ {
+ /*
+ could use more elaborate logic here and sometimes process
+ buffers in-place.
+ */
+
+ destBytePtr = bp->tempInputBuffer;
+
+ if( bp->userInputIsInterleaved )
+ {
+ destStride = bp->inputChannelCount;
+ destBytePtrStride = bp->bytesPerUserInputSample;
+ userInput = bp->tempInputBuffer;
+ }
+ else /* user input is not interleaved */
+ {
+ destStride = 1;
+ destBytePtrStride = frameCount * bp->bytesPerUserInputSample;
+
+ /* setup non-interleaved ptrs */
+ for( i=0; i<bp->inputChannelCount; ++i )
+ {
+ bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
+ i * bp->bytesPerUserInputSample * frameCount;
+ }
+
+ userInput = bp->tempInputBufferPtrs;
+ }
+
+ for( i=0; i<bp->inputChannelCount; ++i )
+ {
+ bp->inputConverter( destBytePtr, destStride,
+ hostInputChannels[i].data,
+ hostInputChannels[i].stride,
+ frameCount, &bp->ditherGenerator );
+
+ destBytePtr += destBytePtrStride; /* skip to next destination channel */
+
+ /* advance src ptr for next iteration */
+ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
+ frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
+ }
+ }
+
+ /* configure user output buffer */
+ if( bp->outputChannelCount == 0 )
+ {
+ /* no output */
+ userOutput = 0;
+ }
+ else /* there are output channels */
+ {
+ if( bp->userOutputIsInterleaved )
+ {
+ userOutput = bp->tempOutputBuffer;
+ }
+ else /* user output is not interleaved */
+ {
+ for( i = 0; i < bp->outputChannelCount; ++i )
+ {
+ bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
+ i * bp->bytesPerUserOutputSample * frameCount;
+ }
+
+ userOutput = bp->tempOutputBufferPtrs;
+ }
+ }
+
+ *streamCallbackResult = bp->streamCallback( userInput, userOutput,
+ frameCount, bp->timeInfo,
+ statusFlags, bp->userData );
+
+ bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
+ bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod;
+
+
+ // FIXME: if streamCallback result is abort, then abort!
+
+ /* convert output data (user -> host) */
+ if( bp->outputChannelCount != 0 )
+ {
+ /*
+ could use more elaborate logic here and sometimes process
+ buffers in-place.
+ */
+
+ srcBytePtr = bp->tempOutputBuffer;
+
+ if( bp->userOutputIsInterleaved )
+ {
+ srcStride = bp->outputChannelCount;
+ srcBytePtrStride = bp->bytesPerUserOutputSample;
+ }
+ else /* user output is not interleaved */
+ {
+ srcStride = 1;
+ srcBytePtrStride = frameCount * bp->bytesPerUserOutputSample;
+ }
+
+ for( i=0; i<bp->outputChannelCount; ++i )
+ {
+ bp->outputConverter( hostOutputChannels[i].data,
+ hostOutputChannels[i].stride,
+ srcBytePtr, srcStride,
+ frameCount, &bp->ditherGenerator );
+
+ srcBytePtr += srcBytePtrStride; /* skip to next source channel */
+
+ /* advance dest ptr for next iteration */
+ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
+ frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
+ }
+ }
+
+ framesProcessed += frameCount;
+
+ framesToGo -= frameCount;
+ }
+ while( framesToGo > 0 );
+
+ return framesProcessed;
+}
+
+
+/*
+ AdaptingInputOnlyProcess() is a half duplex input buffer processor. It
+ converts data from the input buffers into the temporary input buffer,
+ when the temporary input buffer is full, it calls the streamCallback.
+*/
+static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostInputChannels,
+ unsigned long framesToProcess )
+{
+ void *userInput, *userOutput;
+ unsigned char *destBytePtr;
+ unsigned int destStride, destBytePtrStride;
+ unsigned int i;
+ unsigned long frameCount;
+ unsigned long framesToGo = framesToProcess;
+ unsigned long framesProcessed = 0;
+ unsigned long statusFlags = 0; // FIXME: implement this
+
+ userOutput = 0;
+
+ do
+ {
+ frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer )
+ ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer )
+ : framesToGo;
+
+ /* convert frameCount samples into temp buffer */
+
+ if( bp->userInputIsInterleaved )
+ {
+ destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
+ bp->bytesPerUserInputSample * bp->inputChannelCount *
+ bp->framesInTempInputBuffer;
+
+ destStride = bp->inputChannelCount;
+ destBytePtrStride = bp->bytesPerUserInputSample;
+
+ userInput = bp->tempInputBuffer;
+ }
+ else /* user input is not interleaved */
+ {
+ destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
+ bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
+
+ destStride = 1;
+ destBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
+
+ /* setup non-interleaved ptrs */
+ for( i=0; i<bp->inputChannelCount; ++i )
+ {
+ bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
+ i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer;
+ }
+
+ userInput = bp->tempInputBufferPtrs;
+ }
+
+ for( i=0; i<bp->inputChannelCount; ++i )
+ {
+ bp->inputConverter( destBytePtr, destStride,
+ hostInputChannels[i].data,
+ hostInputChannels[i].stride,
+ frameCount, &bp->ditherGenerator );
+
+ destBytePtr += destBytePtrStride; /* skip to next destination channel */
+
+ /* advance src ptr for next iteration */
+ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
+ frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
+ }
+
+ bp->framesInTempInputBuffer += frameCount;
+
+ if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer )
+ {
+ bp->timeInfo->outputBufferDacTime = 0;
+
+ *streamCallbackResult = bp->streamCallback( userInput, userOutput,
+ bp->framesPerUserBuffer, bp->timeInfo,
+ statusFlags, bp->userData );
+
+ bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
+
+ // FIXME: if streamCallback result is abort, then abort!
+
+ bp->framesInTempInputBuffer = 0;
+ }
+
+ framesProcessed += frameCount;
+
+ framesToGo -= frameCount;
+ }while( framesToGo > 0 );
+
+ return framesProcessed;
+}
+
+
+/*
+ AdaptingOutputOnlyProcess() is a half duplex output buffer processor.
+ It converts data from the temporary output buffer, to the output buffers,
+ when the temporary output buffer is empty, it calls the streamCallback.
+*/
+static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult,
+ PaUtilChannelDescriptor *hostOutputChannels,
+ unsigned long framesToProcess )
+{
+ void *userInput, *userOutput;
+ unsigned char *srcBytePtr;
+ unsigned int srcStride, srcBytePtrStride;
+ unsigned int i;
+ unsigned long frameCount;
+ unsigned long framesToGo = framesToProcess;
+ unsigned long framesProcessed = 0;
+ unsigned long statusFlags = 0; // FIXME: implement this
+
+ do
+ {
+ if( bp->framesInTempOutputBuffer == 0 )
+ {
+ userInput = 0;
+
+ /* setup userOutput */
+ if( bp->userOutputIsInterleaved )
+ {
+ userOutput = bp->tempOutputBuffer;
+ }
+ else /* user output is not interleaved */
+ {
+ for( i = 0; i < bp->outputChannelCount; ++i )
+ {
+ bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
+ i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
+ }
+
+ userOutput = bp->tempOutputBufferPtrs;
+ }
+
+ bp->timeInfo->inputBufferAdcTime = 0;
+
+ *streamCallbackResult = bp->streamCallback( userInput, userOutput,
+ bp->framesPerUserBuffer, bp->timeInfo,
+ statusFlags, bp->userData );
+
+ bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
+
+ // FIXME: if streamCallback result is abort, then abort!
+
+ bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
+ }
+
+ frameCount = ( bp->framesInTempOutputBuffer > framesToGo )
+ ? framesToGo
+ : bp->framesInTempOutputBuffer;
+
+ /* convert frameCount frames from user buffer to host buffer */
+
+ if( bp->userOutputIsInterleaved )
+ {
+ srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
+ bp->bytesPerUserOutputSample * bp->outputChannelCount *
+ (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
+
+ srcStride = bp->outputChannelCount;
+ srcBytePtrStride = bp->bytesPerUserOutputSample;
+ }
+ else /* user output is not interleaved */
+ {
+ srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
+ bp->bytesPerUserOutputSample *
+ (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
+
+ srcStride = 1;
+ srcBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
+ }
+
+ for( i=0; i<bp->outputChannelCount; ++i )
+ {
+ bp->outputConverter( hostOutputChannels[i].data,
+ hostOutputChannels[i].stride,
+ srcBytePtr, srcStride,
+ frameCount, &bp->ditherGenerator );
+
+ srcBytePtr += srcBytePtrStride; /* skip to next source channel */
+
+ /* advance dest ptr for next iteration */
+ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
+ frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
+ }
+
+ bp->framesInTempOutputBuffer -= frameCount;
+
+ framesProcessed += frameCount;
+
+ framesToGo -= frameCount;
+
+ }while( framesToGo > 0 );
+
+ return framesProcessed;
+}
+
+
+/*
+ AdaptingProcess is a full duplex adapting buffer processor. It converts
+ data from the temporary output buffer into the host output buffers, then
+ from the host input buffers into the temporary input buffers. Calling the
+ streamCallback when necessary.
+ When processPartialUserBuffers is 0, all available input data will be
+ consumed and all available output space will be filled. When
+ processPartialUserBuffers is non-zero, as many full user buffers
+ as possible will be processed, but partial buffers will not be consumed.
+*/
+static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
+ int *streamCallbackResult, int processPartialUserBuffers )
+{
+ void *userInput, *userOutput;
+ unsigned long framesProcessed = 0;
+ unsigned long framesAvailable;
+ unsigned long endProcessingMinFrameCount;
+ unsigned long maxFramesToCopy;
+ PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels;
+ unsigned int frameCount;
+ unsigned char *srcBytePtr, *destBytePtr;
+ unsigned int srcStride, srcBytePtrStride, destStride, destBytePtrStride;
+ unsigned int i;
+ unsigned long statusFlags = 0; // FIXME: implement this
+
+ framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffers frame count */
+
+ if( processPartialUserBuffers )
+ endProcessingMinFrameCount = 0;
+ else
+ endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1);
+
+ while( framesAvailable > endProcessingMinFrameCount )
+ {
+ /* copy frames from user to host output buffers */
+ while( bp->framesInTempOutputBuffer > 0 &&
+ ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) )
+ {
+ maxFramesToCopy = bp->framesInTempOutputBuffer;
+
+ /* select the output buffer set (1st or 2nd) */
+ if( bp->hostOutputFrameCount[0] > 0 )
+ {
+ hostOutputChannels = bp->hostOutputChannels[0];
+ frameCount = (bp->hostOutputFrameCount[0] < maxFramesToCopy)
+ ? bp->hostOutputFrameCount[0]
+ : maxFramesToCopy;
+ }
+ else
+ {
+ hostOutputChannels = bp->hostOutputChannels[1];
+ frameCount = (bp->hostOutputFrameCount[1] < maxFramesToCopy)
+ ? bp->hostOutputFrameCount[1]
+ : maxFramesToCopy;
+ }
+
+ if( bp->userOutputIsInterleaved )
+ {
+ srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
+ bp->bytesPerUserOutputSample * bp->outputChannelCount *
+ (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
+
+ srcStride = bp->outputChannelCount;
+ srcBytePtrStride = bp->bytesPerUserOutputSample;
+ }
+ else /* user output is not interleaved */
+ {
+ srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
+ bp->bytesPerUserOutputSample *
+ (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
+
+ srcStride = 1;
+ srcBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
+ }
+
+ for( i=0; i<bp->outputChannelCount; ++i )
+ {
+ bp->outputConverter( hostOutputChannels[i].data,
+ hostOutputChannels[i].stride,
+ srcBytePtr, srcStride,
+ frameCount, &bp->ditherGenerator );
+
+ srcBytePtr += srcBytePtrStride; /* skip to next source channel */
+
+ /* advance dest ptr for next iteration */
+ hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
+ frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
+ }
+
+ if( bp->hostOutputFrameCount[0] > 0 )
+ bp->hostOutputFrameCount[0] -= frameCount;
+ else
+ bp->hostOutputFrameCount[1] -= frameCount;
+
+ bp->framesInTempOutputBuffer -= frameCount;
+ }
+
+
+ /* copy frames from host to user input buffers */
+ while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer &&
+ ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) )
+ {
+ maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer;
+
+ /* select the input buffer set (1st or 2nd) */
+ if( bp->hostInputFrameCount[0] > 0 )
+ {
+ hostInputChannels = bp->hostInputChannels[0];
+ frameCount = (bp->hostInputFrameCount[0] < maxFramesToCopy)
+ ? bp->hostInputFrameCount[0]
+ : maxFramesToCopy;
+ }
+ else
+ {
+ hostInputChannels = bp->hostInputChannels[1];
+ frameCount = (bp->hostInputFrameCount[1] < maxFramesToCopy)
+ ? bp->hostInputFrameCount[1]
+ : maxFramesToCopy;
+ }
+
+ /* configure conversion destination pointers */
+ if( bp->userInputIsInterleaved )
+ {
+ destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
+ bp->bytesPerUserInputSample * bp->inputChannelCount *
+ bp->framesInTempInputBuffer;
+
+ destStride = bp->inputChannelCount;
+ destBytePtrStride = bp->bytesPerUserInputSample;
+ }
+ else /* user input is not interleaved */
+ {
+ destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
+ bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
+
+ destStride = 1;
+ destBytePtrStride = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
+ }
+
+ for( i=0; i<bp->inputChannelCount; ++i )
+ {
+ bp->inputConverter( destBytePtr, destStride,
+ hostInputChannels[i].data,
+ hostInputChannels[i].stride,
+ frameCount, &bp->ditherGenerator );
+
+ destBytePtr += destBytePtrStride; /* skip to next destination channel */
+
+ /* advance src ptr for next iteration */
+ hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
+ frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
+ }
+
+ if( bp->hostInputFrameCount[0] > 0 )
+ bp->hostInputFrameCount[0] -= frameCount;
+ else
+ bp->hostInputFrameCount[1] -= frameCount;
+
+ bp->framesInTempInputBuffer += frameCount;
+
+ /* update framesAvailable and framesProcessed based on input consumed
+ unless something is very wrong this will also correspond to the
+ amount of output generated */
+ framesAvailable -= frameCount;
+ framesProcessed += frameCount;
+ }
+
+ /* call streamCallback */
+ if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer &&
+ bp->framesInTempOutputBuffer == 0 )
+ {
+ /* setup userInput */
+ if( bp->userInputIsInterleaved )
+ {
+ userInput = bp->tempInputBuffer;
+ }
+ else /* user input is not interleaved */
+ {
+ for( i = 0; i < bp->inputChannelCount; ++i )
+ {
+ bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
+ i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
+ }
+
+ userInput = bp->tempInputBufferPtrs;
+ }
+
+ /* setup userOutput */
+ if( bp->userOutputIsInterleaved )
+ {
+ userOutput = bp->tempOutputBuffer;
+ }
+ else /* user output is not interleaved */
+ {
+ for( i = 0; i < bp->outputChannelCount; ++i )
+ {
+ bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
+ i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
+ }
+
+ userOutput = bp->tempOutputBufferPtrs;
+ }
+
+ /* call streamCallback */
+
+ *streamCallbackResult = bp->streamCallback( userInput, userOutput,
+ bp->framesPerUserBuffer, bp->timeInfo,
+ statusFlags, bp->userData );
+
+ bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
+ bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
+
+
+ // FIXME: if streamCallback result is abort, then abort!
+
+
+ bp->framesInTempInputBuffer = 0;
+ bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
+ }
+ }
+
+ return framesProcessed;
+}
diff --git a/pd/portaudio/pa_common/pa_process.h b/pd/portaudio/pa_common/pa_process.h
new file mode 100644
index 00000000..47bc0d70
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_process.h
@@ -0,0 +1,203 @@
+#ifndef PA_PROCESS_H
+#define PA_PROCESS_H
+/*
+ * $Id: pa_process.h,v 1.1.2.16 2002/10/26 05:33:29 rossbencina Exp $
+ * Portable Audio I/O Library callback buffer processing adapters
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Phil Burk, Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "portaudio.h"
+#include "pa_converters.h"
+#include "pa_dither.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/** @file
+
+ @todo finish documentation for the buffer processor
+*/
+
+typedef enum {
+ paUtilFixedHostBufferSize,
+ paUtilBoundedHostBufferSize,
+ paUtilUnknownHostBufferSize,
+ paUtilVariableHostBufferSizePartialUsageAllowed, /**< the only mode where process() may not consume the whole buffer */
+}PaUtilHostBufferSizeMode;
+
+
+typedef struct PaUtilChannelDescriptor{
+ void *data;
+ unsigned int stride;
+}PaUtilChannelDescriptor;
+
+
+typedef struct {
+ unsigned long framesPerUserBuffer;
+ unsigned long framesPerHostBuffer;
+
+ PaUtilHostBufferSizeMode hostBufferSizeMode;
+ int useNonAdaptingProcess;
+ unsigned long framesPerTempBuffer;
+
+ unsigned int inputChannelCount;
+ unsigned int bytesPerHostInputSample;
+ unsigned int bytesPerUserInputSample;
+ int userInputIsInterleaved;
+ PaUtilConverter *inputConverter;
+
+ unsigned int outputChannelCount;
+ unsigned int bytesPerHostOutputSample;
+ unsigned int bytesPerUserOutputSample;
+ int userOutputIsInterleaved;
+ PaUtilConverter *outputConverter;
+
+ void *tempInputBuffer; /**< used for slips, block adaption, and conversion. */
+ void **tempInputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user input */
+ unsigned long framesInTempInputBuffer; /**< frames remaining in input buffer from previous adaption iteration */
+
+ void *tempOutputBuffer; /**< used for slips, block adaption, and conversion. */
+ void **tempOutputBufferPtrs; /**< storage for non-interleaved buffer pointers, NULL for interleaved user output */
+ unsigned long framesInTempOutputBuffer; /**< frames remaining in input buffer from previous adaption iteration */
+
+ PaStreamCallbackTimeInfo *timeInfo;
+
+ unsigned long hostInputFrameCount[2];
+ PaUtilChannelDescriptor *hostInputChannels[2];
+ unsigned long hostOutputFrameCount[2];
+ PaUtilChannelDescriptor *hostOutputChannels[2];
+
+ PaUtilTriangularDitherGenerator ditherGenerator;
+
+ double samplePeriod;
+
+ PaStreamCallback *streamCallback;
+ void *userData;
+} PaUtilBufferProcessor;
+
+
+/**
+ @param framesPerHostBuffer Specifies the number of frames per host buffer
+ for fixed the fixed buffer size mode, and the maximum number of frames
+ per host buffer for the bounded host buffer size mode. It is ignored for
+ the other modes.
+
+ @note The interleave flag is ignored for host buffer formats. Host interleave
+ is determined by the use of different SetInput and SetOutput functions.
+*/
+PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bufferProcessor,
+ int numInputChannels, PaSampleFormat userInputSampleFormat,
+ PaSampleFormat hostInputSampleFormat,
+ int numOutputChannels, PaSampleFormat userOutputSampleFormat,
+ PaSampleFormat hostOutputSampleFormat,
+ double sampleRate,
+ PaStreamFlags streamFlags,
+ unsigned long framesPerUserBuffer, /* 0 indicates don't care */
+ unsigned long framesPerHostBuffer,
+ PaUtilHostBufferSizeMode hostBufferSizeMode,
+ PaStreamCallback *streamCallback, void *userData );
+
+
+void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bufferProcessor );
+
+
+/**
+ @param timeInfo Timing information for the first sample of the buffer(s)
+ passed to the buffer processor. The buffer processor may adjust this
+ information as necessary.
+*/
+void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bufferProcessor,
+ PaStreamCallbackTimeInfo* timeInfo );
+
+/** returns the number of frames processed */
+unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bufferProcessor, int *callbackResult );
+
+
+/** a 0 frameCount indicates to use the framesPerHostBuffer value passed to init */
+void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bufferProcessor,
+ unsigned long frameCount );
+
+
+void PaUtil_SetInputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data, unsigned int stride );
+
+/** if channel count is zero use all channels as specified to initialize buffer processor */
+void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int firstChannel, void *data, unsigned int channelCount );
+
+void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data );
+
+
+void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bufferProcessor,
+ unsigned long frameCount );
+
+void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data, unsigned int stride );
+
+/** if channel count is zero use all channels as specified to initialize buffer processor */
+void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int firstChannel, void *data, unsigned int channelCount );
+
+void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data );
+
+/** a 0 frameCount indicates to use the framesPerHostBuffer value passed to init */
+void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,
+ unsigned long frameCount );
+
+void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data, unsigned int stride );
+
+/** if channel count is zero use all channels as specified to initialize buffer processor */
+void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int firstChannel, void *data, unsigned int channelCount );
+
+void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data );
+
+
+void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bufferProcessor,
+ unsigned long frameCount );
+
+void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data, unsigned int stride );
+
+/** if channel count is zero use all channels as specified to initialize buffer processor */
+void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int firstChannel, void *data, unsigned int channelCount );
+
+void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bufferProcessor,
+ unsigned int channel, void *data );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_PROCESS_H */
diff --git a/pd/portaudio/pa_common/pa_process.o b/pd/portaudio/pa_common/pa_process.o
new file mode 100644
index 00000000..3429227b
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_process.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_skeleton.c b/pd/portaudio/pa_common/pa_skeleton.c
new file mode 100644
index 00000000..d9a90f4b
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_skeleton.c
@@ -0,0 +1,724 @@
+/*
+ * $Id: pa_skeleton.c,v 1.1.2.27 2002/12/03 06:30:40 rossbencina Exp $
+ * Portable Audio I/O Library skeleton implementation
+ * demonstrates how to use the common functions to implement support
+ * for a host API
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <string.h> /* strlen() */
+
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
+
+/** @file
+ NOTE TO IMPLEMENTORS:
+
+ This file is provided as a starting point for implementing support for
+ a new host API. IMPLEMENT ME comments are used to indicate functionality
+ which much be customised for each implementation.
+*/
+
+
+/* prototypes for functions declared in this file */
+
+PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+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 GetStreamInputLatency( PaStream *stream );
+static PaTime GetStreamOutputLatency( 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, void *buffer, unsigned long frames );
+static signed long GetStreamReadAvailable( PaStream* stream );
+static signed long GetStreamWriteAvailable( PaStream* stream );
+
+
+/* IMPLEMENT ME: a macro like the following one should be used for reporting
+ host errors */
+#define PA_SKELETON_SET_LAST_HOST_ERROR( errorCode, errorText ) \
+ PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
+
+/* PaSkeletonHostApiRepresentation - host api datastructure specific to this implementation */
+
+typedef struct
+{
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
+
+ PaUtilAllocationGroup *allocations;
+
+ /* implementation specific data goes here */
+}
+PaSkeletonHostApiRepresentation; /* IMPLEMENT ME: rename this */
+
+
+PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ int i, deviceCount;
+ PaSkeletonHostApiRepresentation *skeletonHostApi;
+ PaDeviceInfo *deviceInfoArray;
+
+ skeletonHostApi = (PaSkeletonHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaSkeletonHostApiRepresentation) );
+ if( !skeletonHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !skeletonHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ *hostApi = &skeletonHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paInDevelopment; /* IMPLEMENT ME: change to correct type id */
+ (*hostApi)->info.name = "skeleton implementation"; /* IMPLEMENT ME: change to correct name */
+
+ (*hostApi)->info.defaultInputDevice = paNoDevice; /* IMPLEMENT ME */
+ (*hostApi)->info.defaultOutputDevice = paNoDevice; /* IMPLEMENT ME */
+
+ (*hostApi)->info.deviceCount = 0;
+
+ deviceCount = 0; /* IMPLEMENT ME */
+
+ if( deviceCount > 0 )
+ {
+ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ skeletonHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
+ if( !(*hostApi)->deviceInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* allocate all device info structs in a contiguous block */
+ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ skeletonHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
+ if( !deviceInfoArray )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i=0; i < deviceCount; ++i )
+ {
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+ deviceInfo->name = 0; /* IMPLEMENT ME: allocate block and copy name eg:
+ deviceName = (char*)PaUtil_GroupAllocateMemory( skeletonHostApi->allocations, strlen(srcName) + 1 );
+ if( !deviceName )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ strcpy( deviceName, srcName );
+ deviceInfo->name = deviceName;
+ */
+
+ deviceInfo->maxInputChannels = 0; /* IMPLEMENT ME */
+ deviceInfo->maxOutputChannels = 0; /* IMPLEMENT ME */
+
+ deviceInfo->defaultLowInputLatency = 0.; /* IMPLEMENT ME */
+ deviceInfo->defaultLowOutputLatency = 0.; /* IMPLEMENT ME */
+ deviceInfo->defaultHighInputLatency = 0.; /* IMPLEMENT ME */
+ deviceInfo->defaultHighOutputLatency = 0.; /* IMPLEMENT ME */
+
+ deviceInfo->defaultSampleRate = 0.; /* IMPLEMENT ME */
+
+ (*hostApi)->deviceInfos[i] = deviceInfo;
+ ++(*hostApi)->info.deviceCount;
+ }
+ }
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+
+ return result;
+
+error:
+ if( skeletonHostApi )
+ {
+ if( skeletonHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( skeletonHostApi );
+ }
+ return result;
+}
+
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
+
+ /*
+ IMPLEMENT ME:
+ - clean up any resourced not handled by the allocation group
+ */
+
+ if( skeletonHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( skeletonHostApi );
+}
+
+
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
+{
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ /*
+ IMPLEMENT ME:
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+ */
+
+ return paFormatIsSupported;
+}
+
+/* PaSkeletonStream - a stream data structure specifically for this implementation */
+
+typedef struct PaSkeletonStream
+{ /* IMPLEMENT ME: rename this */
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ /* IMPLEMENT ME:
+ - implementation specific data goes here
+ */
+ unsigned long framesPerHostCallback; /* just an example */
+}
+PaSkeletonStream;
+
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaSkeletonHostApiRepresentation *skeletonHostApi = (PaSkeletonHostApiRepresentation*)hostApi;
+ PaSkeletonStream *stream = 0;
+ unsigned long framesPerHostBuffer = framesPerBuffer; /* these may not be equivalent for all implementations */
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat=0, outputSampleFormat=0;
+ PaSampleFormat hostInputSampleFormat=0, hostOutputSampleFormat=0;
+
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+
+ /* IMPLEMENT ME - establish which host formats are available */
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+
+ /* IMPLEMENT ME - establish which host formats are available */
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ /*
+ IMPLEMENT ME:
+
+ ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() FIXME - checks needed? )
+
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+
+ - alter sampleRate to a close allowable rate if possible / necessary
+
+ - validate suggestedInputLatency and suggestedOutputLatency parameters,
+ use default values where necessary
+ */
+
+
+
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
+
+
+ stream = (PaSkeletonStream*)PaUtil_AllocateMemory( sizeof(PaSkeletonStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( streamCallback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &skeletonHostApi->callbackStreamInterface, streamCallback, userData );
+ }
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &skeletonHostApi->blockingStreamInterface, streamCallback, userData );
+ }
+
+ /*
+ IMPLEMENT ME: initialise the following fields with estimated or actual
+ values.
+ */
+ stream->streamRepresentation.streamInfo.inputLatency = 0.;
+ stream->streamRepresentation.streamInfo.outputLatency = 0.;
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+
+ /* we assume a fixed host buffer size in this example, but the buffer processor
+ can also support bounded and unknown host buffer sizes by passing
+ paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
+ paUtilFixedHostBufferSize below. */
+
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ inputChannelCount, inputSampleFormat, hostInputSampleFormat,
+ outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer,
+ framesPerHostBuffer, paUtilFixedHostBufferSize,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+
+ /*
+ IMPLEMENT ME:
+ - additional stream setup + opening
+ */
+
+ stream->framesPerHostCallback = framesPerHostBuffer;
+
+ *s = (PaStream*)stream;
+
+ return result;
+
+error:
+ if( stream )
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+/*
+ ExampleHostProcessingLoop() illustrates the kind of processing which may
+ occur in a host implementation.
+
+*/
+static void ExampleHostProcessingLoop( void *inputBuffer, void *outputBuffer, void *userData )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)userData;
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
+ int callbackResult;
+ unsigned long framesProcessed;
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ /*
+ IMPLEMENT ME:
+ - generate timing information
+ - handle buffer slips
+ */
+
+ /*
+ If you need to byte swap or shift inputBuffer to convert it into a
+ portaudio format, do it here.
+ */
+
+
+
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo );
+
+ /*
+ depending on whether the host buffers are interleaved, non-interleaved
+ or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
+ PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
+ */
+
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
+ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
+ 0, /* first channel of inputBuffer is channel 0 */
+ inputBuffer,
+ 0 ); /* 0 - use inputChannelCount passed to init buffer processor */
+
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
+ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
+ 0, /* first channel of outputBuffer is channel 0 */
+ outputBuffer,
+ 0 ); /* 0 - use outputChannelCount passed to init buffer processor */
+
+ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
+
+
+ /*
+ If you need to byte swap or shift outputBuffer to convert it to
+ host format, do it here.
+ */
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+
+
+ if( callbackResult == paContinue )
+ {
+ /* nothing special to do */
+ }
+ else if( callbackResult == paAbort )
+ {
+ /* IMPLEMENT ME - finish playback immediately */
+
+ /* once finished, call the finished callback */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+ }
+ else
+ {
+ /* User callback has asked us to stop with paComplete or other non-zero value */
+
+ /* IMPLEMENT ME - finish playback once currently queued audio has completed */
+
+ /* once finished, call the finished callback */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+ }
+}
+
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /*
+ IMPLEMENT ME:
+ - additional stream closing + cleanup
+ */
+
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior */
+
+ return result;
+}
+
+
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior */
+
+ return result;
+}
+
+
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior */
+
+ return result;
+}
+
+
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior */
+
+ return 0;
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior */
+
+ return 0;
+}
+
+
+static PaTime GetStreamTime( PaStream *s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
+/*
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
+
+static PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return paNoError;
+}
+
+
+static PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return paNoError;
+}
+
+
+static signed long GetStreamReadAvailable( PaStream* s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
+}
+
+
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+ PaSkeletonStream *stream = (PaSkeletonStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
+}
+
+
+
diff --git a/pd/portaudio/pa_common/pa_skeleton.o b/pd/portaudio/pa_common/pa_skeleton.o
new file mode 100644
index 00000000..4641670a
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_skeleton.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_stream.c b/pd/portaudio/pa_common/pa_stream.c
new file mode 100644
index 00000000..b2eba53d
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_stream.c
@@ -0,0 +1,114 @@
+/*
+ * $Id: pa_stream.c,v 1.1.2.9 2002/12/03 06:30:40 rossbencina Exp $
+ * Portable Audio I/O Library
+ *
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 2002 Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "pa_stream.h"
+
+void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface,
+ PaError (*Close)( PaStream* ),
+ PaError (*Start)( PaStream* ),
+ PaError (*Stop)( PaStream* ),
+ PaError (*Abort)( PaStream* ),
+ PaError (*IsStopped)( PaStream* ),
+ PaError (*IsActive)( PaStream* ),
+ PaTime (*GetTime)( PaStream* ),
+ double (*GetCpuLoad)( PaStream* ),
+ PaError (*Read)( PaStream*, void *, unsigned long ),
+ PaError (*Write)( PaStream*, void *, unsigned long ),
+ signed long (*GetReadAvailable)( PaStream* ),
+ signed long (*GetWriteAvailable)( PaStream* ) )
+{
+ streamInterface->Close = Close;
+ streamInterface->Start = Start;
+ streamInterface->Stop = Stop;
+ streamInterface->Abort = Abort;
+ streamInterface->IsStopped = IsStopped;
+ streamInterface->IsActive = IsActive;
+ streamInterface->GetTime = GetTime;
+ streamInterface->GetCpuLoad = GetCpuLoad;
+ streamInterface->Read = Read;
+ streamInterface->Write = Write;
+ streamInterface->GetReadAvailable = GetReadAvailable;
+ streamInterface->GetWriteAvailable = GetWriteAvailable;
+}
+
+
+void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation,
+ PaUtilStreamInterface *streamInterface,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ streamRepresentation->magic = PA_STREAM_MAGIC;
+ streamRepresentation->nextOpenStream = 0;
+ streamRepresentation->streamInterface = streamInterface;
+ streamRepresentation->streamCallback = streamCallback;
+ streamRepresentation->streamFinishedCallback = 0;
+
+ streamRepresentation->userData = userData;
+
+ streamRepresentation->streamInfo.inputLatency = 0.;
+ streamRepresentation->streamInfo.outputLatency = 0.;
+ streamRepresentation->streamInfo.sampleRate = 0.;
+}
+
+
+void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation )
+{
+ streamRepresentation->magic = 0;
+}
+
+
+PaError PaUtil_DummyReadWrite( PaStream* stream,
+ void *buffer,
+ unsigned long frames )
+{
+ (void)stream; /* unused parameter */
+ (void)buffer; /* unused parameter */
+ (void)frames; /* unused parameter */
+
+ return paNoError; /* @todo FIXME: need new error code paCantReadWriteToCallbackStream or something */
+}
+
+
+signed long PaUtil_DummyGetAvailable( PaStream* stream )
+{
+ (void)stream; /* unused parameter */
+
+ return 0;
+}
+
+
+double PaUtil_DummyGetCpuLoad( PaStream* stream )
+{
+ (void)stream; /* unused parameter */
+
+ return 0.0;
+}
diff --git a/pd/portaudio/pa_common/pa_stream.h b/pd/portaudio/pa_common/pa_stream.h
new file mode 100644
index 00000000..5e66c097
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_stream.h
@@ -0,0 +1,128 @@
+#ifndef PA_STREAM_H
+#define PA_STREAM_H
+/*
+ * $Id: pa_stream.h,v 1.1.2.9 2002/12/03 06:30:40 rossbencina Exp $
+ * Portable Audio I/O Library
+ * stream interface
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/** @file
+ Interface used by pa_front to virtualise stream calls.
+*/
+
+#include "portaudio.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+#define PA_STREAM_MAGIC (0x18273645)
+
+typedef struct {
+ /*
+ all PaStreamInterface functions are guaranteed to be called with a
+ non-null, valid <stream> parameter
+ */
+ PaError (*Close)( PaStream* stream );
+ PaError (*Start)( PaStream *stream );
+ PaError (*Stop)( PaStream *stream );
+ PaError (*Abort)( PaStream *stream );
+ PaError (*IsStopped)( PaStream *stream );
+ PaError (*IsActive)( PaStream *stream );
+ PaTime (*GetTime)( PaStream *stream );
+ double (*GetCpuLoad)( PaStream* stream );
+ PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames );
+ PaError (*Write)( PaStream* stream, void *buffer, unsigned long frames );
+ signed long (*GetReadAvailable)( PaStream* stream );
+ signed long (*GetWriteAvailable)( PaStream* stream );
+} PaUtilStreamInterface;
+
+
+void PaUtil_InitializeStreamInterface( PaUtilStreamInterface *streamInterface,
+ PaError (*Close)( PaStream* ),
+ PaError (*Start)( PaStream* ),
+ PaError (*Stop)( PaStream* ),
+ PaError (*Abort)( PaStream* ),
+ PaError (*IsStopped)( PaStream* ),
+ PaError (*IsActive)( PaStream* ),
+ PaTime (*GetTime)( PaStream* ),
+ double (*GetCpuLoad)( PaStream* ),
+ PaError (*Read)( PaStream* stream, void *buffer, unsigned long frames ),
+ PaError (*Write)( PaStream* stream, void *buffer, unsigned long frames ),
+ signed long (*GetReadAvailable)( PaStream* stream ),
+ signed long (*GetWriteAvailable)( PaStream* stream ) );
+
+
+/** Use PaUtil_DummyReadWrite and PaUtil_DummyGetAvailable for
+ callback based streams.
+*/
+PaError PaUtil_DummyReadWrite( PaStream* stream,
+ void *buffer,
+ unsigned long frames );
+
+
+signed long PaUtil_DummyGetAvailable( PaStream* stream );
+
+/** Use PaUtil_DummyGetCpuLoad for read/write streams
+*/
+double PaUtil_DummyGetCpuLoad( PaStream* stream );
+
+
+typedef struct PaUtilStreamRepresentation {
+ unsigned long magic; /* set to PA_STREAM_MAGIC */
+ struct PaUtilStreamRepresentation *nextOpenStream; /* field used by multi-api code */
+ PaUtilStreamInterface *streamInterface;
+ PaStreamCallback *streamCallback;
+ PaStreamFinishedCallback *streamFinishedCallback;
+ void *userData;
+ PaStreamInfo streamInfo;
+} PaUtilStreamRepresentation;
+
+
+void PaUtil_InitializeStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation,
+ PaUtilStreamInterface *streamInterface,
+ PaStreamCallback *streamCallback,
+ void *userData );
+
+void PaUtil_TerminateStreamRepresentation( PaUtilStreamRepresentation *streamRepresentation );
+
+
+#define PA_STREAM_REP( streamRepPtr )\
+ ((PaUtilStreamRepresentation*) streamRepPtr )
+
+#define PA_STREAM_INTERFACE( streamRepPtr )\
+ PA_STREAM_REP( streamRepPtr )->streamInterface
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_STREAM_H */
diff --git a/pd/portaudio/pa_common/pa_stream.o b/pd/portaudio/pa_common/pa_stream.o
new file mode 100644
index 00000000..c75789bb
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_stream.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_trace.c b/pd/portaudio/pa_common/pa_trace.c
index d55a6d37..74e8bb2f 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 2002/01/22 00:52:11 phil Exp $
+ * $Id: pa_trace.c,v 1.1.1.1.2.2 2002/10/26 05:34:03 rossbencina Exp $
* Portable Audio I/O Library Trace Facility
* Store trace information in real-time for later printing.
*
@@ -35,7 +35,7 @@
#include <string.h>
#include "pa_trace.h"
-#if TRACE_REALTIME_EVENTS
+#if PA_TRACE_REALTIME_EVENTS
static char *traceTextArray[MAX_TRACE_RECORDS];
static int traceIntArray[MAX_TRACE_RECORDS];
@@ -43,19 +43,19 @@ static int traceIndex = 0;
static int traceBlock = 0;
/*********************************************************************/
-void ResetTraceMessages()
+void PaUtil_ResetTraceMessages()
{
traceIndex = 0;
}
/*********************************************************************/
-void DumpTraceMessages()
+void PaUtil_DumpTraceMessages()
{
int i;
- int numDump = (traceIndex < MAX_TRACE_RECORDS) ? traceIndex : MAX_TRACE_RECORDS;
+ int messageCount = (traceIndex < PA_MAX_TRACE_RECORDS) ? traceIndex : PA_MAX_TRACE_RECORDS;
printf("DumpTraceMessages: traceIndex = %d\n", traceIndex );
- for( i=0; i<numDump; i++ )
+ for( i=0; i<messageCount; i++ )
{
printf("%3d: %s = 0x%08X\n",
i, traceTextArray[i], traceIntArray[i] );
@@ -65,14 +65,14 @@ void DumpTraceMessages()
}
/*********************************************************************/
-void AddTraceMessage( char *msg, int data )
+void PaUtil_AddTraceMessage( const char *msg, int data )
{
- if( (traceIndex == MAX_TRACE_RECORDS) && (traceBlock == 0) )
+ if( (traceIndex == PA_MAX_TRACE_RECORDS) && (traceBlock == 0) )
{
traceBlock = 1;
- /* DumpTraceMessages(); */
+ /* PaUtil_DumpTraceMessages(); */
}
- else if( traceIndex < MAX_TRACE_RECORDS )
+ else if( traceIndex < PA_MAX_TRACE_RECORDS )
{
traceTextArray[traceIndex] = msg;
traceIntArray[traceIndex] = data;
@@ -80,4 +80,4 @@ void AddTraceMessage( char *msg, int data )
}
}
-#endif
+#endif /* TRACE_REALTIME_EVENTS */
diff --git a/pd/portaudio/pa_common/pa_trace.h b/pd/portaudio/pa_common/pa_trace.h
index d0fc904c..069d006d 100644
--- a/pd/portaudio/pa_common/pa_trace.h
+++ b/pd/portaudio/pa_common/pa_trace.h
@@ -1,7 +1,7 @@
#ifndef PA_TRACE_H
#define PA_TRACE_H
/*
- * $Id: pa_trace.h,v 1.1.1.1 2002/01/22 00:52:11 phil Exp $
+ * $Id: pa_trace.h,v 1.1.1.1.2.2 2002/10/22 08:58:16 rossbencina Exp $
* Portable Audio I/O Library Trace Facility
* Store trace information in real-time for later printing.
*
@@ -32,9 +32,13 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+/** @file
+ Event trace mechanism for debugging. Allows data to be written to the buffer
+ at interrupt time and dumped later.
+*/
-#define TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */
-#define MAX_TRACE_RECORDS (2048)
+#define PA_TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */
+#define PA_MAX_TRACE_RECORDS (2048)
#ifdef __cplusplus
extern "C"
@@ -42,24 +46,21 @@ extern "C"
#endif /* __cplusplus */
- /************************************************************************************/
- /****************** Prototypes ******************************************************/
- /************************************************************************************/
-
-#if TRACE_REALTIME_EVENTS
-
- void DumpTraceMessages();
- void ResetTraceMessages();
- void AddTraceMessage( char *msg, int data );
+#if PA_TRACE_REALTIME_EVENTS
+void PaUtil_ResetTraceMessages();
+void PaUtil_AddTraceMessage( const char *msg, int data );
+void PaUtil_DumpTraceMessages();
+
#else
-#define AddTraceMessage(msg,data) /* noop */
-#define ResetTraceMessages() /* noop */
-#define DumpTraceMessages() /* noop */
+#define PaUtil_ResetTraceMessages() /* noop */
+#define PaUtil_AddTraceMessage(msg,data) /* noop */
+#define PaUtil_DumpTraceMessages() /* noop */
#endif
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/pd/portaudio/pa_common/pa_trace.o b/pd/portaudio/pa_common/pa_trace.o
new file mode 100644
index 00000000..0c160bea
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_trace.o
Binary files differ
diff --git a/pd/portaudio/pa_common/pa_util.h b/pd/portaudio/pa_common/pa_util.h
new file mode 100644
index 00000000..c87d71ca
--- /dev/null
+++ b/pd/portaudio/pa_common/pa_util.h
@@ -0,0 +1,143 @@
+#ifndef PA_UTIL_H
+#define PA_UTIL_H
+/*
+ * Id:
+ * Portable Audio I/O Library implementation utilities header
+ * common implementation utilities and interfaces
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "portaudio.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+struct PaUtilHostApiRepresentation;
+
+
+/** Retrieve a specific host API representation. This function can be used
+ by implementations to retrieve a pointer to their representation in
+ host api specific extension functions which aren't passed a rep pointer
+ by pa_front.c.
+
+ @param hostApi A pointer to a host API represenation pointer. Apon success
+ this will receive the requested representation pointer.
+
+ @param type A valid host API type identifier.
+
+ @returns An error code. If the result is PaNoError then a pointer to the
+ requested host API representation will be stored in *hostApi.
+*/
+PaError PaUtil_GetHostApiRepresentation( struct PaUtilHostApiRepresentation **hostApi,
+ PaHostApiTypeId type );
+
+
+/** Convert a PortAudio device index into a host API specific device index.
+ @param hostApiDevice Pointer to a device index, on success this will recieve the
+ converted device index value.
+ @param device The PortAudio device index to convert.
+ @param hostApi The host api which the index should be converted for.
+
+ @returns On success returns PaNoError and places the converted index in the
+ hostApiDevice parameter.
+*/
+PaError PaUtil_DeviceIndexToHostApiDeviceIndex(
+ PaDeviceIndex *hostApiDevice, PaDeviceIndex device,
+ struct PaUtilHostApiRepresentation *hostApi );
+
+
+/** Set the host error information returned by Pa_GetLastHostErrorInfo. This
+ function and the paUnanticipatedHostError error code should be used as a
+ last resort. Implementors should use existing PA error codes where possible,
+ or nominate new ones. Note that at it is always better to use
+ PaUtil_SetLastHostErrorInfo() and paUnanticipatedHostError than to return an
+ ambiguous or inaccurate PaError code.
+
+ @param hostApiType The host API which encountered the error (ie of the caller)
+
+ @param errorCode The error code returned by the native API function.
+
+ @param errorText A string describing the error. PaUtil_SetLastHostErrorInfo
+ makes a copy of the string, so it is not necessary for the pointer to remain
+ valid after the call to PaUtil_SetLastHostErrorInfo() returns.
+
+*/
+void PaUtil_SetLastHostErrorInfo( PaHostApiTypeId hostApiType, long errorCode,
+ const char *errorText );
+
+
+
+/**
+PA_DEBUG() provides a simple debug message printing facility. The macro
+passes it's argument to a printf-like function called PaUtil_DebugPrint()
+which prints to stderr and always flushes the stream after printing.
+Because preprocessor macros cannot directly accept variable length argument
+lists, calls to the macro must include an additional set of parenthesis, eg:
+PA_DEBUG(("errorno: %d", 1001 ));
+*/
+
+void PaUtil_DebugPrint( const char *format, ... );
+
+#if (0) /* set to 1 to print debug messages */
+#define PA_DEBUG(x) PaUtil_DebugPrint x ;
+#else
+#define PA_DEBUG(x)
+#endif
+
+
+/* the following functions are implemented in a per-platform .c file */
+
+void *PaUtil_AllocateMemory( long size );
+/**< Allocate size bytes, guaranteed to be aligned to a FIXME byte boundary */
+
+void PaUtil_FreeMemory( void *block );
+/**< Realease block if non-NULL. block may be NULL */
+
+int PaUtil_CountCurrentlyAllocatedBlocks( void );
+/**<
+ Return the number of currently allocated blocks. This function can be
+ used for detecting memory leaks.
+
+ @note Allocations will only be tracked if PA_TRACK_MEMORY is #defined. If
+ it isn't, this function will always return 0.
+*/
+
+
+void PaUtil_InitializeClock( void );
+double PaUtil_GetTime( void ); /* system time in seconds, used to implement CPU load functions */
+
+/* void Pa_Sleep( long msec ); must also be implemented in per-platform .c file */
+
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_UTIL_H */
diff --git a/pd/portaudio/pa_common/portaudio.h b/pd/portaudio/pa_common/portaudio.h
index 06f7079b..68303e1c 100644
--- a/pd/portaudio/pa_common/portaudio.h
+++ b/pd/portaudio/pa_common/portaudio.h
@@ -1,5 +1,5 @@
-#ifndef PORT_AUDIO_H
-#define PORT_AUDIO_H
+#ifndef PORTAUDIO_H
+#define PORTAUDIO_H
#ifdef __cplusplus
extern "C"
@@ -7,12 +7,12 @@ extern "C"
#endif /* __cplusplus */
/*
- * $Id: portaudio.h,v 1.5 2002/03/26 18:04:22 philburk Exp $
+ * $Id: portaudio.h,v 1.5.2.34 2002/12/03 07:02:54 rossbencina Exp $
* PortAudio Portable Real-Time Audio Library
* PortAudio API Header File
- * Latest version available at: http://www.audiomulch.com/portaudio/
+ * Latest version available at: http://www.portaudio.com/
*
- * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ * Copyright (c) 1999-2002 Ross Bencina and Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -39,14 +39,31 @@ extern "C"
*
*/
+
+/** Retrieve the release number of the currently running PortAudio build,
+ eg 1900.
+*/
+int Pa_GetVersion( void );
+
+
+/** Retrieve a textual description of the current PortAudio build,
+ eg "PortAudio V19-devel 13 October 2002".
+*/
+const char* Pa_GetVersionText( void );
+
+
+/** Error codes returned by PortAudio functions. */
+
typedef int PaError;
-typedef enum {
+typedef enum PaErrorCode
+{
paNoError = 0,
- paHostError = -10000,
+ paNotInitialized = -10000,
+ paUnanticipatedHostError,
paInvalidChannelCount,
paInvalidSampleRate,
- paInvalidDeviceId,
+ paInvalidDevice,
paInvalidFlag,
paSampleFormatNotSupported,
paBadIODeviceCombination,
@@ -57,407 +74,999 @@ typedef enum {
paBadStreamPtr,
paTimedOut,
paInternalError,
- paDeviceUnavailable
-} PaErrorNum;
+ paDeviceUnavailable,
+ paIncompatibleHostApiSpecificStreamInfo,
+ paStreamIsStopped,
+ paStreamIsNotStopped,
+ paInputOverflowed,
+ paOutputUnderflowed
+} PaErrorCode;
-/*
- Pa_Initialize() is the library initialisation function - call this before
- using the library.
+/** Translate the supplied PortAudio error number into a human readable
+ message.
*/
+const char *Pa_GetErrorText( PaError errorNumber );
-PaError Pa_Initialize( void );
-/*
- Pa_Terminate() is the library termination function - call this after
- using the library.
+/** Library initialization function - call this before using PortAudio.
+ This function initialises internal data structures and prepares underlying
+ host APIs for use. This function MUST be called before using any other
+ PortAudio API functions.
+
+ If Pa_Initialize() is called multiple times, each call must be matched with
+ a corresponding call to Pa_Terminate(). Pairs of calls to
+ Pa_Initialize()/Pa_Terminate() may overlap, and are not requireed to be fully
+ nested.
+ @return paNoError if successful, otherwise an error code indicating the cause
+ of failure.
+
+ @see Pa_Terminate
*/
+PaError Pa_Initialize( void );
+
+
+/** Library termination function - call this when finished using PortAudio.
+ This function deallocates all resources allocated by PortAudio since it was
+ initializied by a call to Pa_Initialize(). In cases where Pa_Initialise() has
+ been called multiple times, each call must be matched with a corresponding call
+ to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically
+ close any PortAudio streams that are still open.
+ Pa_Terminate() MUST be called before exiting a program which uses PortAudio.
+ Failure to do so may result in serious resource leaks, such as audio devices
+ not being available until the next reboot.
+
+ @return paNoError if successful, otherwise an error code indicating the cause
+ of failure.
+
+ @see Pa_Initialize
+*/
PaError Pa_Terminate( void );
-/*
- Pa_GetHostError() returns a host specific error code.
- This can be called after receiving a PortAudio error code of paHostError.
+
+/** The type used to refer to audio devices. Values of this type usually
+ range from 0 to (Pa_DeviceCount-1), and may also take on the PaNoDevice
+ and paUseHostApiSpecificDeviceSpecification values.
+
+ @see Pa_DeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification
*/
+typedef int PaDeviceIndex;
-long Pa_GetHostError( void );
-/*
- Pa_GetErrorText() translates the supplied PortAudio error number
- into a human readable message.
-
+/** A special PaDeviceIndex value indicating that no device is available,
+ or should be used.
+
+ @see PaDeviceIndex
*/
+#define paNoDevice ((PaDeviceIndex)-1)
-const char *Pa_GetErrorText( PaError errnum );
-/*
- Sample formats
-
- These are formats used to pass sound data between the callback and the
- stream. Each device has a "native" format which may be used when optimum
- efficiency or control over conversion is required.
-
- Formats marked "always available" are supported (emulated) by all
- PortAudio implementations.
-
- The floating point representation (paFloat32) uses +1.0 and -1.0 as the
- maximum and minimum respectively.
+/** A special PaDeviceIndex value indicating that the device(s) to be used
+ are specified in the host api specific stream info structure.
- paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
+ @see PaDeviceIndex
+*/
+#define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2)
+
+/* Host API enumeration mechanism */
+
+/** The type used to enumerate to host APIs at runtime. Values of this type
+ range from 0 to (Pa_CountHostApis()-1).
+
+ @see Pa_CountHostApis
*/
+typedef int PaHostApiIndex;
-typedef unsigned long PaSampleFormat;
-#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
-#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
-#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
-#define paInt24 ((PaSampleFormat) (1<<3))
-#define paPackedInt24 ((PaSampleFormat) (1<<4))
-#define paInt8 ((PaSampleFormat) (1<<5))
-#define paUInt8 ((PaSampleFormat) (1<<6))
-#define paCustomFormat ((PaSampleFormat) (1<<16))
-/*
- Device enumeration mechanism.
-
- Device ids range from 0 to Pa_CountDevices()-1.
-
- Devices may support input, output or both.
+/** Retrieve the number of available host APIs. Even if a host API is
+ available it may have no devices available.
+ @return A non-negative value indicating the number of available host APIs.
+ Returns a negative PaErrorCode if PortAudio is not initialized or an error
+ is encountered.
+
+ @see PaHostApiIndex
*/
+PaHostApiIndex Pa_CountHostApis( void );
-typedef int PaDeviceID;
-#define paNoDevice -1
-int Pa_CountDevices( void );
+/** Retrieve the index of the default host API. The default host API will be
+ the lowest common denominator host API on the current platform and is
+ unlikely to provide the best performance.
-typedef struct
+ @return A non-negative value indicating the default host API index. Returns a
+ negative PaErrorCode if PortAudio is not initialized or an error is encountered.
+*/
+PaHostApiIndex Pa_GetDefaultHostApi( void );
+
+
+/** Unchanging unique identifiers for each supported host API. This type
+ is used in the PaHostApiInfo structure. The values are guaranteed to be
+ unique and to never change, thus allowing code to be written that
+ conditionally uses host API specific extensions.
+
+ New type ids will be allocated when support for a host API reaches
+ "public alpha" status, prior to that developers should use the
+ paInDevelopment type id.
+
+ @see PaHostApiInfo
+*/
+typedef enum PaHostApiTypeId
+{
+ paInDevelopment=0, /* use while developing support for a new host API */
+ paDirectSound=1,
+ paMME=2,
+ paASIO=3,
+ paSoundManager=4,
+ paCoreAudio=5,
+ paOSS=7,
+ paALSA=8,
+ paAL=9,
+ paBeOS=10
+} PaHostApiTypeId;
+
+
+/** A structure containing information about a particular host API. */
+
+typedef struct PaHostApiInfo
{
+ /** this is struct version 1 */
int structVersion;
+ /** The well known unique identifier of this host API @see PaHostApiTypeId */
+ PaHostApiTypeId type;
+ /** A textual description of the host API for display on user interfaces. */
const char *name;
- int maxInputChannels;
- int maxOutputChannels;
- /* Number of discrete rates, or -1 if range supported. */
- int numSampleRates;
- /* Array of supported sample rates, or {min,max} if range supported. */
- const double *sampleRates;
- PaSampleFormat nativeSampleFormats;
-}
-PaDeviceInfo;
-/*
- Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() return the
- default device ids for input and output respectively, or paNoDevice if
- no device is available.
- The result can be passed to Pa_OpenStream().
-
+ /** The number of devices belonging to this host API. This field may be
+ used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate
+ all devices for this host API.
+ @see Pa_HostApiDeviceIndexToDeviceIndex
+ */
+ int deviceCount;
+
+ /** The the default input device for this host API. The value will be a
+ device index ranging from 0 to (Pa_CountDevices()-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
+ device index ranging from 0 to (Pa_CountDevices()-1), or paNoDevice
+ if no default output device is available.
+ */
+ PaDeviceIndex defaultOutputDevice;
+
+} PaHostApiInfo;
+
+
+/** Retrieve a pointer to a structure containing information about a specific
+ host Api.
+
+ @param hostApi A valid host API index ranging from 0 to (Pa_CountHostApis()-1)
+
+ @return A pointer to an immutable PaHostApiInfo structure describing
+ a specific host API. If the hostApi parameter is out of range or an error
+ is encountered, the function returns NULL.
+
+ The returned structure is owned by the PortAudio implementation and must not
+ be manipulated or freed. The pointer is only guaranteed to be valid between
+ calls to Pa_Initialize() and Pa_Terminate().
+*/
+const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi );
+
+
+/** Convert a static host API unique identifier, into a runtime
+ host API index.
+
+ @param type A unique host API identifier belonging to the PaHostApiTypeId
+ enumeration.
+
+ @return A valid PaHostApiIndex ranging from 0 to (Pa_CountHostApis()-1), or
+ -1 if the host API specified by the type parameter is not available.
+
+ @see PaHostApiTypeId
+*/
+PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type );
+
+
+/** Convert a host-API-specific device index to standard PortAudio device index.
+ This function may be used in conjunction with the deviceCount field of
+ PaHostApiInfo to enumerate all devices for the specified host API.
+
+ @param hostApi A valid host API index ranging from 0 to (Pa_CountHostApis()-1)
+
+ @param hostApiDeviceIndex A valid per-host device index in the range
+ 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1)
+
+ @see PaHostApiInfo
+*/
+PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi,
+ int hostApiDeviceIndex );
+
+
+
+/** Structure used to return information about a host error condition.
+*/
+typedef struct PaHostErrorInfo{
+ PaHostApiTypeId hostApiType; /**< the host API which returned the error code */
+ long errorCode; /**< the error code returned */
+ const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */
+}PaHostErrorInfo;
+
+
+/** Return information about the last host error encountered. The error
+ information returned by Pa_GetLastHostErrorInfo() will never be modified
+ asyncronously by errors occurring in other PortAudio owned threads
+ (such as the thread that manages the stream callback.)
+
+ This function is provided as a last resort, primarily to enhance debugging
+ by providing clients with access to all available error information.
+
+ @return A pointer to an immutable structure constaining information about
+ the host error. The values in this structure will only be valid if a
+ PortAudio function has previously returned the paUnanticipatedHostError
+ error code.
+*/
+const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void );
+
+
+
+/* Device enumeration and capabilities */
+
+/** Retrieve the number of available devices.
+ @return The number of available devices. May return 0 if PortAudio is
+ not initialized or an error has occured.
+*/
+PaDeviceIndex Pa_CountDevices( void );
+
+
+/** Retrieve the index of the default input device. The result can be
+ used in the inputDevice parameter to Pa_OpenStream().
+
+ @return The default input device index for the defualt host API, or paNoDevice
+ if no default input device is available or an error was encountered.
+*/
+PaDeviceIndex Pa_GetDefaultInputDevice( void );
+
+
+/** Retrieve the index of the default output device. The result can be
+ used in the outputDevice parameter to Pa_OpenStream().
+
+ @return The default output device index for the defualt host API, or paNoDevice
+ if no default output device is available or an error was encountered.
+
+ @note
On the PC, the user can specify a default device by
setting an environment variable. For example, to use device #1.
-
- set PA_RECOMMENDED_OUTPUT_DEVICE=1
-
+<pre>
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+</pre>
The user should first determine the available device ids by using
the supplied application "pa_devs".
+*/
+PaDeviceIndex Pa_GetDefaultOutputDevice( void );
+
+/** The type used to represent monotonic time in seconds that can be used
+ for syncronisation. The type is used for the outTime argument to the
+ PaStreamCallback and as the result of Pa_GetStreamTime().
+
+ @see PaStreamCallback, Pa_GetStreamTime
*/
+typedef double PaTime;
-PaDeviceID Pa_GetDefaultInputDeviceID( void );
-PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+/** A type used to specify one or more sample formats. They indicate
+ the formats used to pass sound data between the stream callback and the
+ stream. Each device has one or more "native" formats which may be used when
+ optimum efficiency or control over conversion is required.
+ Formats marked "always available" are supported (emulated) by all
+ PortAudio implementations.
-/*
- Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
- for the device specified.
- If the device parameter is out of range the function returns NULL.
+ The floating point representation (paFloat32) uses +1.0 and -1.0 as the
+ maximum and minimum respectively.
- PortAudio manages the memory referenced by the returned pointer, the client
- must not manipulate or free the memory. The pointer is only guaranteed to be
- valid between calls to Pa_Initialize() and Pa_Terminate().
+ paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
+
+ The paNonInterleaved flag indicates that a multichannel buffer is passed
+ as a set of non-interleaved pointers.
+ @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo
+ @see paFloat32, paInt16, paInt32, paInt24, paInt8
+ @see paUInt8, paCustomFormat, paNonInterleaved
*/
+typedef unsigned long PaSampleFormat;
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID device );
-/*
- PaTimestamp is used to represent a continuous sample clock with arbitrary
- start time that can be used for syncronization. The type is used for the
- outTime argument to the PortAudioCallback and as the result of Pa_StreamTime()
+#define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */
+#define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */
+#define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */
+#define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */
+#define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */
+#define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */
+#define paCustomFormat ((PaSampleFormat) 0x00010000)/**< @see PaSampleFormat */
+
+#define paNonInterleaved ((PaSampleFormat) 0x80000000)
+/** A structure providing information and capabilities of PortAudio devices.
+ Devices may support input, output or both input and output.
*/
+typedef struct PaDeviceInfo
+{
+ int structVersion; /* this is struct version 2 */
+ const char *name;
+ PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/
+
+ int maxInputChannels;
+ int maxOutputChannels;
-typedef double PaTimestamp;
+ /* Default latency values for interactive performance. */
+ PaTime defaultLowInputLatency;
+ PaTime defaultLowOutputLatency;
+ /* Default latency values for robust non-interactive applications (eg. playing sound files). */
+ PaTime defaultHighInputLatency;
+ PaTime defaultHighOutputLatency;
-/*
- PortAudioCallback is implemented by PortAudio clients.
-
- inputBuffer and outputBuffer are arrays of interleaved samples,
- the format, packing and number of channels used by the buffers are
- determined by parameters to Pa_OpenStream() (see below).
-
- framesPerBuffer is the number of sample frames to be processed by the callback.
-
- outTime is the time in samples when the buffer(s) processed by
- this callback will begin being played at the audio output.
- See also Pa_StreamTime()
-
- userData is the value of a user supplied pointer passed to Pa_OpenStream()
- intended for storing synthesis data etc.
-
- return value:
- The callback can return a non-zero value to stop the stream. This may be
- useful in applications such as soundfile players where a specific duration
- of output is required. However, it is not necessary to utilise this mechanism
- as StopStream() will also terminate the stream. A callback returning a
- non-zero value must fill the entire outputBuffer.
-
- NOTE: None of the other stream functions may be called from within the
- callback function except for Pa_GetCPULoad().
+ double defaultSampleRate;
+} PaDeviceInfo;
+
+
+/** Retrieve a pointer to a PaDeviceInfo structure containing information
+ about the specified device.
+ @return A pointer to an immutable PaDeviceInfo structure. If the device
+ parameter is out of range the function returns NULL.
+
+ @param device A valid device index in the range 0 to (Pa_CountDevices()-1)
+ @note PortAudio manages the memory referenced by the returned pointer,
+ the client must not manipulate or free the memory. The pointer is only
+ guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate().
+
+ @see PaDeviceInfo, PaDeviceIndex
*/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device );
-typedef int (PortAudioCallback)(
- void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- PaTimestamp outTime, void *userData );
+/** Parameters for one direction (input or output) of a stream.
+*/
+typedef struct PaStreamParameters
+{
+ /** A valid device index in the range 0 to (Pa_CountDevices()-1)
+ specifying the device to be used or the special constant
+ paUseHostApiSpecificDeviceSpecification which indicates that the actual
+ device(s) to use are specified in hostApiSpecificStreamInfo.
+ This field must not be set to paNoDevice.
+ */
+ PaDeviceIndex device;
+
+ /** The number of channels of sound to be delivered to the
+ stream callback or accessed by Pa_ReadStream() or Pa_WriteStream().
+ It can range from 1 to the value of maxInputChannels in the
+ PaDeviceInfo record for the device specified by the device parameter.
+ */
+ int channelCount;
+
+ /** The sample format of the buffer provided to the stream callback,
+ a_ReadStream() or Pa_WriteStream(). It may be any of the formats described
+ by the PaSampleFormat enumeration.
+ FIXME: wrt below, what are we guaranteeing these days, if anything?
+ PortAudio guarantees support for
+ the device's native formats (nativeSampleFormats in the device info record)
+ and additionally 16 and 32 bit integer and 32 bit floating point formats.
+ Support for other formats is implementation defined.
+ */
+ PaSampleFormat sampleFormat;
+
+ /** The desired latency in seconds. Where practical, implementations should
+ 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.
+ Actual latency values for an open stream may be retrieved using the
+ inputLatency and outputLatency fields of the PaStreamInfo structure
+ returned by Pa_GetStreamInfo().
+ @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo
+ */
+ PaTime suggestedLatency;
+
+ /** An optional pointer to a host api specific data structure
+ containing additional information for device setup and/or stream processing.
+ hostApiSpecificStreamInfo is never required for correct operation.
+ If not used it should be set to paNullHostApiSpecificStreamInfo (aka NULL)
+ FIXME: redocument this based on new changes:
+ If hostApiSpecificStreamInfo is supplied, it's
+ size and hostApi fields must be compatible with the input devices host api.
+ */
+ void *hostApiSpecificStreamInfo;
+
+} PaStreamParameters;
+
+
+/** Return code for Pa_IsFormatSupported indicating success. */
+#define paFormatIsSupported (0)
+
+/** Determine whether it would be possible to open a stream with the specified
+ parameters.
+
+ @param inputParameters A structure that describes the input parameters used to
+ open a stream. The suggestedLatency field is ignored. See PaStreamParameters
+ for a description of these parameters. inputParameters must be NULL for
+ output-only streams.
+
+ @param outputParameters A structure that describes the output parameters used
+ to open a stream. The suggestedLatency field is ignored. See PaStreamParameters
+ for a description of these parameters. outputParameters must be NULL for
+ input-only streams.
+
+ @param sampleRate The required sampleRate. For full-duplex streams it is the
+ sample rate for both input and output
-/*
- Stream flags
-
- These flags may be supplied (ored together) in the streamFlags argument to
- the Pa_OpenStream() function.
+ @return Returns 0 if the format is supported, and an error code indicating why
+ the format is not supported otherwise. The constant paFormatIsSupported is
+ provided to compare with the return value for success.
+ @see paFormatIsSupported, PaStreamParameters
*/
+PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate );
-#define paNoFlag (0)
-#define paClipOff (1<<0) /* disable default clipping of out of range samples */
-#define paDitherOff (1<<1) /* disable default dithering */
-#define paPlatformSpecificFlags (0x00010000)
-typedef unsigned long PaStreamFlags;
-/*
- A single PortAudioStream provides multiple channels of real-time
- input and output audio streaming to a client application.
- Pointers to PortAudioStream objects are passed between PortAudio functions.
+
+/* Streaming types and functions */
+
+
+/**
+ A single PaStream can provide multiple channels of real-time
+ streaming audio input and output to a client application. A stream
+ provides access to audio hardware represented by one or more
+ PaDevices. Depending on the underlying Host API, it may be possible
+ to open multiple streams using the same device, however this behavior
+ is implementation defined. Portable applications should assume that
+ a PaDevice may be simultaneously used by at most one PaStream.
+
+ Pointers to PaStream objects are passed between PortAudio functions that
+ operate on streams.
+
+ @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream,
+ Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive,
+ Pa_GetStreamTime, Pa_GetStreamCpuLoad
+
*/
+typedef void PaStream;
-typedef void PortAudioStream;
-#define PaStream PortAudioStream
-/*
- Pa_OpenStream() opens a stream for either input, output or both.
-
- stream is the address of a PortAudioStream pointer which will receive
+/** Can be passed as the framesPerBuffer parameter to Pa_OpenStream()
+ or Pa_OpenDefaultStream() to indicate that the stream callback will
+ accept buffers of any size.
+*/
+#define paFramesPerBufferUnspecified (0)
+
+
+/** Flags used to control the behavior of a stream. They are passed as
+ parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be
+ ORed together.
+
+ @see Pa_OpenStream, Pa_OpenDefaultStream
+ @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput,
+ paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags
+*/
+typedef unsigned long PaStreamFlags;
+
+/** @see PaStreamFlags */
+#define paNoFlag ((PaStreamFlags) 0)
+
+/** Disable default clipping of out of range samples.
+ @see PaStreamFlags
+*/
+#define paClipOff ((PaStreamFlags) 0x00000001)
+
+/** Disable default dithering.
+ @see PaStreamFlags
+*/
+#define paDitherOff ((PaStreamFlags) 0x00000002)
+
+/** A full duplex stream will not discard overflowed input samples without
+ calling the stream callback, this flag is ignored for blocking read/write
+ streams.
+ @see PaStreamFlags
+*/
+#define paNeverDropInput ((PaStreamFlags) 0x00000004)
+
+/** Call the stream callback to fill initial output buffers, rather than the
+ default behavior of priming the buffers with zeros (silence). This flag has
+ no effect for input-only and blocking read/write streams.
+ @see PaStreamFlags
+*/
+#define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008)
+
+/** A mask specifying the platform specific bits.
+ @see PaStreamFlags
+*/
+#define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000)
+
+/**
+ Timing information for the buffers passed to the stream callback.
+*/
+typedef struct PaStreamCallbackTimeInfo{
+ PaTime inputBufferAdcTime;
+ PaTime currentTime;
+ PaTime outputBufferDacTime;
+} PaStreamCallbackTimeInfo;
+
+
+/**
+ Flag bit constants for the statusFlags to PaStreamCallback.
+
+ @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow,
+ paPrimingOutput
+*/
+typedef unsigned long PaStreamCallbackFlags;
+
+/** Input data is all zeros because no real data is available.
+ @see PaStreamCallbackFlags
+*/
+#define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001)
+
+/** Input data was discarded by PortAudio
+ @see PaStreamCallbackFlags
+*/
+#define paInputOverflow ((PaStreamCallbackFlags) 0x00000002)
+
+/** Output data was inserted by PortAudio because the stream callback is using
+ too much CPU
+ @see PaStreamCallbackFlags
+*/
+#define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004)
+
+/** Output data will be discarded because no room is available.
+ @see PaStreamCallbackFlags
+*/
+#define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008)
+
+/** Some of all of the output data will be used to prime the stream, input
+ data may be zero.
+ @see PaStreamCallbackFlags
+*/
+#define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010)
+
+/**
+ Allowable return values for the PaStreamCallback.
+ @see PaStreamCallback
+*/
+typedef enum PaStreamCallbackResult
+{
+ paContinue=0,
+ paComplete=1,
+ paAbort=2
+} PaStreamCallbackResult;
+
+
+/**
+ Functions of type PaStreamCallback are implemented by PortAudio clients.
+ They consume, process or generate audio in response to requests from an
+ active PortAudio stream.
+
+ @param input and @param output are arrays of interleaved samples,
+ the format, packing and number of channels used by the buffers are
+ determined by parameters to Pa_OpenStream().
+
+ @param frameCount The number of sample frames to be processed by
+ the stream callback.
+
+ @param timeInfo The time in seconds when the first sample of the input
+ buffer was received at the audio input, the time in seconds when the first
+ sample of the output buffer will begin being played at the audio output, and
+ the time in seconds when the stream callback was called.
+ See also Pa_GetStreamTime()
+
+ @param statusFlags Flags indicating whether input and/or output buffers
+ have been inserted or will be dropped to overcome underflow or overflow
+ conditions.
+
+ @param userData The value of a user supplied pointer passed to
+ Pa_OpenStream() intended for storing synthesis data etc.
+
+ @return
+ The stream callback should return one of the values in the
+ PaStreamCallbackResult enumeration. To ensure that the callback is continues
+ to be called, it should return paContinue (0). Either paComplete or paAbort
+ can be returned to finish stream processing, after either of these values is
+ returned the callback will not be called again. If paAbort is returned the
+ stream will finish as soon as possible. If paComplete is returned, the stream
+ will continue until all buffers generated by the callback have been played.
+ This may be useful in applications such as soundfile players where a specific
+ duration of output is required. However, it is not necessary to utilise this
+ mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also
+ be used to stop the stream. The callback must always fill the entire output
+ buffer irrespective of its return value.
+
+ @see Pa_OpenStream, Pa_OpenDefaultStream
+
+ @note With the exception of Pa_GetStreamCpuLoad() it is not permissable to call
+ PortAudio API functions from within the stream callback.
+*/
+typedef int PaStreamCallback(
+ void *input, void *output,
+ unsigned long frameCount,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData );
+
+
+/** Opens a stream for either input, output or both.
+
+ @param stream The address of a PaStream pointer which will receive
a pointer to the newly opened stream.
+
+ @param inputParameters A structure that describes the input parameters used by
+ the opened stream. See PaStreamParameters for a description of these parameters.
+ inputParameters must be NULL for output-only streams.
+
+ @param outputParameters A structure that describes the output parameters used by
+ the opened stream. See PaStreamParameters for a description of these parameters.
+ outputParameters must be NULL for input-only streams.
- inputDevice is the id of the device used for input (see PaDeviceID above.)
- inputDevice may be paNoDevice to indicate that an input device is not required.
-
- numInputChannels is the number of channels of sound to be delivered to the
- callback. It can range from 1 to the value of maxInputChannels in the
- PaDeviceInfo record for the device specified by the inputDevice parameter.
- If inputDevice is paNoDevice numInputChannels is ignored.
-
- inputSampleFormat is the sample format of inputBuffer provided to the callback
- function. inputSampleFormat may be any of the formats described by the
- PaSampleFormat enumeration (see above). PortAudio guarantees support for
- the device's native formats (nativeSampleFormats in the device info record)
- and additionally 16 and 32 bit integer and 32 bit floating point formats.
- Support for other formats is implementation defined.
-
- inputDriverInfo is a pointer to an optional driver specific data structure
- containing additional information for device setup or stream processing.
- inputDriverInfo is never required for correct operation. If not used
- inputDriverInfo should be NULL.
-
- outputDevice is the id of the device used for output (see PaDeviceID above.)
- outputDevice may be paNoDevice to indicate that an output device is not required.
-
- numOutputChannels is the number of channels of sound to be supplied by the
- callback. See the definition of numInputChannels above for more details.
-
- outputSampleFormat is the sample format of the outputBuffer filled by the
- callback function. See the definition of inputSampleFormat above for more
- details.
-
- outputDriverInfo is a pointer to an optional driver specific data structure
- containing additional information for device setup or stream processing.
- outputDriverInfo is never required for correct operation. If not used
- outputDriverInfo should be NULL.
-
- sampleRate is the desired sampleRate. For full-duplex streams it is the
+ @param sampleRate The desired sampleRate. For full-duplex streams it is the
sample rate for both input and output
+
+ @param framesPerBuffer The number of frames passed to the stream callback
+ function, or the preferred block granularity for a blocking read/write stream.
+ The special value paFramesPerBufferUnspecified (0) may be used to request that
+ the stream callback will recieve an optimal (and possibly varying) number of
+ frames based on host requirements and the requested latency settings.
+ Note: With some host APIs, the use of non-zero framesPerBuffer for a callback
+ stream may introduce an additional layer of buffering which could introduce
+ additional latency. PortAudio guarantees that the additional latency
+ will be kept to the theoretical minimum however, it is strongly recommended
+ that a non-zero framesPerBuffer value only be used when your algorithm
+ requires a fixed number of frames per stream callback.
- framesPerBuffer is the length in sample frames of all internal sample buffers
- used for communication with platform specific audio routines. Wherever
- possible this corresponds to the framesPerBuffer parameter passed to the
- callback function.
-
- numberOfBuffers is the number of buffers used for multibuffered communication
- with the platform specific audio routines. If you pass zero, then an optimum
- value will be chosen for you internally. This parameter is provided only
- as a guide - and does not imply that an implementation must use multibuffered
- i/o when reliable double buffering is available (such as SndPlayDoubleBuffer()
- on the Macintosh.)
-
- streamFlags may contain a combination of flags ORed together.
- These flags modify the behaviour of the streaming process. Some flags may only
- be relevant to certain buffer formats.
-
- callback is a pointer to a client supplied function that is responsible
- for processing and filling input and output buffers (see above for details.)
-
- userData is a client supplied pointer which is passed to the callback
+ @param streamFlags Flags which modify the behaviour of the streaming process.
+ This parameter may contain a combination of flags ORed together. Some flags may
+ only be relevant to certain buffer formats.
+
+ @param streamCallback A pointer to a client supplied function that is responsible
+ for processing and filling input and output buffers. If this parameter is NULL
+ the stream will be opened in 'blocking read/write' mode. In blocking mode,
+ the client can receive sample data using Pa_ReadStream and write sample data
+ using Pa_WriteStream, the number of samples that may be read or written
+ without blocking is returned by Pa_GetStreamReadAvailable and
+ Pa_GetStreamWriteAvailable respectively.
+
+ @param userData A client supplied pointer which is passed to the stream callback
function. It could for example, contain a pointer to instance data necessary
for processing the audio buffers.
-
- return value:
- Upon success Pa_OpenStream() returns PaNoError and places a pointer to a
- valid PortAudioStream in the stream argument. The stream is inactive (stopped).
- If a call to Pa_OpenStream() fails a non-zero error code is returned (see
- PaError above) and the value of stream is invalid.
-
+
+ @return
+ Upon success Pa_OpenStream() returns paNoError and places a pointer to a
+ valid PaStream in the stream argument. The stream is inactive (stopped).
+ If a call to Pa_OpenStream() fails, a non-zero error code is returned (see
+ PaError for possible error codes) and the value of stream is invalid.
+
+ @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream,
+ Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable
*/
-
-PaError Pa_OpenStream( PortAudioStream** stream,
- PaDeviceID inputDevice,
- int numInputChannels,
- PaSampleFormat inputSampleFormat,
- void *inputDriverInfo,
- PaDeviceID outputDevice,
- int numOutputChannels,
- PaSampleFormat outputSampleFormat,
- void *outputDriverInfo,
+PaError Pa_OpenStream( PaStream** stream,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
double sampleRate,
unsigned long framesPerBuffer,
- unsigned long numberOfBuffers,
PaStreamFlags streamFlags,
- PortAudioCallback *callback,
+ PaStreamCallback *streamCallback,
void *userData );
-/*
- Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that opens
- the default input and/or output devices. Most parameters have identical meaning
- to their Pa_OpenStream() counterparts, with the following exceptions:
+/** A simplified version of Pa_OpenStream() that opens the default input
+ and/or output devices.
+
+ @param stream The address of a PaStream pointer which will receive
+ a pointer to the newly opened stream.
- If either numInputChannels or numOutputChannels is 0 the respective device
- is not opened. This has the same effect as passing paNoDevice in the device
- arguments to Pa_OpenStream().
+ @param numInputChannels The number of channels of sound that will be supplied
+ to the stream callback or returned by Pa_ReadStream. It can range from 1 to
+ the value of maxInputChannels in the PaDeviceInfo record for the default input
+ device. If 0 the stream is opened as an output-only stream.
+
+ @param numOutputChannels The number of channels of sound to be delivered to the
+ stream callback or passed to Pa_WriteStream. It can range from 1 to the value
+ of maxOutputChannels in the PaDeviceInfo record for the default output dvice.
+ If 0 the stream is opened as an output-only stream.
+
+ @param sampleFormat The sample format of both the input and output buffers
+ provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream.
+ sampleFormat may be any of the formats described by the PaSampleFormat enumeration
+ (see above).
+ FIXME: the following may need to be rewritten - PortAudio guarantees support for
+ the device's native formats (nativeSampleFormats in the device info record)
+ and additionally 16 and 32 bit integer and 32 bit float
- sampleFormat applies to both the input and output buffers.
+ @param sampleRate Same as Pa_OpenStream parameter of the same name.
+ @param framesPerBuffer Same as Pa_OpenStream parameter of the same name.
+ @param streamCallback Same as Pa_OpenStream parameter of the same name.
+ @param userData Same as Pa_OpenStream parameter of the same name.
-*/
+ @return As for Pa_OpenStream
-PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ @see Pa_OpenStream, PaStreamCallback
+*/
+PaError Pa_OpenDefaultStream( PaStream** stream,
int numInputChannels,
int numOutputChannels,
PaSampleFormat sampleFormat,
double sampleRate,
unsigned long framesPerBuffer,
- unsigned long numberOfBuffers,
- PortAudioCallback *callback,
+ PaStreamCallback *streamCallback,
void *userData );
-/*
- Pa_CloseStream() closes an audio stream, flushing any pending buffers.
+/** Closes an audio stream. If the audio stream is active it
+ discards any pending buffers as if Pa_AbortStream() had been called.
+*/
+PaError Pa_CloseStream( PaStream *stream );
+
+
+/** Functions of type PaStreamFinishedCallback are implemented by PortAudio
+ clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback
+ function. Once registered they are called when the stream becomes inactive
+ (ie once a call to Pa_StopStream() will not block).
+ A stream will become inactive after the stream callback returns non-zero,
+ or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio
+ output, if the stream callback returns paComplete, or Pa_StopStream is called,
+ the stream finished callback will not be called until all generated sample data
+ has been played.
+
+ @param userData The userData parameter supplied to Pa_OpenStream()
+
+ @see Pa_SetStreamFinishedCallback
*/
+typedef void PaStreamFinishedCallback( void *userData );
-PaError Pa_CloseStream( PortAudioStream* );
-/*
- Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
- Pa_StopStream() waits until all pending audio buffers have been played.
- Pa_AbortStream() stops playing immediately without waiting for pending
+/** Register a stream finished callback function which will be called when the
+ stream becomes inactive. See the description of PaStreamFinishedCallback for
+ further details about when the callback will be called.
+
+ @param stream a pointer to a PaStream that is in the stopped state - if the
+ stream is not stopped, the stream's finished callback will remain unchanged
+ and an error code will be returned.
+
+ @param streamFinishedCallback a pointer to a function with the same signature
+ as PaStreamFinishedCallback, that will be called when the stream becomes
+ inactive. Passing NULL for this parameter will un-register a previously
+ registered stream finished callback function.
+
+ @return on success returns paNoError, otherwise an error code indicating the cause
+ of the error.
+
+ @see PaStreamFinishedCallback
+*/
+PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback );
+
+
+/** Commences audio processing.
+*/
+PaError Pa_StartStream( PaStream *stream );
+
+
+/** Terminates audio processing. It waits until all pending
+ audio buffers have been played before it returns.
+*/
+PaError Pa_StopStream( PaStream *stream );
+
+
+/** Terminates audio processing immediately without waiting for pending
buffers to complete.
-
*/
+PaError Pa_AbortStream( PaStream *stream );
-PaError Pa_StartStream( PortAudioStream *stream );
-PaError Pa_StopStream( PortAudioStream *stream );
+/** @return Returns one (1) when the stream is stopped, zero (0) when
+ the stream is running, or a negative error number if the stream
+ is invalid. A stream is considered to be stopped prior to a successful
+ call to Pa_StartStream and after a successful call to Pa_StopStream
+ or Pa_AbortStream. If a stream callback returns a value other than
+ paContinue the stream is NOT considered to be stopped.
+*/
+PaError Pa_IsStreamStopped( PaStream *stream );
-PaError Pa_AbortStream( PortAudioStream *stream );
-/*
- Pa_StreamActive() returns one (1) when the stream is active (ie playing
+/** @return Returns one (1) when the stream is active (ie playing
or recording audio), zero (0) when not playing, or a negative error number
if the stream is invalid.
- The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
- but may also become inactive if the callback returns a non-zero value.
- In the latter case, the stream is considered inactive after the last
- buffer has finished playing.
-
+
+ A stream is active after a successful call to Pa_StartStream(), until it
+ becomes inactive either as a result of a call to Pa_StopStream() or
+ Pa_AbortStream(), or as a result of a return value other than paContinue from
+ the stream callback. In the latter case, the stream is considered inactive after
+ the last buffer has finished playing.
+
+ @see Pa_StopStream, Pa_AbortStream
*/
+PaError Pa_IsStreamActive( PaStream *stream );
-PaError Pa_StreamActive( PortAudioStream *stream );
-/*
- Pa_StreamTime() returns the current output time in samples for the stream.
- This time may be used as a time reference (for example synchronizing audio to
- MIDI).
-
+
+/** A structure containing unchanging information about an open stream.
+ @see Pa_GetStreamInfo
*/
-PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+typedef struct PaStreamInfo
+{
+ /** this is struct version 1 */
+ int structVersion;
-/*
- Pa_GetCPULoad() returns the CPU Load for the stream.
- The "CPU Load" is a fraction of total CPU time consumed by the stream's
+ /** The input latency of the stream in seconds. This value provides the most
+ accurate estimate of input latency available to the implementation. It may
+ differ significantly from the suggestedLatency value passed to Pa_OpenStream().
+ The value of this field will be zero (0.) for output-only streams.
+ @see PaTime
+ */
+ PaTime inputLatency;
+
+ /** The output latency of the stream in seconds. This value provides the most
+ accurate estimate of output latency available to the implementation. It may
+ differ significantly from the suggestedLatency value passed to Pa_OpenStream().
+ The value of this field will be zero (0.) for input-only streams.
+ @see PaTime
+ */
+ PaTime outputLatency;
+
+ /** The sample rate of the stream in Hertz (samples per second). In cases
+ where the hardware sample rate is inaccurate and PortAudio is aware of it,
+ the value of this field may be different from the sampleRate parameter
+ passed to Pa_OpenStream(). If information about the actual hardware sample
+ rate is not available, this field will have the same value as the sampleRate
+ parameter passed to Pa_OpenStream().
+ */
+ double sampleRate;
+
+} PaStreamInfo;
+
+
+/** Retrieve a pointer to a PaStreamInfo structure containing information
+ about the specified stream.
+ @return A pointer to an immutable PaStreamInfo structure. If the stream
+ parameter invalid, or an error is encountered, the function returns NULL.
+
+ @param stream A pointer to an open stream previously created with Pa_OpenStream.
+
+ @note PortAudio manages the memory referenced by the returned pointer,
+ the client must not manipulate or free the memory. The pointer is only
+ guaranteed to be valid until the specified stream is closed.
+
+ @see PaStreamInfo
+*/
+const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream );
+
+
+/**
+ @return The current time (in seconds) according to the same clock used to
+ generate buffer timestamps for stream.
+ This time may be used for syncronising other events to the audio stream,
+ for example synchronizing audio to MIDI.
+
+ @see PaTime, PaStreamCallback
+*/
+PaTime Pa_GetStreamTime( PaStream *stream );
+
+
+/** Retrieve CPU usage information for the specified stream.
+ The "CPU Load" is a fraction of total CPU time consumed by a callback stream's
audio processing routines including, but not limited to the client supplied
- callback.
- A value of 0.5 would imply that PortAudio and the sound generating
- callback was consuming roughly 50% of the available CPU time.
- This function may be called from the callback function or the application.
-
+ stream callback. This function does not work with blocking read/write streams.
+
+ This function may be called from the stream callback function or the
+ application.
+
+ @return
+ A floating point value, typically between 0.0 and 1.0, where 1.0 indicates
+ that the stream callback is consuming the maximum number of CPU cycles possible
+ to maintain real-time operation. A value of 0.5 would imply that PortAudio and
+ the stream callback was consuming roughly 50% of the available CPU time. The
+ return value may exceed 1.0. A value of 0.0 will always be returned for a
+ blocking read/write stream.
*/
+double Pa_GetStreamCpuLoad( PaStream* stream );
-double Pa_GetCPULoad( PortAudioStream* stream );
-/*
- Pa_GetMinNumBuffers() returns the minimum number of buffers required by
- the current host based on minimum latency.
- On the PC, for the DirectSound implementation, latency can be optionally set
- by user by setting an environment variable.
- For example, to set latency to 200 msec, put:
-
- set PA_MIN_LATENCY_MSEC=200
-
- in the AUTOEXEC.BAT file and reboot.
- If the environment variable is not set, then the latency will be determined
- based on the OS. Windows NT has higher latency than Win95.
-
+/** Read samples from an input stream. The function doesn't return until
+ the entire buffer has been filled - this may involve waiting for the operating
+ system to supply the data.
+
+ @param buffer A pointer to a buffer of sample frames. The buffer contains
+ samples in the format specified by the inputParameters->sampleFormat field
+ used to open the stream, and the number of channels specified by
+ inputParameters->numChannels. If non-interleaved samples were requested,
+ buffer is a pointer to the first element of an array of non-interleaved
+ buffer pointers, one for each channel.
+
+ @param frames The number of frames to be read into buffer. This parameter
+ is not constrained to a specific range, however high performance applications
+ will want to match this parameter to the framesPerBuffer parameter used
+ when opening the stream.
+
+ @return On success PaNoError will be returned, or PaInputOverflowed if input
+ data was discarded by PortAudio after the previous call and before this call.
*/
+PaError Pa_ReadStream( PaStream* stream,
+ void *buffer,
+ unsigned long frames );
+
+
+/** Write samples to an output stream. This function doesn't return until the
+ entire buffer has been consumed - this may involve waiting for the operating
+ system to consume the data.
+
+ @param buffer A pointer to a buffer of sample frames. The buffer contains
+ samples in the format specified by the outputParameters->sampleFormat field
+ used to open the stream, and the number of channels specified by
+ outputParameters->numChannels. If non-interleaved samples were requested,
+ buffer is a pointer to the first element of an array of non-interleaved
+ buffer pointers, one for each channel.
+
+ @param frames The number of frames to be written from buffer. This parameter
+ is not constrained to a specific range, however high performance applications
+ will want to match this parameter to the framesPerBuffer parameter used
+ when opening the stream.
+
+ @return On success PaNoError will be returned, or paOutputUnderflowed if
+ additional output data was inserted after the previous call and before this
+ call.
+*/
+PaError Pa_WriteStream( PaStream* stream,
+ void *buffer,
+ unsigned long frames );
-int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
-/*
- Pa_Sleep() puts the caller to sleep for at least 'msec' milliseconds.
- You may sleep longer than the requested time so don't rely on this for
- accurate musical timing.
-
- Pa_Sleep() is provided as a convenience for authors of portable code (such as
- the tests and examples in the PortAudio distribution.)
-
+/** Retrieve the number of frames that can be read from the stream without
+ waiting.
+
+ @return If non-negative, the return value is the maximum number of frames
+ that can be read from the stream without blocking or busy waiting. A
+ negative value is a PaErrorCode.
*/
+signed long Pa_GetStreamReadAvailable( PaStream* stream );
-void Pa_Sleep( long msec );
-/*
- Pa_GetSampleSize() returns the size in bytes of a single sample in the
- supplied PaSampleFormat, or paSampleFormatNotSupported if the format is
- no supported.
-
+/** Retrieve the number of frames that can be written to the stream without
+ waiting.
+
+ @return If non-negative, the return value is the maximum number of frames
+ that can be written to the stream without blocking or busy waiting. A
+ negative value is a PaErrorCode.
*/
+signed long Pa_GetStreamWriteAvailable( PaStream* stream );
+
+
+/* Miscellaneous utilities */
+
+/**
+ @return The size in bytes of a single sample in the specified format,
+ or paSampleFormatNotSupported if the format is not supported.
+*/
PaError Pa_GetSampleSize( PaSampleFormat format );
+/** Puts the caller to sleep for at least 'msec' milliseconds.
+ It may sleep longer than requested so don't rely on this for accurate
+ musical timing.
+
+ This function is provided only as a convenience for authors of portable code
+ (such as the tests and examples in the PortAudio distribution.)
+*/
+void Pa_Sleep( long msec );
+
+
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
-#endif /* PORT_AUDIO_H */
+#endif /* PORTAUDIO_H */
diff --git a/pd/portaudio/pa_dll_switch/PaDllEntry.h b/pd/portaudio/pa_dll_switch/PaDllEntry.h
new file mode 100644
index 00000000..e070054b
--- /dev/null
+++ b/pd/portaudio/pa_dll_switch/PaDllEntry.h
@@ -0,0 +1,184 @@
+
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio DLL Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+// changed by zplane.developement in order to generate a DLL
+
+#ifndef __PADLLENTRY_HEADER_INCLUDED__
+
+#define __PADLLENTRY_HEADER_INCLUDED__
+
+typedef int PaError;
+typedef enum {
+ paNoError = 0,
+
+ paHostError = -10000,
+ paInvalidChannelCount,
+ paInvalidSampleRate,
+ paInvalidDeviceId,
+ paInvalidFlag,
+ paSampleFormatNotSupported,
+ paBadIODeviceCombination,
+ paInsufficientMemory,
+ paBufferTooBig,
+ paBufferTooSmall,
+ paNullCallback,
+ paBadStreamPtr,
+ paTimedOut,
+ paInternalError
+} PaErrorNum;
+
+typedef unsigned long PaSampleFormat;
+#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
+#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
+#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
+#define paInt24 ((PaSampleFormat) (1<<3))
+#define paPackedInt24 ((PaSampleFormat) (1<<4))
+#define paInt8 ((PaSampleFormat) (1<<5))
+#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */
+#define paCustomFormat ((PaSampleFormat) (1<<16))
+
+
+typedef int PaDeviceID;
+#define paNoDevice -1
+
+typedef struct
+{
+ int structVersion;
+ const char *name;
+ int maxInputChannels;
+ int maxOutputChannels;
+ /* Number of discrete rates, or -1 if range supported. */
+ int numSampleRates;
+ /* Array of supported sample rates, or {min,max} if range supported. */
+ const double *sampleRates;
+ PaSampleFormat nativeSampleFormats;
+}
+PaDeviceInfo;
+
+
+typedef double PaTimestamp;
+
+
+typedef int (PortAudioCallback)(
+ void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+
+#define paNoFlag (0)
+#define paClipOff (1<<0) /* disable default clipping of out of range samples */
+#define paDitherOff (1<<1) /* disable default dithering */
+#define paPlatformSpecificFlags (0x00010000)
+typedef unsigned long PaStreamFlags;
+
+typedef void PortAudioStream;
+#define PaStream PortAudioStream
+
+extern PaError (__cdecl* Pa_Initialize)( void );
+
+
+
+extern PaError (__cdecl* Pa_Terminate)( void );
+
+
+extern long (__cdecl* Pa_GetHostError)( void );
+
+
+extern const char* (__cdecl* Pa_GetErrorText)( PaError );
+
+
+
+extern int (__cdecl* Pa_CountDevices)(void);
+
+extern PaDeviceID (__cdecl* Pa_GetDefaultInputDeviceID)( void );
+
+extern PaDeviceID (__cdecl* Pa_GetDefaultOutputDeviceID)( void );
+
+
+extern const PaDeviceInfo* (__cdecl* Pa_GetDeviceInfo)( PaDeviceID);
+
+
+
+extern PaError (__cdecl* Pa_OpenStream)(
+ PortAudioStream ** ,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ double ,
+ unsigned long ,
+ unsigned long ,
+ unsigned long ,
+ PortAudioCallback *,
+ void * );
+
+
+
+extern PaError (__cdecl* Pa_OpenDefaultStream)( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+extern PaError (__cdecl* Pa_CloseStream)( PortAudioStream* );
+
+
+extern PaError (__cdecl* Pa_StartStream)( PortAudioStream *stream );
+
+extern PaError (__cdecl* Pa_StopStream)( PortAudioStream *stream );
+
+extern PaError (__cdecl* Pa_AbortStream)( PortAudioStream *stream );
+
+extern PaError (__cdecl* Pa_StreamActive)( PortAudioStream *stream );
+
+extern PaTimestamp (__cdecl* Pa_StreamTime)( PortAudioStream *stream );
+
+extern double (__cdecl* Pa_GetCPULoad)( PortAudioStream* stream );
+
+extern int (__cdecl* Pa_GetMinNumBuffers)( int framesPerBuffer, double sampleRate );
+
+extern void (__cdecl* Pa_Sleep)( long msec );
+
+extern PaError (__cdecl* Pa_GetSampleSize)( PaSampleFormat format );
+
+#endif // __PADLLENTRY_HEADER_INCLUDED__
+
diff --git a/pd/portaudio/pa_dll_switch/letter_from_tim_010817.txt b/pd/portaudio/pa_dll_switch/letter_from_tim_010817.txt
new file mode 100644
index 00000000..a535cd1d
--- /dev/null
+++ b/pd/portaudio/pa_dll_switch/letter_from_tim_010817.txt
Binary files differ
diff --git a/pd/portaudio/pa_dll_switch/loadPA_DLL.cpp b/pd/portaudio/pa_dll_switch/loadPA_DLL.cpp
new file mode 100644
index 00000000..043eda87
--- /dev/null
+++ b/pd/portaudio/pa_dll_switch/loadPA_DLL.cpp
@@ -0,0 +1,203 @@
+//////////////////////////////////////////////////////////////////////////
+
+
+HINSTANCE pPaDll;
+
+/*
+ the function pointers to the PortAudio DLLs
+*/
+
+PaError (__cdecl* Pa_Initialize)( void );
+
+
+
+PaError (__cdecl* Pa_Terminate)( void );
+
+
+long (__cdecl* Pa_GetHostError)( void );
+
+
+const char* (__cdecl* Pa_GetErrorText)( PaError );
+
+
+int (__cdecl* Pa_CountDevices)(void);
+
+PaDeviceID (__cdecl* Pa_GetDefaultInputDeviceID)( void );
+
+PaDeviceID (__cdecl* Pa_GetDefaultOutputDeviceID)( void );
+
+
+const PaDeviceInfo* (__cdecl* Pa_GetDeviceInfo)( PaDeviceID);
+
+
+
+PaError (__cdecl* Pa_OpenStream)(
+ PortAudioStream ** ,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ double ,
+ unsigned long ,
+ unsigned long ,
+ unsigned long ,
+ PortAudioCallback *,
+ void * );
+
+
+
+PaError (__cdecl* Pa_OpenDefaultStream)( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+PaError (__cdecl* Pa_CloseStream)( PortAudioStream* );
+
+
+PaError (__cdecl* Pa_StartStream)( PortAudioStream *stream );
+
+PaError (__cdecl* Pa_StopStream)( PortAudioStream *stream );
+
+PaError (__cdecl* Pa_AbortStream)( PortAudioStream *stream );
+
+PaError (__cdecl* Pa_StreamActive)( PortAudioStream *stream );
+
+PaTimestamp (__cdecl* Pa_StreamTime)( PortAudioStream *stream );
+
+double (__cdecl* Pa_GetCPULoad)( PortAudioStream* stream );
+
+int (__cdecl* Pa_GetMinNumBuffers)( int framesPerBuffer, double sampleRate );
+
+void (__cdecl* Pa_Sleep)( long msec );
+
+PaError (__cdecl* Pa_GetSampleSize)( PaSampleFormat format );
+
+
+//////////////////////////////////////////////////////////////////////////
+
+...
+
+ZERROR AudioEngine::DirectXSupport(ZBOOL bSupDX)
+{
+ if (bSupDX)
+ if (CheckForDirectXSupport())
+ bSupportDirectX = _TRUE;
+ else
+ return _NO_SOUND;
+ else
+ bSupportDirectX = _FALSE;
+ return _NO_ERROR;
+}
+
+
+
+ZBOOL AudioEngine::CheckForDirectXSupport()
+{
+ HMODULE pTestDXLib;
+ FARPROC pFunctionality;
+
+ pTestDXLib=LoadLibrary("DSOUND");
+ if (pTestDXLib!=NULL) // check if there is a DirectSound
+ {
+ pFunctionality = GetProcAddress(pTestDXLib, (char*) 7);
+ if (pFunctionality!=NULL)
+ {
+ FreeLibrary(pTestDXLib);
+ return _TRUE;
+ }
+ else
+ {
+ FreeLibrary(pTestDXLib);
+ return _FALSE;
+ }
+ }
+ else
+ return _FALSE;
+}
+
+
+ZERROR AudioEngine::LoadPALib()
+{
+#ifdef _DEBUG
+ if (bSupportDirectX)
+ pPaDll = LoadLibrary("PA_DXD");
+ else
+ pPaDll = LoadLibrary("PA_MMED");
+#else
+ if (bSupportDirectX)
+ pPaDll = LoadLibrary("PA_DX");
+ else
+ pPaDll = LoadLibrary("PA_MME");
+#endif
+ if (pPaDll!=NULL)
+ {
+
+ Pa_Initialize = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_Initialize");
+ Pa_Terminate = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_Terminate");
+ Pa_GetHostError = (long (__cdecl* )( void )) GetProcAddress(pPaDll,"Pa_GetHostError");
+ Pa_GetErrorText = (const char* (__cdecl* )( PaError )) GetProcAddress(pPaDll,"Pa_GetErrorText");
+ Pa_CountDevices = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_CountDevices");
+ Pa_GetDefaultInputDeviceID = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_GetDefaultInputDeviceID");
+ Pa_GetDefaultOutputDeviceID = (int (__cdecl*)(void))GetProcAddress(pPaDll,"Pa_GetDefaultOutputDeviceID");
+ Pa_GetDeviceInfo = (const PaDeviceInfo* (__cdecl* )( PaDeviceID)) GetProcAddress(pPaDll,"Pa_GetDeviceInfo");
+ Pa_OpenStream = ( PaError (__cdecl* )(
+ PortAudioStream ** ,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ PaDeviceID ,
+ int ,
+ PaSampleFormat ,
+ void *,
+ double ,
+ unsigned long ,
+ unsigned long ,
+ unsigned long ,
+ PortAudioCallback *,
+ void * )) GetProcAddress(pPaDll,"Pa_OpenStream");
+
+ Pa_OpenDefaultStream = (PaError (__cdecl* )( PortAudioStream** ,
+ int ,
+ int ,
+ PaSampleFormat ,
+ double ,
+ unsigned long ,
+ unsigned long ,
+ PortAudioCallback *,
+ void * )) GetProcAddress(pPaDll,"Pa_OpenDefaultStream");
+ Pa_CloseStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_CloseStream");
+ Pa_StartStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_StartStream");
+ Pa_StopStream = (PaError (__cdecl* )( PortAudioStream* ))GetProcAddress(pPaDll,"Pa_StopStream");
+ Pa_AbortStream = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_AbortStream");
+ Pa_StreamActive = (PaError (__cdecl* )( PortAudioStream* )) GetProcAddress(pPaDll,"Pa_StreamActive");
+ Pa_StreamTime = (PaTimestamp (__cdecl* )( PortAudioStream *))GetProcAddress(pPaDll,"Pa_StreamTime");
+ Pa_GetCPULoad = (double (__cdecl* )( PortAudioStream* ))GetProcAddress(pPaDll,"Pa_GetCPULoad");
+ Pa_GetMinNumBuffers = (int (__cdecl* )( int , double )) GetProcAddress(pPaDll,"Pa_GetMinNumBuffers");
+ Pa_Sleep = (void (__cdecl* )( long )) GetProcAddress(pPaDll,"Pa_Sleep");
+ Pa_GetSampleSize = (PaError (__cdecl* )( PaSampleFormat )) GetProcAddress(pPaDll,"Pa_GetSampleSize");
+
+ return _NO_ERROR;
+ }
+ else
+ return _DLL_NOT_FOUND;
+}
+
+ZERROR AudioEngine::UnLoadPALib()
+{
+ if (pPaDll!=NULL)
+ FreeLibrary(pPaDll);
+ return _NO_ERROR;
+}
+
+...
diff --git a/pd/portaudio/pa_dll_switch/pa_lib.c b/pd/portaudio/pa_dll_switch/pa_lib.c
new file mode 100644
index 00000000..86601592
--- /dev/null
+++ b/pd/portaudio/pa_dll_switch/pa_lib.c
@@ -0,0 +1,827 @@
+/*
+ * Portable Audio I/O Library
+ * Host Independant Layer
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* Modification History:
+ PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
+#ifdef _WIN32
+#ifndef __MWERKS__
+#include <memory.h>
+#endif /* __MWERKS__ */
+#else /* !_WIN32 */
+#include <memory.h>
+#endif /* _WIN32 */
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+/* The reason we might NOT want to validate the rate before opening the stream
+ * is because many DirectSound drivers lie about the rates they actually support.
+ */
+#define PA_VALIDATE_RATE (0) /* If true validate sample rate against driver info. */
+
+/*
+O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for conversion
+*/
+
+#ifndef FALSE
+ #define FALSE (0)
+ #define TRUE (!FALSE)
+#endif
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */
+
+static PaError Pa_KillStream( PortAudioStream *stream, int abort );
+
+/***********************************************************************/
+int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, int numRates, double frameRate )
+{
+ double err, minErr = allowableError;
+ int i, bestFit = -1;
+
+ for( i=0; i<numRates; i++ )
+ {
+ err = fabs( frameRate - rateTable[i] );
+ if( err < minErr )
+ {
+ minErr = err;
+ bestFit = i;
+ }
+ }
+ return bestFit;
+}
+
+/**************************************************************************
+** Make sure sample rate is legal and also convert to enumeration for driver.
+*/
+PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
+ double *closestFrameRatePtr )
+{
+ long bestRateIndex;
+ const PaDeviceInfo *pdi;
+ pdi = Pa_GetDeviceInfo( id );
+ if( pdi == NULL ) return paInvalidDeviceId;
+
+ if( pdi->numSampleRates == -1 )
+ {
+ /* Is it out of range? */
+ if( (requestedFrameRate < pdi->sampleRates[0]) ||
+ (requestedFrameRate > pdi->sampleRates[1]) )
+ {
+ return paInvalidSampleRate;
+ }
+
+ *closestFrameRatePtr = requestedFrameRate;
+ }
+ else
+ {
+ bestRateIndex = PaHost_FindClosestTableEntry( 1.0, pdi->sampleRates, pdi->numSampleRates, requestedFrameRate );
+ if( bestRateIndex < 0 ) return paInvalidSampleRate;
+ *closestFrameRatePtr = pdi->sampleRates[bestRateIndex];
+ }
+ return paNoError;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_OpenStream(
+ PortAudioStream** streamPtrPtr,
+ PaDeviceID inputDeviceID,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDeviceID,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ unsigned long streamFlags,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ internalPortAudioStream *past = NULL;
+ PaError result = paNoError;
+ int bitsPerInputSample;
+ int bitsPerOutputSample;
+ /* Print passed parameters. */
+ DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n",
+ streamPtrPtr, inputDeviceID, numInputChannels,
+ inputSampleFormat, inputDriverInfo ));
+ DBUG((" %d, %d, %d, %p, /* output */\n",
+ outputDeviceID, numOutputChannels,
+ outputSampleFormat, outputDriverInfo ));
+ DBUG((" %g, %d, %d, 0x%x, , %p )\n",
+ sampleRate, framesPerBuffer, numberOfBuffers,
+ streamFlags, userData ));
+
+ /* Check for parameter errors. */
+ if( (streamFlags & ~(paClipOff | paDitherOff)) != 0 ) return paInvalidFlag;
+ if( streamPtrPtr == NULL ) return paBadStreamPtr;
+ if( inputDriverInfo != NULL ) return paHostError; /* REVIEW */
+ if( outputDriverInfo != NULL ) return paHostError; /* REVIEW */
+ if( (inputDeviceID < 0) && ( outputDeviceID < 0) ) return paInvalidDeviceId;
+ if( (outputDeviceID >= Pa_CountDevices()) || (inputDeviceID >= Pa_CountDevices()) ) return paInvalidDeviceId;
+ if( (numInputChannels <= 0) && ( numOutputChannels <= 0) ) return paInvalidChannelCount;
+
+#if SUPPORT_AUDIO_CAPTURE
+ if( inputDeviceID >= 0 )
+ {
+ PaError size = Pa_GetSampleSize( inputSampleFormat );
+ if( size < 0 ) return size;
+ bitsPerInputSample = 8 * size;
+ if( (numInputChannels <= 0) ) return paInvalidChannelCount;
+ }
+#else
+ if( inputDeviceID >= 0 )
+ {
+ return paInvalidChannelCount;
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ else
+ {
+ if( numInputChannels > 0 ) return paInvalidChannelCount;
+ bitsPerInputSample = 0;
+ }
+
+ if( outputDeviceID >= 0 )
+ {
+ PaError size = Pa_GetSampleSize( outputSampleFormat );
+ if( size < 0 ) return size;
+ bitsPerOutputSample = 8 * size;
+ if( (numOutputChannels <= 0) ) return paInvalidChannelCount;
+ }
+ else
+ {
+ if( numOutputChannels > 0 ) return paInvalidChannelCount;
+ bitsPerOutputSample = 0;
+ }
+
+ if( callback == NULL ) return paNullCallback;
+
+ /* Allocate and clear stream structure. */
+ past = (internalPortAudioStream *) PaHost_AllocateFastMemory( sizeof(internalPortAudioStream) );
+ if( past == NULL ) return paInsufficientMemory;
+ memset( past, 0, sizeof(internalPortAudioStream) );
+ AddTraceMessage("Pa_OpenStream: past", (long) past );
+
+ past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */
+ past->past_FramesPerUserBuffer = framesPerBuffer;
+ past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() NMUST CHECK FOR ZERO! */
+ past->past_Callback = callback;
+ past->past_UserData = userData;
+ past->past_OutputSampleFormat = outputSampleFormat;
+ past->past_InputSampleFormat = inputSampleFormat;
+ past->past_OutputDeviceID = outputDeviceID;
+ past->past_InputDeviceID = inputDeviceID;
+ past->past_NumInputChannels = numInputChannels;
+ past->past_NumOutputChannels = numOutputChannels;
+ past->past_Flags = streamFlags;
+
+ /* Check for absurd sample rates. */
+ if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
+ {
+ result = paInvalidSampleRate;
+ goto cleanup;
+ }
+
+ /* Allocate buffers that may be used for format conversion from user to native buffers. */
+ if( numInputChannels > 0 )
+ {
+
+#if PA_VALIDATE_RATE
+ result = PaHost_ValidateSampleRate( inputDeviceID, sampleRate, &past->past_SampleRate );
+ if( result < 0 )
+ {
+ goto cleanup;
+ }
+#else
+ past->past_SampleRate = sampleRate;
+#endif
+ /* Allocate single Input buffer. */
+ past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8);
+ past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize);
+ if( past->past_InputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ past->past_InputBuffer = NULL;
+ }
+
+ /* Allocate single Output buffer. */
+ if( numOutputChannels > 0 )
+ {
+#if PA_VALIDATE_RATE
+ result = PaHost_ValidateSampleRate( outputDeviceID, sampleRate, &past->past_SampleRate );
+ if( result < 0 )
+ {
+ goto cleanup;
+ }
+#else
+ past->past_SampleRate = sampleRate;
+#endif
+ past->past_OutputBufferSize = framesPerBuffer * numOutputChannels * ((bitsPerOutputSample+7) / 8);
+ past->past_OutputBuffer = PaHost_AllocateFastMemory(past->past_OutputBufferSize);
+ if( past->past_OutputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ past->past_OutputBuffer = NULL;
+ }
+
+ result = PaHost_OpenStream( past );
+ if( result < 0 ) goto cleanup;
+
+ *streamPtrPtr = (void *) past;
+
+ return result;
+
+cleanup:
+ if( past != NULL ) Pa_CloseStream( past );
+ *streamPtrPtr = NULL;
+ return result;
+}
+
+
+/*************************************************************************/
+DLL_API PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ return Pa_OpenStream(
+ stream,
+ ((numInputChannels > 0) ? Pa_GetDefaultInputDeviceID() : paNoDevice),
+ numInputChannels, sampleFormat, NULL,
+ ((numOutputChannels > 0) ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
+ numOutputChannels, sampleFormat, NULL,
+ sampleRate, framesPerBuffer, numberOfBuffers, paNoFlag, callback, userData );
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_CloseStream( PortAudioStream* stream)
+{
+ PaError result;
+ internalPortAudioStream *past;
+
+ DBUG(("Pa_CloseStream()\n"));
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ Pa_AbortStream( past );
+ result = PaHost_CloseStream( past );
+
+ if( past->past_InputBuffer ) PaHost_FreeFastMemory( past->past_InputBuffer, past->past_InputBufferSize );
+ if( past->past_OutputBuffer ) PaHost_FreeFastMemory( past->past_OutputBuffer, past->past_OutputBufferSize );
+ PaHost_FreeFastMemory( past, sizeof(internalPortAudioStream) );
+
+ return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_StartStream( PortAudioStream *stream )
+{
+ PaError result = paHostError;
+ internalPortAudioStream *past;
+
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ past->past_FrameCount = 0.0;
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ result = PaHost_StartInput( past );
+ DBUG(("Pa_StartStream: PaHost_StartInput returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ result = PaHost_StartOutput( past );
+ DBUG(("Pa_StartStream: PaHost_StartOutput returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ result = PaHost_StartEngine( past );
+ DBUG(("Pa_StartStream: PaHost_StartEngine returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+
+ return paNoError;
+
+error:
+ return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_StopStream( PortAudioStream *stream )
+{
+ return Pa_KillStream( stream, 0 );
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_AbortStream( PortAudioStream *stream )
+{
+ return Pa_KillStream( stream, 1 );
+}
+
+/*************************************************************************/
+static PaError Pa_KillStream( PortAudioStream *stream, int abort )
+{
+ PaError result = paNoError;
+ internalPortAudioStream *past;
+
+ DBUG(("Pa_StopStream().\n"));
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ if( (past->past_NumInputChannels > 0) || (past->past_NumOutputChannels > 0) )
+ {
+ result = PaHost_StopEngine( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopEngine returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ result = PaHost_StopInput( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopInput returned = 0x%X.\n", result));
+ if( result != paNoError ) goto error;
+ }
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ result = PaHost_StopOutput( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopOutput returned = 0x%X.\n", result));
+ if( result != paNoError ) goto error;
+ }
+
+error:
+ past->past_Usage = 0;
+ past->past_IfLastExitValid = 0;
+
+ return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_StreamActive( PortAudioStream *stream )
+{
+ internalPortAudioStream *past;
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+ return PaHost_StreamActive( past );
+}
+
+/*************************************************************************/
+DLL_API const char *Pa_GetErrorText( PaError errnum )
+{
+ const char *msg;
+
+ switch(errnum)
+ {
+ case paNoError: msg = "Success"; break;
+ case paHostError: msg = "Host error."; break;
+ case paInvalidChannelCount: msg = "Invalid number of channels."; break;
+ case paInvalidSampleRate: msg = "Invalid sample rate."; break;
+ case paInvalidDeviceId: msg = "Invalid device ID."; break;
+ case paInvalidFlag: msg = "Invalid flag."; break;
+ case paSampleFormatNotSupported: msg = "Sample format not supported"; break;
+ case paBadIODeviceCombination: msg = "Illegal combination of I/O devices."; break;
+ case paInsufficientMemory: msg = "Insufficient memory."; break;
+ case paBufferTooBig: msg = "Buffer too big."; break;
+ case paBufferTooSmall: msg = "Buffer too small."; break;
+ case paNullCallback: msg = "No callback routine specified."; break;
+ case paBadStreamPtr: msg = "Invalid stream pointer."; break;
+ case paTimedOut : msg = "Wait Timed Out."; break;
+ case paInternalError: msg = "Internal PortAudio Error."; break;
+ default: msg = "Illegal error number."; break;
+ }
+ return msg;
+}
+
+/*
+ Get CPU Load as a fraction of total CPU time.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ The amount may vary depending on CPU load.
+ This function may be called from the callback function.
+*/
+DLL_API double Pa_GetCPULoad( PortAudioStream* stream)
+{
+ internalPortAudioStream *past;
+ if( stream == NULL ) return (double) paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+ return past->past_Usage;
+}
+
+/*************************************************************
+** Calculate 2 LSB dither signal with a triangular distribution.
+** Ranged properly for adding to a 32 bit integer prior to >>15.
+*/
+#define DITHER_BITS (15)
+#define DITHER_SCALE (1.0f / ((1<<DITHER_BITS)-1))
+static long Pa_TriangularDither( void )
+{
+ static unsigned long previous = 0;
+ static unsigned long randSeed1 = 22222;
+ static unsigned long randSeed2 = 5555555;
+ long current, highPass;
+ /* Generate two random numbers. */
+ randSeed1 = (randSeed1 * 196314165) + 907633515;
+ randSeed2 = (randSeed2 * 196314165) + 907633515;
+ /* Generate triangular distribution about 0. */
+ current = (((long)randSeed1)>>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS));
+ /* High pass filter to reduce audibility. */
+ highPass = current - previous;
+ previous = current;
+ return highPass;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from Int16, call user code, then convert output
+** to Int16 format for native use.
+** Assumes host native format is paInt16.
+** Returns result from user callback.
+*/
+long Pa_CallConvertInt16( internalPortAudioStream *past,
+ short *nativeInputBuffer,
+ short *nativeOutputBuffer )
+{
+ long temp;
+ long bytesEmpty = 0;
+ long bytesFilled = 0;
+ int userResult;
+ unsigned int i;
+ void *inputBuffer = NULL;
+ void *outputBuffer = NULL;
+
+#if SUPPORT_AUDIO_CAPTURE
+ /* Get native data from DirectSound. */
+ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+ {
+ /* Convert from native format to PA format. */
+ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels;
+ switch(past->past_InputSampleFormat)
+ {
+
+ case paFloat32:
+ {
+ float *inBufPtr = (float *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = nativeInputBuffer[i] * (1.0f / 32767.0f);
+ }
+ break;
+ }
+
+ case paInt32:
+ {
+ /* Convert 16 bit data to 32 bit integers */
+ int *inBufPtr = (int *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = nativeInputBuffer[i] << 16;
+ }
+ break;
+ }
+
+ case paInt16:
+ {
+ /* Already in correct format so don't copy. */
+ inputBuffer = nativeInputBuffer;
+ break;
+ }
+
+ case paInt8:
+ {
+ /* Convert 16 bit data to 8 bit chars */
+ char *inBufPtr = (char *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = (char)(nativeInputBuffer[i] >> 8);
+ }
+ }
+ else
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = nativeInputBuffer[i];
+ temp += Pa_TriangularDither() >> 7;
+ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ inBufPtr[i] = (char)(temp >> 8);
+ }
+ }
+ break;
+ }
+
+ case paUInt8:
+ {
+ /* Convert 16 bit data to 8 bit unsigned chars */
+ unsigned char *inBufPtr = (unsigned char *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = ((unsigned char)(nativeInputBuffer[i] >> 8)) + 0x80;
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = nativeInputBuffer[i];
+ temp += Pa_TriangularDither() >> 7;
+ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ inBufPtr[i] = (unsigned char)(temp + 0x80);
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+
+ /* Are we doing output time? */
+ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+ {
+ /* May already be in native format so just write directly to native buffer. */
+ outputBuffer = (past->past_OutputSampleFormat == paInt16) ?
+ nativeOutputBuffer : past->past_OutputBuffer;
+ }
+ /*
+ AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+ AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+ */
+ /* Call user callback routine. */
+ userResult = past->past_Callback(
+ inputBuffer,
+ outputBuffer,
+ past->past_FramesPerUserBuffer,
+ past->past_FrameCount,
+ past->past_UserData );
+
+ past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
+
+ /* Convert to native format if necessary. */
+ if( outputBuffer != NULL )
+ {
+ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
+ switch(past->past_OutputSampleFormat)
+ {
+ case paFloat32:
+ {
+ float *outBufPtr = (float *) past->past_OutputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ if( past->past_Flags & paClipOff ) /* NOTHING */
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (outBufPtr[i] * (32767.0f));
+ }
+ }
+ else /* CLIP */
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = (long)(outBufPtr[i] * 32767.0f);
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ float dither = Pa_TriangularDither()*DITHER_SCALE;
+ float dithered = (outBufPtr[i] * (32767.0f)) + dither;
+ temp = (long) (dithered);
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ break;
+ }
+
+ case paInt32:
+ {
+ int *outBufPtr = (int *) past->past_OutputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (outBufPtr[i] >> 16 );
+ }
+ }
+ else
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ /* Shift one bit down before dithering so that we have room for overflow from add. */
+ temp = (outBufPtr[i] >> 1) + Pa_TriangularDither();
+ temp = temp >> 15;
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ break;
+ }
+
+ case paInt8:
+ {
+ char *outBufPtr = (char *) past->past_OutputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = ((short)outBufPtr[i]) << 8;
+ }
+ break;
+ }
+
+ case paUInt8:
+ {
+ unsigned char *outBufPtr = (unsigned char *) past->past_OutputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = ((short)(outBufPtr[i] - 0x80)) << 8;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+
+ return userResult;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from Float32, call user code, then convert output
+** to Float32 format for native use.
+** Assumes host native format is Float32.
+** Returns result from user callback.
+** FIXME - Unimplemented for formats other than paFloat32!!!!
+*/
+long Pa_CallConvertFloat32( internalPortAudioStream *past,
+ float *nativeInputBuffer,
+ float *nativeOutputBuffer )
+{
+ long bytesEmpty = 0;
+ long bytesFilled = 0;
+ int userResult;
+ void *inputBuffer = NULL;
+ void *outputBuffer = NULL;
+
+ /* Get native data from DirectSound. */
+ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+ {
+ inputBuffer = nativeInputBuffer; // FIXME
+ }
+
+ /* Are we doing output time? */
+ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+ {
+ /* May already be in native format so just write directly to native buffer. */
+ outputBuffer = (past->past_OutputSampleFormat == paFloat32) ?
+ nativeOutputBuffer : past->past_OutputBuffer;
+ }
+ /*
+ AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+ AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+ */
+ /* Call user callback routine. */
+ userResult = past->past_Callback(
+ inputBuffer,
+ outputBuffer,
+ past->past_FramesPerUserBuffer,
+ past->past_FrameCount,
+ past->past_UserData );
+
+ past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
+
+ /* Convert to native format if necessary. */ // FIXME
+ return userResult;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_Initialize( void )
+{
+ if( gInitCount++ > 0 ) return paNoError;
+ ResetTraceMessages();
+ return PaHost_Init();
+}
+
+DLL_API PaError Pa_Terminate( void )
+{
+ PaError result = paNoError;
+
+ if( gInitCount == 0 ) return paNoError;
+ else if( --gInitCount == 0 )
+ {
+ result = PaHost_Term();
+ DumpTraceMessages();
+ }
+ return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_GetSampleSize( PaSampleFormat format )
+{
+ int size;
+ switch(format )
+ {
+
+ case paUInt8:
+ case paInt8:
+ size = 1;
+ break;
+
+ case paInt16:
+ size = 2;
+ break;
+
+ case paPackedInt24:
+ size = 3;
+ break;
+
+ case paFloat32:
+ case paInt32:
+ case paInt24:
+ size = 4;
+ break;
+
+ default:
+ size = paSampleFormatNotSupported;
+ break;
+ }
+ return (PaError) size;
+}
+
+
diff --git a/pd/portaudio/pa_dll_switch/portaudio.h b/pd/portaudio/pa_dll_switch/portaudio.h
new file mode 100644
index 00000000..9632521e
--- /dev/null
+++ b/pd/portaudio/pa_dll_switch/portaudio.h
@@ -0,0 +1,439 @@
+#ifndef PORT_AUDIO_H
+#define PORT_AUDIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio API Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+// added by zplane.developement in order to generate a DLL
+
+#if defined(PA_MME_EXPORTS) || defined(PA_DX_EXPORTS)
+#define DLL_API __declspec( dllexport )
+#elif defined(_LIB) || defined(_STATIC_LINK) || defined(_STATIC_APP)
+#define DLL_API
+#else
+#define DLL_API __declspec(dllexport)
+#endif
+
+
+typedef int PaError;
+typedef enum {
+ paNoError = 0,
+
+ paHostError = -10000,
+ paInvalidChannelCount,
+ paInvalidSampleRate,
+ paInvalidDeviceId,
+ paInvalidFlag,
+ paSampleFormatNotSupported,
+ paBadIODeviceCombination,
+ paInsufficientMemory,
+ paBufferTooBig,
+ paBufferTooSmall,
+ paNullCallback,
+ paBadStreamPtr,
+ paTimedOut,
+ paInternalError
+} PaErrorNum;
+
+/*
+ Pa_Initialize() is the library initialisation function - call this before
+ using the library.
+*/
+
+DLL_API PaError Pa_Initialize( void );
+
+/*
+ Pa_Terminate() is the library termination function - call this after
+ using the library.
+*/
+
+DLL_API PaError Pa_Terminate( void );
+
+/*
+ Return host specific error.
+ This can be called after receiving a paHostError.
+*/
+DLL_API long Pa_GetHostError( void );
+
+/*
+ Translate the error number into a human readable message.
+*/
+DLL_API const char *Pa_GetErrorText( PaError errnum );
+
+/*
+ Sample formats
+
+ These are formats used to pass sound data between the callback and the
+ stream. Each device has a "native" format which may be used when optimum
+ efficiency or control over conversion is required.
+
+ Formats marked "always available" are supported (emulated) by all devices.
+
+ The floating point representation uses +1.0 and -1.0 as the respective
+ maximum and minimum.
+
+*/
+
+typedef unsigned long PaSampleFormat;
+#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
+#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
+#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
+#define paInt24 ((PaSampleFormat) (1<<3))
+#define paPackedInt24 ((PaSampleFormat) (1<<4))
+#define paInt8 ((PaSampleFormat) (1<<5))
+#define paUInt8 ((PaSampleFormat) (1<<6)) /* unsigned 8 bit, 128 is "ground" */
+#define paCustomFormat ((PaSampleFormat) (1<<16))
+
+/*
+ Device enumeration mechanism.
+
+ Device ids range from 0 to Pa_CountDevices()-1.
+
+ Devices may support input, output or both. Device 0 is always the "default"
+ device and should support at least stereo in and out if that is available
+ on the taget platform _even_ if this involves kludging an input/output
+ device on platforms that usually separate input from output. Other platform
+ specific devices are specified by positive device ids.
+*/
+
+typedef int PaDeviceID;
+#define paNoDevice -1
+
+typedef struct
+{
+ int structVersion;
+ const char *name;
+ int maxInputChannels;
+ int maxOutputChannels;
+ /* Number of discrete rates, or -1 if range supported. */
+ int numSampleRates;
+ /* Array of supported sample rates, or {min,max} if range supported. */
+ const double *sampleRates;
+ PaSampleFormat nativeSampleFormats;
+}
+PaDeviceInfo;
+
+
+DLL_API int Pa_CountDevices();
+/*
+ Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID()
+
+ Return the default device ID or paNoDevice if there is no devices.
+ The result can be passed to Pa_OpenStream().
+
+ On the PC, the user can specify a default device by
+ setting an environment variable. For example, to use device #1.
+
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ID by using
+ the supplied application "pa_devs".
+*/
+DLL_API PaDeviceID Pa_GetDefaultInputDeviceID( void );
+DLL_API PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+
+/*
+ PaTimestamp is used to represent a continuous sample clock with arbitrary
+ start time useful for syncronisation. The type is used in the outTime
+ argument to the callback function and the result of Pa_StreamTime()
+*/
+
+typedef double PaTimestamp;
+
+/*
+ Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
+ referring to the device specified by id.
+ If id is out of range the function returns NULL.
+
+ The returned structure is owned by the PortAudio implementation and must
+ not be manipulated or freed. The pointer is guaranteed to be valid until
+ between calls to Pa_Initialize() and Pa_Terminate().
+*/
+
+DLL_API const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id );
+
+/*
+ PortAudioCallback is implemented by clients of the portable audio api.
+
+ inputBuffer and outputBuffer are arrays of interleaved samples,
+ the format, packing and number of channels used by the buffers are
+ determined by parameters to Pa_OpenStream() (see below).
+
+ framesPerBuffer is the number of sample frames to be processed by the callback.
+
+ outTime is the time in samples when the buffer(s) processed by
+ this callback will begin being played at the audio output.
+ See also Pa_StreamTime()
+
+ userData is the value of a user supplied pointer passed to Pa_OpenStream()
+ intended for storing synthesis data etc.
+
+ return value:
+ The callback can return a nonzero value to stop the stream. This may be
+ useful in applications such as soundfile players where a specific duration
+ of output is required. However, it is not necessary to utilise this mechanism
+ as StopStream() will also terminate the stream. A callback returning a
+ nonzero value must fill the entire outputBuffer.
+
+ NOTE: None of the other stream functions may be called from within the
+ callback function except for Pa_GetCPULoad().
+
+*/
+
+typedef int (PortAudioCallback)(
+ void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+
+/*
+ Stream flags
+
+ These flags may be supplied (ored together) in the streamFlags argument to
+ the Pa_OpenStream() function.
+
+ [ suggestions? ]
+*/
+
+#define paNoFlag (0)
+#define paClipOff (1<<0) /* disable defult clipping of out of range samples */
+#define paDitherOff (1<<1) /* disable default dithering */
+#define paPlatformSpecificFlags (0x00010000)
+typedef unsigned long PaStreamFlags;
+
+/*
+ A single PortAudioStream provides multiple channels of real-time
+ input and output audio streaming to a client application.
+ Pointers to PortAudioStream objects are passed between PortAudio functions.
+*/
+
+typedef void PortAudioStream;
+#define PaStream PortAudioStream
+
+/*
+ Pa_OpenStream() opens a stream for either input, output or both.
+
+ stream is the address of a PortAudioStream pointer which will receive
+ a pointer to the newly opened stream.
+
+ inputDevice is the id of the device used for input (see PaDeviceID above.)
+ inputDevice may be paNoDevice to indicate that an input device is not required.
+
+ numInputChannels is the number of channels of sound to be delivered to the
+ callback. It can range from 1 to the value of maxInputChannels in the
+ device input record for the device specified in the inputDevice parameter.
+ If inputDevice is paNoDevice numInputChannels is ignored.
+
+ inputSampleFormat is the format of inputBuffer provided to the callback
+ function. inputSampleFormat may be any of the formats described by the
+ PaSampleFormat enumeration (see above). PortAudio guarantees support for
+ the sound devices native formats (nativeSampleFormats in the device info
+ record) and additionally 16 and 32 bit integer and 32 bit floating point
+ formats. Support for other formats is implementation defined.
+
+ inputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ inputDriverInfo is never required for correct operation. If not used
+ inputDriverInfo should be NULL.
+
+ outputDevice is the id of the device used for output (see PaDeviceID above.)
+ outputDevice may be paNoDevice to indicate that an output device is not required.
+
+ numOutputChannels is the number of channels of sound to be supplied by the
+ callback. See the definition of numInputChannels above for more details.
+
+ outputSampleFormat is the sample format of the outputBuffer filled by the
+ callback function. See the definition of inputSampleFormat above for more
+ details.
+
+ outputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ outputDriverInfo is never required for correct operation. If not used
+ outputDriverInfo should be NULL.
+
+ sampleRate is the desired sampleRate for input and output
+
+ framesPerBuffer is the length in sample frames of all internal sample buffers
+ used for communication with platform specific audio routines. Wherever
+ possible this corresponds to the framesPerBuffer parameter passed to the
+ callback function.
+
+ numberOfBuffers is the number of buffers used for multibuffered
+ communication with the platform specific audio routines. This parameter is
+ provided only as a guide - and does not imply that an implementation must
+ use multibuffered i/o when reliable double buffering is available (such as
+ SndPlayDoubleBuffer() on the Macintosh.)
+
+ streamFlags may contain a combination of flags ORed together.
+ These flags modify the behavior of the
+ streaming process. Some flags may only be relevant to certain buffer formats.
+
+ callback is a pointer to a client supplied function that is responsible
+ for processing and filling input and output buffers (see above for details.)
+
+ userData is a client supplied pointer which is passed to the callback
+ function. It could for example, contain a pointer to instance data necessary
+ for processing the audio buffers.
+
+ return value:
+ Apon success Pa_OpenStream() returns PaNoError and places a pointer to a
+ valid PortAudioStream in the stream argument. The stream is inactive (stopped).
+ If a call to Pa_OpenStream() fails a nonzero error code is returned (see
+ PAError above) and the value of stream is invalid.
+
+*/
+
+DLL_API PaError Pa_OpenStream( PortAudioStream** stream,
+ PaDeviceID inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+/*
+ Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that
+ opens the default input and/or ouput devices. Most parameters have
+ identical meaning to their Pa_OpenStream() counterparts, with the following
+ exceptions:
+
+ If either numInputChannels or numOutputChannels is 0 the respective device
+ is not opened (same as passing paNoDevice in the device arguments to Pa_OpenStream() )
+
+ sampleFormat applies to both the input and output buffers.
+*/
+
+DLL_API PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+/*
+ Pa_CloseStream() closes an audio stream, flushing any pending buffers.
+*/
+
+DLL_API PaError Pa_CloseStream( PortAudioStream* );
+
+/*
+ Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
+ When Pa_StopStream() returns, all pending audio buffers have been played.
+ Pa_AbortStream() stops playing immediately without waiting for pending
+ buffers to complete.
+*/
+
+DLL_API PaError Pa_StartStream( PortAudioStream *stream );
+
+DLL_API PaError Pa_StopStream( PortAudioStream *stream );
+
+DLL_API PaError Pa_AbortStream( PortAudioStream *stream );
+
+/*
+ Pa_StreamActive() returns one when the stream is playing audio,
+ zero when not playing, or a negative error number if the
+ stream is invalid.
+ The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
+ but may also become inactive if the callback returns a non-zero value.
+ In the latter case, the stream is considered inactive after the last
+ buffer has finished playing.
+*/
+
+DLL_API PaError Pa_StreamActive( PortAudioStream *stream );
+
+/*
+ Pa_StreamTime() returns the current output time for the stream in samples.
+ This time may be used as a time reference (for example syncronising audio to
+ MIDI).
+*/
+
+DLL_API PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+
+/*
+ The "CPU Load" is a fraction of total CPU time consumed by the
+ stream's audio processing.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ This function may be called from the callback function or the application.
+*/
+DLL_API double Pa_GetCPULoad( PortAudioStream* stream );
+
+/*
+ Use Pa_GetMinNumBuffers() to determine minimum number of buffers required for
+ the current host based on minimum latency.
+ On the PC, for the DirectSound implementation, latency can be optionally set
+ by user by setting an environment variable.
+ For example, to set latency to 200 msec, put:
+
+ set PA_MIN_LATENCY_MSEC=200
+
+ in the AUTOEXEC.BAT file and reboot.
+ If the environment variable is not set, then the latency will be determined
+ based on the OS. Windows NT has higher latency than Win95.
+*/
+
+DLL_API int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
+
+/*
+ Sleep for at least 'msec' milliseconds.
+ You may sleep longer than the requested time so don't rely
+ on this for accurate musical timing.
+*/
+DLL_API void Pa_Sleep( long msec );
+
+/*
+ Return size in bytes of a single sample in a given PaSampleFormat
+ or paSampleFormatNotSupported.
+*/
+DLL_API PaError Pa_GetSampleSize( PaSampleFormat format );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PORT_AUDIO_H */
diff --git a/pd/portaudio/pa_jack/pa_jack.c b/pd/portaudio/pa_jack/pa_jack.c
new file mode 100644
index 00000000..4efeff81
--- /dev/null
+++ b/pd/portaudio/pa_jack/pa_jack.c
@@ -0,0 +1,864 @@
+/*
+ * $Id: pa_jack.c,v 1.1.2.1 2002/07/31 04:22:56 joshua Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * JACK Implementation by Joshua Haberman
+ *
+ * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <string.h>
+#include <regex.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <jack/types.h>
+#include <jack/jack.h>
+
+#include "pa_util.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_process.h"
+#include "pa_allocation.h"
+#include "pa_cpuload.h"
+
+PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi,
+ PaHostApiIndex hostApiIndex );
+
+/*
+ * Functions that directly map to the PortAudio stream interface
+ */
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ PaDeviceIndex inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ unsigned long inputLatency,
+ PaHostApiSpecificStreamInfo *inputStreamInfo,
+ PaDeviceIndex outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ unsigned long outputLatency,
+ PaHostApiSpecificStreamInfo *outputStreamInfo,
+ double sampleRate,
+ unsigned long framesPerCallback,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ 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 PaTimestamp GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+
+/*
+ * Data specific to this API
+ */
+
+typedef struct
+{
+ PaUtilHostApiRepresentation commonHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+
+ PaUtilAllocationGroup *deviceInfoMemory;
+
+ jack_client_t *jack_client;
+ PaHostApiIndex hostApiIndex;
+}
+PaJackHostApiRepresentation;
+
+#define MAX_CLIENTS 100
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * Functions specific to this API
+ */
+
+static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi );
+static int JackCallback( jack_nframes_t frames, void *userData );
+
+
+
+/*
+ *
+ * Implementation
+ *
+ */
+
+
+/* BuildDeviceList():
+ *
+ * The process of determining a list of PortAudio "devices" from
+ * JACK's client/port system is fairly involved, so it is separated
+ * into its own routine.
+ */
+
+static PaError BuildDeviceList( PaJackHostApiRepresentation *jackApi )
+{
+ /* Utility macros for the repetitive process of allocating memory */
+
+ /* ... MALLOC: allocate memory as part of the device list
+ * allocation group */
+#define MALLOC(size) \
+ (PaUtil_GroupAllocateMemory( jackApi->deviceInfoMemory, (size) ))
+
+ /* ... MEMVERIFY: make sure we didn't get NULL */
+#define MEMVERIFY(ptr) \
+ if( (ptr) == NULL ) return paInsufficientMemory;
+
+ /* JACK has no concept of a device. To JACK, there are clients
+ * which have an arbitrary number of ports. To make this
+ * intelligible to PortAudio clients, we will group each JACK client
+ * into a device, and make each port of that client a channel */
+
+ PaUtilHostApiRepresentation *commonApi = &jackApi->commonHostApiRep;
+
+ const char **jack_ports;
+ char *client_names[MAX_CLIENTS];
+ int num_clients = 0;
+ int port_index, client_index, i;
+ double *globalSampleRate;
+ regex_t port_regex;
+
+ /* since we are rebuilding the list of devices, free all memory
+ * associated with the previous list */
+ PaUtil_FreeAllAllocations( jackApi->deviceInfoMemory );
+
+ /* We can only retrieve the list of clients indirectly, by first
+ * asking for a list of all ports, then parsing the port names
+ * according to the client_name:port_name convention (which is
+ * enforced by jackd) */
+ jack_ports = jack_get_ports( jackApi->jack_client, "", "", 0 );
+
+ if( jack_ports == NULL )
+ return paHostError;
+
+ /* Parse the list of ports, using a regex to grab the client names */
+ regcomp( &port_regex, "^[^:]*", REG_EXTENDED );
+
+ /* Build a list of clients from the list of ports */
+ for( port_index = 0; jack_ports[port_index] != NULL; port_index++ )
+ {
+ int client_seen;
+ regmatch_t match_info;
+ char tmp_client_name[100];
+
+ /* extract the client name from the port name, using a regex
+ * that parses the clientname:portname syntax */
+ regexec( &port_regex, jack_ports[port_index], 1, &match_info, 0 );
+ memcpy( tmp_client_name, &jack_ports[port_index][match_info.rm_so],
+ match_info.rm_eo - match_info.rm_so );
+ tmp_client_name[ match_info.rm_eo - match_info.rm_so ] = '\0';
+
+ /* do we know about this port's client yet? */
+ client_seen = FALSE;
+
+ for( i = 0; i < num_clients; i++ )
+ if( strcmp( tmp_client_name, client_names[i] ) == 0 )
+ client_seen = TRUE;
+
+ if( client_seen == FALSE )
+ {
+ client_names[num_clients] = (char*)MALLOC(strlen(tmp_client_name) + 1);
+ MEMVERIFY( client_names[num_clients] );
+
+ /* The alsa_pcm client should go in spot 0. If this
+ * is the alsa_pcm client AND we are NOT about to put
+ * it in spot 0 put it in spot 0 and move whatever
+ * was already in spot 0 to the end. */
+ if( strcmp( "alsa_pcm", tmp_client_name ) == 0 && num_clients > 0 )
+ {
+ /* alsa_pcm goes in spot 0 */
+ strcpy( client_names[ num_clients ], client_names[0] );
+ strcpy( client_names[0], "alsa_pcm" );
+ num_clients++;
+ }
+ else
+ {
+ /* put the new client at the end of the client list */
+ strcpy( client_names[ num_clients ], tmp_client_name );
+ num_clients++;
+ }
+ }
+ }
+ free( jack_ports );
+
+ /* Now we have a list of clients, which will become the list of
+ * PortAudio devices. */
+
+ commonApi->deviceCount = num_clients;
+ commonApi->defaultInputDeviceIndex = 0;
+ commonApi->defaultOutputDeviceIndex = 0;
+
+ /* there is one global sample rate all clients must conform to */
+
+ globalSampleRate = (double*)MALLOC( sizeof(double) );
+ MEMVERIFY( globalSampleRate );
+ *globalSampleRate = jack_get_sample_rate( jackApi->jack_client );
+
+ commonApi->deviceInfos = (PaDeviceInfo**)MALLOC( sizeof(PaDeviceInfo*) *
+ num_clients );
+ MEMVERIFY(commonApi->deviceInfos);
+
+ /* Create a PaDeviceInfo structure for every client */
+ for( client_index = 0; client_index < num_clients; client_index++ )
+ {
+ char regex_pattern[100];
+ PaDeviceInfo *curDevInfo;
+
+ curDevInfo = (PaDeviceInfo*)MALLOC( sizeof(PaDeviceInfo) );
+ MEMVERIFY( curDevInfo );
+
+ curDevInfo->name = (char*)MALLOC( strlen(client_names[client_index]) + 1 );
+ MEMVERIFY( curDevInfo->name );
+ strcpy( (char*)curDevInfo->name, client_names[client_index] );
+
+ curDevInfo->structVersion = 2;
+ curDevInfo->hostApi = jackApi->hostApiIndex;
+
+ /* JACK is very inflexible: there is one sample rate the whole
+ * system must run at, and all clients must speak IEEE float. */
+ curDevInfo->numSampleRates = 1;
+ curDevInfo->sampleRates = globalSampleRate;
+ curDevInfo->nativeSampleFormats = paFloat32|paNonInterleaved;
+
+ /* To determine how many input and output channels are available,
+ * we re-query jackd with more specific parameters. */
+
+ sprintf( regex_pattern, "%s:.*", client_names[client_index] );
+
+ /* ... what are your output ports (that we could input to)? */
+ jack_ports = jack_get_ports( jackApi->jack_client, regex_pattern,
+ NULL, JackPortIsOutput);
+ curDevInfo->maxInputChannels = 0;
+ for( i = 0; jack_ports[i] != NULL ; i++)
+ {
+ /* The number of ports returned is the number of output channels.
+ * We don't care what they are, we just care how many */
+ curDevInfo->maxInputChannels++;
+ }
+ free(jack_ports);
+
+ /* ... what are your input ports (that we could output to)? */
+ jack_ports = jack_get_ports( jackApi->jack_client, regex_pattern,
+ NULL, JackPortIsInput);
+ curDevInfo->maxOutputChannels = 0;
+ for( i = 0; jack_ports[i] != NULL ; i++)
+ {
+ /* The number of ports returned is the number of input channels.
+ * We don't care what they are, we just care how many */
+ curDevInfo->maxOutputChannels++;
+ }
+ free(jack_ports);
+
+ /* Add this client to the list of devices */
+ commonApi->deviceInfos[client_index] = curDevInfo;
+ }
+
+#undef MALLOC
+#undef MEMVERIFY
+ return paNoError;
+}
+
+PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi,
+ PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ PaJackHostApiRepresentation *jackHostApi;
+
+ jackHostApi = (PaJackHostApiRepresentation*)
+ PaUtil_AllocateMemory( sizeof(PaJackHostApiRepresentation) );
+ if( !jackHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* Try to become a client of the JACK server. If we cannot do
+ * this, than this API cannot be used. */
+
+ jackHostApi->jack_client = jack_client_new( "PortAudio client" );
+ if( jackHostApi->jack_client == 0 )
+ {
+ /* the V19 development docs say that if an implementation
+ * detects that it cannot be used, it should return a NULL
+ * interface and paNoError */
+ result = paNoError;
+ *hostApi = NULL;
+ goto error;
+ }
+
+ jackHostApi->deviceInfoMemory = PaUtil_CreateAllocationGroup();
+ if( !jackHostApi->deviceInfoMemory )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ jackHostApi->hostApiIndex = hostApiIndex;
+
+ *hostApi = &jackHostApi->commonHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paInDevelopment;
+ (*hostApi)->info.name = "JACK Audio Connection Kit";
+
+ /* Build a device list by querying the JACK server */
+
+ result = BuildDeviceList( jackHostApi );
+ if( result != paNoError )
+ goto error;
+
+ /* Register functions */
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+
+ PaUtil_InitializeStreamInterface( &jackHostApi->callbackStreamInterface,
+ CloseStream, StartStream,
+ StopStream, AbortStream,
+ IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite,
+ PaUtil_DummyGetAvailable,
+ PaUtil_DummyGetAvailable );
+
+ return result;
+
+error:
+ if( jackHostApi )
+ {
+ if( jackHostApi->deviceInfoMemory )
+ {
+ PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory );
+ PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory );
+ }
+
+ PaUtil_FreeMemory( jackHostApi );
+ }
+ return result;
+}
+
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
+
+ jack_client_close( jackHostApi->jack_client );
+
+ if( jackHostApi->deviceInfoMemory )
+ {
+ PaUtil_FreeAllAllocations( jackHostApi->deviceInfoMemory );
+ PaUtil_DestroyAllocationGroup( jackHostApi->deviceInfoMemory );
+ }
+
+ PaUtil_FreeMemory( jackHostApi );
+}
+
+
+/* PaJackStream - a stream data structure specifically for this implementation */
+
+typedef struct PaJackStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilBufferProcessor bufferProcessor;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+
+ /* our input and output ports */
+ jack_port_t **local_input_ports;
+ jack_port_t **local_output_ports;
+
+ /* the input and output ports of the client we are connecting to */
+ jack_port_t **remote_input_ports;
+ jack_port_t **remote_output_ports;
+
+ int num_incoming_connections;
+ int num_outgoing_connections;
+
+ jack_client_t *jack_client;
+
+ /* The stream is running if it's still producing samples.
+ * The stream is active if samples it produced are still being heard.
+ */
+ int is_running;
+ int is_active;
+
+ jack_nframes_t t0;
+ unsigned long total_frames_sent;
+
+ PaUtilAllocationGroup *stream_memory;
+}
+PaJackStream;
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ PaDeviceIndex inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ unsigned long inputLatency,
+ PaHostApiSpecificStreamInfo *inputStreamInfo,
+ PaDeviceIndex outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ unsigned long outputLatency,
+ PaHostApiSpecificStreamInfo *outputStreamInfo,
+ double sampleRate,
+ unsigned long framesPerCallback,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaJackHostApiRepresentation *jackHostApi = (PaJackHostApiRepresentation*)hostApi;
+ PaJackStream *stream = 0;
+ char port_string[100];
+ char regex_pattern[100];
+ const char **jack_ports;
+ int jack_max_buffer_size = jack_get_buffer_size( jackHostApi->jack_client );
+ int i;
+
+ /* the client has no say over the frames per callback */
+
+ (void)framesPerCallback;
+
+ /* Preliminary checks */
+
+ /* ... check that input device can support numInputChannels */
+
+ if( inputDevice != paNoDevice &&
+ numInputChannels > hostApi->deviceInfos[ inputDevice ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* ... check that output device can support numOutputChannels */
+
+ if( outputDevice != paNoDevice &&
+ numOutputChannels > hostApi->deviceInfos[ outputDevice ]->maxOutputChannels)
+ return paInvalidChannelCount;
+
+ /* ... check that the sample rate exactly matches the ONE acceptable rate */
+
+#define ABS(x) ( (x) > 0 ? (x) : -(x) )
+ if( ABS(sampleRate - hostApi->deviceInfos[0]->sampleRates[0]) > 1 )
+ return paInvalidSampleRate;
+#undef ABS
+
+ /* ... this implementation doesn't use custom stream info */
+
+ if( inputStreamInfo )
+ return paIncompatibleStreamInfo;
+
+ /* ... this implementation doesn't use custom stream info */
+
+ if( outputStreamInfo )
+ return paIncompatibleStreamInfo;
+
+ /* ... this implementation doesn't use platform-specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag;
+
+ /* Allocate memory for structuures */
+
+#define MALLOC(size) \
+ (PaUtil_GroupAllocateMemory( stream->stream_memory, (size) ))
+
+#define MEMVERIFY(ptr) \
+ if( (ptr) == NULL ) \
+ { \
+ result = paInsufficientMemory; \
+ goto error; \
+ }
+
+ stream = (PaJackStream*)PaUtil_AllocateMemory( sizeof(PaJackStream) );
+ MEMVERIFY( stream );
+
+ stream->stream_memory = PaUtil_CreateAllocationGroup();
+ stream->jack_client = jackHostApi->jack_client;
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+ stream->local_input_ports =
+ (jack_port_t**) MALLOC(sizeof(jack_port_t*) * numInputChannels );
+ stream->local_output_ports =
+ (jack_port_t**) MALLOC( sizeof(jack_port_t*) * numOutputChannels );
+ stream->remote_output_ports =
+ (jack_port_t**) MALLOC( sizeof(jack_port_t*) * numInputChannels );
+ stream->remote_input_ports =
+ (jack_port_t**) MALLOC( sizeof(jack_port_t*) * numOutputChannels );
+
+ MEMVERIFY( stream->local_input_ports );
+ MEMVERIFY( stream->local_output_ports );
+ MEMVERIFY( stream->remote_input_ports );
+ MEMVERIFY( stream->remote_output_ports );
+
+ stream->num_incoming_connections = numInputChannels;
+ stream->num_outgoing_connections = numOutputChannels;
+
+ if( callback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &jackHostApi->callbackStreamInterface, callback, userData );
+ }
+ else
+ {
+ /* we do not support blocking I/O */
+ return paBadIODeviceCombination;
+ }
+
+ /* create the JACK ports. We cannot connect them until audio
+ * processing begins */
+
+ for( i = 0; i < numInputChannels; i++ )
+ {
+ sprintf( port_string, "in_%d", i );
+ stream->local_input_ports[i] = jack_port_register(
+ jackHostApi->jack_client, port_string,
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
+ }
+
+ for( i = 0; i < numOutputChannels; i++ )
+ {
+ sprintf( port_string, "out_%d", i );
+ stream->local_output_ports[i] = jack_port_register(
+ jackHostApi->jack_client, port_string,
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
+ }
+
+ /* look up the jack_port_t's for the remote ports. We could do
+ * this at stream start time, but doing it here ensures the
+ * name lookup only happens once. */
+
+ if( numInputChannels > 0 )
+ {
+ /* ... remote output ports (that we input from) */
+ sprintf( regex_pattern, "%s:.*", hostApi->deviceInfos[ inputDevice ]->name );
+ jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
+ NULL, JackPortIsOutput);
+ for( i = 0; i < numInputChannels && jack_ports[i]; i++ )
+ {
+ stream->remote_output_ports[i] = jack_port_by_name(
+ jackHostApi->jack_client, jack_ports[i] );
+ }
+ if( i < numInputChannels )
+ {
+ /* we found fewer ports than we expected */
+ return paInternalError;
+ }
+ free( jack_ports ); // XXX: this doesn't happen if we exit prematurely
+ }
+
+
+ if( numOutputChannels > 0 )
+ {
+ /* ... remote input ports (that we output to) */
+ sprintf( regex_pattern, "%s:.*", hostApi->deviceInfos[ outputDevice ]->name );
+ jack_ports = jack_get_ports( jackHostApi->jack_client, regex_pattern,
+ NULL, JackPortIsInput);
+ for( i = 0; i < numOutputChannels && jack_ports[i]; i++ )
+ {
+ stream->remote_input_ports[i] = jack_port_by_name(
+ jackHostApi->jack_client, jack_ports[i] );
+ }
+ if( i < numOutputChannels )
+ {
+ /* we found fewer ports than we expected */
+ return paInternalError;
+ }
+ free( jack_ports ); // XXX: this doesn't happen if we exit prematurely
+ }
+
+ result = PaUtil_InitializeBufferProcessor(
+ &stream->bufferProcessor,
+ numInputChannels,
+ inputSampleFormat,
+ paFloat32, /* hostInputSampleFormat */
+ numOutputChannels,
+ outputSampleFormat,
+ paFloat32, /* hostOutputSampleFormat */
+ sampleRate,
+ streamFlags,
+ framesPerCallback,
+ jack_max_buffer_size,
+ paUtilFixedHostBufferSize,
+ callback,
+ userData );
+
+ if( result != paNoError )
+ goto error;
+
+ stream->is_running = FALSE;
+ stream->t0 = -1;/* set the first time through the callback*/
+ stream->total_frames_sent = 0;
+
+ jack_set_process_callback( jackHostApi->jack_client, JackCallback, stream );
+
+ *s = (PaStream*)stream;
+
+ return result;
+
+error:
+ if( stream )
+ {
+ if( stream->stream_memory )
+ {
+ PaUtil_FreeAllAllocations( stream->stream_memory );
+ PaUtil_DestroyAllocationGroup( stream->stream_memory );
+ }
+
+ PaUtil_FreeMemory( stream );
+ }
+
+ return result;
+
+#undef MALLOC
+#undef MEMVERIFY
+}
+
+
+static int JackCallback( jack_nframes_t frames, void *userData )
+{
+ PaJackStream *stream = (PaJackStream*)userData;
+ PaTimestamp outTime = 0; /* IMPLEMENT ME */
+ int callbackResult;
+ int chn;
+ int framesProcessed;
+
+ if( stream->t0 == -1 )
+ {
+ if( stream->num_outgoing_connections == 0 )
+ {
+ /* TODO: how to handle stream time for capture-only operation? */
+ }
+ else
+ {
+ /* the beginning time needs to be initialized */
+ stream->t0 = jack_frame_time( stream->jack_client ) -
+ jack_frames_since_cycle_start( stream->jack_client) +
+ jack_port_get_total_latency( stream->jack_client,
+ stream->local_output_ports[0] );
+ }
+ }
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, outTime );
+
+ for( chn = 0; chn < stream->num_incoming_connections; chn++ )
+ {
+ jack_default_audio_sample_t *channel_buf;
+ channel_buf = (jack_default_audio_sample_t*)
+ jack_port_get_buffer( stream->local_input_ports[chn],
+ frames );
+
+ PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor,
+ chn,
+ channel_buf );
+ }
+
+ for( chn = 0; chn < stream->num_outgoing_connections; chn++ )
+ {
+ jack_default_audio_sample_t *channel_buf;
+ channel_buf = (jack_default_audio_sample_t*)
+ jack_port_get_buffer( stream->local_output_ports[chn],
+ frames );
+
+ PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor,
+ chn,
+ channel_buf );
+ }
+
+ if( stream->num_incoming_connections > 0 )
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, frames );
+
+ if( stream->num_outgoing_connections > 0 )
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, frames );
+
+ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
+ &callbackResult );
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+ stream->total_frames_sent += frames;
+
+
+ if( callbackResult == paContinue )
+ {
+ /* nothing special */
+ }
+ else if( callbackResult == paAbort )
+ {
+ /* finish playback immediately */
+
+ /* TODO: memset 0 the outgoing samples to "cancel" them */
+
+ stream->is_active = FALSE;
+
+ /* return nonzero so we get deactivated (and the callback won't
+ * get called again) */
+ return 1;
+ }
+ else
+ {
+ /* User callback has asked us to stop with paComplete or other non-zero value. */
+
+ stream->is_active = FALSE;
+
+ /* return nonzero so we get deactivated (and the callback won't
+ * get called again) */
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaJackStream *stream = (PaJackStream*)s;
+
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaJackStream *stream = (PaJackStream*)s;
+ int i;
+
+ /* start the audio thread */
+
+ jack_activate( stream->jack_client );
+
+ /* connect the ports */
+
+ /* NOTE: I would rather use jack_port_connect which uses jack_port_t's
+ * instead of port names, but it is not implemented yet. */
+ if( stream->num_incoming_connections > 0 )
+ {
+ for( i = 0; i < stream->num_incoming_connections; i++ )
+ jack_connect( stream->jack_client,
+ jack_port_name(stream->remote_output_ports[i]),
+ jack_port_name(stream->local_input_ports[i] ) );
+ }
+
+ if( stream->num_outgoing_connections > 0 )
+ {
+ for( i = 0; i < stream->num_outgoing_connections; i++ )
+ jack_connect( stream->jack_client,
+ jack_port_name(stream->local_output_ports[i]),
+ jack_port_name(stream->remote_input_ports[i]) );
+ }
+
+ stream->is_running = TRUE;
+
+ return result;
+}
+
+
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaJackStream *stream = (PaJackStream*)s;
+
+ /* note: this automatically disconnects all ports, since a deactivated
+ * client is not allowed to have any ports connected */
+ jack_deactivate( stream->jack_client );
+
+ stream->is_running = FALSE;
+
+ /* TODO: block until playback complete */
+
+ stream->is_active = FALSE;
+
+ return result;
+}
+
+
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaJackStream *stream = (PaJackStream*)s;
+
+ /* There's no way to cancel samples already submitted, but we can
+ * return immediately */
+
+ /* note: this automatically disconnects all ports, since a deactivated
+ * client is not allowed to have any ports connected */
+ jack_deactivate( stream->jack_client );
+
+ stream->is_running = FALSE;
+ stream->is_active = FALSE;
+
+ return result;
+}
+
+
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaJackStream *stream = (PaJackStream*)s;
+
+ return stream->is_running == FALSE;
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+ PaJackStream *stream = (PaJackStream*)s;
+
+ return stream->is_active == TRUE;
+}
+
+
+static PaTimestamp GetStreamTime( PaStream *s )
+{
+ PaJackStream *stream = (PaJackStream*)s;
+
+ /* TODO: what if we're recording-only? */
+ return jack_frame_time( stream->jack_client ) - stream->t0;
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaJackStream *stream = (PaJackStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
diff --git a/pd/portaudio/pa_linux_alsa/blocking_calls.c b/pd/portaudio/pa_linux_alsa/blocking_calls.c
new file mode 100644
index 00000000..6304b117
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/blocking_calls.c
@@ -0,0 +1,61 @@
+
+#include "pa_stream.h"
+
+#include "pa_linux_alsa.h"
+
+PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ /* TODO: handle failure, xruns */
+
+ if( stream->capture_interleaved )
+ {
+ snd_pcm_mmap_readi( stream->pcm_capture, buffer, frames );
+ }
+ else
+ {
+ snd_pcm_mmap_readn( stream->pcm_capture, (void**)buffer, frames );
+ }
+
+ return paNoError;
+}
+
+
+PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ if( stream->playback_interleaved )
+ {
+ snd_pcm_mmap_writei( stream->pcm_playback, buffer, frames );
+ }
+ else
+ {
+ snd_pcm_mmap_writen( stream->pcm_playback, (void**)buffer, frames );
+ }
+
+ return paNoError;
+}
+
+
+unsigned long GetStreamReadAvailable( PaStream* s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ return snd_pcm_avail_update( stream->pcm_capture );
+}
+
+
+unsigned long GetStreamWriteAvailable( PaStream* s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ return snd_pcm_avail_update( stream->pcm_playback );
+}
+
+
diff --git a/pd/portaudio/pa_linux_alsa/blocking_calls.o b/pd/portaudio/pa_linux_alsa/blocking_calls.o
new file mode 100644
index 00000000..d4bc2108
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/blocking_calls.o
Binary files differ
diff --git a/pd/portaudio/pa_linux_alsa/callback_thread.c b/pd/portaudio/pa_linux_alsa/callback_thread.c
new file mode 100644
index 00000000..483557b6
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/callback_thread.c
@@ -0,0 +1,374 @@
+
+#include <sys/poll.h>
+#include <limits.h>
+#include <math.h> /* abs() */
+
+#include <alsa/asoundlib.h>
+
+#include "pa_linux_alsa.h"
+
+#define MIN(x,y) ( (x) < (y) ? (x) : (y) )
+
+static int wait( PaAlsaStream *stream )
+{
+ int need_capture;
+ int need_playback;
+ int capture_avail = INT_MAX;
+ int playback_avail = INT_MAX;
+ int common_avail;
+
+ if( stream->pcm_capture )
+ need_capture = 1;
+ else
+ need_capture = 0;
+
+ if( stream->pcm_playback )
+ need_playback = 1;
+ else
+ need_playback = 0;
+
+ while( need_capture || need_playback )
+ {
+ int playback_pfd_offset=0;
+ int total_fds = 0;
+
+ /* if the main thread has requested that we stop, do so now */
+ pthread_testcancel();
+
+ /*printf("still polling...\n");
+ if( need_capture )
+ printf("need capture.\n");
+ if( need_playback )
+ printf("need playback.\n"); */
+
+ /* get the fds, packing all applicable fds into a single array,
+ * so we can check them all with a single poll() call */
+
+ if( need_capture )
+ {
+ snd_pcm_poll_descriptors( stream->pcm_capture, stream->pfds,
+ stream->capture_nfds );
+ total_fds += stream->capture_nfds;
+ }
+
+ if( need_playback )
+ {
+ playback_pfd_offset = total_fds;
+ snd_pcm_poll_descriptors( stream->pcm_playback,
+ stream->pfds + playback_pfd_offset,
+ stream->playback_nfds );
+ total_fds += stream->playback_nfds;
+ }
+
+ /* now poll on the combination of playback and capture fds.
+ * TODO: handle interrupt and/or failure */
+ poll( stream->pfds, total_fds, 1000 );
+
+ /* check the return status of our pfds */
+ if( need_capture )
+ {
+ short revents;
+ snd_pcm_poll_descriptors_revents( stream->pcm_capture, stream->pfds,
+ stream->capture_nfds, &revents );
+ if( revents == POLLIN )
+ need_capture = 0;
+ }
+
+ if( need_playback )
+ {
+ short revents;
+ snd_pcm_poll_descriptors_revents( stream->pcm_playback,
+ stream->pfds + playback_pfd_offset,
+ stream->playback_nfds, &revents );
+ //if( revents & POLLOUT )
+ //if( revents & POLLERR )
+ // printf("polling error!");
+ if( revents == POLLOUT )
+ need_playback = 0;
+ }
+ }
+
+ /* we have now established that there are buffers ready to be
+ * operated on. Now determine how many frames are available. */
+ if( stream->pcm_capture )
+ capture_avail = snd_pcm_avail_update( stream->pcm_capture );
+
+ if( stream->pcm_playback )
+ playback_avail = snd_pcm_avail_update( stream->pcm_playback );
+
+ common_avail = MIN(capture_avail, playback_avail);
+ common_avail -= common_avail % stream->frames_per_period;
+
+ return common_avail;
+}
+
+static int setup_buffers( PaAlsaStream *stream, int frames_avail )
+{
+ int i;
+ int capture_frames_avail = INT_MAX;
+ int playback_frames_avail = INT_MAX;
+ int common_frames_avail;
+
+ if( stream->pcm_capture )
+ {
+ const snd_pcm_channel_area_t *capture_areas;
+ const snd_pcm_channel_area_t *area;
+ snd_pcm_uframes_t frames = frames_avail;
+
+ /* I do not understand this code fragment yet, it is copied out of the
+ * alsa-devel archives... */
+ snd_pcm_mmap_begin( stream->pcm_capture, &capture_areas,
+ &stream->capture_offset, &frames);
+
+ if( stream->capture_interleaved )
+ {
+ void *interleaved_capture_buffer;
+ area = &capture_areas[0];
+ interleaved_capture_buffer = area->addr +
+ (area->first + area->step * stream->capture_offset) / 8;
+ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
+ 0, /* starting at channel 0 */
+ interleaved_capture_buffer,
+ 0 /* default numInputChannels */
+ );
+ }
+ else
+ {
+ /* noninterleaved */
+ void *noninterleaved_capture_buffers[1000];
+ for( i = 0; i < stream->capture_channels; i++ )
+ {
+ area = &capture_areas[i];
+ noninterleaved_capture_buffers[i] = area->addr +
+ (area->first + area->step * stream->capture_offset) / 8;
+ PaUtil_SetNonInterleavedInputChannel( &stream->bufferProcessor,
+ i,
+ noninterleaved_capture_buffers[i]);
+ }
+ }
+
+ capture_frames_avail = frames;
+ }
+
+ if( stream->pcm_playback )
+ {
+ const snd_pcm_channel_area_t *playback_areas;
+ const snd_pcm_channel_area_t *area;
+ snd_pcm_uframes_t frames = frames_avail;
+
+ /* I do not understand this code fragment yet, it is copied out of the
+ * alsa-devel archives... */
+ snd_pcm_mmap_begin( stream->pcm_playback, &playback_areas,
+ &stream->playback_offset, &frames);
+
+ if( stream->playback_interleaved )
+ {
+ void *interleaved_playback_buffer;
+ area = &playback_areas[0];
+ interleaved_playback_buffer = area->addr +
+ (area->first + area->step * stream->playback_offset) / 8;
+ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
+ 0, /* starting at channel 0 */
+ interleaved_playback_buffer,
+ 0 /* default numInputChannels */
+ );
+ }
+ else
+ {
+ /* noninterleaved */
+ void *noninterleaved_playback_buffers[1000];
+ for( i = 0; i < stream->playback_channels; i++ )
+ {
+ area = &playback_areas[i];
+ noninterleaved_playback_buffers[i] = area->addr +
+ (area->first + area->step * stream->playback_offset) / 8;
+ PaUtil_SetNonInterleavedOutputChannel( &stream->bufferProcessor,
+ i,
+ noninterleaved_playback_buffers[i]);
+ }
+ }
+
+ playback_frames_avail = frames;
+ }
+
+
+ common_frames_avail = MIN(capture_frames_avail, playback_frames_avail);
+ common_frames_avail -= common_frames_avail % stream->frames_per_period;
+ //printf( "%d capture frames available\n", capture_frames_avail );
+ //printf( "%d frames playback available\n", playback_frames_avail );
+ //printf( "%d frames available\n", common_frames_avail );
+
+ if( stream->pcm_capture )
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, common_frames_avail );
+
+ if( stream->pcm_playback )
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, common_frames_avail );
+
+ return common_frames_avail;
+}
+
+void *CallbackThread( void *userData )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)userData;
+
+ if( stream->pcm_capture )
+ snd_pcm_start( stream->pcm_capture );
+ if( stream->pcm_playback )
+ snd_pcm_start( stream->pcm_playback );
+
+ while(1)
+ {
+ int frames_avail;
+ int frames_got;
+
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* IMPLEMENT ME */
+ int callbackResult;
+ int framesProcessed;
+
+ pthread_testcancel();
+ {
+ /* calculate time info */
+ snd_timestamp_t capture_timestamp;
+ snd_timestamp_t playback_timestamp;
+ snd_pcm_status_t *capture_status;
+ snd_pcm_status_t *playback_status;
+ snd_pcm_status_alloca( &capture_status );
+ snd_pcm_status_alloca( &playback_status );
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_status( stream->pcm_capture, capture_status );
+ snd_pcm_status_get_tstamp( capture_status, &capture_timestamp );
+ }
+ if( stream->pcm_playback )
+ {
+ snd_pcm_status( stream->pcm_playback, playback_status );
+ snd_pcm_status_get_tstamp( playback_status, &playback_timestamp );
+ }
+
+ /* Hmm, we potentially have both a playback and a capture timestamp.
+ * Hopefully they are the same... */
+ if( stream->pcm_capture && stream->pcm_playback )
+ {
+ float capture_time = capture_timestamp.tv_sec +
+ ((float)capture_timestamp.tv_usec/1000000);
+ float playback_time= playback_timestamp.tv_sec +
+ ((float)playback_timestamp.tv_usec/1000000);
+ if( fabsf(capture_time-playback_time) > 0.01 )
+ printf("Capture time and playback time differ by %f\n", fabsf(capture_time-playback_time));
+ timeInfo.currentTime = capture_time;
+ }
+ else if( stream->pcm_playback )
+ {
+ timeInfo.currentTime = playback_timestamp.tv_sec +
+ ((float)playback_timestamp.tv_usec/1000000);
+ }
+ else
+ {
+ timeInfo.currentTime = capture_timestamp.tv_sec +
+ ((float)capture_timestamp.tv_usec/1000000);
+ }
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_sframes_t capture_delay = snd_pcm_status_get_delay( capture_status );
+ timeInfo.inputBufferAdcTime = timeInfo.currentTime -
+ (float)capture_delay / stream->streamRepresentation.streamInfo.sampleRate;
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_sframes_t playback_delay = snd_pcm_status_get_delay( playback_status );
+ timeInfo.outputBufferDacTime = timeInfo.currentTime +
+ (float)playback_delay / stream->streamRepresentation.streamInfo.sampleRate;
+ }
+ }
+
+
+ /*
+ IMPLEMENT ME:
+ - handle buffer slips
+ */
+
+ /*
+ depending on whether the host buffers are interleaved, non-interleaved
+ or a mixture, you will want to call PaUtil_ProcessInterleavedBuffers(),
+ PaUtil_ProcessNonInterleavedBuffers() or PaUtil_ProcessBuffers() here.
+ */
+
+ frames_avail = wait( stream );
+ //printf( "%d frames available\n", frames_avail );
+
+ /* Now we know the soundcard is ready to produce/receive at least
+ * one period. We just need to get the buffers for the client
+ * to read/write. */
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo );
+
+ frames_got = setup_buffers( stream, frames_avail );
+
+ if( frames_avail == frames_got )
+ ;//printf("good, they were both %d\n", frames_avail );
+ else
+ printf("damn, they were different: avail: %d, got: %d\n", frames_avail, frames_got );
+
+ /* this calls the callback */
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor,
+ &callbackResult );
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+
+ /* inform ALSA how many frames we wrote */
+
+ if( stream->pcm_capture )
+ snd_pcm_mmap_commit( stream->pcm_capture, stream->capture_offset, frames_avail );
+
+ if( stream->pcm_playback )
+ snd_pcm_mmap_commit( stream->pcm_playback, stream->playback_offset, frames_avail );
+
+
+ /*
+ If you need to byte swap outputBuffer, you can do it here using
+ routines in pa_byteswappers.h
+ */
+
+ if( callbackResult == paContinue )
+ {
+ /* nothing special to do */
+ }
+ else if( callbackResult == paAbort )
+ {
+ stream->callback_finished = 1;
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_drop( stream->pcm_capture );
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_drop( stream->pcm_playback );
+ }
+ pthread_exit(NULL);
+ }
+ else
+ {
+ stream->callback_finished = 1;
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_drain( stream->pcm_capture );
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_drain( stream->pcm_playback );
+ }
+ pthread_exit(NULL);
+ }
+
+ }
+}
+
diff --git a/pd/portaudio/pa_linux_alsa/callback_thread.o b/pd/portaudio/pa_linux_alsa/callback_thread.o
new file mode 100644
index 00000000..a242d490
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/callback_thread.o
Binary files differ
diff --git a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c
new file mode 100644
index 00000000..9582b5b8
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.c
@@ -0,0 +1,989 @@
+/*
+ * $Id: pa_linux_alsa.c,v 1.1.2.3 2003/02/01 21:55:03 joshua Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * ALSA implementation by Joshua Haberman
+ *
+ * Copyright (c) 2002 Joshua Haberman <joshua@haberman.com>
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <sys/poll.h>
+#include <pthread.h>
+
+#include <string.h> /* strlen() */
+#include <limits.h>
+
+#include <alsa/asoundlib.h>
+
+#include "portaudio.h"
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
+
+#include "pa_linux_alsa.h"
+
+/* PaAlsaHostApiRepresentation - host api datastructure specific to this implementation */
+
+typedef struct
+{
+ PaUtilHostApiRepresentation commonHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
+
+ PaUtilAllocationGroup *allocations;
+
+ PaHostApiIndex hostApiIndex;
+}
+PaAlsaHostApiRepresentation;
+
+
+/* prototypes for functions declared in this file */
+
+PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *callback,
+ void *userData );
+static PaError CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError BuildDeviceList( PaAlsaHostApiRepresentation *hostApi );
+
+/* blocking calls are in blocking_calls.c */
+extern PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+extern PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+extern signed long GetStreamReadAvailable( PaStream* stream );
+extern signed long GetStreamWriteAvailable( PaStream* stream );
+
+/* all callback-related functions are in callback_thread.c */
+extern void *CallbackThread( void *userData );
+
+
+PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ int i, deviceCount;
+ PaAlsaHostApiRepresentation *skeletonHostApi;
+
+ skeletonHostApi = (PaAlsaHostApiRepresentation*)
+ PaUtil_AllocateMemory( sizeof(PaAlsaHostApiRepresentation) );
+ if( !skeletonHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ skeletonHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !skeletonHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ skeletonHostApi->hostApiIndex = hostApiIndex;
+ *hostApi = (PaUtilHostApiRepresentation*)skeletonHostApi;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paALSA;
+ (*hostApi)->info.name = "ALSA implementation";
+
+ BuildDeviceList( skeletonHostApi );
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+
+ PaUtil_InitializeStreamInterface( &skeletonHostApi->callbackStreamInterface,
+ CloseStream, StartStream,
+ StopStream, AbortStream,
+ IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite,
+ PaUtil_DummyGetAvailable,
+ PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &skeletonHostApi->blockingStreamInterface,
+ CloseStream, StartStream,
+ StopStream, AbortStream,
+ IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream,
+ GetStreamReadAvailable,
+ GetStreamWriteAvailable );
+
+ return result;
+
+error:
+ if( skeletonHostApi )
+ {
+ if( skeletonHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( skeletonHostApi );
+ }
+ return result;
+}
+
+static PaError BuildDeviceList( PaAlsaHostApiRepresentation *alsaApi )
+{
+ PaUtilHostApiRepresentation *commonApi = &alsaApi->commonHostApiRep;
+ PaDeviceInfo *deviceInfoArray;
+ int deviceCount = 0;
+ int card_idx;
+ int device_idx;
+ snd_ctl_t *ctl;
+ snd_ctl_card_info_t *card_info;
+
+ /* count the devices by enumerating all the card numbers */
+
+ /* snd_card_next() modifies the integer passed to it to be:
+ * the index of the first card if the parameter is -1
+ * the index of the next card if the parameter is the index of a card
+ * -1 if there are no more cards
+ *
+ * The function itself returns 0 if it succeeded. */
+ card_idx = -1;
+ while( snd_card_next( &card_idx ) == 0 && card_idx >= 0 )
+ {
+ deviceCount++;
+ }
+
+ /* allocate deviceInfo memory based on the number of devices */
+
+ commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ alsaApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
+ if( !commonApi->deviceInfos )
+ {
+ return paInsufficientMemory;
+ }
+
+ /* allocate all device info structs in a contiguous block */
+ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ alsaApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
+ if( !deviceInfoArray )
+ {
+ return paInsufficientMemory;
+ }
+
+ /* now loop over the list of devices again, filling in the deviceInfo for each */
+ card_idx = -1;
+ device_idx = 0;
+ while( snd_card_next( &card_idx ) == 0 && card_idx >= 0 )
+ {
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[device_idx];
+ char *deviceName;
+ char alsaDeviceName[50];
+ const char *cardName;
+
+ commonApi->deviceInfos[device_idx++] = deviceInfo;
+
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = alsaApi->hostApiIndex;
+
+ sprintf( alsaDeviceName, "hw:%d", card_idx );
+ snd_ctl_open( &ctl, alsaDeviceName, 0 );
+ snd_ctl_card_info_malloc( &card_info );
+ snd_ctl_card_info( ctl, card_info );
+ cardName = snd_ctl_card_info_get_id( card_info );
+
+ deviceName = (char*)PaUtil_GroupAllocateMemory( alsaApi->allocations,
+ strlen(cardName) + 1 );
+ if( !deviceName )
+ {
+ return paInsufficientMemory;
+ }
+ strcpy( deviceName, cardName );
+ deviceInfo->name = deviceName;
+
+ snd_ctl_card_info_free( card_info );
+
+ /* to determine max. channels, we must open the device and query the
+ * hardware parameter configuration space */
+ {
+ snd_pcm_t *pcm_handle;
+ snd_pcm_hw_params_t *hw_params;
+ int dir;
+
+ snd_pcm_hw_params_malloc( &hw_params );
+
+ /* get max channels for capture */
+
+ if( snd_pcm_open( &pcm_handle, alsaDeviceName, SND_PCM_STREAM_CAPTURE, 0 ) < 0 )
+ {
+ deviceInfo->maxInputChannels = 0;
+ }
+ else
+ {
+ snd_pcm_hw_params_any( pcm_handle, hw_params );
+ deviceInfo->maxInputChannels = snd_pcm_hw_params_get_channels_max( hw_params );
+ /* TODO: I'm not really sure what to do here */
+ //deviceInfo->defaultLowInputLatency = snd_pcm_hw_params_get_period_size_min( hw_params, &dir );
+ //deviceInfo->defaultHighInputLatency = snd_pcm_hw_params_get_period_size_max( hw_params, &dir );
+ deviceInfo->defaultLowInputLatency = 128. / 44100;
+ deviceInfo->defaultHighInputLatency = 16384. / 44100;
+ snd_pcm_close( pcm_handle );
+ }
+
+ /* get max channels for playback */
+ if( snd_pcm_open( &pcm_handle, alsaDeviceName, SND_PCM_STREAM_PLAYBACK, 0 ) < 0 )
+ {
+ deviceInfo->maxOutputChannels = 0;
+ }
+ else
+ {
+ snd_pcm_hw_params_any( pcm_handle, hw_params );
+ deviceInfo->maxOutputChannels = snd_pcm_hw_params_get_channels_max( hw_params );
+ /* TODO: I'm not really sure what to do here */
+ //deviceInfo->defaultLowOutputLatency = snd_pcm_hw_params_get_period_size_min( hw_params, &dir );
+ //deviceInfo->defaultHighOutputLatency = snd_pcm_hw_params_get_period_size_max( hw_params, &dir );
+ deviceInfo->defaultLowOutputLatency = 128. / 44100;
+ deviceInfo->defaultHighOutputLatency = 16384. / 44100;
+ snd_pcm_close( pcm_handle );
+ }
+
+ snd_pcm_hw_params_free( hw_params );
+ }
+
+ deviceInfo->defaultSampleRate = 44100.; /* IMPLEMENT ME */
+ }
+
+ commonApi->info.deviceCount = deviceCount;
+ commonApi->info.defaultInputDevice = 0;
+ commonApi->info.defaultOutputDevice = 0;
+
+ return paNoError;
+}
+
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaAlsaHostApiRepresentation *skeletonHostApi;
+ skeletonHostApi = (PaAlsaHostApiRepresentation*)hostApi;
+
+ /*
+ IMPLEMENT ME:
+ - clean up any resourced not handled by the allocation group
+ */
+
+ if( skeletonHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( skeletonHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( skeletonHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( skeletonHostApi );
+}
+
+
+/* Given an open stream, what sample formats are available? */
+
+static PaSampleFormat GetAvailableFormats( snd_pcm_t *stream )
+{
+ PaSampleFormat available = 0;
+ snd_pcm_hw_params_t *hw_params;
+ snd_pcm_hw_params_alloca( &hw_params );
+
+ snd_pcm_hw_params_any( stream, hw_params );
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_FLOAT ) == 0)
+ available |= paFloat32;
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S16 ) == 0)
+ available |= paInt16;
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S24 ) == 0)
+ available |= paInt24;
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S32 ) == 0)
+ available |= paInt32;
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_S8 ) == 0)
+ available |= paInt8;
+
+ if( snd_pcm_hw_params_test_format( stream, hw_params, SND_PCM_FORMAT_U8 ) == 0)
+ available |= paUInt8;
+
+ return available;
+}
+
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
+
+static PaError ConfigureStream( snd_pcm_t *stream, int channels,
+ int interleaved, unsigned long rate,
+ PaSampleFormat pa_format, int framesPerBuffer )
+{
+#define ENSURE(functioncall) \
+ if( (functioncall) < 0 ) { \
+ printf("Error executing ALSA call, line %d\n", __LINE__); \
+ return 1; \
+ } \
+ else { \
+ printf("ALSA call at line %d succeeded\n", __LINE__ ); \
+ }
+
+ snd_pcm_access_t access_mode;
+ snd_pcm_format_t alsa_format;
+
+ /* configuration consists of setting all of ALSA's parameters.
+ * These parameters come in two flavors: hardware parameters
+ * and software paramters. Hardware parameters will affect
+ * the way the device is initialized, software parameters
+ * affect the way ALSA interacts with me, the user-level client. */
+
+ snd_pcm_hw_params_t *hw_params;
+ snd_pcm_sw_params_t *sw_params;
+
+ snd_pcm_hw_params_alloca( &hw_params );
+
+ /* ... fill up the configuration space with all possibile
+ * combinations of parameters this device will accept */
+ ENSURE( snd_pcm_hw_params_any( stream, hw_params ) );
+
+ if( interleaved )
+ access_mode = SND_PCM_ACCESS_MMAP_INTERLEAVED;
+ else
+ access_mode = SND_PCM_ACCESS_MMAP_NONINTERLEAVED;
+
+ ENSURE( snd_pcm_hw_params_set_access( stream, hw_params, access_mode ) );
+
+ /* set the format based on what the user selected */
+ switch( pa_format )
+ {
+ case paFloat32:
+ alsa_format = SND_PCM_FORMAT_FLOAT;
+ break;
+
+ case paInt16:
+ alsa_format = SND_PCM_FORMAT_S16;
+ break;
+
+ case paInt24:
+ alsa_format = SND_PCM_FORMAT_S24;
+ break;
+
+ case paInt32:
+ alsa_format = SND_PCM_FORMAT_S32;
+ break;
+
+ case paInt8:
+ alsa_format = SND_PCM_FORMAT_S8;
+ break;
+
+ case paUInt8:
+ alsa_format = SND_PCM_FORMAT_U8;
+ break;
+
+ default:
+ printf("Unknown PortAudio format %d\n", (int)pa_format );
+ return 1;
+ }
+ //printf("PortAudio format: %d\n", pa_format);
+ printf("ALSA format: %d\n", alsa_format);
+ ENSURE( snd_pcm_hw_params_set_format( stream, hw_params, alsa_format ) );
+
+ /* ... set the sample rate */
+ ENSURE( snd_pcm_hw_params_set_rate( stream, hw_params, rate, 0 ) );
+
+ /* ... set the number of channels */
+ ENSURE( snd_pcm_hw_params_set_channels( stream, hw_params, channels ) );
+
+ /* ... set the number of periods to 2, which is essentially double buffering.
+ * this makes the latency the number of samples per buffer, which is the best
+ * it can be */
+ ENSURE( snd_pcm_hw_params_set_periods ( stream, hw_params, 2, 0 ) );
+
+ /* ... set the period size, which is essentially the hardware buffer size */
+ if( framesPerBuffer != 0 )
+ {
+ ENSURE( snd_pcm_hw_params_set_period_size( stream, hw_params,
+ framesPerBuffer, 0 ) );
+ }
+ else
+ {
+ ENSURE( snd_pcm_hw_params_set_period_size( stream, hw_params,
+ 2048, 0 ) );
+ }
+
+
+ /* Set the parameters! */
+ ENSURE( snd_pcm_hw_params( stream, hw_params ) );
+
+ return 0;
+#undef ENSURE
+}
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *callback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaAlsaHostApiRepresentation *skeletonHostApi =
+ (PaAlsaHostApiRepresentation*)hostApi;
+ PaAlsaStream *stream = 0;
+ PaSampleFormat hostInputSampleFormat=0, hostOutputSampleFormat=0;
+ int numInputChannels, numOutputChannels;
+ PaSampleFormat inputSampleFormat=0, outputSampleFormat=0;
+ unsigned long framesPerHostBuffer = framesPerBuffer;
+
+ if( framesPerHostBuffer == paFramesPerBufferUnspecified )
+ {
+ // TODO: have some reason
+ framesPerHostBuffer = 2048;
+ }
+
+ if( inputParameters )
+ {
+ numInputChannels = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification.
+ [JH] this could be supported in the future, to allow ALSA device strings
+ like hw:0 */
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support numInputChannels */
+ if( numInputChannels > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numInputChannels = 0;
+ }
+
+ if( outputParameters )
+ {
+ numOutputChannels = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification
+ [JH] this could be supported in the future, to allow ALSA device strings
+ like hw:0 */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support numInputChannels */
+ if( numOutputChannels > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ numOutputChannels = 0;
+ }
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
+
+ /* allocate and do basic initialization of the stream structure */
+
+ stream = (PaAlsaStream*)PaUtil_AllocateMemory( sizeof(PaAlsaStream) );
+ if( !stream )
+ {
+ printf("memory point 2\n");
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ stream->pcm_capture = NULL;
+ stream->pcm_playback = NULL;
+ stream->callback_mode = (callback != 0);
+ stream->callback_finished = 0;
+
+ if( callback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &skeletonHostApi->callbackStreamInterface,
+ callback, userData );
+ }
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &skeletonHostApi->blockingStreamInterface,
+ callback, userData );
+ }
+
+
+ stream->streamRepresentation.streamInfo.inputLatency = framesPerHostBuffer;
+ stream->streamRepresentation.streamInfo.outputLatency = framesPerHostBuffer;
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+ /* open the devices now, so we can obtain info about the available formats */
+
+ if( numInputChannels > 0 )
+ {
+ char inputDeviceName[50];
+
+ sprintf( inputDeviceName, "hw:CARD=%s", hostApi->deviceInfos[inputParameters->device]->name );
+ if( snd_pcm_open( &stream->pcm_capture, inputDeviceName, SND_PCM_STREAM_CAPTURE, 0 ) < 0 )
+ {
+ result = paBadIODeviceCombination;
+ goto error;
+ }
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( GetAvailableFormats(stream->pcm_capture),
+ inputSampleFormat );
+ }
+
+ if( numOutputChannels > 0 )
+ {
+ char outputDeviceName[50];
+
+ sprintf( outputDeviceName, "hw:CARD=%s", hostApi->deviceInfos[outputParameters->device]->name );
+ if( snd_pcm_open( &stream->pcm_playback, outputDeviceName, SND_PCM_STREAM_PLAYBACK, 0 ) < 0 )
+ {
+ result = paBadIODeviceCombination;
+ goto error;
+ }
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( GetAvailableFormats(stream->pcm_playback),
+ outputSampleFormat );
+ stream->playback_hostsampleformat = hostOutputSampleFormat;
+ }
+
+
+
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ numInputChannels, inputSampleFormat, hostInputSampleFormat,
+ numOutputChannels, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer, framesPerHostBuffer,
+ paUtilFixedHostBufferSize, callback, userData );
+ if( result != paNoError )
+ goto error;
+
+ /* configure the streams */
+
+ if( numInputChannels > 0 )
+ {
+ int interleaved;
+ PaSampleFormat plain_format = hostInputSampleFormat & ~paNonInterleaved;
+
+ if( inputSampleFormat & paNonInterleaved )
+ interleaved = 0;
+ else
+ interleaved = 1;
+
+ if( ConfigureStream( stream->pcm_capture, numInputChannels, interleaved,
+ sampleRate, plain_format, framesPerHostBuffer ) != 0 )
+ {
+ result = paBadIODeviceCombination;
+ goto error;
+ }
+
+ stream->capture_interleaved = interleaved;
+ }
+
+ if( numOutputChannels > 0 )
+ {
+ int interleaved;
+ PaSampleFormat plain_format = hostOutputSampleFormat & ~paNonInterleaved;
+
+ if( outputSampleFormat & paNonInterleaved )
+ interleaved = 0;
+ else
+ interleaved = 1;
+
+ if( ConfigureStream( stream->pcm_playback, numOutputChannels, interleaved,
+ sampleRate, plain_format, framesPerHostBuffer ) != 0 )
+ {
+ result = paBadIODeviceCombination;
+ goto error;
+ }
+
+ stream->playback_interleaved = interleaved;
+ }
+
+ stream->capture_nfds = 0;
+ stream->playback_nfds = 0;
+
+ if( stream->pcm_capture )
+ stream->capture_nfds = snd_pcm_poll_descriptors_count( stream->pcm_capture );
+
+ if( stream->pcm_playback )
+ stream->playback_nfds = snd_pcm_poll_descriptors_count( stream->pcm_playback );
+
+ /* TODO: free this properly */
+ printf("trying to allocate %d bytes of memory\n", (stream->capture_nfds + stream->playback_nfds + 1) * sizeof(struct pollfd) );
+ stream->pfds = (struct pollfd*)PaUtil_AllocateMemory( (stream->capture_nfds +
+ stream->playback_nfds + 1) *
+ sizeof(struct pollfd) );
+ if( !stream->pfds )
+ {
+ printf("bad memory point 1\n");
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ stream->frames_per_period = framesPerHostBuffer;
+ stream->capture_channels = numInputChannels;
+ stream->playback_channels = numOutputChannels;
+
+ *s = (PaStream*)stream;
+
+ return result;
+
+error:
+ if( stream )
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_close( stream->pcm_capture );
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_close( stream->pcm_playback );
+ }
+
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ /* TODO: support errorText */
+#define ENSURE(x) \
+ { \
+ int error_ret; \
+ error_ret = (x); \
+ if( error_ret != 0 ) { \
+ PaHostErrorInfo err; \
+ err.errorCode = error_ret; \
+ err.hostApiType = paALSA; \
+ printf("call at %d failed\n", __LINE__); \
+ return paUnanticipatedHostError; \
+ } \
+ else \
+ printf("call at line %d succeeded\n", __LINE__); \
+ }
+
+ if( stream->pcm_capture )
+ {
+ ENSURE( snd_pcm_prepare( stream->pcm_capture ) );
+ }
+
+ if( stream->pcm_playback )
+ {
+ const snd_pcm_channel_area_t *playback_areas, *area;
+ snd_pcm_uframes_t offset, frames;
+ int sample_size = Pa_GetSampleSize( stream->playback_hostsampleformat );
+ printf("Sample size: %d\n", sample_size );
+ ENSURE( snd_pcm_prepare( stream->pcm_playback ) );
+ frames = snd_pcm_avail_update( stream->pcm_playback );
+ printf("frames: %d\n", (int)frames );
+ printf("channels: %d\n", stream->playback_channels );
+
+ snd_pcm_mmap_begin( stream->pcm_playback, &playback_areas, &offset, &frames );
+
+ /* Insert silence */
+ if( stream->playback_interleaved )
+ {
+ void *playback_buffer;
+ area = &playback_areas[0];
+ playback_buffer = area->addr + (area->first + area->step * offset) / 8;
+ memset( playback_buffer, 0,
+ frames * stream->playback_channels * sample_size );
+ }
+ else
+ {
+ int i;
+ for( i = 0; i < stream->playback_channels; i++ )
+ {
+ void *channel_buffer;
+ area = &playback_areas[i];
+ channel_buffer = area->addr + (area->first + area->step * offset) / 8;
+ memset( channel_buffer, 0, frames * sample_size );
+ }
+ }
+
+ snd_pcm_mmap_commit( stream->pcm_playback, offset, frames );
+ }
+
+ if( stream->callback_mode )
+ {
+ ENSURE( pthread_create( &stream->callback_thread, NULL, &CallbackThread, stream ) );
+
+ /* we'll do the snd_pcm_start() in the callback thread */
+ }
+ else
+ {
+ if( stream->pcm_capture )
+ snd_pcm_start( stream->pcm_capture );
+ if( stream->pcm_playback )
+ snd_pcm_start( stream->pcm_playback );
+ }
+
+ /* On my machine, the pcm stream will not transition to the RUNNING
+ * state for a while after snd_pcm_start is called. The PortAudio
+ * client needs to be able to depend on Pa_IsStreamActive() returning
+ * true the second after this function returns. So I sleep briefly here.
+ *
+ * I don't like this one bit.
+ */
+ Pa_Sleep( 100 );
+
+ stream->callback_finished = 0;
+
+ return result;
+}
+
+
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ /* First deal with the callback thread, cancelling and/or joining
+ * it if necessary
+ */
+
+ if( stream->callback_mode && stream->callback_finished )
+ {
+ /* We are running in callback mode but the callback thread has
+ * already been cancelled by the return value from the user's
+ * callback function. Therefore we don't need to cancel the
+ * thread, but we do want to wait for it. */
+ pthread_join( stream->callback_thread, NULL );
+ }
+ else if( stream->callback_mode )
+ {
+ /* We are running in callback mode, and the callback thread
+ * is still running. Cancel it and wait for it to be done. */
+ pthread_cancel( stream->callback_thread );
+ pthread_join( stream->callback_thread, NULL );
+ }
+
+ /* Stop the ALSA streams if necessary */
+
+ if( stream->callback_mode && stream->callback_finished )
+ {
+ /* If we are in the callback_finished state the callback thread
+ * already stopped the streams. So there is nothing to do here.
+ */
+ }
+ else
+ {
+ if( stream->pcm_capture )
+ {
+ snd_pcm_drain( stream->pcm_capture );
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_drain( stream->pcm_playback );
+ }
+ }
+
+ stream->callback_finished = 0;
+
+ return result;
+}
+
+
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ /* First deal with the callback thread, cancelling and/or joining
+ * it if necessary
+ */
+
+ if( stream->callback_mode && stream->callback_finished )
+ {
+ /* We are running in callback mode but the callback thread has
+ * already been cancelled by the return value from the user's
+ * callback function. Therefore we don't need to cancel the
+ * thread, but we do want to wait for it. */
+ pthread_join( stream->callback_thread, NULL );
+ }
+ else if( stream->callback_mode )
+ {
+ /* We are running in callback mode, and the callback thread
+ * is still running. Cancel it and wait for it to be done. */
+ pthread_cancel( stream->callback_thread );
+ pthread_join( stream->callback_thread, NULL );
+ }
+
+ /* Stop the ALSA streams if necessary */
+
+ if( stream->callback_mode && stream->callback_finished )
+ {
+ /* If we are in the callback_finished state the callback thread
+ * already stopped the streams. So there is nothing to do here.
+ */
+ }
+ else
+ {
+ if( stream->pcm_capture )
+ {
+ snd_pcm_drop( stream->pcm_capture );
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_drop( stream->pcm_playback );
+ }
+ }
+
+ stream->callback_finished = 0;
+
+ return result;
+}
+
+
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ if( IsStreamActive(s) || stream->callback_finished )
+ return 0;
+ else
+ return 1;
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_state_t capture_state = snd_pcm_state( stream->pcm_capture );
+
+ if( capture_state == SND_PCM_STATE_RUNNING /*||
+ capture_state == SND_PCM_STATE_PREPARED*/ )
+ return 1;
+ }
+
+ if( stream->pcm_playback )
+ {
+ snd_pcm_state_t playback_state = snd_pcm_state( stream->pcm_playback );
+
+ if( playback_state == SND_PCM_STATE_RUNNING /*||
+ playback_state == SND_PCM_STATE_PREPARED*/ )
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static PaTime GetStreamTime( PaStream *s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ snd_output_t *output;
+ snd_timestamp_t timestamp;
+ snd_pcm_status_t *status;
+ snd_pcm_status_alloca( &status );
+
+ /* TODO: what if we have both? does it really matter? */
+
+ /* TODO: if running in callback mode, this will mean
+ * libasound routines are being called form multiple threads.
+ * need to verify that libasound is thread-safe. */
+
+ if( stream->pcm_capture )
+ {
+ snd_pcm_status( stream->pcm_capture, status );
+ }
+ else if( stream->pcm_playback )
+ {
+ snd_pcm_status( stream->pcm_playback, status );
+ }
+
+ snd_pcm_status_get_tstamp( status, &timestamp );
+
+ return timestamp.tv_sec + ((float)timestamp.tv_usec/1000000);
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaAlsaStream *stream = (PaAlsaStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
diff --git a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.h b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.h
new file mode 100644
index 00000000..62c9512c
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.h
@@ -0,0 +1,45 @@
+
+#include <alsa/asoundlib.h>
+
+#include <pthread.h>
+
+#include "pa_util.h"
+#include "pa_process.h"
+#include "pa_cpuload.h"
+#include "pa_stream.h"
+
+typedef struct PaAlsaStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ snd_pcm_t *pcm_capture;
+ snd_pcm_t *pcm_playback;
+
+ int callback_finished; /* bool: are we in the "callback finished" state? */
+
+ int frames_per_period;
+ int playback_hostsampleformat;
+
+ int capture_channels;
+ int playback_channels;
+
+ int capture_interleaved; /* bool: is capture interleaved? */
+ int playback_interleaved; /* bool: is playback interleaved? */
+
+ int callback_mode; /* bool: are we running in callback mode? */
+ pthread_t callback_thread;
+
+ /* the callback thread uses these to poll the sound device, waiting
+ * for data to be ready/available */
+ unsigned int capture_nfds;
+ unsigned int playback_nfds;
+ struct pollfd *pfds;
+
+ /* these aren't really stream state, the callback uses them */
+ snd_pcm_uframes_t capture_offset;
+ snd_pcm_uframes_t playback_offset;
+}
+PaAlsaStream;
+
diff --git a/pd/portaudio/pa_linux_alsa/pa_linux_alsa.o b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.o
new file mode 100644
index 00000000..f79af61d
--- /dev/null
+++ b/pd/portaudio/pa_linux_alsa/pa_linux_alsa.o
Binary files differ
diff --git a/pd/portaudio/pa_mac_core/notes.txt b/pd/portaudio/pa_mac_core/notes.txt
index 3b557d9a..c79b90e6 100644
--- a/pd/portaudio/pa_mac_core/notes.txt
+++ b/pd/portaudio/pa_mac_core/notes.txt
@@ -2,25 +2,25 @@ Notes on Core Audio Implementation of PortAudio
by Phil Burk and Darren Gibbs
-Document last updated October 18, 2002
+Document last updated March 20, 2002
WHAT WORKS
Output with very low latency, <10 msec.
Half duplex input or output.
-Full duplex
+Full duplex on the same CoreAudio device.
The paFLoat32, paInt16, paInt8, paUInt8 sample formats.
Pa_GetCPULoad()
Pa_StreamTime()
KNOWN BUGS OR LIMITATIONS
-The iMic supports multiple sample rates.
-But there is a bug when changing sample rates:
- Run patest_record.c at rate A - it works.
- Then run patest_record.c at rate B - it FAIL!
- Then run patest_record.c again at rate B - it works!
+We do not yet support simultaneous input and output on different
+devices. Note that some CoreAudio devices like the Roland UH30 look
+like one device but are actually two different CoreAudio devices. The
+BuiltIn audio is typically one CoreAudio device.
+Mono doesn't work.
DEVICE MAPPING
diff --git a/pd/portaudio/pa_mac_core/pa_mac_core.c b/pd/portaudio/pa_mac_core/pa_mac_core.c
index de781d09..9a4b1488 100644
--- a/pd/portaudio/pa_mac_core/pa_mac_core.c
+++ b/pd/portaudio/pa_mac_core/pa_mac_core.c
@@ -1,5 +1,5 @@
/*
- * $Id: pa_mac_core.c,v 1.8.4.3 2002/10/18 01:29:06 philburk Exp $
+ * $Id: pa_mac_core.c,v 1.8 2002/04/12 18:07:20 philburk Exp $
* pa_mac_core.c
* Implementation of PortAudio for Mac OS X Core Audio
*
@@ -7,18 +7,7 @@
* Latest Version at: http://www.portaudio.com
*
* Authors: Ross Bencina and Phil Burk
- * Copyright (c) 1999-2002 Ross Bencina and Phil Burk
- *
- * Theory of Operation
- *
- * This code uses the HAL (Hardware Access Layer) of the Apple CoreAudio library.
- * This is the layer closes to the hardware.
- * The HAL layer only supports the native HW supported sample rates.
- * So if the chip only supports 44100 Hz, then the HAL only supports 44100.
- * To provide other rates we use the handy Apple AUConverter which provides
- * sample rate conversion, mono-to-stereo conversion, and buffer size adaptation.
- *
- * License
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
@@ -54,28 +43,18 @@
audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices).
2.22.2002 - Stephane Letz - Explicit cast needed for compilation with Code Warrior 7
3.19.2002 - Phil Burk - Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file.
- Return error if opened in mono mode cuz not supported. [Supported 10.12.2002]
+ Return error if opened in mono mode cuz not supported.
Add support for Pa_GetCPULoad();
Fixed timestamp in callback and Pa_StreamTime() (Thanks n++k for the advice!)
Check for invalid sample rates and return an error.
- Check for getenv("PA_MIN_LATENCY_MSEC") to set latency externally.
+ Check for getenv("PA_MIN_LATEWNCY_MSEC") to set latency externally.
Better error checking for invalid channel counts and invalid devices.
3.29.2002 - Phil Burk - Fixed Pa_GetCPULoad() for small buffers.
3.31.2002 - Phil Burk - Use getrusage() instead of gettimeofday() for CPU Load calculation.
- 10.12.2002 - Phil Burk - Use AudioConverter to allow wide range of sample rates, and mono.
- Use FIFO (from pablio/rinbuffer.h) so that we can pull data through converter.
- Added PaOSX_FixVolumeScalar() to make iMic audible.
- 10.17.2002 - Phil Burk - Support full duplex between two different devices.
- Name internal functions PaOSX_*
- Dumped useless PA_MIN_LATENCY_MSEC environment variable.
- Use kAudioDevicePropertyStreamFormatMatch to determine max channels.
TODO:
-O- debug problem when changing sample rates on iMic
-O- add support for paInt32 format
-O- Why does iMic have grunge for the first second or two then clears up?
-O- request notification when formats change or device unplugged
-O- Why does patest_wire.c on iMic chop up sound when SR=34567Hz?
+O- how do mono output?
+O- FIFO between input and output callbacks if different devices, like in pa_mac.c
*/
#include <CoreServices/CoreServices.h>
@@ -83,14 +62,10 @@ O- Why does patest_wire.c on iMic chop up sound when SR=34567Hz?
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
-#include <AudioUnit/AudioUnit.h>
-#include <AudioToolbox/DefaultAudioOutput.h>
-#include <AudioToolbox/AudioConverter.h>
#include "portaudio.h"
#include "pa_host.h"
#include "pa_trace.h"
-#include "ringbuffer.h"
/************************************************* Constants ********/
@@ -98,45 +73,37 @@ O- Why does patest_wire.c on iMic chop up sound when SR=34567Hz?
#define PA_TRACE_RUN (0)
#define PA_TRACE_START_STOP (1)
-#define PA_MIN_LATENCY_MSEC (1)
+#define PA_MIN_LATENCY_MSEC (8)
#define MIN_TIMEOUT_MSEC (1000)
#define PRINT(x) { printf x; fflush(stdout); }
-#define PRINT_ERR( msg, err ) PRINT(( msg ": error = 0x%0lX = '%s'\n", (err), ErrorToString(err)) )
-#define DBUG(x) /* PRINT(x) */
-#define DBUGBACK(x) /* if( sMaxBackgroundErrorMessages-- > 0 ) PRINT(x) */
-#define DBUGX(x)
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) /**/
+#define DBUGX(x) /* PRINT(x) /**/
// define value of isInput passed to CoreAudio routines
#define IS_INPUT (true)
#define IS_OUTPUT (false)
-typedef struct PaHostInOut
-{
- AudioDeviceID audioDeviceID; // CoreAudio specific ID
- int bytesPerUserNativeBuffer; /* User buffer size in native host format. Depends on numChannels. */
- AudioConverterRef converter;
- void *converterBuffer;
-} PaHostInOut;
-
/**************************************************************
* Structure for internal host specific stream data.
* This is allocated on a per stream basis.
*/
typedef struct PaHostSoundControl
{
- PaHostInOut input;
- PaHostInOut output;
- AudioDeviceID primaryDeviceID;
- Boolean usingSecondDevice;
- int framesPerHostBuffer;
- /* For sample rate, format conversion, or when using two devices. */
- RingBuffer ringBuffer;
- char *ringBufferData;
+ AudioDeviceID pahsc_AudioDeviceID; // Must be the same for input and output for now.
+ /* Input -------------- */
+ int pahsc_BytesPerUserNativeInputBuffer; /* native buffer size in bytes per user chunk */
+ /* Output -------------- */
+ int pahsc_BytesPerUserNativeOutputBuffer; /* native buffer size in bytes per user chunk */
+ /* Init Time -------------- */
+ int pahsc_FramesPerHostBuffer;
+ int pahsc_UserBuffersPerHostBuffer;
/* For measuring CPU utilization. */
- struct rusage entryRusage;
- double inverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
-} PaHostSoundControl;
+ struct rusage pahsc_EntryRusage;
+ double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
+}
+PaHostSoundControl;
/**************************************************************
* Structure for internal extended device info.
@@ -158,18 +125,14 @@ static int sNumOutputDevices = 0;
static PaHostDeviceInfo *sDeviceInfos = NULL;
static int sDefaultInputDeviceID = paNoDevice;
static int sDefaultOutputDeviceID = paNoDevice;
-static int sSavedHostError = 0;
+static int sPaHostError = 0;
+
static int sNumCoreDevices = 0;
static AudioDeviceID *sCoreDeviceIDs; // Array of Core AudioDeviceIDs
-static const double supportedSampleRateRange[] = { 8000.0, 96000.0 };
static const char sMapperSuffixInput[] = " - Input";
static const char sMapperSuffixOutput[] = " - Output";
-/* Debug support. */
-//static int sMaxBackgroundErrorMessages = 100;
-//static int sCoverageCounter = 1; // used to check code coverage during validation
-
/* We index the input devices first, then the output devices. */
#define LOWEST_INPUT_DEVID (0)
#define HIGHEST_INPUT_DEVID (sNumInputDevices - 1)
@@ -180,64 +143,15 @@ static const char sMapperSuffixOutput[] = " - Output";
/************************************************* Prototypes **********/
-static PaError PaOSX_QueryDevices( void );
-static int PaOSX_ScanDevices( Boolean isInput );
-static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput );
-static PaDeviceID PaOSX_QueryDefaultInputDevice( void );
-static PaDeviceID PaOSX_QueryDefaultOutputDevice( void );
-static void PaOSX_CalcHostBufferSize( internalPortAudioStream *past );
-
-/**********************************************************************/
-/* OS X errors are 4 character ID that can be printed.
- * Note that uses a static pad so result must be printed immediately.
- */
-static OSStatus statusText[2] = { 0, 0 };
-static const char *ErrorToString( OSStatus err )
-{
- const char *str;
-
- switch (err)
- {
- case kAudioHardwareUnspecifiedError:
- str = "kAudioHardwareUnspecifiedError";
- break;
- case kAudioHardwareNotRunningError:
- str = "kAudioHardwareNotRunningError";
- break;
- case kAudioHardwareUnknownPropertyError:
- str = "kAudioHardwareUnknownPropertyError";
- break;
- case kAudioDeviceUnsupportedFormatError:
- str = "kAudioDeviceUnsupportedFormatError";
- break;
- case kAudioHardwareBadPropertySizeError:
- str = "kAudioHardwareBadPropertySizeError";
- break;
- case kAudioHardwareIllegalOperationError:
- str = "kAudioHardwareIllegalOperationError";
- break;
- default:
- str = "Unknown CoreAudio Error!";
- statusText[0] = err;
- str = (const char *)statusText;
- break;
- }
+static PaError Pa_QueryDevices( void );
+PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past );
- return str;
-}
+static int PaHost_ScanDevices( Boolean isInput );
+static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput );
-/**********************************************************************/
-static unsigned long RoundUpToNextPowerOf2( unsigned long n )
-{
- long numBits = 0;
- if( ((n-1) & n) == 0) return n; /* Already Power of two. */
- while( n > 0 )
- {
- n= n>>1;
- numBits++;
- }
- return (1<<numBits);
-}
+static PaDeviceID Pa_QueryDefaultInputDevice( void );
+static PaDeviceID Pa_QueryDefaultOutputDevice( void );
+static void PaHost_CalcHostBufferSize( internalPortAudioStream *past );
/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
static void Pa_StartUsageCalculation( internalPortAudioStream *past )
@@ -245,7 +159,7 @@ static void Pa_StartUsageCalculation( internalPortAudioStream *past )
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return;
/* Query user CPU timer for usage analysis and to prevent overuse of CPU. */
- getrusage( RUSAGE_SELF, &pahsc->entryRusage );
+ getrusage( RUSAGE_SELF, &pahsc->pahsc_EntryRusage );
}
static long SubtractTime_AminusB( struct timeval *timeA, struct timeval *timeB )
@@ -274,10 +188,10 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past )
if( getrusage( RUSAGE_SELF, &currentRusage ) == 0 )
{
- usecsElapsed = SubtractTime_AminusB( &currentRusage.ru_utime, &pahsc->entryRusage.ru_utime );
+ usecsElapsed = SubtractTime_AminusB( &currentRusage.ru_utime, &pahsc->pahsc_EntryRusage.ru_utime );
/* Use inverse because it is faster than the divide. */
- newUsage = usecsElapsed * pahsc->inverseMicrosPerHostBuffer;
+ newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer;
past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
(LOWPASS_COEFFICIENT_1 * newUsage);
@@ -286,104 +200,92 @@ static void Pa_EndUsageCalculation( internalPortAudioStream *past )
/****************************************** END CPU UTILIZATION *******/
/************************************************************************/
-static PaDeviceID PaOSX_QueryDefaultInputDevice( void )
+static PaDeviceID Pa_QueryDefaultInputDevice( void )
{
- OSStatus err = noErr;
- UInt32 count;
- int i;
+ OSStatus err = noErr;
+ UInt32 count;
+ int i;
AudioDeviceID tempDeviceID = kAudioDeviceUnknown;
- PaDeviceID defaultDeviceID = paNoDevice;
+ PaDeviceID defaultDeviceID = paNoDevice;
// get the default output device for the HAL
// it is required to pass the size of the data to be returned
count = sizeof(tempDeviceID);
err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice, &count, (void *) &tempDeviceID);
- if (err != noErr) goto error;
+ if (err != noErr) goto Bail;
// scan input devices to see which one matches this device
defaultDeviceID = paNoDevice;
for( i=LOWEST_INPUT_DEVID; i<=HIGHEST_INPUT_DEVID; i++ )
{
- DBUG(("PaOSX_QueryDefaultInputDevice: i = %d, aDevId = %ld\n", i, sDeviceInfos[i].audioDeviceID ));
+ DBUG(("Pa_QueryDefaultInputDevice: i = %d, aDevId = %d\n", i, sDeviceInfos[i].audioDeviceID ));
if( sDeviceInfos[i].audioDeviceID == tempDeviceID )
{
defaultDeviceID = i;
break;
}
}
-error:
+Bail:
return defaultDeviceID;
}
/************************************************************************/
-static PaDeviceID PaOSX_QueryDefaultOutputDevice( void )
+static PaDeviceID Pa_QueryDefaultOutputDevice( void )
{
- OSStatus err = noErr;
- UInt32 count;
- int i;
+ OSStatus err = noErr;
+ UInt32 count;
+ int i;
AudioDeviceID tempDeviceID = kAudioDeviceUnknown;
- PaDeviceID defaultDeviceID = paNoDevice;
+ PaDeviceID defaultDeviceID = paNoDevice;
// get the default output device for the HAL
// it is required to pass the size of the data to be returned
count = sizeof(tempDeviceID);
err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &tempDeviceID);
- if (err != noErr) goto error;
+ if (err != noErr) goto Bail;
// scan output devices to see which one matches this device
defaultDeviceID = paNoDevice;
for( i=LOWEST_OUTPUT_DEVID; i<=HIGHEST_OUTPUT_DEVID; i++ )
{
- DBUG(("PaOSX_QueryDefaultOutputDevice: i = %d, aDevId = %ld\n", i, sDeviceInfos[i].audioDeviceID ));
+ DBUG(("Pa_QueryDefaultOutputDevice: i = %d, aDevId = %d\n", i, sDeviceInfos[i].audioDeviceID ));
if( sDeviceInfos[i].audioDeviceID == tempDeviceID )
{
defaultDeviceID = i;
break;
}
}
-error:
+Bail:
return defaultDeviceID;
}
/******************************************************************/
-static PaError PaOSX_QueryDevices( void )
+static PaError Pa_QueryDevices( void )
{
OSStatus err = noErr;
UInt32 outSize;
Boolean outWritable;
- int numBytes;
+ int numBytes;
// find out how many Core Audio devices there are, if any
- outSize = sizeof(outWritable);
err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &outSize, &outWritable);
if (err != noErr)
- {
- PRINT_ERR("Couldn't get info about list of audio devices", err);
- sSavedHostError = err;
- return paHostError;
- }
-
+ ERR_RPT(("Couldn't get info about list of audio devices\n"));
+
// calculate the number of device available
sNumCoreDevices = outSize / sizeof(AudioDeviceID);
// Bail if there aren't any devices
if (sNumCoreDevices < 1)
- {
- PRINT(("No Devices Available"));
- return paHostError;
- }
-
+ ERR_RPT(("No Devices Available\n"));
+
// make space for the devices we are about to get
sCoreDeviceIDs = (AudioDeviceID *)malloc(outSize);
// get an array of AudioDeviceIDs
err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &outSize, (void *)sCoreDeviceIDs);
if (err != noErr)
- {
- PRINT_ERR("Couldn't get list of audio device IDs", err);
- sSavedHostError = err;
- return paHostError;
- }
+ ERR_RPT(("Couldn't get list of audio device IDs\n"));
// Allocate structures to hold device info pointers.
// There will be a maximum of two Pa devices per Core Audio device, input and/or output.
@@ -393,22 +295,35 @@ static PaError PaOSX_QueryDevices( void )
// Scan all the Core Audio devices to see which support input and allocate a
// PaHostDeviceInfo structure for each one.
- PaOSX_ScanDevices( IS_INPUT );
+ PaHost_ScanDevices( IS_INPUT );
sNumInputDevices = sNumPaDevices;
// Now scan all the output devices.
- PaOSX_ScanDevices( IS_OUTPUT );
+ PaHost_ScanDevices( IS_OUTPUT );
sNumOutputDevices = sNumPaDevices - sNumInputDevices;
// Figure out which of the devices that we scanned is the default device.
- sDefaultInputDeviceID = PaOSX_QueryDefaultInputDevice();
- sDefaultOutputDeviceID = PaOSX_QueryDefaultOutputDevice();
+ sDefaultInputDeviceID = Pa_QueryDefaultInputDevice();
+ sDefaultOutputDeviceID = Pa_QueryDefaultOutputDevice();
return paNoError;
}
+/************************************************************************************/
+long Pa_GetHostError()
+{
+ return sPaHostError;
+}
+
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ if( sNumPaDevices <= 0 ) Pa_Initialize();
+ return sNumPaDevices;
+}
+
/*************************************************************************/
/* Allocate a string containing the device name. */
-static char *PaOSX_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput )
+static char *PaHost_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput )
{
OSStatus err = noErr;
UInt32 outSize;
@@ -424,18 +339,87 @@ static char *PaOSX_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput )
{
err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, deviceName);
if (err != noErr)
- PRINT_ERR("Couldn't get audio device name", err);
+ ERR_RPT(("Couldn't get audio device name.\n"));
}
}
return deviceName;
}
+/*************************************************************************/
+// An AudioStreamBasicDescription is passed in to query whether or not
+// the format is supported. A kAudioDeviceUnsupportedFormatError will
+// be returned if the format is not supported and kAudioHardwareNoError
+// will be returned if it is supported. AudioStreamBasicDescription
+// fields set to 0 will be ignored in the query, but otherwise values
+// must match exactly.
+
+Boolean deviceDoesSupportFormat(AudioDeviceID deviceID, AudioStreamBasicDescription *desc, Boolean isInput )
+{
+ OSStatus err = noErr;
+ UInt32 outSize;
+
+ outSize = sizeof(*desc);
+ err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &outSize, desc);
+
+ if (err == kAudioHardwareNoError)
+ return true;
+ else
+ return false;
+}
+
+/*************************************************************************/
+// return an error string
+char* coreAudioErrorString (int errCode )
+{
+ char *str;
+
+ switch (errCode)
+ {
+ case kAudioHardwareUnspecifiedError:
+ str = "kAudioHardwareUnspecifiedError";
+ break;
+ case kAudioHardwareNotRunningError:
+ str = "kAudioHardwareNotRunningError";
+ break;
+ case kAudioHardwareUnknownPropertyError:
+ str = "kAudioHardwareUnknownPropertyError";
+ break;
+ case kAudioDeviceUnsupportedFormatError:
+ str = "kAudioDeviceUnsupportedFormatError";
+ break;
+ case kAudioHardwareBadPropertySizeError:
+ str = "kAudioHardwareBadPropertySizeError";
+ break;
+ case kAudioHardwareIllegalOperationError:
+ str = "kAudioHardwareIllegalOperationError";
+ break;
+ default:
+ str = "Unknown CoreAudio Error!";
+ break;
+ }
+
+ return str;
+}
+
+/*************************************************************************
+** PaDeviceInfo structures have already been created
+** so just return the pointer.
+**
+*/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ if( id < 0 || id >= sNumPaDevices )
+ return NULL;
+
+ return &sDeviceInfos[id].paInfo;
+}
+
/*************************************************************************
** Scan all of the Core Audio devices to see which support input or output.
** Changes sNumDevices, and fills in sDeviceInfos.
*/
-static int PaOSX_ScanDevices( Boolean isInput )
+static int PaHost_ScanDevices( Boolean isInput )
{
int coreDeviceIndex;
int result;
@@ -446,8 +430,8 @@ static int PaOSX_ScanDevices( Boolean isInput )
{
// try to fill in next PaHostDeviceInfo
hostDeviceInfo = &sDeviceInfos[sNumPaDevices];
- result = PaOSX_QueryDeviceInfo( hostDeviceInfo, coreDeviceIndex, isInput );
- DBUGX(("PaOSX_ScanDevices: paDevId = %d, coreDevId = %d\n", sNumPaDevices, coreDeviceIndex ));
+ result = PaHost_QueryDeviceInfo( hostDeviceInfo, coreDeviceIndex, isInput );
+ DBUG(("PaHost_ScanDevices: paDevId = %d, coreDevId = %d\n", sNumPaDevices, hostDeviceInfo->audioDeviceID ));
if( result > 0 )
{
sNumPaDevices += 1; // bump global counter if we got one
@@ -458,7 +442,6 @@ static int PaOSX_ScanDevices( Boolean isInput )
return numAdded;
}
-
/*************************************************************************
** Try to fill in the device info for this device.
** Return 1 if a good device that PA can use.
@@ -466,55 +449,59 @@ static int PaOSX_ScanDevices( Boolean isInput )
** or return negative error.
**
*/
-static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput )
+static int PaHost_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput )
{
- OSStatus err;
- UInt32 outSize;
+ OSErr err;
+ int index;
+ UInt32 outSize;
AudioStreamBasicDescription formatDesc;
+ Boolean result;
AudioDeviceID devID;
- PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo;
+ double *sampleRates = NULL; /* non-const ptr */
+
+ PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo;
+ double possibleSampleRates[] = {8000.0, 11025.0, 22050.0, 44100.0, 48000.0, 88200.0, 96000.0};
+ int maxNumSampleRates = sizeof( possibleSampleRates ) / sizeof( double );
deviceInfo->structVersion = 1;
deviceInfo->maxInputChannels = 0;
deviceInfo->maxOutputChannels = 0;
-
- deviceInfo->sampleRates = supportedSampleRateRange; // because we use sample rate converter to get continuous rates
deviceInfo->numSampleRates = -1;
devID = sCoreDeviceIDs[ coreDeviceIndex ];
hostDeviceInfo->audioDeviceID = devID;
- DBUG(("PaOSX_QueryDeviceInfo: coreDeviceIndex = %d, devID = %d, isInput = %d\n",
- coreDeviceIndex, devID, isInput ));
- // Get data format info from the device.
- outSize = sizeof(formatDesc);
- err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc);
- // This just may not be an appropriate device for input or output so leave quietly.
- if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error;
- // Right now the Core Audio headers only define one formatID: LinearPCM
- // Apparently LinearPCM must be Float32 for now.
- if( (formatDesc.mFormatID == kAudioFormatLinearPCM) &&
- (formatDesc.mFormatFlags & kLinearPCMFormatFlagIsFloat) )
- {
- deviceInfo->nativeSampleFormats = paFloat32;
- }
- else
+ // Figure out supported sample rates
+ // Make room in case device supports all rates.
+ sampleRates = (double*)PaHost_AllocateFastMemory( maxNumSampleRates * sizeof(double) );
+ if( sampleRates == NULL ) return paInsufficientMemory;
+
+ deviceInfo->sampleRates = sampleRates;
+ deviceInfo->numSampleRates = 0;
+
+ // Loop through the possible sampling rates and check each to see if the device supports it.
+ for (index = 0; index < maxNumSampleRates; index ++)
{
- return paSampleFormatNotSupported;
+ memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
+ formatDesc.mSampleRate = possibleSampleRates[index];
+ result = deviceDoesSupportFormat( devID, &formatDesc, isInput );
+
+ if (result == true)
+ {
+ deviceInfo->numSampleRates += 1;
+ *sampleRates = possibleSampleRates[index];
+ sampleRates++;
+ }
}
+ // If no sample rates supported, then not a very good device.
+ if( deviceInfo->numSampleRates == 0 ) goto error;
- // Determine maximum number of channels supported.
- memset( &formatDesc, 0, sizeof(formatDesc));
- formatDesc.mChannelsPerFrame = 256; // FIXME - what about device with > 256 channels
+ // Get data format info from the device.
outSize = sizeof(formatDesc);
- err = AudioDeviceGetProperty( devID, 0,
- isInput, kAudioDevicePropertyStreamFormatMatch, &outSize, &formatDesc);
- if( err != noErr )
- {
- PRINT_ERR("PaOSX_QueryDeviceInfo: Could not get device format match", err);
- sSavedHostError = err;
- return paHostError;
- }
+ err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc);
+
+ // If no channels supported, then not a very good device.
+ if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error;
if( isInput )
{
@@ -525,268 +512,205 @@ static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDevi
deviceInfo->maxOutputChannels = formatDesc.mChannelsPerFrame;
}
+ // FIXME - where to put current sample rate?: formatDesc.mSampleRate
+
+ // Right now the Core Audio headers only define one formatID: LinearPCM
+ // Apparently LinearPCM must be Float32 for now.
+ switch (formatDesc.mFormatID)
+ {
+ case kAudioFormatLinearPCM:
+ deviceInfo->nativeSampleFormats = paFloat32;
+
+ // FIXME - details about the format are in these flags.
+ // formatDesc.mFormatFlags
+
+ // here are the possibilities
+ // kLinearPCMFormatFlagIsFloat // set for floating point, clear for integer
+ // kLinearPCMFormatFlagIsBigEndian // set for big endian, clear for little
+ // kLinearPCMFormatFlagIsSignedInteger // set for signed integer, clear for unsigned integer,
+ // only valid if kLinearPCMFormatFlagIsFloat is clear
+ // kLinearPCMFormatFlagIsPacked // set if the sample bits are packed as closely together as possible,
+ // clear if they are high or low aligned within the channel
+ // kLinearPCMFormatFlagIsAlignedHigh // set if the sample bits are placed
+ break;
+
+ default:
+ deviceInfo->nativeSampleFormats = paFloat32; // FIXME
+ break;
+ }
+
// Get the device name
- deviceInfo->name = PaOSX_DeviceNameFromID( devID, isInput );
+ deviceInfo->name = PaHost_DeviceNameFromID( devID, isInput );
return 1;
error:
+ if( sampleRates != NULL ) free( sampleRates );
return 0;
}
-/**********************************************************************/
-static PaError PaOSX_MaybeQueryDevices( void )
+/*************************************************************************
+** Returns recommended device ID.
+** On the PC, the recommended device can be specified by the user by
+** setting an environment variable. For example, to use device #1.
+**
+** set PA_RECOMMENDED_OUTPUT_DEVICE=1
+**
+** The user should first determine the available device ID by using
+** the supplied application "pa_devs".
+*/
+#define PA_ENV_BUF_SIZE (32)
+#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE")
+#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE")
+
+static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName )
+{
+#if 0
+ UInt32 hresult;
+ char envbuf[PA_ENV_BUF_SIZE];
+ PaDeviceID recommendedID = paNoDevice;
+
+ /* Let user determine default device by setting environment variable. */
+ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE );
+ if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
+ {
+ recommendedID = atoi( envbuf );
+ }
+
+ return recommendedID;
+#endif
+ return paNoDevice;
+}
+
+static PaError Pa_MaybeQueryDevices( void )
{
if( sNumPaDevices == 0 )
{
- return PaOSX_QueryDevices();
+ return Pa_QueryDevices();
}
return 0;
}
-static char zeroPad[256] = { 0 };
-
/**********************************************************************
-** This is the proc that supplies the data to the AudioConverterFillBuffer call.
-** We can pass back arbitrarily sized blocks so if the FIFO region is split
-** just pass back the first half.
+** Check for environment variable, else query devices and use result.
*/
-static OSStatus PaOSX_InputConverterCallbackProc (AudioConverterRef inAudioConverter,
- UInt32* outDataSize,
- void** outData,
- void* inUserData)
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
{
- internalPortAudioStream *past = (internalPortAudioStream *) inUserData;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- void *dataPtr1;
- long size1;
- void *dataPtr2;
- long size2;
-
- /* Pass contiguous region from FIFO directly to converter. */
- RingBuffer_GetReadRegions( &pahsc->ringBuffer, *outDataSize,
- &dataPtr1, &size1, &dataPtr2, &size2 );
-
- if( size1 > 0 )
+ PaError result;
+ result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME );
+ if( result < 0 )
{
- *outData = dataPtr1;
- *outDataSize = size1;
- RingBuffer_AdvanceReadIndex( &pahsc->ringBuffer, size1 );
- DBUGX(("PaOSX_InputConverterCallbackProc: read %ld bytes from FIFO.\n", size1 ));
+ result = Pa_MaybeQueryDevices();
+ if( result < 0 ) return result;
+ result = sDefaultInputDeviceID;
}
- else
- {
- DBUGBACK(("PaOSX_InputConverterCallbackProc: got no data!\n"));
- *outData = zeroPad; // Give it zero data to keep it happy.
- *outDataSize = sizeof(zeroPad);
- }
- return noErr;
+ return result;
}
-/*****************************************************************************
-** Get audio input, if any, from passed in buffer, or from converter or from FIFO
-** and run PA callback.
-*/
-static OSStatus PaOSX_LoadAndProcess( internalPortAudioStream *past,
- void *inputBuffer, void *outputBuffer )
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
{
- OSStatus err = noErr;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
-
- if( past->past_StopSoon )
- {
- if( outputBuffer )
- {
- /* Clear remainder of audio buffer if we are waiting for stop. */
- AddTraceMessage("PaOSX_HandleInputOutput: zero rest of wave buffer ", i );
- memset( outputBuffer, 0, pahsc->output.bytesPerUserNativeBuffer );
- }
- }
- else
+ PaError result;
+ result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME );
+ if( result < 0 )
{
- /* Do we need data from the converted input? */
- if( pahsc->input.converter != NULL )
- {
- UInt32 size = pahsc->input.bytesPerUserNativeBuffer;
- err = AudioConverterFillBuffer(
- pahsc->input.converter,
- PaOSX_InputConverterCallbackProc,
- past,
- &size,
- pahsc->input.converterBuffer);
- if( err != noErr ) return err;
- inputBuffer = pahsc->input.converterBuffer;
- }
- /* Or should just get the data directly from the FIFO? */
- else if( pahsc->ringBufferData != NULL )
- {
- if( RingBuffer_GetReadAvailable( &pahsc->ringBuffer ) >= pahsc->input.bytesPerUserNativeBuffer)
- {
- RingBuffer_Read( &pahsc->ringBuffer, pahsc->input.converterBuffer, pahsc->input.bytesPerUserNativeBuffer );
- inputBuffer = pahsc->input.converterBuffer;
- }
- }
-
- /* Fill part of audio converter buffer by converting input to user format,
- * calling user callback, then converting output to native format. */
- if( PaConvert_Process( past, inputBuffer, outputBuffer ))
- {
- past->past_StopSoon = 1;
- }
+ result = Pa_MaybeQueryDevices();
+ if( result < 0 ) return result;
+ result = sDefaultOutputDeviceID;
}
- return err;
+ return result;
}
-/*****************************************************************************
-** This is the proc that supplies the data to the AudioConverterFillBuffer call
+/**********************************************************************
+** Initialize Host dependant part of API.
*/
-static OSStatus PaOSX_OutputConverterCallbackProc (AudioConverterRef inAudioConverter,
- UInt32* outDataSize,
- void** outData,
- void* inUserData)
+
+PaError PaHost_Init( void )
{
- internalPortAudioStream *past = (internalPortAudioStream *) inUserData;
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
-
- *outData = pahsc->output.converterBuffer;
- *outDataSize = pahsc->output.bytesPerUserNativeBuffer;
-
- return PaOSX_LoadAndProcess ( past, pahsc->input.converterBuffer, pahsc->output.converterBuffer );
+ return Pa_MaybeQueryDevices();
}
/**********************************************************************
** Fill any available output buffers and use any available
** input buffers by calling user callback.
-** Will set past->past_StopSoon if user callback indicates that it is finished.
*/
-static OSStatus PaOSX_HandleInputOutput( internalPortAudioStream *past,
- const AudioBufferList* inInputData,
- AudioBufferList* outOutputData )
+static PaError Pa_TimeSlice( internalPortAudioStream *past, const AudioBufferList* inInputData,
+ AudioBufferList* outOutputData )
{
- OSStatus err = noErr;
- char *inputNativeBufferfPtr = NULL;
- char *outputNativeBufferfPtr = NULL;
- int i;
+ PaError result = 0;
+ char *inputNativeBufferfPtr = NULL;
+ char *outputNativeBufferfPtr = NULL;
+ int i;
+ int buffersProcessed = 0;
+ int done = 0;
PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+
+ past->past_NumCallbacks += 1;
+
+#if PA_TRACE_RUN
+ AddTraceMessage("Pa_TimeSlice: past_NumCallbacks ", past->past_NumCallbacks );
+#endif
+
+ Pa_StartUsageCalculation( past );
/* If we are using output, then we need an empty output buffer. */
- if( outOutputData->mNumberBuffers > 0 )
+ if( past->past_NumOutputChannels > 0 )
{
outputNativeBufferfPtr = (char*)outOutputData->mBuffers[0].mData;
}
- if( inInputData->mNumberBuffers > 0 )
+ /* If we are using input, then we need a full input buffer. */
+ if( past->past_NumInputChannels > 0 )
{
inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData;
-
- /* If there is a FIFO for input then write to it. */
- if( (pahsc->ringBufferData != NULL) && !pahsc->usingSecondDevice )
- {
- long writeRoom = RingBuffer_GetWriteAvailable( &pahsc->ringBuffer );
- long numBytes = inInputData->mBuffers[0].mDataByteSize;
- if( numBytes <= writeRoom )
- {
- RingBuffer_Write( &pahsc->ringBuffer, inputNativeBufferfPtr, numBytes );
- DBUGBACK(("PaOSX_HandleInputOutput: wrote %ld bytes to FIFO.\n", inInputData->mBuffers[0].mDataByteSize));
- } // FIXME else ???
- }
- }
-
- if( pahsc->output.converter != NULL )
- {
- /* Using output and input converter. */
- UInt32 size = outOutputData->mBuffers[0].mDataByteSize;
- err = AudioConverterFillBuffer(
- pahsc->output.converter,
- PaOSX_OutputConverterCallbackProc,
- past,
- &size,
- outputNativeBufferfPtr);
- if( err != noErr )
- {
- PRINT_ERR("PaOSX_HandleInputOutput: AudioConverterFillBuffer failed", err);
- goto error;
- }
- }
- else if( (pahsc->input.converter != NULL) && !pahsc->usingSecondDevice)
- {
- /* Using just an input converter. */
- /* Generate user buffers as long as we have a half full input FIFO. */
- long gotHalf = pahsc->ringBuffer.bufferSize / 2;
- while( (RingBuffer_GetReadAvailable( &pahsc->ringBuffer ) >= gotHalf) &&
- (past->past_StopSoon == 0) )
- {
- err = PaOSX_LoadAndProcess ( past, NULL, outputNativeBufferfPtr );
- if( err != noErr ) goto error;
- if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->output.bytesPerUserNativeBuffer;
- }
}
- else
- {
- /* No AUConverters used. */
- /* Each host buffer contains multiple user buffers so do them all now. */
- for( i=0; i<past->past_NumUserBuffers; i++ )
- {
- err = PaOSX_LoadAndProcess ( past, inputNativeBufferfPtr, outputNativeBufferfPtr );
- if( err != noErr ) goto error;
- if( inputNativeBufferfPtr ) inputNativeBufferfPtr += pahsc->input.bytesPerUserNativeBuffer;
- if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->output.bytesPerUserNativeBuffer;
- }
- }
-
-error:
- return err;
-}
-/******************************************************************
- * This callback is used when two separate devices are used for input and output.
- * This often happens when using USB devices which present as two devices: input and output.
- * It just writes its data to a FIFO so that it can be read by the main callback
- * proc PaOSX_CoreAudioIOCallback().
- */
-static OSStatus PaOSX_CoreAudioInputCallback (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime,
- void* contextPtr)
-{
- internalPortAudioStream *past = (internalPortAudioStream *) contextPtr;
- PaHostSoundControl *pahsc;
- pahsc = (PaHostSoundControl *) past->past_DeviceData;
-
- /* If there is a FIFO for input then write to it. */
- if( pahsc->ringBufferData != NULL )
+ buffersProcessed += 1;
+
+ /* Each host buffer contains multiple user buffers so do them all now. */
+ for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
{
- long writeRoom = RingBuffer_GetWriteAvailable( &pahsc->ringBuffer );
- long numBytes = inInputData->mBuffers[0].mDataByteSize;
- if( numBytes <= writeRoom )
+ if( done )
{
- RingBuffer_Write( &pahsc->ringBuffer, inInputData->mBuffers[0].mData, inInputData->mBuffers[0].mDataByteSize );
+ if( outputNativeBufferfPtr )
+ {
+ /* Clear remainder of wave buffer if we are waiting for stop. */
+ AddTraceMessage("Pa_TimeSlice: zero rest of wave buffer ", i );
+ memset( outputNativeBufferfPtr, 0, pahsc->pahsc_BytesPerUserNativeOutputBuffer );
+ }
}
else
{
- DBUGBACK(("PaOSX_CoreAudioInputCallback: FIFO too full to write!\n"));
- }
+ /* Convert 32 bit native data to user data and call user routine. */
+ result = PaConvert_Process( past, inputNativeBufferfPtr, outputNativeBufferfPtr );
+ if( result != 0) done = 1;
+ }
+ if( inputNativeBufferfPtr ) inputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeInputBuffer;
+ if( outputNativeBufferfPtr) outputNativeBufferfPtr += pahsc->pahsc_BytesPerUserNativeOutputBuffer;
}
-
- return noErr;
+
+ Pa_EndUsageCalculation( past );
+
+#if PA_TRACE_RUN
+ AddTraceMessage("Pa_TimeSlice: buffersProcessed ", buffersProcessed );
+#endif
+
+ return (result != 0) ? result : done;
}
-/******************************************************************
- * This is the primary callback for CoreAudio.
- * It can handle input and/or output for a single device.
- * It takes input from CoreAudio, converts it and passes it to the
- * PortAudio callback. Then takes the PA results and passes it back to CoreAudio.
- */
-static OSStatus PaOSX_CoreAudioIOCallback (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
+OSStatus appIOProc (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime,
AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime,
void* contextPtr)
{
- OSStatus err = noErr;
+
+ PaError result = 0;
internalPortAudioStream *past;
PaHostSoundControl *pahsc;
past = (internalPortAudioStream *) contextPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
+// printf("Num input Buffers: %d; Num output Buffers: %d.\n", inInputData->mNumberBuffers, outOutputData->mNumberBuffers);
+
/* Has someone asked us to abort by calling Pa_AbortStream()? */
if( past->past_StopNow )
{
@@ -797,7 +721,7 @@ static OSStatus PaOSX_CoreAudioIOCallback (AudioDeviceID inDevice, const AudioT
*/
else if( past->past_StopSoon )
{
- // FIXME - Pretend all done. Should wait for audio to play out but CoreAudio latency very low.
+ // FIXME - pretend all done
past->past_IsActive = 0; /* Will cause thread to return. */
}
else
@@ -808,220 +732,63 @@ static OSStatus PaOSX_CoreAudioIOCallback (AudioDeviceID inDevice, const AudioT
past->past_FrameCount = inOutputTime->mSampleTime;
}
- /* Measure CPU load. */
- Pa_StartUsageCalculation( past );
- past->past_NumCallbacks += 1;
-
/* Process full input buffer and fill up empty output buffers. */
- err = PaOSX_HandleInputOutput( past, inInputData, outOutputData );
-
- Pa_EndUsageCalculation( past );
+ if( (result = Pa_TimeSlice( past, inInputData, outOutputData )) != 0)
+ {
+ /* User callback has asked us to stop. */
+#if PA_TRACE_START_STOP
+ AddTraceMessage( "Pa_OutputThreadProc: TimeSlice() returned ", result );
+#endif
+ past->past_StopSoon = 1; /* Request that audio play out then stop. */
+ result = paNoError;
+ }
}
- // FIXME PaOSX_UpdateStreamTime( pahsc );
- if( err != 0 ) DBUG(("PaOSX_CoreAudioIOCallback: returns %ld.\n", err ));
+ // FIXME PaHost_UpdateStreamTime( pahsc );
+
+ return result;
+}
- return err;
+#if 0
+static int PaHost_CalcTimeOut( internalPortAudioStream *past )
+{
+ /* Calculate timeOut longer than longest time it could take to play all buffers. */
+ int timeOut = (UInt32) (1500.0 * PaHost_GetTotalBufferFrames( past ) / past->past_SampleRate);
+ if( timeOut < MIN_TIMEOUT_MSEC ) timeOut = MIN_TIMEOUT_MSEC;
+ return timeOut;
}
+#endif
+
/*******************************************************************/
/* Attempt to set device sample rate. */
-static PaError PaOSX_SetSampleRate( AudioDeviceID devID, Boolean isInput, double sampleRate )
+static PaError PaHost_SetSampleRate( AudioDeviceID devID, Boolean isInput, double sampleRate )
{
AudioStreamBasicDescription formatDesc;
- PaError result = paNoError;
OSStatus err;
- UInt32 dataSize;
-
- // try to set to desired rate
memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
formatDesc.mSampleRate = sampleRate;
err = AudioDeviceSetProperty( devID, 0, 0,
isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
- if (err != noErr)
- {
- result = paInvalidSampleRate;
-
- /* Could not set to desired rate so query for closest match. */
- DBUG(("PaOSX_SetSampleRate: couldn't set to %f. Try to find match.\n", sampleRate ));
- dataSize = sizeof(formatDesc);
- AudioDeviceGetProperty( devID, 0,
- isInput, kAudioDevicePropertyStreamFormatMatch, &dataSize, &formatDesc);
- formatDesc.mSampleRate = sampleRate;
- err = AudioDeviceGetProperty( devID, 0,
- isInput, kAudioDevicePropertyStreamFormatMatch, &dataSize, &formatDesc);
- if (err == noErr)
- {
- /* Set to that matching rate. */
- sampleRate = formatDesc.mSampleRate;
- DBUG(("PaOSX_SetSampleRate: match succeeded, set to %f instead\n", sampleRate ));
- memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
- formatDesc.mSampleRate = sampleRate;
- AudioDeviceSetProperty( devID, 0, 0,
- isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
- }
- }
- return result;
-}
-
-/*******************************************************************
- * Check volume level of device. If below threshold, then set to newLevel.
- * Using volume instead of decibels because decibel range varies by device.
- */
-static void PaOSX_FixVolumeScalars( AudioDeviceID devID, Boolean isInput,
- int numChannels, double threshold, double newLevel )
-{
- OSStatus err = noErr;
- UInt32 dataSize;
- int iChannel;
-
-/* The master channel is 0. Left and right are channels 1 and 2. */
-/* Fix volume. */
- for( iChannel = 0; iChannel<=numChannels; iChannel++ )
- {
- Float32 fdata32;
- dataSize = sizeof( fdata32 );
- err = AudioDeviceGetProperty( devID, iChannel, isInput,
- kAudioDevicePropertyVolumeScalar, &dataSize, &fdata32 );
- if( err == noErr )
- {
- DBUG(("kAudioDevicePropertyVolumeScalar for channel %d = %f\n", iChannel, fdata32));
- if( fdata32 <= (Float32) threshold )
- {
- dataSize = sizeof( fdata32 );
- fdata32 = (Float32) newLevel;
- err = AudioDeviceSetProperty( devID, 0, iChannel, isInput,
- kAudioDevicePropertyVolumeScalar, dataSize, &fdata32 );
- if( err != noErr )
- {
- PRINT(("Warning: audio volume is very low and could not be turned up.\n"));
- }
- else
- {
- PRINT(("Volume for audio channel %d was <= %4.2f so set to %4.2f by PortAudio!\n",
- iChannel, threshold, newLevel ));
- }
- }
- }
- }
-/* Unmute if muted. */
- for( iChannel = 0; iChannel<=numChannels; iChannel++ )
- {
- UInt32 uidata32;
- dataSize = sizeof( uidata32 );
- err = AudioDeviceGetProperty( devID, iChannel, isInput,
- kAudioDevicePropertyMute, &dataSize, &uidata32 );
- if( err == noErr )
- {
- DBUG(("uidata32 for channel %d = %ld\n", iChannel, uidata32));
- if( uidata32 == 1 ) // muted?
- {
- dataSize = sizeof( uidata32 );
- uidata32 = 0; // unmute
- err = AudioDeviceSetProperty( devID, 0, iChannel, isInput,
- kAudioDevicePropertyMute, dataSize, &uidata32 );
- if( err != noErr )
- {
- PRINT(("Warning: audio is muted and could not be unmuted!\n"));
- }
- else
- {
- PRINT(("Audio channel %d was unmuted by PortAudio!\n", iChannel ));
- }
- }
- }
- }
+ if (err != kAudioHardwareNoError) return paInvalidSampleRate;
+ else return paNoError;
}
-#if 0
-static void PaOSX_DumpDeviceInfo( AudioDeviceID devID, Boolean isInput )
-{
- OSStatus err = noErr;
- UInt32 dataSize;
- UInt32 uidata32;
- Float32 fdata32;
- AudioValueRange audioRange;
-
- dataSize = sizeof( uidata32 );
- err = AudioDeviceGetProperty( devID, 0, isInput,
- kAudioDevicePropertyLatency, &dataSize, &uidata32 );
- if( err != noErr )
- {
- PRINT_ERR("Error reading kAudioDevicePropertyLatency", err);
- return;
- }
- PRINT(("kAudioDevicePropertyLatency = %d\n", (int)uidata32 ));
-
- dataSize = sizeof( fdata32 );
- err = AudioDeviceGetProperty( devID, 1, isInput,
- kAudioDevicePropertyVolumeScalar, &dataSize, &fdata32 );
- if( err != noErr )
- {
- PRINT_ERR("Error reading kAudioDevicePropertyVolumeScalar", err);
- return;
- }
- PRINT(("kAudioDevicePropertyVolumeScalar = %f\n", fdata32 ));
-
- dataSize = sizeof( uidata32 );
- err = AudioDeviceGetProperty( devID, 0, isInput,
- kAudioDevicePropertyBufferSize, &dataSize, &uidata32 );
- if( err != noErr )
- {
- PRINT_ERR("Error reading buffer size", err);
- return;
- }
- PRINT(("kAudioDevicePropertyBufferSize = %d bytes\n", (int)uidata32 ));
-
- dataSize = sizeof( audioRange );
- err = AudioDeviceGetProperty( devID, 0, isInput,
- kAudioDevicePropertyBufferSizeRange, &dataSize, &audioRange );
- if( err != noErr )
- {
- PRINT_ERR("Error reading buffer size range", err);
- return;
- }
- PRINT(("kAudioDevicePropertyBufferSizeRange = %g to %g bytes\n", audioRange.mMinimum, audioRange.mMaximum ));
-
- dataSize = sizeof( uidata32 );
- err = AudioDeviceGetProperty( devID, 0, isInput,
- kAudioDevicePropertyBufferFrameSize, &dataSize, &uidata32 );
- if( err != noErr )
- {
- PRINT_ERR("Error reading buffer size", err);
- return;
- }
- PRINT(("kAudioDevicePropertyBufferFrameSize = %d frames\n", (int)uidata32 ));
-
- dataSize = sizeof( audioRange );
- err = AudioDeviceGetProperty( devID, 0, isInput,
- kAudioDevicePropertyBufferFrameSizeRange, &dataSize, &audioRange );
- if( err != noErr )
- {
- PRINT_ERR("Error reading buffer size range", err);
- return;
- }
- PRINT(("kAudioDevicePropertyBufferFrameSizeRange = %g to %g frames\n", audioRange.mMinimum, audioRange.mMaximum ));
-
- return;
-}
-#endif
-
/*******************************************************************/
-static PaError PaOSX_OpenInputDevice( internalPortAudioStream *past )
+PaError PaHost_OpenInputStream( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc;
const PaHostDeviceInfo *hostDeviceInfo;
PaError result = paNoError;
+ UInt32 bytesPerHostBuffer;
UInt32 dataSize;
OSStatus err = noErr;
- int needConverter = 0;
- double deviceRate = past->past_SampleRate;
-
- DBUG(("PaOSX_OpenInputDevice: -------------\n"));
+ int bytesPerInputFrame;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_InputDeviceID));
if( (past->past_InputDeviceID < LOWEST_INPUT_DEVID) ||
(past->past_InputDeviceID > HIGHEST_INPUT_DEVID) )
{
@@ -1029,134 +796,68 @@ static PaError PaOSX_OpenInputDevice( internalPortAudioStream *past )
}
hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID];
- PaOSX_FixVolumeScalars( pahsc->input.audioDeviceID, IS_INPUT,
- hostDeviceInfo->paInfo.maxInputChannels, 0.1, 0.9 );
-
/* Try to set sample rate. */
- result = PaOSX_SetSampleRate( pahsc->input.audioDeviceID, IS_INPUT, past->past_SampleRate );
- if( result != paNoError )
- {
- DBUG(("PaOSX_OpenInputDevice: Need converter for sample rate = %f\n", past->past_SampleRate ));
- needConverter = 1;
- result = paNoError;
- }
- else
- {
- DBUG(("PaOSX_OpenInputDevice: successfully set sample rate to %f\n", past->past_SampleRate ));
- }
+ result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_INPUT, past->past_SampleRate );
+ if( result != paNoError ) return result;
- /* Try to set number of channels. */
- if( past->past_NumInputChannels > hostDeviceInfo->paInfo.maxInputChannels )
- {
- return paInvalidChannelCount; /* Too many channels! */
- }
- else if( past->past_NumInputChannels < hostDeviceInfo->paInfo.maxInputChannels )
+ if( past->past_NumInputChannels != hostDeviceInfo->paInfo.maxInputChannels )
{
-
+#if 1
+ return paInvalidChannelCount; // FIXME - how support mono?
+#else
+FIXME - should this be set on a stream basis? Is it possible to change?
+ /* Attempt to set number of channels. */
AudioStreamBasicDescription formatDesc;
OSStatus err;
memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
formatDesc.mChannelsPerFrame = past->past_NumInputChannels;
- err = AudioDeviceSetProperty( pahsc->input.audioDeviceID, 0, 0,
+
+ err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0,
IS_INPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
- if (err != noErr)
+ if (err != kAudioHardwareNoError)
{
- needConverter = 1;
+ result = paInvalidChannelCount;
+ goto error;
}
+#endif
}
- /* Try to set the I/O bufferSize of the device. */
- dataSize = sizeof(pahsc->framesPerHostBuffer);
- err = AudioDeviceSetProperty( pahsc->input.audioDeviceID, 0, 0, IS_INPUT,
- kAudioDevicePropertyBufferFrameSize, dataSize,
- &pahsc->framesPerHostBuffer);
+ // calculate native buffer sizes in bytes
+ bytesPerInputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels;
+ pahsc->pahsc_BytesPerUserNativeInputBuffer = past->past_FramesPerUserBuffer * bytesPerInputFrame;
+ bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerInputFrame;
+
+ // Change the bufferSize of the device! Is this per device or just for our stream?
+ dataSize = sizeof(UInt32);
+ err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_INPUT,
+ kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer);
if( err != noErr )
{
- DBUG(("PaOSX_OpenInputDevice: Need converter for buffer size = %d\n", pahsc->framesPerHostBuffer));
- needConverter = 1;
+ ERR_RPT(("Could not force buffer size!"));
+ result = paHostError;
+ goto error;
}
-
- // setup PA conversion procedure
+
+ // setup conversion procedure
result = PaConvert_SetupInput( past, paFloat32 );
-
- if( needConverter )
- {
- AudioStreamBasicDescription sourceStreamFormat, destStreamFormat;
-
- /* Get source device format */
- dataSize = sizeof(sourceStreamFormat);
- err = AudioDeviceGetProperty(pahsc->input.audioDeviceID, 0, IS_INPUT,
- kAudioDevicePropertyStreamFormat, &dataSize, &sourceStreamFormat);
- if( err != noErr )
- {
- PRINT_ERR("PaOSX_OpenInputDevice: Could not get input device format", err);
- sSavedHostError = err;
- return paHostError;
- }
- deviceRate = sourceStreamFormat.mSampleRate;
- DBUG(("PaOSX_OpenInputDevice: current device sample rate = %f\n", deviceRate ));
-
- /* Set target user format. */
- destStreamFormat = sourceStreamFormat;
- destStreamFormat.mSampleRate = past->past_SampleRate; // sample rate of the user synthesis code
- destStreamFormat.mChannelsPerFrame = past->past_NumInputChannels; // the number of channels in each frame
-
- err = AudioConverterNew (
- &sourceStreamFormat,
- &destStreamFormat,
- &pahsc->input.converter);
- if( err != noErr )
- {
- PRINT_ERR("Could not create input format converter", err);
- sSavedHostError = err;
- return paHostError;
- }
- }
-
- /* Allocate FIFO between Device callback and Converter callback so that device can push data
- * and converter can pull data.
- */
- if( needConverter || pahsc->usingSecondDevice )
- {
- double sampleRateRatio;
- long minSize, numBytes;
-
- /* Allocate an input buffer because we need it between the user callback and the converter. */
- pahsc->input.converterBuffer = PaHost_AllocateFastMemory( pahsc->input.bytesPerUserNativeBuffer );
- if( pahsc->input.converterBuffer == NULL )
- {
- return paInsufficientMemory;
- }
- sampleRateRatio = deviceRate / past->past_SampleRate;
- minSize = pahsc->input.bytesPerUserNativeBuffer * 4 * sampleRateRatio;
- numBytes = RoundUpToNextPowerOf2( minSize );
- DBUG(("PaOSX_OpenInputDevice: FIFO numBytes = %ld\n", numBytes));
- pahsc->ringBufferData = PaHost_AllocateFastMemory( numBytes );
- if( pahsc->ringBufferData == NULL )
- {
- return paInsufficientMemory;
- }
- RingBuffer_Init( &pahsc->ringBuffer, numBytes, pahsc->ringBufferData );
- // make it look full at beginning
- RingBuffer_AdvanceWriteIndex( &pahsc->ringBuffer, numBytes );
- }
-
+ return result;
+
+error:
return result;
}
/*******************************************************************/
-static PaError PaOSX_OpenOutputDevice( internalPortAudioStream *past )
+PaError PaHost_OpenOutputStream( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc;
const PaHostDeviceInfo *hostDeviceInfo;
PaError result = paNoError;
+ UInt32 bytesPerHostBuffer;
UInt32 dataSize;
OSStatus err = noErr;
- int needConverter = 0;
+ int bytesPerOutputFrame;
- DBUG(("PaOSX_OpenOutputDevice: -------------\n"));
-
pahsc = (PaHostSoundControl *) past->past_DeviceData;
DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID));
@@ -1165,141 +866,101 @@ static PaError PaOSX_OpenOutputDevice( internalPortAudioStream *past )
{
return paInvalidDeviceId;
}
-
hostDeviceInfo = &sDeviceInfos[past->past_OutputDeviceID];
-
- //PaOSX_DumpDeviceInfo( pahsc->output.audioDeviceID, IS_OUTPUT );
- PaOSX_FixVolumeScalars( pahsc->output.audioDeviceID, IS_OUTPUT,
- hostDeviceInfo->paInfo.maxOutputChannels, 0.1, 0.9 );
-
/* Try to set sample rate. */
- result = PaOSX_SetSampleRate( pahsc->output.audioDeviceID, IS_OUTPUT, past->past_SampleRate );
- if( result != paNoError )
- {
- DBUG(("PaOSX_OpenOutputDevice: Need converter for sample rate = %f\n", past->past_SampleRate ));
- needConverter = 1;
- result = paNoError;
- }
- else
- {
- DBUG(("PaOSX_OpenOutputDevice: successfully set sample rate to %f\n", past->past_SampleRate ));
- }
+ result = PaHost_SetSampleRate( hostDeviceInfo->audioDeviceID, IS_OUTPUT, past->past_SampleRate );
+ if( result != paNoError ) return result;
- if( past->past_NumOutputChannels > hostDeviceInfo->paInfo.maxOutputChannels )
- {
- return paInvalidChannelCount; /* Too many channels! */
- }
- else
+ if( past->past_NumOutputChannels != hostDeviceInfo->paInfo.maxOutputChannels )
{
+#if 1
+ return paInvalidChannelCount; // FIXME - how support mono?
+#else
/* Attempt to set number of channels. */
AudioStreamBasicDescription formatDesc;
OSStatus err;
memset( &formatDesc, 0, sizeof(AudioStreamBasicDescription) );
formatDesc.mChannelsPerFrame = past->past_NumOutputChannels;
- err = AudioDeviceSetProperty( pahsc->output.audioDeviceID, 0, 0,
+ err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0,
IS_OUTPUT, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
+
if (err != kAudioHardwareNoError)
{
- DBUG(("PaOSX_OpenOutputDevice: Need converter for num channels.\n"));
- needConverter = 1;
+ result = paInvalidChannelCount;
+ goto error;
}
+#endif
}
- /* Change the I/O bufferSize of the device. */
- dataSize = sizeof(pahsc->framesPerHostBuffer);
- err = AudioDeviceSetProperty( pahsc->output.audioDeviceID, 0, 0, IS_OUTPUT,
- kAudioDevicePropertyBufferFrameSize, dataSize,
- &pahsc->framesPerHostBuffer);
+ // calculate buffer sizes in bytes
+ bytesPerOutputFrame = Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels;
+ pahsc->pahsc_BytesPerUserNativeOutputBuffer = past->past_FramesPerUserBuffer * bytesPerOutputFrame;
+ bytesPerHostBuffer = pahsc->pahsc_FramesPerHostBuffer * bytesPerOutputFrame;
+
+ // Change the bufferSize of the device! Is this per device or just for our stream?
+ dataSize = sizeof(bytesPerHostBuffer);
+ err = AudioDeviceSetProperty( hostDeviceInfo->audioDeviceID, 0, 0, IS_OUTPUT,
+ kAudioDevicePropertyBufferSize, dataSize, &bytesPerHostBuffer);
if( err != noErr )
{
- DBUG(("PaOSX_OpenOutputDevice: Need converter for buffer size = %d\n", pahsc->framesPerHostBuffer));
- needConverter = 1;
+ ERR_RPT(("Could not force buffer size!"));
+ result = paHostError;
+ goto error;
}
-
+
// setup conversion procedure
result = PaConvert_SetupOutput( past, paFloat32 );
- if( needConverter )
- {
- AudioStreamBasicDescription sourceStreamFormat, destStreamFormat;
- DBUG(("PaOSX_OpenOutputDevice: using AUConverter!\n"));
- /* Get target device format */
- dataSize = sizeof(destStreamFormat);
- err = AudioDeviceGetProperty(pahsc->output.audioDeviceID, 0, IS_OUTPUT,
- kAudioDevicePropertyStreamFormat, &dataSize, &destStreamFormat);
- if( err != noErr )
- {
- PRINT_ERR("PaOSX_OpenOutputDevice: Could not get output device format", err);
- sSavedHostError = err;
- return paHostError;
- }
+ return result;
- /* Set source user format. */
- sourceStreamFormat = destStreamFormat;
- sourceStreamFormat.mSampleRate = past->past_SampleRate; // sample rate of the user synthesis code
- sourceStreamFormat.mChannelsPerFrame = past->past_NumOutputChannels; // the number of channels in each frame
-
- /* Allocate an output buffer because we need it between the user callback and the converter. */
- pahsc->output.converterBuffer = PaHost_AllocateFastMemory( pahsc->output.bytesPerUserNativeBuffer );
- err = AudioConverterNew (
- &sourceStreamFormat,
- &destStreamFormat,
- &pahsc->output.converter);
- if( err != noErr )
- {
- PRINT_ERR("Could not create output format converter", err);
- sSavedHostError = err;
- return paHostError;
- }
- }
-
+error:
return result;
}
+/*******************************************************************/
+PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ return pahsc->pahsc_FramesPerHostBuffer;
+}
+
+
/*******************************************************************
* Determine how many User Buffers we can put into our CoreAudio stream buffer.
* Uses:
* past->past_FramesPerUserBuffer, etc.
* Sets:
* past->past_NumUserBuffers
-* pahsc->framesPerHostBuffer
-* pahsc->input.bytesPerUserNativeBuffer
-* pahsc->output.bytesPerUserNativeBuffer
+* pahsc->pahsc_UserBuffersPerHostBuffer
+* pahsc->pahsc_FramesPerHostBuffer
*/
-static void PaOSX_CalcHostBufferSize( internalPortAudioStream *past )
+static void PaHost_CalcHostBufferSize( internalPortAudioStream *past )
{
PaHostSoundControl *pahsc = ( PaHostSoundControl *)past->past_DeviceData;
+ unsigned int minNumUserBuffers;
- // Determine number of user buffers based strictly on minimum reasonable buffer size.
- // We ignore the Pa_OpenStream numBuffer parameter because CoreAudio has a big
- // mix buffer and handles latency automatically.
- past->past_NumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
+ // Determine number of user buffers based on minimum latency.
+ minNumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
+ // Compare to user requested number in user wants more than the minimum.
+ past->past_NumUserBuffers = ( minNumUserBuffers > past->past_NumUserBuffers ) ?
+ minNumUserBuffers : past->past_NumUserBuffers;
+ DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
+ // For CoreAudio, we only have one Host buffer, so...
+ pahsc->pahsc_UserBuffersPerHostBuffer = past->past_NumUserBuffers;
// Calculate size of CoreAudio buffer.
- pahsc->framesPerHostBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers;
+ pahsc->pahsc_FramesPerHostBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers;
- // calculate buffer sizes in bytes
- pahsc->input.bytesPerUserNativeBuffer = past->past_FramesPerUserBuffer *
- Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels;
- pahsc->output.bytesPerUserNativeBuffer = past->past_FramesPerUserBuffer *
- Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels;
-
- DBUG(("PaOSX_CalcNumHostBuffers: past_NumUserBuffers = %ld\n", past->past_NumUserBuffers ));
- DBUG(("PaOSX_CalcNumHostBuffers: framesPerHostBuffer = %d\n", pahsc->framesPerHostBuffer ));
- DBUG(("PaOSX_CalcNumHostBuffers: input.bytesPerUserNativeBuffer = %d\n", pahsc->input.bytesPerUserNativeBuffer ));
- DBUG(("PaOSX_CalcNumHostBuffers: output.bytesPerUserNativeBuffer = %d\n", pahsc->output.bytesPerUserNativeBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));
}
-/*****************************************************************************/
-/************** Internal Host API ********************************************/
-/*****************************************************************************/
+/*******************************************************************/
PaError PaHost_OpenStream( internalPortAudioStream *past )
{
PaError result = paNoError;
PaHostSoundControl *pahsc;
- Boolean useInput;
- Boolean useOutput;
/* Allocate and initialize host data. */
pahsc = (PaHostSoundControl *) malloc(sizeof(PaHostSoundControl));
@@ -1310,53 +971,43 @@ PaError PaHost_OpenStream( internalPortAudioStream *past )
}
memset( pahsc, 0, sizeof(PaHostSoundControl) );
past->past_DeviceData = (void *) pahsc;
- pahsc->primaryDeviceID = kAudioDeviceUnknown;
- pahsc->input.audioDeviceID = kAudioDeviceUnknown;
- pahsc->output.audioDeviceID = kAudioDeviceUnknown;
-
- PaOSX_CalcHostBufferSize( past );
-
- /* Setup constants for CPU load measurement. */
- pahsc->inverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->framesPerHostBuffer);
- useOutput = (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0);
- useInput = (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0);
-
- // Set device IDs
- if( useOutput )
+ // If we are using both input and out, then they must be on the same CoreAudio device,
+ // until we implement a FIFO between two devices.
+ if( (past->past_OutputDeviceID != paNoDevice) && (past->past_InputDeviceID != paNoDevice) )
{
- pahsc->output.audioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID;
- pahsc->primaryDeviceID = pahsc->output.audioDeviceID;
- if( useInput )
+ AudioDeviceID inputID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
+ AudioDeviceID outputID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID;
+ if( inputID != outputID )
{
- pahsc->input.audioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
- if( pahsc->input.audioDeviceID != pahsc->primaryDeviceID )
- {
- pahsc->usingSecondDevice = TRUE; // Use two separate devices!
- }
+ ERR_RPT(("PortAudio: input and output must use same CoreAudio device!\n"));
+ return paInvalidDeviceId;
}
}
- else
+
+ PaHost_CalcHostBufferSize( past );
+
{
- /* Just input, not output. */
- pahsc->input.audioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
- pahsc->primaryDeviceID = pahsc->input.audioDeviceID;
+ int msecLatency = (int) ((PaHost_GetTotalBufferFrames(past) * 1000) / past->past_SampleRate);
+ PRINT(("PortAudio on OS X - Latency = %d frames, %d msec\n", PaHost_GetTotalBufferFrames(past), msecLatency ));
}
- DBUG(("outputDeviceID = %ld\n", pahsc->output.audioDeviceID ));
- DBUG(("inputDeviceID = %ld\n", pahsc->input.audioDeviceID ));
- DBUG(("primaryDeviceID = %ld\n", pahsc->primaryDeviceID ));
+ /* Setup constants for CPU load measurement. */
+ pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer);
+
/* ------------------ OUTPUT */
- if( useOutput )
+ if( (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0) )
{
- result = PaOSX_OpenOutputDevice( past );
+ pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID;
+ result = PaHost_OpenOutputStream( past );
if( result < 0 ) goto error;
}
/* ------------------ INPUT */
- if( useInput )
+ if( (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0) )
{
- result = PaOSX_OpenInputDevice( past );
+ pahsc->pahsc_AudioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
+ result = PaHost_OpenInputStream( past );
if( result < 0 ) goto error;
}
@@ -1390,49 +1041,21 @@ PaError PaHost_StartEngine( internalPortAudioStream *past )
past->past_StopNow = 0;
past->past_IsActive = 1;
-/* If full duplex and using two separate devices then start input device. */
- if( pahsc->usingSecondDevice )
- {
- // Associate an IO proc with the device and pass a pointer to the audio data context
- err = AudioDeviceAddIOProc(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback, past);
- if (err != noErr)
- {
- PRINT_ERR("PaHost_StartEngine: AudioDeviceAddIOProc secondary failed", err );
- goto error;
- }
-
- // start playing sound through the device
- err = AudioDeviceStart(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback);
- if (err != noErr)
- {
- PRINT_ERR("PaHost_StartEngine: AudioDeviceStart secondary failed", err );
- PRINT(("The program may succeed if you run it again!\n"));
- goto error;
- }
- }
-
// Associate an IO proc with the device and pass a pointer to the audio data context
- err = AudioDeviceAddIOProc(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback, past);
- if (err != noErr)
- {
- PRINT_ERR("PaHost_StartEngine: AudioDeviceAddIOProc primary failed", err );
- goto error;
- }
+ err = AudioDeviceAddIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc, past);
+ if (err != noErr) goto error;
// start playing sound through the device
- err = AudioDeviceStart(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback);
- if (err != noErr)
- {
- PRINT_ERR("PaHost_StartEngine: AudioDeviceStart primary failed", err );
- PRINT(("The program may succeed if you run it again!\n"));
- goto error;
- }
-
+ err = AudioDeviceStart(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc);
+ if (err != noErr) goto error;
return result;
+#if PA_TRACE_START_STOP
+ AddTraceMessage( "PaHost_StartEngine: TimeSlice() returned ", result );
+#endif
+
error:
- sSavedHostError = err;
- return paHostError;
+ return paHostError; // FIXME - save host error
}
/*************************************************************************/
@@ -1454,29 +1077,16 @@ PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
#endif
// FIXME - we should ask proc to stop instead of stopping abruptly
- err = AudioDeviceStop(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback);
- if (err != noErr)
- {
- goto error;
- }
+ err = AudioDeviceStop(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc);
+ if (err != noErr) goto Bail;
- err = AudioDeviceRemoveIOProc(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback);
- if (err != noErr) goto error;
-
-/* If full duplex and using two separate devices then start input device. */
- if( pahsc->usingSecondDevice )
- {
- err = AudioDeviceStop(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback);
- if (err != noErr) goto error;
- err = AudioDeviceRemoveIOProc(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback);
- if (err != noErr) goto error;
- }
+ err = AudioDeviceRemoveIOProc(pahsc->pahsc_AudioDeviceID, (AudioDeviceIOProc)appIOProc);
+ if (err != noErr) goto Bail;
return paNoError;
-error:
- sSavedHostError = err;
- return paHostError;
+Bail:
+ return paHostError; // FIXME - save err
}
/*************************************************************************/
@@ -1499,47 +1109,70 @@ PaError PaHost_CloseStream( internalPortAudioStream *past )
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
if( pahsc == NULL ) return paNoError;
-
- //PaOSX_DumpDeviceInfo( sDeviceInfos[past->past_OutputDeviceID].audioDeviceID, IS_OUTPUT );
#if PA_TRACE_START_STOP
AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
#endif
- if( pahsc->output.converterBuffer != NULL )
- {
- PaHost_FreeFastMemory( pahsc->output.converterBuffer, pahsc->output.bytesPerUserNativeBuffer );
- }
- if( pahsc->input.converterBuffer != NULL )
- {
- PaHost_FreeFastMemory( pahsc->input.converterBuffer, pahsc->input.bytesPerUserNativeBuffer );
- }
- if( pahsc->ringBufferData != NULL )
- {
- PaHost_FreeFastMemory( pahsc->ringBufferData, pahsc->ringBuffer.bufferSize );
- }
- if( pahsc->output.converter != NULL )
- {
- verify_noerr(AudioConverterDispose (pahsc->output.converter));
- }
- if( pahsc->input.converter != NULL )
- {
- verify_noerr(AudioConverterDispose (pahsc->input.converter));
- }
-
free( pahsc );
past->past_DeviceData = NULL;
return paNoError;
}
-/**********************************************************************
-** Initialize Host dependant part of API.
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+**
+** set PA_MIN_LATENCY_MSEC=200
+**
+** in the cshrc file.
*/
-PaError PaHost_Init( void )
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+
+#if 1
+int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond )
+{
+ int minBuffers;
+ int denominator;
+ int minLatencyMsec = PA_MIN_LATENCY_MSEC;
+ char *minLatencyText = getenv(PA_LATENCY_ENV_NAME);
+ if( minLatencyText != NULL )
+ {
+ PRINT(("PA_MIN_LATENCY_MSEC = %s\n", minLatencyText ));
+ minLatencyMsec = atoi( minLatencyText );
+ if( minLatencyMsec < 1 ) minLatencyMsec = 1;
+ else if( minLatencyMsec > 5000 ) minLatencyMsec = 5000;
+ }
+
+ denominator = 1000.0 * framesPerBuffer;
+ minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator );
+ if( minBuffers < 1 ) minBuffers = 1;
+ return minBuffers;
+}
+#else
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency.
+*/
+int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate )
{
- return PaOSX_MaybeQueryDevices();
+ int minUserBuffers;
+ int minFramesPerHostBuffer;
+
+ // Calculate minimum and maximum sizes based on timing and sample rate.
+ minFramesPerHostBuffer = (int) (PA_MIN_LATENCY_MSEC * sampleRate / 1000.0);
+ // round up to nearest multiple of 8
+ minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
+ DBUG(("Pa_GetMinNumBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
+
+ minUserBuffers = (minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer;
+ if( minUserBuffers < 1 ) minUserBuffers = 1;
+
+ return minUserBuffers;
}
+#endif
/*************************************************************************
** Cleanup device info.
@@ -1552,10 +1185,8 @@ PaError PaHost_Term( void )
{
for( i=0; i<sNumPaDevices; i++ )
{
- if( sDeviceInfos[i].paInfo.name != NULL )
- {
- free( (char*)sDeviceInfos[i].paInfo.name );
- }
+ if( sDeviceInfos[i].paInfo.name != NULL ) free( (char*)sDeviceInfos[i].paInfo.name );
+ if( sDeviceInfos[i].paInfo.sampleRates != NULL ) free( (void*)sDeviceInfos[i].paInfo.sampleRates );
}
free( sDeviceInfos );
sDeviceInfos = NULL;
@@ -1565,6 +1196,19 @@ PaError PaHost_Term( void )
return paNoError;
}
+/*************************************************************************/
+void Pa_Sleep( long msec )
+{
+#if 0
+ struct timeval timeout;
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+ select( 0, NULL, NULL, NULL, &timeout );
+#else
+ usleep( msec * 1000 );
+#endif
+}
+
/*************************************************************************
* Allocate memory that can be accessed in real-time.
* This may need to be held in physical memory so that it is not
@@ -1573,7 +1217,7 @@ PaError PaHost_Term( void )
*/
void *PaHost_AllocateFastMemory( long numBytes )
{
- void *addr = malloc( numBytes ); /* FIXME - do we need physical memory, not virtual memory? */
+ void *addr = malloc( numBytes ); /* FIXME - do we need physical memory? */
if( addr != NULL ) memset( addr, 0, numBytes );
return addr;
}
@@ -1598,57 +1242,6 @@ PaError PaHost_StreamActive( internalPortAudioStream *past )
return (PaError) past->past_IsActive;
}
-/*******************************************************************/
-PaError PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
-{
- PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
- return pahsc->framesPerHostBuffer;
-}
-
-/*****************************************************************************/
-/************** External User API ********************************************/
-/*****************************************************************************/
-
-/**********************************************************************
-** Query devices and use result.
-*/
-PaDeviceID Pa_GetDefaultInputDeviceID( void )
-{
- PaError result = PaOSX_MaybeQueryDevices();
- if( result < 0 ) return result;
- return sDefaultInputDeviceID;
-}
-
-PaDeviceID Pa_GetDefaultOutputDeviceID( void )
-{
- PaError result = PaOSX_MaybeQueryDevices();
- if( result < 0 ) return result;
- return sDefaultOutputDeviceID;
-}
-
-
-/*************************************************************************
-** Determine minimum number of buffers required for this host based
-** on minimum latency. Because CoreAudio manages latency, this just sets
-** a reasonable small buffer size.
-*/
-int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond )
-{
- int minBuffers;
- double denominator;
- int minLatencyMsec = PA_MIN_LATENCY_MSEC;
- denominator = 1000.0 * framesPerBuffer;
- minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator );
- if( minBuffers < 1 ) minBuffers = 1;
- return minBuffers;
-}
-
-/*************************************************************************/
-void Pa_Sleep( long msec )
-{
- usleep( msec * 1000 );
-}
-
/*************************************************************************/
PaTimestamp Pa_StreamTime( PortAudioStream *stream )
{
@@ -1659,37 +1252,10 @@ PaTimestamp Pa_StreamTime( PortAudioStream *stream )
if( past == NULL ) return paBadStreamPtr;
pahsc = (PaHostSoundControl *) past->past_DeviceData;
- AudioDeviceGetCurrentTime(pahsc->primaryDeviceID, &timeStamp);
+ AudioDeviceGetCurrentTime(pahsc->pahsc_AudioDeviceID, &timeStamp);
streamTime = ( timeStamp.mFlags & kAudioTimeStampSampleTimeValid) ?
timeStamp.mSampleTime : past->past_FrameCount;
return streamTime;
}
-
-/************************************************************************************/
-long Pa_GetHostError()
-{
- return sSavedHostError;
-}
-
-/*************************************************************************/
-int Pa_CountDevices()
-{
- if( sNumPaDevices <= 0 ) Pa_Initialize();
- return sNumPaDevices;
-}
-
-/*************************************************************************
-** PaDeviceInfo structures have already been created
-** so just return the pointer.
-**
-*/
-const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
-{
- if( id < 0 || id >= sNumPaDevices )
- return NULL;
-
- return &sDeviceInfos[id].paInfo;
-}
-
diff --git a/pd/portaudio/pa_mac_sm/pa_mac_sm.c b/pd/portaudio/pa_mac_sm/pa_mac_sm.c
new file mode 100644
index 00000000..59457ded
--- /dev/null
+++ b/pd/portaudio/pa_mac_sm/pa_mac_sm.c
@@ -0,0 +1,1656 @@
+/*
+ * $Id: pa_mac_sm.c,v 1.1.2.1 2002/06/07 21:20:48 rossb Exp $
+ * Portable Audio I/O Library for Macintosh
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Special thanks to Chris Rolfe for his many helpful suggestions, bug fixes,
+ * and code contributions.
+ * Thanks also to Tue Haste Andersen, Alberto Ricci, Nico Wald,
+ * Roelf Toxopeus and Tom Erbe for testing the code and making
+ * numerous suggestions.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+/* Modification History
+ PLB20010415 - ScanInputDevices was setting sDefaultOutputDeviceID instead of sDefaultInputDeviceID
+ PLB20010415 - Device Scan was crashing for anything other than siBadSoundInDevice, but some Macs may return other errors!
+ PLB20010420 - Fix TIMEOUT in record mode.
+ PLB20010420 - Change CARBON_COMPATIBLE to TARGET_API_MAC_CARBON
+ PLB20010907 - Pass unused event to WaitNextEvent to prevent Mac OSX crash. Thanks Dominic Mazzoni.
+ PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni.
+ PLB20011009 - Use NewSndCallBackUPP() for CARBON
+ PLB20020417 - I used to call Pa_GetMinNumBuffers() which doesn't take into account the
+ variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will
+ give lower latency when virtual memory is turned off.
+ Thanks Kristoffer Jensen and Georgios Marentakis for spotting this bug.
+ PLB20020423 - Use new method to calculate CPU load similar to other ports. Based on num frames calculated.
+ Fixed Pa_StreamTime(). Now estimates how many frames have played based on MicroSecond timer.
+ Added PA_MAX_USAGE_ALLOWED to prevent Mac form hanging when CPU load approaches 100%.
+ PLB20020424 - Fixed return value in Pa_StreamTime
+*/
+
+/*
+COMPATIBILITY
+This Macintosh implementation is designed for use with Mac OS 7, 8 and
+9 on PowerMacs, and OS X if compiled with CARBON
+
+OUTPUT
+A circular array of CmpSoundHeaders is used as a queue. For low latency situations
+there will only be two small buffers used. For higher latency, more and larger buffers
+may be used.
+To play the sound we use SndDoCommand() with bufferCmd. Each buffer is followed
+by a callbackCmd which informs us when the buffer has been processsed.
+
+INPUT
+The SndInput Manager SPBRecord call is used for sound input. If only
+input is used, then the PA user callback is called from the Input completion proc.
+For full-duplex, or output only operation, the PA callback is called from the
+HostBuffer output completion proc. In that case, input sound is passed to the
+callback by a simple FIFO.
+
+TODO:
+O- Add support for native sample data formats other than int16.
+O- Review buffer sizing. Should it be based on result of siDeviceBufferInfo query?
+O- Determine default devices somehow.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <math.h>
+
+/* Mac specific includes */
+#include "OSUtils.h"
+#include <MacTypes.h>
+#include <Math64.h>
+#include <Errors.h>
+#include <Sound.h>
+#include <SoundInput.h>
+#include <SoundComponents.h>
+#include <Devices.h>
+#include <DateTimeUtils.h>
+#include <Timer.h>
+#include <Gestalt.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+#ifndef FALSE
+ #define FALSE (0)
+ #define TRUE (!FALSE)
+#endif
+
+/* #define TARGET_API_MAC_CARBON (1) */
+
+/*
+ * Define maximum CPU load that will be allowed. User callback will
+ * be skipped if load exceeds this limit. This is to prevent the Mac
+ * from hanging when the CPU is hogged by the sound thread.
+ * On my PowerBook G3, the mac hung when I used 94% of CPU ( usage = 0.94 ).
+ */
+#define PA_MAX_USAGE_ALLOWED (0.92)
+
+/* Debugging output macros. */
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) /**/
+#define DBUGX(x) /* PRINT(x) /**/
+
+#define MAC_PHYSICAL_FRAMES_PER_BUFFER (512) /* Minimum number of stereo frames per SoundManager double buffer. */
+#define MAC_VIRTUAL_FRAMES_PER_BUFFER (4096) /* Need this many when using Virtual Memory for recording. */
+#define PA_MIN_NUM_HOST_BUFFERS (2)
+#define PA_MAX_NUM_HOST_BUFFERS (16) /* Do not exceed!! */
+#define PA_MAX_DEVICE_INFO (32)
+
+/* Conversions for 16.16 fixed point code. */
+#define DoubleToUnsignedFixed(x) ((UnsignedFixed) ((x) * 65536.0))
+#define UnsignedFixedToDouble(fx) (((double)(fx)) * (1.0/(1<<16)))
+
+/************************************************************************************/
+/****************** Structures ******************************************************/
+/************************************************************************************/
+/* Use for passing buffers from input callback to output callback for processing. */
+typedef struct MultiBuffer
+{
+ char *buffers[PA_MAX_NUM_HOST_BUFFERS];
+ int numBuffers;
+ int nextWrite;
+ int nextRead;
+}
+MultiBuffer;
+
+/* Define structure to contain all Macintosh specific data. */
+typedef struct PaHostSoundControl
+{
+ UInt64 pahsc_EntryCount;
+ double pahsc_InverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
+
+ /* Use char instead of Boolean for atomic operation. */
+ volatile char pahsc_IsRecording; /* Recording in progress. Set by foreground. Cleared by background. */
+ volatile char pahsc_StopRecording; /* Signal sent to background. */
+ volatile char pahsc_IfInsideCallback;
+ /* Input */
+ SPB pahsc_InputParams;
+ SICompletionUPP pahsc_InputCompletionProc;
+ MultiBuffer pahsc_InputMultiBuffer;
+ int32 pahsc_BytesPerInputHostBuffer;
+ int32 pahsc_InputRefNum;
+ /* Output */
+ CmpSoundHeader pahsc_SoundHeaders[PA_MAX_NUM_HOST_BUFFERS];
+ int32 pahsc_BytesPerOutputHostBuffer;
+ SndChannelPtr pahsc_Channel;
+ SndCallBackUPP pahsc_OutputCompletionProc;
+ int32 pahsc_NumOutsQueued;
+ int32 pahsc_NumOutsPlayed;
+ PaTimestamp pahsc_NumFramesDone;
+ UInt64 pahsc_WhenFramesDoneIncremented;
+ /* Init Time -------------- */
+ int32 pahsc_NumHostBuffers;
+ int32 pahsc_FramesPerHostBuffer;
+ int32 pahsc_UserBuffersPerHostBuffer;
+ int32 pahsc_MinFramesPerHostBuffer; /* Can vary depending on virtual memory usage. */
+}
+PaHostSoundControl;
+
+/* Mac specific device information. */
+typedef struct internalPortAudioDevice
+{
+ long pad_DeviceRefNum;
+ long pad_DeviceBufferSize;
+ Component pad_Identifier;
+ PaDeviceInfo pad_Info;
+}
+internalPortAudioDevice;
+
+/************************************************************************************/
+/****************** Data ************************************************************/
+/************************************************************************************/
+static int sNumDevices = 0;
+static internalPortAudioDevice sDevices[PA_MAX_DEVICE_INFO] = { 0 };
+static int32 sPaHostError = 0;
+static int sDefaultOutputDeviceID;
+static int sDefaultInputDeviceID;
+
+/************************************************************************************/
+/****************** Prototypes ******************************************************/
+/************************************************************************************/
+static PaError PaMac_TimeSlice( internalPortAudioStream *past, int16 *macOutputBufPtr );
+static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr );
+static PaError PaMac_RecordNext( internalPortAudioStream *past );
+static void PaMac_StartLoadCalculation( internalPortAudioStream *past );
+static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerBuffer, double sampleRate );
+static double *PaMac_GetSampleRatesFromHandle ( int numRates, Handle h );
+static PaError PaMac_ScanInputDevices( void );
+static PaError PaMac_ScanOutputDevices( void );
+static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad );
+static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad );
+static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader );
+static void PaMac_EndLoadCalculation( internalPortAudioStream *past );
+static void PaMac_PlayNext ( internalPortAudioStream *past, int index );
+static long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index );
+static pascal void PaMac_InputCompletionProc(SPBPtr recParams);
+static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCmd);
+static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index );
+long PaHost_GetTotalBufferFrames( internalPortAudioStream *past );
+static int Mac_IsVirtualMemoryOn( void );
+static void PToCString(unsigned char* inString, char* outString);
+char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf );
+char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf );
+int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf );
+int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf );
+int MultiBuffer_IsWriteable( MultiBuffer *mbuf );
+int MultiBuffer_IsReadable( MultiBuffer *mbuf );
+void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf );
+void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf );
+
+/*************************************************************************
+** Simple FIFO index control for multiple buffers.
+** Read and Write indices range from 0 to 2N-1.
+** This allows us to distinguish between full and empty.
+*/
+char *MultiBuffer_GetNextWriteBuffer( MultiBuffer *mbuf )
+{
+ return mbuf->buffers[mbuf->nextWrite % mbuf->numBuffers];
+}
+char *MultiBuffer_GetNextReadBuffer( MultiBuffer *mbuf )
+{
+ return mbuf->buffers[mbuf->nextRead % mbuf->numBuffers];
+}
+int MultiBuffer_GetNextReadIndex( MultiBuffer *mbuf )
+{
+ return mbuf->nextRead % mbuf->numBuffers;
+}
+int MultiBuffer_GetNextWriteIndex( MultiBuffer *mbuf )
+{
+ return mbuf->nextWrite % mbuf->numBuffers;
+}
+
+int MultiBuffer_IsWriteable( MultiBuffer *mbuf )
+{
+ int bufsFull = mbuf->nextWrite - mbuf->nextRead;
+ if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers);
+ return (bufsFull < mbuf->numBuffers);
+}
+int MultiBuffer_IsReadable( MultiBuffer *mbuf )
+{
+ int bufsFull = mbuf->nextWrite - mbuf->nextRead;
+ if( bufsFull < 0 ) bufsFull += (2 * mbuf->numBuffers);
+ return (bufsFull > 0);
+}
+void MultiBuffer_AdvanceReadIndex( MultiBuffer *mbuf )
+{
+ int temp = mbuf->nextRead + 1;
+ mbuf->nextRead = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp;
+}
+void MultiBuffer_AdvanceWriteIndex( MultiBuffer *mbuf )
+{
+ int temp = mbuf->nextWrite + 1;
+ mbuf->nextWrite = (temp >= (2 * mbuf->numBuffers)) ? 0 : temp;
+}
+
+/*************************************************************************
+** String Utility by Chris Rolfe
+*/
+static void PToCString(unsigned char* inString, char* outString)
+{
+ long i;
+ for(i=0; i<inString[0]; i++) /* convert Pascal to C string */
+ outString[i] = inString[i+1];
+ outString[i]=0;
+}
+
+/*************************************************************************/
+PaError PaHost_Term( void )
+{
+ int i;
+ PaDeviceInfo *dev;
+ double *rates;
+ /* Free any allocated sample rate arrays. */
+ for( i=0; i<sNumDevices; i++ )
+ {
+ dev = &sDevices[i].pad_Info;
+ rates = (double *) dev->sampleRates;
+ if( (rates != NULL) ) free( rates ); /* MEM_011 */
+ dev->sampleRates = NULL;
+ if( dev->name != NULL ) free( (void *) dev->name ); /* MEM_010 */
+ dev->name = NULL;
+ }
+ sNumDevices = 0;
+ return paNoError;
+}
+
+/*************************************************************************
+ PaHost_Init() is the library initialization function - call this before
+ using the library.
+*/
+PaError PaHost_Init( void )
+{
+ PaError err;
+ NumVersionVariant version;
+
+ version.parts = SndSoundManagerVersion();
+ DBUG(("SndSoundManagerVersion = 0x%x\n", version.whole));
+
+ /* Have we already initialized the device info? */
+ err = (PaError) Pa_CountDevices();
+ if( err < 0 ) return err;
+ else return paNoError;
+}
+
+/*************************************************************************
+ PaMac_ScanOutputDevices() queries the properties of all output devices.
+*/
+static PaError PaMac_ScanOutputDevices( void )
+{
+ PaError err;
+ Component identifier=0;
+ ComponentDescription criteria = { kSoundOutputDeviceType, 0, 0, 0, 0 };
+ long numComponents, i;
+
+ /* Search the system linked list for output components */
+ numComponents = CountComponents (&criteria);
+ identifier = 0;
+ sDefaultOutputDeviceID = sNumDevices; /* FIXME - query somehow */
+ for (i = 0; i < numComponents; i++)
+ {
+ /* passing nil returns first matching component. */
+ identifier = FindNextComponent( identifier, &criteria);
+ sDevices[sNumDevices].pad_Identifier = identifier;
+
+ /* Set up for default OUTPUT devices. */
+ err = PaMac_QueryOutputDeviceInfo( identifier, &sDevices[sNumDevices] );
+ if( err < 0 ) return err;
+ else sNumDevices++;
+
+ }
+
+ return paNoError;
+}
+
+/*************************************************************************
+ PaMac_ScanInputDevices() queries the properties of all input devices.
+*/
+static PaError PaMac_ScanInputDevices( void )
+{
+ Str255 deviceName;
+ int count;
+ Handle iconHandle;
+ PaError err;
+ OSErr oserr;
+ count = 1;
+ sDefaultInputDeviceID = sNumDevices; /* FIXME - query somehow */ /* PLB20010415 - was setting sDefaultOutputDeviceID */
+ while(true)
+ {
+ /* Thanks Chris Rolfe and Alberto Ricci for this trick. */
+ oserr = SPBGetIndexedDevice(count++, deviceName, &iconHandle);
+ DBUG(("PaMac_ScanInputDevices: SPBGetIndexedDevice returned %d\n", oserr ));
+#if 1
+ /* PLB20010415 - was giving error for anything other than siBadSoundInDevice, but some Macs may return other errors! */
+ if(oserr != noErr) break; /* Some type of error is expected when count > devices */
+#else
+ if(oserr == siBadSoundInDevice)
+ { /* it's expected when count > devices */
+ oserr = noErr;
+ break;
+ }
+ if(oserr != noErr)
+ {
+ ERR_RPT(("ERROR: SPBGetIndexedDevice(%d,,) returned %d\n", count-1, oserr ));
+ sPaHostError = oserr;
+ return paHostError;
+ }
+#endif
+ DisposeHandle(iconHandle); /* Don't need the icon */
+
+ err = PaMac_QueryInputDeviceInfo( deviceName, &sDevices[sNumDevices] );
+ DBUG(("PaMac_ScanInputDevices: PaMac_QueryInputDeviceInfo returned %d\n", err ));
+ if( err < 0 ) return err;
+ else if( err == 1 ) sNumDevices++;
+ }
+
+ return paNoError;
+}
+
+/* Sample rate info returned by using siSampleRateAvailable selector in SPBGetDeviceInfo() */
+/* Thanks to Chris Rolfe for help with this query. */
+#pragma options align=mac68k
+typedef struct
+{
+ int16 numRates;
+ UnsignedFixed (**rates)[]; /* Handle created by SPBGetDeviceInfo */
+}
+SRateInfo;
+#pragma options align=reset
+
+/*************************************************************************
+** PaMac_QueryOutputDeviceInfo()
+** Query information about a named output device.
+** Clears contents of ipad and writes info based on queries.
+** Return one if OK,
+** zero if device cannot be used,
+** or negative error.
+*/
+static PaError PaMac_QueryOutputDeviceInfo( Component identifier, internalPortAudioDevice *ipad )
+{
+ int len;
+ OSErr err;
+ PaDeviceInfo *dev = &ipad->pad_Info;
+ SRateInfo srinfo = {0};
+ int numRates;
+ ComponentDescription tempD;
+ Handle nameH=nil, infoH=nil, iconH=nil;
+
+ memset( ipad, 0, sizeof(internalPortAudioDevice) );
+
+ dev->structVersion = 1;
+ dev->maxInputChannels = 0;
+ dev->maxOutputChannels = 2;
+ dev->nativeSampleFormats = paInt16; /* FIXME - query to see if 24 or 32 bit data can be handled. */
+
+ /* Get sample rates supported. */
+ err = GetSoundOutputInfo(identifier, siSampleRateAvailable, (Ptr) &srinfo);
+ if(err != noErr)
+ {
+ ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetSoundOutputInfo siSampleRateAvailable returned %d\n", err ));
+ goto error;
+ }
+ numRates = srinfo.numRates;
+ DBUG(("PaMac_QueryOutputDeviceInfo: srinfo.numRates = 0x%x\n", srinfo.numRates ));
+ if( numRates == 0 )
+ {
+ dev->numSampleRates = -1;
+ numRates = 2;
+ }
+ else
+ {
+ dev->numSampleRates = numRates;
+ }
+ dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates );
+ /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */
+ DisposeHandle((Handle) srinfo.rates);
+
+ /* Device name */
+ /* we pass an existing handle for the component name;
+ we don't care about the info (type, subtype, etc.) or icon, so set them to nil */
+ infoH = nil;
+ iconH = nil;
+ nameH = NewHandle(0);
+ if(nameH == nil) return paInsufficientMemory;
+ err = GetComponentInfo(identifier, &tempD, nameH, infoH, iconH);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryOutputDeviceInfo: GetComponentInfo returned %d\n", err ));
+ goto error;
+ }
+ len = (*nameH)[0] + 1;
+ dev->name = (char *) malloc(len); /* MEM_010 */
+ if( dev->name == NULL )
+ {
+ DisposeHandle(nameH);
+ return paInsufficientMemory;
+ }
+ else
+ {
+ PToCString((unsigned char *)(*nameH), (char *) dev->name);
+ DisposeHandle(nameH);
+ }
+
+ DBUG(("PaMac_QueryOutputDeviceInfo: dev->name = %s\n", dev->name ));
+ return paNoError;
+
+error:
+ sPaHostError = err;
+ return paHostError;
+
+}
+
+/*************************************************************************
+** PaMac_QueryInputDeviceInfo()
+** Query information about a named input device.
+** Clears contents of ipad and writes info based on queries.
+** Return one if OK,
+** zero if device cannot be used,
+** or negative error.
+*/
+static PaError PaMac_QueryInputDeviceInfo( Str255 deviceName, internalPortAudioDevice *ipad )
+{
+ PaError result = paNoError;
+ int len;
+ OSErr err;
+ long mRefNum = 0;
+ long tempL;
+ int16 tempS;
+ Fixed tempF;
+ PaDeviceInfo *dev = &ipad->pad_Info;
+ SRateInfo srinfo = {0};
+ int numRates;
+
+ memset( ipad, 0, sizeof(internalPortAudioDevice) );
+ dev->maxOutputChannels = 0;
+
+ /* Open device based on name. If device is in use, it may not be able to open in write mode. */
+ err = SPBOpenDevice( deviceName, siWritePermission, &mRefNum);
+ if (err)
+ {
+ /* If device is in use, it may not be able to open in write mode so try read mode. */
+ err = SPBOpenDevice( deviceName, siReadPermission, &mRefNum);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBOpenDevice returned %d\n", err ));
+ sPaHostError = err;
+ return paHostError;
+ }
+ }
+
+ /* Define macros for printing out device info. */
+#define PrintDeviceInfo(selector,var) \
+ err = SPBGetDeviceInfo(mRefNum, selector, (Ptr) &var); \
+ if (err) { \
+ DBUG(("query %s failed\n", #selector )); \
+ }\
+ else { \
+ DBUG(("query %s = 0x%x\n", #selector, var )); \
+ }
+
+ PrintDeviceInfo( siContinuous, tempS );
+ PrintDeviceInfo( siAsync, tempS );
+ PrintDeviceInfo( siNumberChannels, tempS );
+ PrintDeviceInfo( siSampleSize, tempS );
+ PrintDeviceInfo( siSampleRate, tempF );
+ PrintDeviceInfo( siChannelAvailable, tempS );
+ PrintDeviceInfo( siActiveChannels, tempL );
+ PrintDeviceInfo( siDeviceBufferInfo, tempL );
+
+ err = SPBGetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL);
+ if (err == 0) DBUG(("%s = 0x%x\n", "siActiveChannels", tempL ));
+ /* Can we use this device? */
+ err = SPBGetDeviceInfo(mRefNum, siAsync, (Ptr) &tempS);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siAsync returned %d\n", err ));
+ goto error;
+ }
+ if( tempS == 0 ) goto useless; /* Does not support async recording so forget about it. */
+
+ err = SPBGetDeviceInfo(mRefNum, siChannelAvailable, (Ptr) &tempS);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siChannelAvailable returned %d\n", err ));
+ goto error;
+ }
+ dev->maxInputChannels = tempS;
+
+ /* Get sample rates supported. */
+ err = SPBGetDeviceInfo(mRefNum, siSampleRateAvailable, (Ptr) &srinfo);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleRateAvailable returned %d\n", err ));
+ goto error;
+ }
+
+ numRates = srinfo.numRates;
+ DBUG(("numRates = 0x%x\n", numRates ));
+ if( numRates == 0 )
+ {
+ dev->numSampleRates = -1;
+ numRates = 2;
+ }
+ else
+ {
+ dev->numSampleRates = numRates;
+ }
+ dev->sampleRates = PaMac_GetSampleRatesFromHandle( numRates, (Handle) srinfo.rates );
+ /* SPBGetDeviceInfo created the handle, but it's OUR job to release it. */
+ DisposeHandle((Handle) srinfo.rates);
+
+ /* Get size of device buffer. */
+ err = SPBGetDeviceInfo(mRefNum, siDeviceBufferInfo, (Ptr) &tempL);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siDeviceBufferInfo returned %d\n", err ));
+ goto error;
+ }
+ ipad->pad_DeviceBufferSize = tempL;
+ DBUG(("siDeviceBufferInfo = %d\n", tempL ));
+
+ /* Set format based on sample size. */
+ err = SPBGetDeviceInfo(mRefNum, siSampleSize, (Ptr) &tempS);
+ if (err)
+ {
+ ERR_RPT(("Error in PaMac_QueryInputDeviceInfo: SPBGetDeviceInfo siSampleSize returned %d\n", err ));
+ goto error;
+ }
+ switch( tempS )
+ {
+ case 0x0020:
+ dev->nativeSampleFormats = paInt32; /* FIXME - warning, code probably won't support this! */
+ break;
+ case 0x0010:
+ default: /* FIXME - What about other formats? */
+ dev->nativeSampleFormats = paInt16;
+ break;
+ }
+ DBUG(("nativeSampleFormats = %d\n", dev->nativeSampleFormats ));
+
+ /* Device name */
+ len = deviceName[0] + 1; /* Get length of Pascal string */
+ dev->name = (char *) malloc(len); /* MEM_010 */
+ if( dev->name == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ PToCString(deviceName, (char *) dev->name);
+ DBUG(("deviceName = %s\n", dev->name ));
+ result = (PaError) 1;
+ /* All done so close up device. */
+cleanup:
+ if( mRefNum ) SPBCloseDevice(mRefNum);
+ return result;
+
+error:
+ if( mRefNum ) SPBCloseDevice(mRefNum);
+ sPaHostError = err;
+ return paHostError;
+
+useless:
+ if( mRefNum ) SPBCloseDevice(mRefNum);
+ return (PaError) 0;
+}
+
+/*************************************************************************
+** Allocate a double array and fill it with listed sample rates.
+*/
+static double * PaMac_GetSampleRatesFromHandle ( int numRates, Handle h )
+{
+ OSErr err = noErr;
+ SInt8 hState;
+ int i;
+ UnsignedFixed *fixedRates;
+ double *rates = (double *) malloc( numRates * sizeof(double) ); /* MEM_011 */
+ if( rates == NULL ) return NULL;
+ /* Save and restore handle state as suggested by TechNote at:
+ http://developer.apple.com/technotes/tn/tn1122.html
+ */
+ hState = HGetState (h);
+ if (!(err = MemError ()))
+ {
+ HLock (h);
+ if (!(err = MemError ( )))
+ {
+ fixedRates = (UInt32 *) *h;
+ for( i=0; i<numRates; i++ )
+ {
+ rates[i] = UnsignedFixedToDouble(fixedRates[i]);
+ }
+
+ HSetState (h,hState);
+ err = MemError ( );
+ }
+ }
+ if( err )
+ {
+ free( rates );
+ ERR_RPT(("Error in PaMac_GetSampleRatesFromHandle = %d\n", err ));
+ }
+ return rates;
+}
+
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ PaError err;
+ DBUG(("Pa_CountDevices()\n"));
+ /* If no devices, go find some. */
+ if( sNumDevices <= 0 )
+ {
+ err = PaMac_ScanOutputDevices();
+ if( err != paNoError ) goto error;
+ err = PaMac_ScanInputDevices();
+ if( err != paNoError ) goto error;
+ }
+ return sNumDevices;
+
+error:
+ PaHost_Term();
+ DBUG(("Pa_CountDevices: returns %d\n", err ));
+ return err;
+
+}
+
+/*************************************************************************/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
+ return &sDevices[id].pad_Info;
+}
+/*************************************************************************/
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
+{
+ return sDefaultInputDeviceID;
+}
+
+/*************************************************************************/
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
+{
+ return sDefaultOutputDeviceID;
+}
+
+/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
+static void PaMac_StartLoadCalculation( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ UnsignedWide widePad;
+ if( pahsc == NULL ) return;
+ /* Query system timer for usage analysis and to prevent overuse of CPU. */
+ Microseconds( &widePad );
+ pahsc->pahsc_EntryCount = UnsignedWideToUInt64( widePad );
+}
+
+/******************************************************************************
+** Measure fractional CPU load based on real-time it took to calculate
+** buffers worth of output.
+*/
+/**************************************************************************/
+static void PaMac_EndLoadCalculation( internalPortAudioStream *past )
+{
+ UnsignedWide widePad;
+ UInt64 currentCount;
+ long usecsElapsed;
+ double newUsage;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+
+ /* Measure CPU utilization during this callback. Note that this calculation
+ ** assumes that we had the processor the whole time.
+ */
+#define LOWPASS_COEFFICIENT_0 (0.95)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+ Microseconds( &widePad );
+ currentCount = UnsignedWideToUInt64( widePad );
+
+ usecsElapsed = (long) U64Subtract(currentCount, pahsc->pahsc_EntryCount);
+
+ /* Use inverse because it is faster than the divide. */
+ newUsage = usecsElapsed * pahsc->pahsc_InverseMicrosPerHostBuffer;
+
+ past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
+ (LOWPASS_COEFFICIENT_1 * newUsage);
+
+}
+
+/***********************************************************************
+** Called by Pa_StartStream()
+*/
+PaError PaHost_StartInput( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ pahsc->pahsc_IsRecording = 0;
+ pahsc->pahsc_StopRecording = 0;
+ pahsc->pahsc_InputMultiBuffer.nextWrite = 0;
+ pahsc->pahsc_InputMultiBuffer.nextRead = 0;
+ return PaMac_RecordNext( past );
+}
+
+/***********************************************************************
+** Called by Pa_StopStream().
+** May be called during error recovery or cleanup code
+** so protect against NULL pointers.
+*/
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
+{
+ int32 timeOutMsec;
+ PaError result = paNoError;
+ OSErr err = 0;
+ long mRefNum;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+
+ (void) abort;
+
+ mRefNum = pahsc->pahsc_InputRefNum;
+
+ DBUG(("PaHost_StopInput: mRefNum = %d\n", mRefNum ));
+ if( mRefNum )
+ {
+ DBUG(("PaHost_StopInput: pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording ));
+ if( pahsc->pahsc_IsRecording )
+ {
+ /* PLB20010420 - Fix TIMEOUT in record mode. */
+ pahsc->pahsc_StopRecording = 1; /* Request that we stop recording. */
+ err = SPBStopRecording(mRefNum);
+ DBUG(("PaHost_StopInput: then pahsc_IsRecording = %d\n", pahsc->pahsc_IsRecording ));
+
+ /* Calculate timeOut longer than longest time it could take to play one buffer. */
+ timeOutMsec = (int32) ((1500.0 * pahsc->pahsc_FramesPerHostBuffer) / past->past_SampleRate);
+ /* Keep querying sound channel until it is no longer busy playing. */
+ while( !err && pahsc->pahsc_IsRecording && (timeOutMsec > 0))
+ {
+ Pa_Sleep(20);
+ timeOutMsec -= 20;
+ }
+ if( timeOutMsec <= 0 )
+ {
+ ERR_RPT(("PaHost_StopInput: timed out!\n"));
+ return paTimedOut;
+ }
+ }
+ }
+ if( err )
+ {
+ sPaHostError = err;
+ result = paHostError;
+ }
+
+ DBUG(("PaHost_StopInput: finished.\n", mRefNum ));
+ return result;
+}
+
+/***********************************************************************/
+static void PaMac_InitSoundHeader( internalPortAudioStream *past, CmpSoundHeader *sndHeader )
+{
+ sndHeader->numChannels = past->past_NumOutputChannels;
+ sndHeader->sampleRate = DoubleToUnsignedFixed(past->past_SampleRate);
+ sndHeader->loopStart = 0;
+ sndHeader->loopEnd = 0;
+ sndHeader->encode = cmpSH;
+ sndHeader->baseFrequency = kMiddleC;
+ sndHeader->markerChunk = nil;
+ sndHeader->futureUse2 = nil;
+ sndHeader->stateVars = nil;
+ sndHeader->leftOverSamples = nil;
+ sndHeader->compressionID = 0;
+ sndHeader->packetSize = 0;
+ sndHeader->snthID = 0;
+ sndHeader->sampleSize = 8 * sizeof(int16); // FIXME - might be 24 or 32 bits some day;
+ sndHeader->sampleArea[0] = 0;
+ sndHeader->format = kSoundNotCompressed;
+}
+
+static void SetFramesDone( PaHostSoundControl *pahsc, PaTimestamp framesDone )
+{
+ UnsignedWide now;
+ Microseconds( &now );
+ pahsc->pahsc_NumFramesDone = framesDone;
+ pahsc->pahsc_WhenFramesDoneIncremented = UnsignedWideToUInt64( now );
+}
+
+/***********************************************************************/
+PaError PaHost_StartOutput( internalPortAudioStream *past )
+{
+ SndCommand pauseCommand;
+ SndCommand resumeCommand;
+ int i;
+ OSErr error;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+ if( pahsc->pahsc_Channel == NULL ) return paInternalError;
+
+ past->past_StopSoon = 0;
+ past->past_IsActive = 1;
+ pahsc->pahsc_NumOutsQueued = 0;
+ pahsc->pahsc_NumOutsPlayed = 0;
+
+ SetFramesDone( pahsc, 0.0 );
+
+ /* Pause channel so it does not do back ground processing while we are still filling the queue. */
+ pauseCommand.cmd = pauseCmd;
+ pauseCommand.param1 = pauseCommand.param2 = 0;
+ error = SndDoCommand (pahsc->pahsc_Channel, &pauseCommand, true);
+ if (noErr != error) goto exit;
+
+ /* Queue all of the buffers so we start off full. */
+ for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
+ {
+ PaMac_PlayNext( past, i );
+ }
+
+ /* Resume channel now that the queue is full. */
+ resumeCommand.cmd = resumeCmd;
+ resumeCommand.param1 = resumeCommand.param2 = 0;
+ error = SndDoImmediate( pahsc->pahsc_Channel, &resumeCommand );
+ if (noErr != error) goto exit;
+
+ return paNoError;
+exit:
+ past->past_IsActive = 0;
+ sPaHostError = error;
+ ERR_RPT(("Error in PaHost_StartOutput: SndDoCommand returned %d\n", error ));
+ return paHostError;
+}
+
+/*******************************************************************/
+long PaHost_GetTotalBufferFrames( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ return (long) (pahsc->pahsc_NumHostBuffers * pahsc->pahsc_FramesPerHostBuffer);
+}
+
+/***********************************************************************
+** Called by Pa_StopStream().
+** May be called during error recovery or cleanup code
+** so protect against NULL pointers.
+*/
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+{
+ int32 timeOutMsec;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ if( pahsc->pahsc_Channel == NULL ) return paNoError;
+
+ DBUG(("PaHost_StopOutput()\n"));
+ if( past->past_IsActive == 0 ) return paNoError;
+
+ /* Set flags for callback function to see. */
+ if( abort ) past->past_StopNow = 1;
+ past->past_StopSoon = 1;
+ /* Calculate timeOut longer than longest time it could take to play all buffers. */
+ timeOutMsec = (int32) ((1500.0 * PaHost_GetTotalBufferFrames( past )) / past->past_SampleRate);
+ /* Keep querying sound channel until it is no longer busy playing. */
+ while( past->past_IsActive && (timeOutMsec > 0))
+ {
+ Pa_Sleep(20);
+ timeOutMsec -= 20;
+ }
+ if( timeOutMsec <= 0 )
+ {
+ ERR_RPT(("PaHost_StopOutput: timed out!\n"));
+ return paTimedOut;
+ }
+ else return paNoError;
+}
+
+/***********************************************************************/
+PaError PaHost_StartEngine( internalPortAudioStream *past )
+{
+ (void) past; /* Prevent unused variable warnings. */
+ return paNoError;
+}
+
+/***********************************************************************/
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+{
+ (void) past; /* Prevent unused variable warnings. */
+ (void) abort; /* Prevent unused variable warnings. */
+ return paNoError;
+}
+/***********************************************************************/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ return (PaError) ( past->past_IsActive + pahsc->pahsc_IsRecording );
+}
+int Mac_IsVirtualMemoryOn( void )
+{
+ long attr;
+ OSErr result = Gestalt( gestaltVMAttr, &attr );
+ DBUG(("gestaltVMAttr : 0x%x\n", attr ));
+ return ((attr >> gestaltVMHasPagingControl ) & 1);
+}
+
+/*******************************************************************
+* Determine number of host Buffers
+* and how many User Buffers we can put into each host buffer.
+*/
+static void PaHost_CalcNumHostBuffers( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ int32 minNumBuffers;
+ int32 minFramesPerHostBuffer;
+ int32 minTotalFrames;
+ int32 userBuffersPerHostBuffer;
+ int32 framesPerHostBuffer;
+ int32 numHostBuffers;
+
+ minFramesPerHostBuffer = pahsc->pahsc_MinFramesPerHostBuffer;
+ minFramesPerHostBuffer = (minFramesPerHostBuffer + 7) & ~7;
+ DBUG(("PaHost_CalcNumHostBuffers: minFramesPerHostBuffer = %d\n", minFramesPerHostBuffer ));
+
+ /* Determine number of user buffers based on minimum latency. */
+ /* PLB20020417 I used to call Pa_GetMinNumBuffers() which doesn't take into account the
+ ** variable minFramesPerHostBuffer. Now I call PaMac_GetMinNumBuffers() which will
+ ** gove lower latency when virtual memory is turned off. */
+ /* minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate ); WRONG */
+ minNumBuffers = PaMac_GetMinNumBuffers( minFramesPerHostBuffer, past->past_FramesPerUserBuffer, past->past_SampleRate );
+
+ past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers;
+ DBUG(("PaHost_CalcNumHostBuffers: min past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
+ minTotalFrames = past->past_NumUserBuffers * past->past_FramesPerUserBuffer;
+
+ /* We cannot make the buffers too small because they may not get serviced quickly enough. */
+ if( (int32) past->past_FramesPerUserBuffer < minFramesPerHostBuffer )
+ {
+ userBuffersPerHostBuffer =
+ (minFramesPerHostBuffer + past->past_FramesPerUserBuffer - 1) /
+ past->past_FramesPerUserBuffer;
+ }
+ else
+ {
+ userBuffersPerHostBuffer = 1;
+ }
+ framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
+
+ /* Calculate number of host buffers needed. Round up to cover minTotalFrames. */
+ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
+ /* Make sure we have enough host buffers. */
+ if( numHostBuffers < PA_MIN_NUM_HOST_BUFFERS)
+ {
+ numHostBuffers = PA_MIN_NUM_HOST_BUFFERS;
+ }
+ else
+ {
+ /* If we have too many host buffers, try to put more user buffers in a host buffer. */
+ while(numHostBuffers > PA_MAX_NUM_HOST_BUFFERS)
+ {
+ userBuffersPerHostBuffer += 1;
+ framesPerHostBuffer = past->past_FramesPerUserBuffer * userBuffersPerHostBuffer;
+ numHostBuffers = (minTotalFrames + framesPerHostBuffer - 1) / framesPerHostBuffer;
+ }
+ }
+
+ pahsc->pahsc_UserBuffersPerHostBuffer = userBuffersPerHostBuffer;
+ pahsc->pahsc_FramesPerHostBuffer = framesPerHostBuffer;
+ pahsc->pahsc_NumHostBuffers = numHostBuffers;
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_UserBuffersPerHostBuffer = %d\n", pahsc->pahsc_UserBuffersPerHostBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_NumHostBuffers = %d\n", pahsc->pahsc_NumHostBuffers ));
+ DBUG(("PaHost_CalcNumHostBuffers: pahsc_FramesPerHostBuffer = %d\n", pahsc->pahsc_FramesPerHostBuffer ));
+ DBUG(("PaHost_CalcNumHostBuffers: past_NumUserBuffers = %d\n", past->past_NumUserBuffers ));
+}
+
+/*******************************************************************/
+PaError PaHost_OpenStream( internalPortAudioStream *past )
+{
+ OSErr err;
+ PaError result = paHostError;
+ PaHostSoundControl *pahsc;
+ int i;
+ /* Allocate and initialize host data. */
+ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
+ if( pahsc == NULL )
+ {
+ return paInsufficientMemory;
+ }
+ past->past_DeviceData = (void *) pahsc;
+
+ /* If recording, and virtual memory is turned on, then use bigger buffers to prevent glitches. */
+ if( (past->past_NumInputChannels > 0) && Mac_IsVirtualMemoryOn() )
+ {
+ pahsc->pahsc_MinFramesPerHostBuffer = MAC_VIRTUAL_FRAMES_PER_BUFFER;
+ }
+ else
+ {
+ pahsc->pahsc_MinFramesPerHostBuffer = MAC_PHYSICAL_FRAMES_PER_BUFFER;
+ }
+
+ PaHost_CalcNumHostBuffers( past );
+
+ /* Setup constants for CPU load measurement. */
+ pahsc->pahsc_InverseMicrosPerHostBuffer = past->past_SampleRate / (1000000.0 * pahsc->pahsc_FramesPerHostBuffer);
+
+ /* ------------------ OUTPUT */
+ if( past->past_NumOutputChannels > 0 )
+ {
+ /* Create sound channel to which we can send commands. */
+ pahsc->pahsc_Channel = 0L;
+ err = SndNewChannel(&pahsc->pahsc_Channel, sampledSynth, 0, nil); /* FIXME - use kUseOptionalOutputDevice if not default. */
+ if(err != 0)
+ {
+ ERR_RPT(("Error in PaHost_OpenStream: SndNewChannel returned 0x%x\n", err ));
+ goto error;
+ }
+
+ /* Install our callback function pointer straight into the sound channel structure */
+ /* Use new CARBON name for callback procedure. */
+#if TARGET_API_MAC_CARBON
+ pahsc->pahsc_OutputCompletionProc = NewSndCallBackUPP(PaMac_OutputCompletionProc);
+#else
+ pahsc->pahsc_OutputCompletionProc = NewSndCallBackProc(PaMac_OutputCompletionProc);
+#endif
+
+ pahsc->pahsc_Channel->callBack = pahsc->pahsc_OutputCompletionProc;
+
+ pahsc->pahsc_BytesPerOutputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumOutputChannels * sizeof(int16);
+ for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
+ {
+ char *buf = (char *)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputHostBuffer);
+ if (buf == NULL)
+ {
+ ERR_RPT(("Error in PaHost_OpenStream: could not allocate output buffer. Size = \n", pahsc->pahsc_BytesPerOutputHostBuffer ));
+ goto memerror;
+ }
+
+ PaMac_InitSoundHeader( past, &pahsc->pahsc_SoundHeaders[i] );
+ pahsc->pahsc_SoundHeaders[i].samplePtr = buf;
+ pahsc->pahsc_SoundHeaders[i].numFrames = (unsigned long) pahsc->pahsc_FramesPerHostBuffer;
+
+ }
+ }
+#ifdef SUPPORT_AUDIO_CAPTURE
+ /* ------------------ INPUT */
+ /* Use double buffer scheme that matches output. */
+ if( past->past_NumInputChannels > 0 )
+ {
+ int16 tempS;
+ long tempL;
+ Fixed tempF;
+ long mRefNum;
+ unsigned char noname = 0; /* FIXME - use real device names. */
+#if TARGET_API_MAC_CARBON
+ pahsc->pahsc_InputCompletionProc = NewSICompletionUPP((SICompletionProcPtr)PaMac_InputCompletionProc);
+#else
+ pahsc->pahsc_InputCompletionProc = NewSICompletionProc((ProcPtr)PaMac_InputCompletionProc);
+#endif
+ pahsc->pahsc_BytesPerInputHostBuffer = pahsc->pahsc_FramesPerHostBuffer * past->past_NumInputChannels * sizeof(int16);
+ for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
+ {
+ char *buf = (char *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputHostBuffer);
+ if ( buf == NULL )
+ {
+ ERR_RPT(("PaHost_OpenStream: could not allocate input buffer. Size = \n", pahsc->pahsc_BytesPerInputHostBuffer ));
+ goto memerror;
+ }
+ pahsc->pahsc_InputMultiBuffer.buffers[i] = buf;
+ }
+ pahsc->pahsc_InputMultiBuffer.numBuffers = pahsc->pahsc_NumHostBuffers;
+
+ err = SPBOpenDevice( (const unsigned char *) &noname, siWritePermission, &mRefNum); /* FIXME - use name so we get selected device */
+ // FIXME err = SPBOpenDevice( (const unsigned char *) sDevices[past->past_InputDeviceID].pad_Info.name, siWritePermission, &mRefNum);
+ if (err) goto error;
+ pahsc->pahsc_InputRefNum = mRefNum;
+ DBUG(("PaHost_OpenStream: mRefNum = %d\n", mRefNum ));
+
+ /* Set input device characteristics. */
+ tempS = 1;
+ err = SPBSetDeviceInfo(mRefNum, siContinuous, (Ptr) &tempS);
+ if (err)
+ {
+ ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siContinuous returned %d\n", err ));
+ goto error;
+ }
+
+ tempL = 0x03;
+ err = SPBSetDeviceInfo(mRefNum, siActiveChannels, (Ptr) &tempL);
+ if (err)
+ {
+ DBUG(("PaHost_OpenStream: setting siActiveChannels returned 0x%x. Error ignored.\n", err ));
+ }
+
+ /* PLB20010908 - Use requested number of input channels. Thanks Dominic Mazzoni. */
+ tempS = past->past_NumInputChannels;
+ err = SPBSetDeviceInfo(mRefNum, siNumberChannels, (Ptr) &tempS);
+ if (err)
+ {
+ ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siNumberChannels returned %d\n", err ));
+ goto error;
+ }
+
+ tempF = ((unsigned long)past->past_SampleRate) << 16;
+ err = SPBSetDeviceInfo(mRefNum, siSampleRate, (Ptr) &tempF);
+ if (err)
+ {
+ ERR_RPT(("Error in PaHost_OpenStream: SPBSetDeviceInfo siSampleRate returned %d\n", err ));
+ goto error;
+ }
+
+ /* Setup record-parameter block */
+ pahsc->pahsc_InputParams.inRefNum = mRefNum;
+ pahsc->pahsc_InputParams.milliseconds = 0; // not used
+ pahsc->pahsc_InputParams.completionRoutine = pahsc->pahsc_InputCompletionProc;
+ pahsc->pahsc_InputParams.interruptRoutine = 0;
+ pahsc->pahsc_InputParams.userLong = (long) past;
+ pahsc->pahsc_InputParams.unused1 = 0;
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ DBUG(("PaHost_OpenStream: complete.\n"));
+ return paNoError;
+
+error:
+ PaHost_CloseStream( past );
+ ERR_RPT(("PaHost_OpenStream: sPaHostError = 0x%x.\n", err ));
+ sPaHostError = err;
+ return paHostError;
+
+memerror:
+ PaHost_CloseStream( past );
+ return paInsufficientMemory;
+}
+
+/***********************************************************************
+** Called by Pa_CloseStream().
+** May be called during error recovery or cleanup code
+** so protect against NULL pointers.
+*/
+PaError PaHost_CloseStream( internalPortAudioStream *past )
+{
+ PaError result = paNoError;
+ OSErr err = 0;
+ int i;
+ PaHostSoundControl *pahsc;
+
+ DBUG(("PaHost_CloseStream( 0x%x )\n", past ));
+
+ if( past == NULL ) return paBadStreamPtr;
+
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ /* TRUE means flush now instead of waiting for quietCmd to be processed. */
+ if( pahsc->pahsc_Channel != NULL ) SndDisposeChannel(pahsc->pahsc_Channel, TRUE);
+ {
+ for (i = 0; i<pahsc->pahsc_NumHostBuffers; i++)
+ {
+ Ptr p = (Ptr) pahsc->pahsc_SoundHeaders[i].samplePtr;
+ if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerOutputHostBuffer );
+ }
+ }
+ }
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ if( pahsc->pahsc_InputRefNum )
+ {
+ err = SPBCloseDevice(pahsc->pahsc_InputRefNum);
+ pahsc->pahsc_InputRefNum = 0;
+ if( err )
+ {
+ sPaHostError = err;
+ result = paHostError;
+ }
+ }
+ {
+ for (i = 0; i<pahsc->pahsc_InputMultiBuffer.numBuffers; i++)
+ {
+ Ptr p = (Ptr) pahsc->pahsc_InputMultiBuffer.buffers[i];
+ if( p != NULL ) PaHost_FreeFastMemory( p, pahsc->pahsc_BytesPerInputHostBuffer );
+ }
+ }
+ }
+
+ past->past_DeviceData = NULL;
+ PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) );
+
+ DBUG(("PaHost_CloseStream: complete.\n", past ));
+ return result;
+}
+/*************************************************************************/
+int Pa_GetMinNumBuffers( int framesPerUserBuffer, double sampleRate )
+{
+/* We use the MAC_VIRTUAL_FRAMES_PER_BUFFER because we might be recording.
+** This routine doesn't have enough information to determine the best value
+** and is being depracated. */
+ return PaMac_GetMinNumBuffers( MAC_VIRTUAL_FRAMES_PER_BUFFER, framesPerUserBuffer, sampleRate );
+}
+/*************************************************************************/
+static int PaMac_GetMinNumBuffers( int minFramesPerHostBuffer, int framesPerUserBuffer, double sampleRate )
+{
+ int minUserPerHost = ( minFramesPerHostBuffer + framesPerUserBuffer - 1) / framesPerUserBuffer;
+ int numBufs = PA_MIN_NUM_HOST_BUFFERS * minUserPerHost;
+ if( numBufs < PA_MIN_NUM_HOST_BUFFERS ) numBufs = PA_MIN_NUM_HOST_BUFFERS;
+ (void) sampleRate;
+ return numBufs;
+}
+
+/*************************************************************************/
+void Pa_Sleep( int32 msec )
+{
+ EventRecord event;
+ int32 sleepTime, endTime;
+ /* Convert to ticks. Round up so we sleep a MINIMUM of msec time. */
+ sleepTime = ((msec * 60) + 999) / 1000;
+ if( sleepTime < 1 ) sleepTime = 1;
+ endTime = TickCount() + sleepTime;
+ do
+ {
+ DBUGX(("Sleep for %d ticks.\n", sleepTime ));
+ /* Use WaitNextEvent() to sleep without getting events. */
+ /* PLB20010907 - Pass unused event to WaitNextEvent instead of NULL to prevent
+ * Mac OSX crash. Thanks Dominic Mazzoni. */
+ WaitNextEvent( 0, &event, sleepTime, NULL );
+ sleepTime = endTime - TickCount();
+ }
+ while( sleepTime > 0 );
+}
+/*************************************************************************/
+int32 Pa_GetHostError( void )
+{
+ int32 err = sPaHostError;
+ sPaHostError = 0;
+ return err;
+}
+
+/*************************************************************************
+ * Allocate memory that can be accessed in real-time.
+ * This may need to be held in physical memory so that it is not
+ * paged to virtual memory.
+ * This call MUST be balanced with a call to PaHost_FreeFastMemory().
+ */
+void *PaHost_AllocateFastMemory( long numBytes )
+{
+ void *addr = NewPtrClear( numBytes );
+ if( (addr == NULL) || (MemError () != 0) ) return NULL;
+
+#if (TARGET_API_MAC_CARBON == 0)
+ if( HoldMemory( addr, numBytes ) != noErr )
+ {
+ DisposePtr( (Ptr) addr );
+ return NULL;
+ }
+#endif
+ return addr;
+}
+
+/*************************************************************************
+ * Free memory that could be accessed in real-time.
+ * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
+ */
+void PaHost_FreeFastMemory( void *addr, long numBytes )
+{
+ if( addr == NULL ) return;
+#if TARGET_API_MAC_CARBON
+ (void) numBytes;
+#else
+ UnholdMemory( addr, numBytes );
+#endif
+ DisposePtr( (Ptr) addr );
+}
+
+/*************************************************************************/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ PaTimestamp framesDone1;
+ PaTimestamp framesDone2;
+ UInt64 whenIncremented;
+ UnsignedWide now;
+ UInt64 now64;
+ long microsElapsed;
+ long framesElapsed;
+
+ PaHostSoundControl *pahsc;
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+/* Capture information from audio thread.
+ * We have to be careful that we don't get interrupted in the middle.
+ * So we grab the pahsc_NumFramesDone twice and make sure it didn't change.
+ */
+ do
+ {
+ framesDone1 = pahsc->pahsc_NumFramesDone;
+ whenIncremented = pahsc->pahsc_WhenFramesDoneIncremented;
+ framesDone2 = pahsc->pahsc_NumFramesDone;
+ } while( framesDone1 != framesDone2 );
+
+ /* Calculate how many microseconds have elapsed and convert to frames. */
+ Microseconds( &now );
+ now64 = UnsignedWideToUInt64( now );
+ microsElapsed = U64Subtract( now64, whenIncremented );
+ framesElapsed = microsElapsed * past->past_SampleRate * 0.000001;
+
+ return framesDone1 + framesElapsed;
+}
+
+/**************************************************************************
+** Callback for Input, SPBRecord()
+*/
+int gRecordCounter = 0;
+int gPlayCounter = 0;
+pascal void PaMac_InputCompletionProc(SPBPtr recParams)
+{
+ PaError result = paNoError;
+ int finished = 1;
+ internalPortAudioStream *past;
+ PaHostSoundControl *pahsc;
+
+ gRecordCounter += 1; /* debug hack to see if engine running */
+
+ /* Get our PA data from Mac structure. */
+ past = (internalPortAudioStream *) recParams->userLong;
+ if( past == NULL ) return;
+
+ if( past->past_Magic != PA_MAGIC )
+ {
+ AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, past", (long) past );
+ AddTraceMessage("PaMac_InputCompletionProc: bad MAGIC, magic", (long) past->past_Magic );
+ goto error;
+ }
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ past->past_NumCallbacks += 1;
+
+ /* Have we been asked to stop recording? */
+ if( (recParams->error == abortErr) || pahsc->pahsc_StopRecording ) goto error;
+
+ /* If there are no output channels, then we need to call the user callback function from here.
+ * Otherwise we will call the user code during the output completion routine.
+ */
+ if(past->past_NumOutputChannels == 0)
+ {
+ SetFramesDone( pahsc,
+ pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
+ result = PaMac_CallUserLoop( past, NULL );
+ }
+
+ /* Did user code ask us to stop? If not, issue another recording request. */
+ if( (result == paNoError) && (pahsc->pahsc_StopRecording == 0) )
+ {
+ result = PaMac_RecordNext( past );
+ if( result != paNoError ) pahsc->pahsc_IsRecording = 0;
+ }
+ else goto error;
+
+ return;
+
+error:
+ pahsc->pahsc_IsRecording = 0;
+ pahsc->pahsc_StopRecording = 0;
+ return;
+}
+
+/***********************************************************************
+** Called by either input or output completion proc.
+** Grabs input data if any present, and calls PA conversion code,
+** that in turn calls user code.
+*/
+static PaError PaMac_CallUserLoop( internalPortAudioStream *past, int16 *outPtr )
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ int16 *inPtr = NULL;
+ int i;
+
+
+ /* Advance read index for sound input FIFO here, independantly of record/write process. */
+ if(past->past_NumInputChannels > 0)
+ {
+ if( MultiBuffer_IsReadable( &pahsc->pahsc_InputMultiBuffer ) )
+ {
+ inPtr = (int16 *) MultiBuffer_GetNextReadBuffer( &pahsc->pahsc_InputMultiBuffer );
+ MultiBuffer_AdvanceReadIndex( &pahsc->pahsc_InputMultiBuffer );
+ }
+ }
+
+ /* Call user code enough times to fill buffer. */
+ if( (inPtr != NULL) || (outPtr != NULL) )
+ {
+ PaMac_StartLoadCalculation( past ); /* CPU usage */
+
+#ifdef PA_MAX_USAGE_ALLOWED
+ /* If CPU usage exceeds limit, skip user callback to prevent hanging CPU. */
+ if( past->past_Usage > PA_MAX_USAGE_ALLOWED )
+ {
+ past->past_FrameCount += (PaTimestamp) pahsc->pahsc_FramesPerHostBuffer;
+ }
+ else
+#endif
+ {
+
+ for( i=0; i<pahsc->pahsc_UserBuffersPerHostBuffer; i++ )
+ {
+ result = (PaError) Pa_CallConvertInt16( past, inPtr, outPtr );
+ if( result != 0)
+ {
+ /* Recording might be in another process, so tell it to stop with a flag. */
+ pahsc->pahsc_StopRecording = pahsc->pahsc_IsRecording;
+ break;
+ }
+ /* Advance sample pointers. */
+ if(inPtr != NULL) inPtr += past->past_FramesPerUserBuffer * past->past_NumInputChannels;
+ if(outPtr != NULL) outPtr += past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
+ }
+ }
+
+ PaMac_EndLoadCalculation( past );
+ }
+ return result;
+}
+
+/***********************************************************************
+** Setup next recording buffer in FIFO and issue recording request to Snd Input Manager.
+*/
+static PaError PaMac_RecordNext( internalPortAudioStream *past )
+{
+ PaError result = paNoError;
+ OSErr err;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ /* Get pointer to next buffer to record into. */
+ pahsc->pahsc_InputParams.bufferPtr = MultiBuffer_GetNextWriteBuffer( &pahsc->pahsc_InputMultiBuffer );
+
+ /* Advance write index if there is room. Otherwise keep writing same buffer. */
+ if( MultiBuffer_IsWriteable( &pahsc->pahsc_InputMultiBuffer ) )
+ {
+ MultiBuffer_AdvanceWriteIndex( &pahsc->pahsc_InputMultiBuffer );
+ }
+
+ AddTraceMessage("PaMac_RecordNext: bufferPtr", (long) pahsc->pahsc_InputParams.bufferPtr );
+ AddTraceMessage("PaMac_RecordNext: nextWrite", pahsc->pahsc_InputMultiBuffer.nextWrite );
+
+ /* Setup parameters and issue an asynchronous recording request. */
+ pahsc->pahsc_InputParams.bufferLength = pahsc->pahsc_BytesPerInputHostBuffer;
+ pahsc->pahsc_InputParams.count = pahsc->pahsc_BytesPerInputHostBuffer;
+ err = SPBRecord(&pahsc->pahsc_InputParams, true);
+ if( err )
+ {
+ AddTraceMessage("PaMac_RecordNext: SPBRecord error ", err );
+ sPaHostError = err;
+ result = paHostError;
+ }
+ else
+ {
+ pahsc->pahsc_IsRecording = 1;
+ }
+ return result;
+}
+
+/**************************************************************************
+** Callback for Output Playback()
+** Return negative error, 0 to continue, 1 to stop.
+*/
+long PaMac_FillNextOutputBuffer( internalPortAudioStream *past, int index )
+{
+ PaHostSoundControl *pahsc;
+ long result = 0;
+ int finished = 1;
+ char *outPtr;
+
+ gPlayCounter += 1; /* debug hack */
+
+ past->past_NumCallbacks += 1;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return -1;
+ /* Are we nested?! */
+ if( pahsc->pahsc_IfInsideCallback ) return 0;
+ pahsc->pahsc_IfInsideCallback = 1;
+ /* Get pointer to buffer to fill. */
+ outPtr = pahsc->pahsc_SoundHeaders[index].samplePtr;
+ /* Combine with any sound input, and call user callback. */
+ result = PaMac_CallUserLoop( past, (int16 *) outPtr );
+
+ pahsc->pahsc_IfInsideCallback = 0;
+ return result;
+}
+
+/*************************************************************************************
+** Called by SoundManager when ready for another buffer.
+*/
+static pascal void PaMac_OutputCompletionProc (SndChannelPtr theChannel, SndCommand * theCallBackCmd)
+{
+ internalPortAudioStream *past;
+ PaHostSoundControl *pahsc;
+ (void) theChannel;
+ (void) theCallBackCmd;
+
+ /* Get our data from Mac structure. */
+ past = (internalPortAudioStream *) theCallBackCmd->param2;
+ if( past == NULL ) return;
+
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ pahsc->pahsc_NumOutsPlayed += 1;
+
+ SetFramesDone( pahsc,
+ pahsc->pahsc_NumFramesDone + pahsc->pahsc_FramesPerHostBuffer );
+
+ PaMac_BackgroundManager( past, theCallBackCmd->param1 );
+}
+
+/*******************************************************************/
+static PaError PaMac_BackgroundManager( internalPortAudioStream *past, int index )
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ /* Has someone asked us to abort by calling Pa_AbortStream()? */
+ if( past->past_StopNow )
+ {
+ SndCommand command;
+ /* Clear the queue of any pending commands. */
+ command.cmd = flushCmd;
+ command.param1 = command.param2 = 0;
+ SndDoImmediate( pahsc->pahsc_Channel, &command );
+ /* Then stop currently playing buffer, if any. */
+ command.cmd = quietCmd;
+ SndDoImmediate( pahsc->pahsc_Channel, &command );
+ past->past_IsActive = 0;
+ }
+ /* Has someone asked us to stop by calling Pa_StopStream()
+ * OR has a user callback returned '1' to indicate finished.
+ */
+ else if( past->past_StopSoon )
+ {
+ if( (pahsc->pahsc_NumOutsQueued - pahsc->pahsc_NumOutsPlayed) <= 0 )
+ {
+ past->past_IsActive = 0; /* We're finally done. */
+ }
+ }
+ else
+ {
+ PaMac_PlayNext( past, index );
+ }
+ return result;
+}
+
+/*************************************************************************************
+** Fill next buffer with sound and queue it for playback.
+*/
+static void PaMac_PlayNext ( internalPortAudioStream *past, int index )
+{
+ OSErr error;
+ long result;
+ SndCommand playCmd;
+ SndCommand callbackCmd;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ /* If this was the last buffer, or abort requested, then just be done. */
+ if ( past->past_StopSoon ) goto done;
+
+ /* Load buffer with sound. */
+ result = PaMac_FillNextOutputBuffer ( past, index );
+ if( result > 0 ) past->past_StopSoon = 1; /* Stop generating audio but wait until buffers play. */
+ else if( result < 0 ) goto done;
+
+ /* Play the next buffer. */
+ playCmd.cmd = bufferCmd;
+ playCmd.param1 = 0;
+ playCmd.param2 = (long) &pahsc->pahsc_SoundHeaders[ index ];
+ error = SndDoCommand (pahsc->pahsc_Channel, &playCmd, true );
+ if( error != noErr ) goto gotError;
+
+ /* Ask for a callback when it is done. */
+ callbackCmd.cmd = callBackCmd;
+ callbackCmd.param1 = index;
+ callbackCmd.param2 = (long)past;
+ error = SndDoCommand (pahsc->pahsc_Channel, &callbackCmd, true );
+ if( error != noErr ) goto gotError;
+ pahsc->pahsc_NumOutsQueued += 1;
+
+ return;
+
+gotError:
+ sPaHostError = error;
+done:
+ return;
+}
diff --git a/pd/portaudio/pa_sgi/Makefile b/pd/portaudio/pa_sgi/Makefile
new file mode 100644
index 00000000..6548c6c5
--- /dev/null
+++ b/pd/portaudio/pa_sgi/Makefile
@@ -0,0 +1,51 @@
+# Make PortAudio for Silicon Graphics IRIX (6.2)
+# Pieter suurmond, september 23, 2001. (pa_sgi sub-version #0.21 for PA v15.)
+# Based on SGI-specific sproc()-method to spawn children, not on POSIX-threads.
+
+# Instead of "-lpthread", as with linux,
+# just the audio- and math-library for SGI:
+LIBS = -laudio -lm
+
+CDEFINES = -I../pa_common
+
+# Possible CFLAGS with MIPSpro compiler are: -32, -o32, -n32, -64,
+# -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging.
+# And use for example -O2 or -O3 for better optimization:
+CFLAGS = -O2
+PASRC = ../pa_common/pa_lib.c pa_sgi.c
+PAINC = ../pa_common/portaudio.h
+
+# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2).
+TESTC = $(PASRC) ../pa_tests/patest_record.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_saw.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK
+#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore.
+
+# Tests that were not yet performed.
+#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # test??
+#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # test??
+#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # test??
+
+TESTH = $(PAINC)
+
+all: patest
+
+# "cc" for the MIPSpro compiler, may be changed to "gcc":
+patest: $(TESTC) $(TESTH) Makefile
+ cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest
+
+run: patest
+ ./patest
+
diff --git a/pd/portaudio/pa_sgi/pa_sgi.c b/pd/portaudio/pa_sgi/pa_sgi.c
new file mode 100644
index 00000000..4b91f02c
--- /dev/null
+++ b/pd/portaudio/pa_sgi/pa_sgi.c
@@ -0,0 +1,999 @@
+/*
+ * $Id: pa_sgi.c,v 1.2 2002/05/04 20:38:42 philburk Exp $
+ * PortAudio Portable Real-Time Audio Library. Copyright (c) 1999-2001 Phil Burk.
+ * Latest Version at: http://www.portaudio.com
+ *
+ * Silicon Graphics IRIX implementation by Pieter Suurmond, september 23, 2001.
+ * pa_sgi-sub-version number 0.21, for PortAudio v15.
+ * This implementation uses the sproc()-method, not the POSIX method.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+Modfication History:
+ 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2.
+ 8/17/2001 - v15 pa_sgi sub-version #0.04 (unstable alpha release) Sent to Phil & Ross.
+ 9/23/2001 - #0.21 Many fixes and changes: POLLIN for input, not POLLOUT.
+ Open and close ALports in the audio-process-thread.
+ Proper semaphore communication now.
+ Hopefully stable enough now (for beta release?).
+TODO:
+ - Test under IRIX 6.5.
+ - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion),
+ and maybe also the other natively supported formats? (might increase performance)
+ - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4.
+REFERENCES:
+ - IRIX 6.2 man pages regarding SGI AL library.
+ - IRIS Digital MediaProgramming Guide (online books and man-pages come
+ with IRIX 6.2 and may not be publically available on the internet).
+*/
+
+#include <stdio.h> /* Standard libraries. */
+#include <stdlib.h>
+
+#include "../pa_common/portaudio.h" /* BETTER PATH !!!???? Portaudio headers. */
+#include "../pa_common/pa_host.h"
+#include "../pa_common/pa_trace.h"
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/prctl.h>
+#include <sys/schedctl.h> /* For schedctl(NDPRI, NDPHIMIN). */
+#include <fcntl.h> /* fcntl.h needed. */
+#include <unistd.h> /* For streams, ioctl(), etc. */
+#include <ulocks.h>
+#include <poll.h>
+#include <dmedia/audio.h> /* System specific (IRIX 6.2). */
+
+/*--------------------------------------------*/
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */
+#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */
+
+typedef struct internalPortAudioDevice /* IRIX specific device info: */
+{
+ PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */
+ long pad_ALdevice; /* SGI-number! */
+ double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */
+ char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */
+ PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */
+ /* int structVersion; */
+ /* const char* name; */
+ /* int maxInputChannels, maxOutputChannels; */
+ /* int numSampleRates; Num rates, or -1 if range supprtd. */
+ /* const double* sampleRates; Array of supported sample rates, */
+ /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */
+ struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */
+} internalPortAudioDevice;
+
+typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */
+{
+ ALconfig pahsc_ALconfigIN, /* IRIX-audio-library-datatype. Configuration */
+ pahsc_ALconfigOUT; /* stucts separate for input and output ports. */
+ ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */
+ pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */
+ int pahsc_threadPID; /* Sproc()-result, written by PaHost_StartEngine(). */
+ short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */
+ *pahsc_NativeOutputBuffer;
+ unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */
+ pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */
+ unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */
+ pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */
+ struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */
+ pahsc_LastExitTime;
+ long pahsc_InsideCountSum,
+ pahsc_TotalCountSum;
+} PaHostSoundControl;
+
+/*-------------------------------------------------------- Shared Data -------------------------------*/
+static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */
+static int sPaHostError = 0; /* Maybe more than one process writing errs!? */
+usema_t *SendSema, /* These variables are shared between the */
+ *RcvSema; /* audio handling process and main process. */
+/*--------------------------*/
+long Pa_GetHostError(void)
+{
+ return (long)sPaHostError;
+}
+
+/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/
+/* (copied from source pa_linux_oss/pa_linux_oss.c) */
+static void Pa_StartUsageCalculation( internalPortAudioStream *past )
+{
+ struct itimerval itimer;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+/* Query system timer for usage analysis and to prevent overuse of CPU. */
+ getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime );
+}
+
+static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB )
+{
+ long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec;
+ long usecs = secs * 1000000;
+ usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec);
+ return usecs;
+}
+
+static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+{
+ struct itimerval currentTime;
+ long insideCount;
+ long totalCount; /* Measure CPU utilization during this callback. */
+
+#define LOWPASS_COEFFICIENT_0 (0.95)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (pahsc == NULL)
+ return;
+ if (getitimer( ITIMER_REAL, &currentTime ) == 0 )
+ {
+ if (past->past_IfLastExitValid)
+ {
+ insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, &currentTime );
+ pahsc->pahsc_InsideCountSum += insideCount;
+ totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, &currentTime );
+ pahsc->pahsc_TotalCountSum += totalCount;
+ /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */
+ /* Low pass filter the result because sometimes we get called several times in a row. */
+ /* That can cause the TotalCount to be very low which can cause the usage to appear */
+ /* unnaturally high. So we must filter numerator and denominator separately!!! */
+ if (pahsc->pahsc_InsideCountSum > 0)
+ {
+ past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
+ (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum));
+ past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
+ (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum));
+ past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
+ pahsc->pahsc_InsideCountSum = 0;
+ pahsc->pahsc_TotalCountSum = 0;
+ }
+ }
+ past->past_IfLastExitValid = 1;
+ }
+ pahsc->pahsc_LastExitTime.it_value.tv_sec = 100;
+ pahsc->pahsc_LastExitTime.it_value.tv_usec = 0;
+ setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL );
+ past->past_IfLastExitValid = 1;
+} /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/
+
+
+/*--------------------------------------------------------------------------------------*/
+PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */
+{ /* call to report via ERR_RPT(), yields a PaError-num. */
+ const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */
+ switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */
+ {
+ case AL_BAD_OUT_OF_MEM:
+ ERR_RPT(("%sout of memory.\n", a));
+ return paInsufficientMemory; /* Known PaError. */
+ case AL_BAD_CONFIG:
+ ERR_RPT(("%sconfiguration invalid or NULL.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_CHANNELS:
+ ERR_RPT(("%schannels not 1,2 or 4.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_NO_PORTS:
+ ERR_RPT(("%sout of audio ports.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DEVICE:
+ ERR_RPT(("%swrong device number.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DEVICE_ACCESS:
+ ERR_RPT(("%swrong device access.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DIRECTION:
+ ERR_RPT(("%sinvalid direction.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_SAMPFMT:
+ ERR_RPT(("%sdoesn't accept sampleformat.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_FLOATMAX:
+ ERR_RPT(("%smax float value is zero.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_WIDTH:
+ ERR_RPT(("%sunsupported samplewidth.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_QSIZE:
+ ERR_RPT(("%sinvalid queue size.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_PVBUFFER:
+ ERR_RPT(("%sPVbuffer null.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_BUFFERLENGTH_NEG:
+ ERR_RPT(("%snegative bufferlength.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_BUFFERLENGTH_ODD:
+ ERR_RPT(("%sodd bufferlength.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_PARAM:
+ ERR_RPT(("%sparameter not valid for device.\n", a));
+ return paHostError; /* Generic PaError. */
+ default:
+ ERR_RPT(("%sunknown error.\n", a));
+ return paHostError; /* Generic PaError. */
+ }
+}
+
+/*------------------------------------------------------------------------------------------*/
+/* Tries to set various rates and formats and fill in the device info structure. */
+static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */
+ PaDeviceID id, /* (DefaultI|ODeviceID()) */
+ char* name, /* (for example "SGI AL") */
+ internalPortAudioDevice* pad) /* Result written to pad. */
+{
+ int format;
+ long min, max; /* To catch hardware characteristics. */
+ ALseterrorhandler(0); /* 0 = turn off the default error handler. */
+ /*--------------------------------------------------------------------------------------*/
+ pad->pad_ALdevice = ALdev; /* Set the AL device number. */
+ pad->pad_DeviceID = id; /* Set the PA device number. */
+ if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */
+ {
+ ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name));
+ return paHostError;
+ }
+ strcpy(pad->pad_DeviceName, name); /* Write name-string. */
+ pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */
+ /*--------------------------------- natively supported sample formats: -----------------*/
+ pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */
+ /* Then also choose other CallConvertXX()! */
+ /*--------------------------------- number of available i/o channels: ------------------*/
+ if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max))
+ return translateSGIerror();
+ pad->pad_Info.maxInputChannels = max;
+ DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels))
+ if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max))
+ return translateSGIerror();
+ pad->pad_Info.maxOutputChannels = max;
+ DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels))
+ /*--------------------------------- supported samplerates: ----------------------*/
+ pad->pad_Info.numSampleRates = 7;
+ pad->pad_Info.sampleRates = pad->pad_SampleRates;
+ pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */
+ pad->pad_SampleRates[1] = (double)AL_RATE_11025;
+ pad->pad_SampleRates[2] = (double)AL_RATE_16000;
+ pad->pad_SampleRates[3] = (double)AL_RATE_22050;
+ pad->pad_SampleRates[4] = (double)AL_RATE_32000;
+ pad->pad_SampleRates[5] = (double)AL_RATE_44100;
+ pad->pad_SampleRates[6] = (double)AL_RATE_48000;
+ if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */
+ return translateSGIerror(); /* double -> long. */
+ if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */
+ goto weird;
+ if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */
+ return translateSGIerror();
+ if (max != (long)(0.5 + pad->pad_SampleRates[6]))
+ {
+weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max));
+ return paHostError; /* Or make it a warning and just carry on... */
+ }
+ /*-------------------------------------------------------------------------------*/
+ return paNoError;
+}
+
+
+/*--------------------------------------------------------------------------------*/
+int Pa_CountDevices() /* Name of this function suggests it only counts and */
+{ /* is NOT destructive, it however resets whole PA ! */
+ int numDevices = 0; /* Let 's not do that here. */
+ internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */
+#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */
+ if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */
+ Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */
+#endif /* friendly to clients that forgot to initialize PA. */
+ while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */
+ {
+ numDevices++;
+ currentDevice = currentDevice->pad_Next;
+ }
+ return numDevices;
+}
+
+/*-------------------------------------------------------------------------------*/
+static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id)
+{
+ int numDevices = 0;
+ internalPortAudioDevice *res = (internalPortAudioDevice*)NULL;
+ internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */
+ while (pad) /* pad may be NULL, that's ok, return 0. */
+ { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */
+ if (pad->pad_DeviceID == id) /* This the device we were looking for? */
+ res = pad; /* But keep on(!) counting so we don't */
+ numDevices++; /* have to call Pa_CountDevices() later. */
+ pad = pad->pad_Next; /* Advance to the next device or NULL. */
+ } /* No assumptions about order of ID's in */
+ if (!res) /* the list. */
+ ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id));
+ if ((id < 0) || (id >= numDevices))
+ {
+ ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id));
+#if 1 /* Be strict, even when found, */
+ res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */
+#endif
+ }
+ return res;
+}
+
+/*----------------------------------------------------------------------*/
+const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id)
+{
+ PaDeviceInfo* res = (PaDeviceInfo*)NULL;
+ internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */
+ if (pad)
+ res = &pad->pad_Info; /* Not finding the specified ID is not */
+ if (!res) /* the same as &pad->pad_Info == NULL. */
+ ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id));
+ return res; /* So (maybe) a second/third ERR_RPT(). */
+}
+
+/*------------------------------------------------*/
+PaDeviceID Pa_GetDefaultInputDeviceID(void)
+{
+ return 0; /* 0 is the default device ID. */
+}
+/*------------------------------------------------*/
+PaDeviceID Pa_GetDefaultOutputDeviceID(void)
+{
+ return 0;
+}
+
+/*-------------------------------------------------------------------------------------------------*/
+/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */
+PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */
+{
+ internalPortAudioDevice* pad;
+ PaError r = paNoError;
+ int audioLibFileID; /* To test for the presence of audio. */
+
+ if (sDeviceList) /* Allow re-init, only warn, no error. */
+ {
+ ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n"));
+ return r;
+ }
+ /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/
+ audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */
+ if (audioLibFileID < 0) /* IO port. On failure, machine */
+ { /* has no audio ability. */
+ ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n"));
+ return paHostError;
+ }
+ close(audioLibFileID); /* Allocate fast mem to hold device info. */
+ pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice));
+ if (pad == NULL)
+ return paInsufficientMemory;
+ memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */
+ r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */
+ Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */
+ "AL default", /* A suitable name. */
+ pad); /* Write args and queried info into pad. */
+ if (r != paNoError)
+ {
+ ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r));
+ PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */
+ }
+ else
+ sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */
+ /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/
+ /*---------------------------------------------------------------------------------------------*/
+ return r;
+}
+
+/*--------------------------------------------------------------------------------------------*/
+#define MIN(a,b) ((a)<(b)?(a):(b)) /* MIN()-function is used below. */
+#define kPollSEMA 0 /* To index the pollfd-array, reads nicer than just */
+#define kPollOUT 1 /* numbers. */
+#define kPollIN 2
+void Pa_SgiAudioProcess(void *v) /* This function is sproc-ed by PaHost_StartEngine() */
+{ /* as a separate thread. (Argument must be void*). */
+ short evtLoop; /* Reset by parent indirectly, or at local errors. */
+ PaError result;
+ struct pollfd PollFD[3]; /* To catch kPollSEMA-, kPollOUT- and kPollIN-events. */
+ internalPortAudioStream *past = (internalPortAudioStream*)v; /* Copy void-ptr-argument.*/
+ PaHostSoundControl *pahsc;
+ short inputEvent, outputEvent, /* .revents members are of type short. */
+ semaEvent = 0;
+ DBUG(("Entering sproc-thread.\n"));
+ if (!past)
+ {
+ sPaHostError = paInternalError; /* Or paBadStreamPtr ? */
+ ERR_RPT(("argument NULL!\n"));
+ goto skip;
+ }
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (!pahsc)
+ {
+ sPaHostError = paInternalError; /* The only way is to signal error to shared area?! */
+ ERR_RPT(("past_DeviceData NULL!\n"));
+ goto skip; /* Sproc-ed threads MAY NOT RETURN paInternalError. */
+ }
+ /*----------------------------- open AL-ports here, after sproc(): -----------------------*/
+ if (past->past_NumInputChannels > 0) /* Open input port. */
+ {
+ pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", pahsc->pahsc_ALconfigIN);
+ if (!pahsc->pahsc_ALportIN)
+ {
+ ERR_RPT(("Failed to open AL input port.\n"));
+ sPaHostError = paInternalError;
+ goto skip;
+ }
+ DBUG(("Opened %d input channel(s).\n", past->past_NumInputChannels));
+ }
+ if (past->past_NumOutputChannels > 0) /* Open output port. */
+ {
+ pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", pahsc->pahsc_ALconfigOUT);
+ if (!pahsc->pahsc_ALportOUT)
+ {
+ ERR_RPT(("Failed to open AL output port.\n"));
+ sPaHostError = paInternalError; /* Assume pahsc_ALconfigs are the */
+ goto skip; /* same for IN and OUT in case */
+ } /* both ports are opened (bidir). */
+ DBUG(("Opened %d output channel(s).\n", past->past_NumOutputChannels));
+ }
+ /*-----------------------------------------------------------------------*/
+ past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */
+ PollFD[kPollIN].fd = ALgetfd(pahsc->pahsc_ALportIN); /* ALgetfd returns -1 on failures */
+ PollFD[kPollIN].events = POLLIN; /* such as ALport not there. */
+ PollFD[kPollOUT].fd = ALgetfd(pahsc->pahsc_ALportOUT);
+ PollFD[kPollOUT].events = POLLOUT; /* .events = POLLOUT is OK. */
+ schedctl(NDPRI, NDPHIMIN); /* Sets non-degrading priority for this process. */
+ PollFD[kPollSEMA].fd = usopenpollsema(SendSema, 0777); /* To communicate with parent. */
+ PollFD[kPollSEMA].events = POLLIN; /* .events = POLLIN is OK. */
+ uspsema(SendSema); /* Blocks until ... MUST be here, this uspsema(). */
+ evtLoop = ((past->past_StopNow | past->past_StopSoon) == 0);
+ while (evtLoop)
+ {
+ /*---------------------------- SET FILLPOINTS AND WAIT UNTIL SOMETHING HAPPENS: ----------*/
+ if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */
+ /* For input port, fill point is number of locations in the sample queue that must be */
+ /* filled in order to trigger a return from select(). (or poll()) */
+ /* Notice IRIX docs mention number of samples as argument, not number of sampleframes.*/
+ if (ALsetfillpoint(pahsc->pahsc_ALportIN, pahsc->pahsc_SamplesPerInputBuffer))
+ { /* Same amount as transferred per time. */
+ ERR_RPT(("ALsetfillpoint() for ALportIN failed.\n"));
+ sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */
+ goto skip;
+ }
+ if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */
+ /* For output port, fill point is number of locations that must be free in order to */
+ /* wake up from select(). (or poll()) */
+ if (ALsetfillpoint(pahsc->pahsc_ALportOUT, pahsc->pahsc_SamplesPerOutputBuffer))
+ {
+ ERR_RPT(("ALsetfillpoint() for ALportOUT failed.\n"));
+ sPaHostError = paInternalError; /* (Using exit(-1) would be a bit rude.) */
+ goto skip;
+ } /* poll() with timeout=-1 makes it block until a requested */
+ poll(PollFD, 3, -1); /* event occurs or until call is interrupted. If fd-value in */
+ /* array <0, events is ignored and revents is set to 0. */
+ /*---------------------------- MESSAGE-EVENT FROM PARENT THREAD: -------------------------*/
+ semaEvent = PollFD[kPollSEMA].revents & POLLIN;
+ if (semaEvent)
+ {
+ if (past->past_StopSoon)
+ evtLoop = 0;
+ if (past->past_StopNow)
+ goto skip;
+ }
+ /*------------------------------------- FILLED-EVENT FROM INPUT BUFFER: --------------------------*/
+ inputEvent = PollFD[kPollIN].revents & POLLIN;
+ if (inputEvent) /* Don't need to check (pahsc->pahsc_NativeInputBuffer): */
+ { /* if buffer was not there, ALport not there, no events! */
+ if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer,
+ pahsc->pahsc_SamplesPerInputBuffer))
+ { /* Here again: number of samples instead of number of frames. */
+ ERR_RPT(("ALreadsamps() failed.\n"));
+ sPaHostError = paInternalError;
+ goto skip;
+ }
+ }
+ outputEvent = PollFD[kPollOUT].revents & POLLOUT;
+ /*------------------------------------- USER-CALLBACK-ROUTINE: -----------------------------------*/
+ if (inputEvent | outputEvent) /* (Bitwise is ok.) */
+ { /* To be sure we that really DID input-transfer or gonna DO output-transfer, and that it is */
+ /* not just "sema"- (i.e. user)-event, or some other system-event that awakened the poll(). */
+ Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */
+ result = Pa_CallConvertInt16(past, /* user data and call user routine. */
+ pahsc->pahsc_NativeInputBuffer,
+ pahsc->pahsc_NativeOutputBuffer);
+ Pa_EndUsageCalculation(past);
+ if (result)
+ {
+ DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result));
+ goto skip; /* This is apparently NOT an error! */
+ } /* Just letting the userCallBack stop us. */
+ }
+ /*------------------------------------- FREE-EVENT FROM OUTPUT BUFFER: ---------------------------*/
+ if (outputEvent) /* Don't need to check (pahsc->pahsc_NativeOutputBuffer) */
+ { /* because if filedescriptor not there, no event for it. */
+ if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer,
+ pahsc->pahsc_SamplesPerOutputBuffer))
+ {
+ ERR_RPT(("ALwritesamps() failed.\n")); /* Better use SEMAS for messaging back to parent! */
+ sPaHostError = paInternalError;
+ goto skip;
+ }
+ }
+ }
+skip:
+ /*------------------------------- close AL-ports ----------------------------*/
+ if (pahsc->pahsc_ALportIN)
+ {
+ if (ALcloseport(pahsc->pahsc_ALportIN))
+ translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
+ else /* But go on anyway... to release other stuff... */
+ pahsc->pahsc_ALportIN = (ALport)0;
+ }
+ if (pahsc->pahsc_ALportOUT)
+ {
+ if (ALcloseport(pahsc->pahsc_ALportOUT))
+ translateSGIerror();
+ else
+ pahsc->pahsc_ALportOUT = (ALport)0;
+ }
+ past->past_IsActive = 0;
+ if (semaEvent)
+ {
+ uspsema(SendSema); /* StopEngine() was still waiting for this acknowledgement. */
+ usvsema(RcvSema); /* (semaEvent initialized with 0.) */
+ }
+ DBUG(("Leaving sproc-thread.\n"));
+}
+
+
+#define kALinternalQueuesizeFact 4L /* Internal queue 4 times as large as transferSize. */
+ /* Used below, twice: for input and for output. */
+/*--------------------------------------------------------------------------------------*/
+PaError PaHost_OpenStream(internalPortAudioStream *past)
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+ unsigned int minNumBuffers;
+ internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */
+ long pvbuf[8]; /* To get/set hardware configs. */
+ long sr;
+ DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */
+ if (!past)
+ {
+ ERR_RPT(("Streampointer NULL!\n"));
+ result = paBadStreamPtr; goto done;
+ }
+ pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
+ if (pahsc == NULL)
+ {
+ ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */
+ result = paInsufficientMemory; goto done; /* code (nothing will be freed). */
+ }
+ memset(pahsc, 0, sizeof(PaHostSoundControl));
+ pahsc->pahsc_threadPID = -1; /* Should pahsc_threadPID be inited to */
+ past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */
+ /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/
+ ALseterrorhandler(0); /* 0 = turn off the default error handler. */
+ pvbuf[0] = AL_INPUT_RATE;
+ pvbuf[2] = AL_INPUT_COUNT;
+ pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */
+ pvbuf[6] = AL_OUTPUT_COUNT;
+ sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */
+ /*---------------------------------------------------- SET INPUT CONFIGURATION: ------------------------*/
+ if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */
+ { /* sponding native AL-number(s). */
+ /*--------------------------------------------------- Allocate native buffers: --------*/
+ pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */
+ past->past_NumInputChannels; /* audio-thread. */
+ pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short);
+ pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer);
+ if (!pahsc->pahsc_NativeInputBuffer)
+ {
+ ERR_RPT(("Fast memory allocation failed (in).\n"));
+ result = paInsufficientMemory;
+ goto done;
+ }
+ padIN = Pa_GetInternalDevice(past->past_InputDeviceID);
+ if (!padIN)
+ {
+ ERR_RPT(("Pa_GetInternalDevice() for input failed.\n"));
+ result = paHostError;
+ goto done;
+ }
+ if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */
+ goto sgiError; /* the same AL-device, the AL-library might */
+ if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */
+ { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */
+ if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */
+ {
+ ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \
+another process is currently using input at %ld kHz.\n", sr, pvbuf[1]));
+ result = paHostError;
+ goto done;
+ }
+ pvbuf[1] = sr; /* Then set input-rate. */
+ if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2))
+ goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */
+ } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */
+ pahsc->pahsc_ALconfigIN = ALnewconfig(); /* Released at PaHost_CloseStream(). */
+ if (pahsc->pahsc_ALconfigIN == (ALconfig)0)
+ goto sgiError;
+ if (ALsetsampfmt(pahsc->pahsc_ALconfigIN, AL_SAMPFMT_TWOSCOMP))/* Choose paInt16 as native i/o-format. */
+ goto sgiError;
+ if (ALsetwidth (pahsc->pahsc_ALconfigIN, AL_SAMPLE_16)) /* Only meaningful when sample format for */
+ goto sgiError; /* config is set to two's complement format. */
+ /************************ Future versions might (dynamically) switch to 32-bit floats? *******
+ if (ALsetsampfmt(pahsc_ALconfigIN, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.)
+ goto sgiError;
+ if (ALsetfloatmax (pahsc_ALconfigIN, 1.0)) Only meaningful when sample format for config
+ goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */
+ /*--------- Set internal AL queuesize (in samples) -------------------------------*/
+ if (ALsetqueuesize(pahsc->pahsc_ALconfigIN, (long)pahsc->pahsc_SamplesPerInputBuffer *
+ (long)kALinternalQueuesizeFact))
+ goto sgiError; /* Or should we use past_NumUserBuffers here? */
+ /* Do 4 timea, using 2 times may give glitches. */
+ if (ALsetchannels (pahsc->pahsc_ALconfigIN, (long)(past->past_NumInputChannels)))
+ goto sgiError; /* Returns 0 on success, -1 on failure. */
+ }
+ /*---------------------------------------------------- SET OUTPUT CONFIGURATION: ------------------------*/
+ if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */
+ { /* We use padOUT/IN later on, or at least 1 of both. */
+ pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */
+ past->past_NumOutputChannels; /* audio-thread. */
+ pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short);
+
+ pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer);
+ if (!pahsc->pahsc_NativeOutputBuffer)
+ {
+ ERR_RPT(("Fast memory allocation failed (out).\n"));
+ result = paInsufficientMemory;
+ goto done;
+ }
+ padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID);
+ if (!padOUT)
+ {
+ ERR_RPT(("Pa_GetInternalDevice() for output failed.\n"));
+ result = paHostError;
+ goto done;
+ }
+ if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4))
+ goto sgiError;
+ if (pvbuf[5] != sr)
+ { /* Output needed and rate different from current harware-rate. */
+ if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */
+ {
+ ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \
+another process is currently using output at %ld kHz.\n", sr, pvbuf[5]));
+ result = paHostError;
+ goto done; /* Will free again the inputbuffer */
+ } /* that was just created above. */
+ pvbuf[5] = sr; /* Then set output-rate. */
+ if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2))
+ goto sgiError;
+ }
+ pahsc->pahsc_ALconfigOUT = ALnewconfig(); /* Released at PaHost_CloseStream(). */
+ if (pahsc->pahsc_ALconfigOUT == (ALconfig)0)
+ goto sgiError;
+ if (ALsetsampfmt(pahsc->pahsc_ALconfigOUT, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */
+ goto sgiError;
+ if (ALsetwidth (pahsc->pahsc_ALconfigOUT, AL_SAMPLE_16)) /* Only meaningful when sample format for */
+ goto sgiError; /* config is set to two's complement format. */
+ /************************************ Future versions might (dynamically) switch to 32-bit floats? *******/
+ if (ALsetqueuesize(pahsc->pahsc_ALconfigOUT, (long)pahsc->pahsc_SamplesPerOutputBuffer *
+ (long)kALinternalQueuesizeFact))
+ goto sgiError; /* Or should we use past_NumUserBuffers here?*/
+ if (ALsetchannels (pahsc->pahsc_ALconfigOUT, (long)(past->past_NumOutputChannels)))
+ goto sgiError;
+ }
+ /*---------- ?? --------------------*/
+ /* DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); */
+ minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, past->past_SampleRate);
+ past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ?
+ minNumBuffers : past->past_NumUserBuffers; /* I don't yet use past_NumUserBuffers */
+ /*----------------------------------------------- TEST DEVICE ID's: --------------------*/
+ if ((past->past_OutputDeviceID != past->past_InputDeviceID) && /* Who SETS these devive-numbers? */
+ (past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0))
+ {
+ ERR_RPT(("Cannot setup bidirectional stream between different devices.\n"));
+ result = paHostError;
+ goto done;
+ }
+ goto done; /* (no errors occured) */
+sgiError:
+ result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
+done:
+ if (result != paNoError)
+ PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */
+ return result;
+}
+
+/*-----------------------------------------------------*/
+PaError PaHost_StartOutput(internalPortAudioStream *past)
+{
+ return paNoError; /* Hmm, not implemented yet? */
+}
+PaError PaHost_StartInput(internalPortAudioStream *past)
+{
+ return paNoError;
+}
+
+/*------------------------------------------------------------------------------*/
+PaError PaHost_StartEngine(internalPortAudioStream *past)
+{
+ PaHostSoundControl *pahsc;
+ usptr_t *arena;
+ if (!past) /* Test argument. */
+ {
+ ERR_RPT(("PaHost_StartEngine(NULL)!\n"));
+ return paBadStreamPtr;
+ }
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (!pahsc)
+ {
+ ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData = NULL!\n"));
+ return paHostError;
+ }
+ past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */
+ past->past_StopNow = 0; /* Why don't we check pahsc for NULL? */
+ past->past_IsActive = 1;
+
+ /* Although the pthread_create() function, as well as <pthread.h>, may be */
+ /* available in IRIX, use sproc() on SGI to create audio-background-thread. */
+ /* (Linux/oss uses pthread_create() instead of __clone() because: */
+ /* - pthread_create also works for other UNIX systems like Solaris, */
+ /* - Java HotSpot VM crashes in pthread_setcanceltype() using __clone().) */
+
+ usconfig(CONF_ARENATYPE, US_SHAREDONLY); /* (From SGI-AL-examples, file */
+ arena = usinit(tmpnam(0)); /* motifexample.c, function */
+ SendSema = usnewpollsema(arena, 0); /* InitializeAudioProcess().) */
+ RcvSema = usnewsema(arena, 1); /* 1= common mutual exclusion semaphore, where 1 and only 1 process
+ will be permitted through a semaphore at a time. Values > 1
+ imply that up to val resources may be simultaneously used, but requests
+ for more than val resources cause the calling process to block until a
+ resource comes free (by a process holding a resource performing a
+ usvsema(). IS THIS usnewsema() TOO PLATFORM SPECIFIC? */
+ prctl(PR_SETEXITSIG, 0); /* No not (void*)9, but 0, which doesn't kill the parent! */
+ /* PR_SETEXITSIG controls whether all members of a share group will be
+ signaled if any one of them leaves the share group (either via exit()
+ or exec()). If 2nd arg, interpreted as an int is 0, then normal IRIX
+ process termination rules apply, namely that the parent is sent a
+ SIGCLD upon death of child, but no indication of death of parent is
+ given. If the second argument is a valid signal number then if any
+ member of a share group leaves the share group, a signal is
+ sent to ALL surviving members of the share group. */
+ /* SPAWN AUDIO-CHILD: */
+ pahsc->pahsc_threadPID = sproc(Pa_SgiAudioProcess, /* Returns process ID of */
+ PR_SALL, /* new process, or -1. */
+ (void*)past); /* Pass past as optional */ /* IS THIS SAFE, will past never */
+ if (pahsc->pahsc_threadPID == -1) /* third void-ptr-arg. */ /* be moved around in memory???? */
+ {
+ ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n"));
+ sPaHostError = oserror(); /* Pass native error-number to shared area. */
+ return paHostError; /* But return the generic error-number. */
+ }
+ return paNoError; /* Hmmm, errno may come from other threads in same group! */
+} /* ("man sproc" in IRIX6.2 to read about _SGI_MP_SOURCE.) */
+
+/*------------------------------------------------------------------------------*/
+PaError PaHost_StopEngine(internalPortAudioStream *past, int abort)
+{
+ int hres;
+ long timeOut;
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+
+ DBUG(("PaHost_StopEngine() called.\n"));
+ if (!past)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ /* Prevent from doing this twice!! */
+ if ((!pahsc) || /* Some tests call this CLOSE twice!! */
+ (!past->past_IsActive) ||
+ past->past_StopSoon || past->past_StopNow)
+ return result; /* paNoError (already stopped, no err?). */
+ past->past_StopSoon = 1; /* Tell background thread to stop generating */
+ if (abort) /* more and to let current data play out. If */
+ past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */
+ /*---- USE SEMAPHORE LOCK TO COMMUNICATE: -----*/
+ usvsema(SendSema); /* Increments count associated with SendSema. */
+ /* Wait for the response. */
+ uspsema(RcvSema); /* Decrements count of previously allocated */
+ /* semaphore specified by RcvSema. */
+ while (past->past_IsActive) /* REALLY WAIT. */
+ {
+ /* DBUG(("wait 1 ms for audio-thread to stop.\n")); */
+ Pa_Sleep(1);
+ }
+
+#if 0 /* We don't need to KILL(), just COMMUNICATE and be patient... */
+ if (pahsc->pahsc_threadPID != -1) /* Did we really init it to -1 somewhere? */
+ {
+ DBUG(("PaHost_StopEngine() is about to kill(SIGKILL) audio-thread.\n"));
+ if (kill(pahsc->pahsc_threadPID, SIGKILL)) /* Or SIGTERM or SIGQUIT(core) */
+ { /* Returns -1 in case of error. */
+ result = paHostError;
+ sPaHostError = oserror(); /* Hmmm, other threads may also write here! */
+ ERR_RPT(("PaHost_StopEngine() failed to kill audio-thread.\n"));
+ }
+ else
+ pahsc->pahsc_threadPID = -1; /* Notify that we've killed this thread. */
+ }
+#endif
+ past->past_IsActive = 0; /* Even when kill() failed and pahsc_threadPID still there??? */
+ return result;
+}
+
+/*---------------------------------------------------------------*/
+PaError PaHost_StopOutput(internalPortAudioStream *past, int abort)
+{
+ return paNoError; /* Not implemented yet? */
+}
+PaError PaHost_StopInput(internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+/*******************************************************************/
+PaError PaHost_CloseStream(internalPortAudioStream *past)
+{
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+
+ DBUG(("PaHost_CloseStream() called.\n"));
+ if (!past)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (!pahsc) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */
+ return result; /* This test prevents from freeing NULL-pointers. */
+
+ if (pahsc->pahsc_ALconfigIN)
+ { /* Release configuration structs, only if allocated. */
+ ALfreeconfig(pahsc->pahsc_ALconfigIN);
+ pahsc->pahsc_ALconfigIN = NULL;
+ }
+ if (pahsc->pahsc_ALconfigOUT)
+ {
+ ALfreeconfig(pahsc->pahsc_ALconfigOUT); /* (Al-ports were already closed by audioProcess). */
+ pahsc->pahsc_ALconfigOUT = NULL;
+ }
+ if (pahsc->pahsc_NativeInputBuffer)
+ {
+ PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer);
+ pahsc->pahsc_NativeInputBuffer = NULL;
+ }
+ if (pahsc->pahsc_NativeOutputBuffer)
+ {
+ PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer);
+ pahsc->pahsc_NativeOutputBuffer = NULL;
+ }
+ PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl));
+ past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST MEM. */
+ return result;
+}
+
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+** set PA_MIN_LATENCY_MSEC=200
+** in the AUTOEXEC.BAT file and reboot.
+** If the environment variable is not set, then the latency will be
+** determined based on the OS. Windows NT has higher latency than Win95.
+*/
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
+{
+ return 2;
+}
+/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */
+/* Do we HAVE to do it this way under IRIX???.... */
+/*--------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------*/
+PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */
+{ /* Called by Pa_Terminate() from pa_lib.c. */
+ internalPortAudioDevice *pad = sDeviceList,
+ *nxt;
+ while (pad)
+ {
+ DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName));
+ nxt = pad->pad_Next;
+ PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice));
+ pad = nxt; /* PaHost_Init allocated this FAST MEM.*/
+ }
+ sDeviceList = (internalPortAudioDevice*)NULL;
+ return 0; /* Got rid of sNumDevices=0; */
+}
+
+/***********************************************************************/
+void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */
+{
+#if 0
+ struct timeval timeout;
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+ select(0, NULL, NULL, NULL, &timeout);
+#else
+ long usecs = msec * 1000;
+ usleep( usecs );
+#endif
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Allocate memory that can be accessed in real-time. This may need to be held in physi- */
+/* cal memory so that it is not paged to virtual memory. This call MUST be balanced with */
+/* a call to PaHost_FreeFastMemory(). */
+void *PaHost_AllocateFastMemory(long numBytes)
+{
+ void *addr = malloc(numBytes); /* mpin() reads into memory all pages over the given */
+ if (addr) /* range and locks the pages into memory. A counter */
+ { /* is incremented each time the page is locked. The */
+ if (mpin(addr, numBytes)) /* superuser can lock as many pages as it wishes, */
+ { /* others are limited to the configurable PLOCK_MA. */
+ ERR_RPT(("PaHost_AllocateFastMemory() failed to mpin() memory.\n"));
+#if 1
+ free(addr); /* You MAY cut out these 2 lines to be less strict, */
+ addr = NULL; /* you then only get the warning but PA goes on... */
+#endif /* Only problem then may be corresponding munpin() */
+ } /* call at PaHost_FreeFastMemory(), below. */
+ memset(addr, 0, numBytes); /* Locks established with mlock are not inherited by */
+ } /* a child process after a fork. Furthermore, IRIX- */
+ return addr; /* man-pages warn against mixing both mpin and mlock */
+} /* in 1 piece of code, so stick to mpin()/munpin() ! */
+
+
+/*---------------------------------------------------------------------------------------*/
+/* Free memory that could be accessed in real-time. This call MUST be balanced with a */
+/* call to PaHost_AllocateFastMemory(). */
+void PaHost_FreeFastMemory(void *addr, long numBytes)
+{
+ if (addr)
+ {
+ if (munpin(addr, numBytes)) /* Will munpin() fail when it was never mpinned? */
+ ERR_RPT(("WARNING: PaHost_FreeFastMemory() failed to munpin() memory.\n"));
+ free(addr); /* But go on, try to release it, just warn... */
+ }
+}
+
+/*----------------------------------------------------------*/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ if (past == NULL)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (pahsc == NULL)
+ return paInternalError;
+ return (PaError)(past->past_IsActive != 0);
+}
+
+/*-------------------------------------------------------------------*/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+/* FIXME - return actual frames played, not frames generated.
+** Need to query the output device somehow.
+*/
+ return past->past_FrameCount;
+}
diff --git a/pd/portaudio/pa_sgi/pthread-Makefile b/pd/portaudio/pa_sgi/pthread-Makefile
new file mode 100644
index 00000000..527677a8
--- /dev/null
+++ b/pd/portaudio/pa_sgi/pthread-Makefile
@@ -0,0 +1,52 @@
+# Make PortAudio for Silicon Graphics IRIX (6.2)
+# Pieter suurmond, september 22, 2001. (v15 pa_sgi sub-version #0.18)
+
+# pthread, math (as with linux) and SGI audio library:
+# SGI-books say -lpthread should be the last on the line.
+LIBS = -lm -laudio -lpthread
+
+CDEFINES = -I../pa_common
+
+# Possible CFLAGS with MIPSpro compiler are: -32, -o32, -n32, -64,
+# -mips1, -mips2, -mips3, -mips4, etc. Use -g, -g2, -g3 for debugging.
+# And use for example -O2 or -O3 for better optimization:
+CFLAGS = -O2
+PASRC = ../pa_common/pa_lib.c pa_sgi.c
+PAINC = ../pa_common/portaudio.h
+
+# Tests that work (SGI Indy with R5000 @ 180MHz running IRIX 6.2).
+#TESTC = $(PASRC) ../pa_tests/patest_record.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_many.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_latency.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_longsine.c # OK but needs more than 4 buffers to do without glitches.
+TESTC = $(PASRC) ../pa_tests/patest_saw.c # Seems OK (does it gracefully exit?).
+#TESTC = $(PASRC) ../pa_tests/patest_wire.c # OK
+#TESTC = $(PASRC) ../pa_tests/pa_devs.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sine8.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_leftright.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_pink.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_clip.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_stop.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_dither.c # OK
+#TESTC = $(PASRC) ../pa_tests/patest_sync.c # BEEPS and delta's, no crashes anymore.
+
+# Tests that do not yet work.
+#TESTC = $(PASRC) ../pa_tests/paqa_devs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 1 output channel(s) on AL default
+#TESTC = $(PASRC) ../pa_tests/paqa_errs.c # Heavy crash with core-dump after PaHost_OpenStream: opening 2 output channel(s) on AL default
+#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c # THIS FUZZ CRASHED MY WHOLE IRIX SYSTEM after "ENTER"! :-(
+ # PROCESS IN ITSELF RUNS OK, WITH LARGER BUFFSIZES THOUGH.
+ # OH MAYBE IT WAS BECAUSE DEBUGGING WAS ON???
+ # ANYWAY, I'M NOT GONNA RUN THAT AGAIN... WAY TOO DANGEROUS!
+TESTH = $(PAINC)
+
+all: patest
+
+# "cc" for the MIPSpro compiler, may be changed to "gcc":
+patest: $(TESTC) $(TESTH) Makefile
+ cc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest
+
+run: patest
+ ./patest
+
diff --git a/pd/portaudio/pa_sgi/pthread-pa_sgi.c b/pd/portaudio/pa_sgi/pthread-pa_sgi.c
new file mode 100644
index 00000000..e9ab273c
--- /dev/null
+++ b/pd/portaudio/pa_sgi/pthread-pa_sgi.c
@@ -0,0 +1,908 @@
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * SGI IRIX implementation by Pieter Suurmond, september 22, 2001 (#0.18).
+ *
+ * Copyright (c) 1999-2001 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+/*
+Modfication History:
+ 8/12/2001 - Pieter Suurmond - took the v15 pa_linux_oss.c file and started to adapt for IRIX 6.2.
+ 8/17/2001 - alpha release with IRIX sproc()-method, may sometimes let IRIX6.2 crash at closing audiostream.
+ 9/22/2001 - #0.18 pthread starts to work a bit:
+ BUT UNDER IRIX6.2, I DON'T GET IT TO WORK REALLY CORRECTLY,
+ this POSIX-attempt,
+ DON'T USE THIS FILE FOR RELIABLE OPERATION, IT IS HERE JUST
+ FOR DOCUMENTATION/ARCHIVE... OR FOR ANYONE WHO WANTS TO FIX......
+TODO:
+ - Test under IRIX 6.5.
+ - Dynamically switch to 32 bit float as native format when appropriate (let SGI do the conversion),
+ and maybe also the other natively supported formats? (might increase performance)
+ - Not sure whether CPU UTILIZATION MEASUREMENT (from OSS/linux) really works. Changed nothing yet,
+ seems ok, but I've not yet tested it thoroughly. (maybe utilization-code may be made _unix_common_ then?)
+ - The minimal number of buffers setting... I do not yet fully understand it.. I now just take *4.
+REFERENCES:
+ - IRIX 6.2 man pages regarding SGI AL library.
+ - IRIS Digital MediaProgramming Guide (online books as well as man-pages come with IRIX 6.2 and
+ may not be publically available on the internet).
+*/
+
+#include <stdio.h> /* Standard libraries. */
+#include <stdlib.h>
+
+#include "../pa_common/portaudio.h" /* Portaudio headers. */
+#include "../pa_common/pa_host.h"
+#include "../pa_common/pa_trace.h"
+
+/*
+#include <malloc.h>
+#include <memory.h>
+#include <sys/prctl.h> Not needed
+#include <sys/types.h>
+#include <sys/schedctl.h>
+#include <signal.h>
+#include <sys/ioctl.h> Needed?
+#include <sys/time.h>
+#include <sched.h> sched_param struct and related functions
+ used in setting thread priorities.
+#include <limits.h> Some POSIX constants such as _POSIX_THREAD_THREADS_MAX
+*/
+
+#include <pthread.h> /* Pthreads are supported by IRIX 6.2 after */
+ /* patches 1361, 1367, and 1429 are applied. */
+
+#include <fcntl.h> /* fcntl.h needed for "O_RDONLY". */
+#include <unistd.h> /* For usleep() and constants used when calling sysconf() */
+ /* to query POSIX limits (see the sysconf(3) ref. page. */
+
+#include <dmedia/audio.h> /* SGI-specific audio library. */
+
+
+/*--------------------------------------------*/
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) PRINT(x)
+#define DBUGX(x) /* PRINT(x) */
+
+#define MAX_CHARS_DEVNAME (16) /* Was 32 in OSS (20 for AL but "in"/"out" is concat. */
+#define MAX_SAMPLE_RATES (8) /* Known from SGI AL there are 7 (was 10 in OSS v15). */
+
+typedef struct internalPortAudioDevice /* IRIX specific device info: */
+{
+ PaDeviceID /* NEW: */ pad_DeviceID; /* THIS "ID" IS NEW HERE (Pieter)! */
+ long pad_ALdevice; /* SGI-number! */
+ double pad_SampleRates[MAX_SAMPLE_RATES]; /* for pointing to from pad_Info */
+ char pad_DeviceName[MAX_CHARS_DEVNAME+1]; /* +1 for \0, one more than OSS. */
+ PaDeviceInfo pad_Info; /* pad_Info (v15) contains: */
+ /* int structVersion; */
+ /* const char* name; */
+ /* int maxInputChannels, maxOutputChannels; */
+ /* int numSampleRates; Num rates, or -1 if range supprtd. */
+ /* const double* sampleRates; Array of supported sample rates, */
+ /* PaSampleFormat nativeSampleFormats; or {min,max} if range supported. */
+ struct internalPortAudioDevice* pad_Next; /* Singly linked list, (NULL=end). */
+} internalPortAudioDevice;
+
+typedef struct PaHostSoundControl /* Structure to contain all SGI IRIX specific data. */
+{
+ ALport pahsc_ALportIN, /* IRIX-audio-library-datatype. ALports can only be */
+ pahsc_ALportOUT; /* unidirectional, so we sometimes need 2 of them. */
+ pthread_t pahsc_ThreadPID;
+ short *pahsc_NativeInputBuffer, /* Allocated here, in this file, if necessary. */
+ *pahsc_NativeOutputBuffer;
+ unsigned int pahsc_BytesPerInputBuffer, /* Native buffer sizes in bytes, really needed here */
+ pahsc_BytesPerOutputBuffer; /* to free FAST memory, if buffs were alloctd FAST. */
+ unsigned int pahsc_SamplesPerInputBuffer, /* These amounts are needed again and again in the */
+ pahsc_SamplesPerOutputBuffer; /* audio-thread (don't need to be kept globally). */
+ struct itimerval pahsc_EntryTime, /* For measuring CPU utilization (same as linux). */
+ pahsc_LastExitTime;
+ long pahsc_InsideCountSum,
+ pahsc_TotalCountSum;
+} PaHostSoundControl;
+
+/*----------------------------- Shared Data ------------------------------------------------------*/
+static internalPortAudioDevice* sDeviceList = NULL; /* FIXME - put Mutex around this shared data. */
+static int sPaHostError = 0; /* Maybe more than one process writing errs!? */
+
+long Pa_GetHostError(void)
+{
+ return (long)sPaHostError;
+}
+
+/*----------------------------- BEGIN CPU UTILIZATION MEASUREMENT -----------------*/
+/* (copied from source pa_linux_oss/pa_linux_oss.c) */
+static void Pa_StartUsageCalculation( internalPortAudioStream *past )
+{
+ struct itimerval itimer;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+/* Query system timer for usage analysis and to prevent overuse of CPU. */
+ getitimer( ITIMER_REAL, &pahsc->pahsc_EntryTime );
+}
+
+static long SubtractTime_AminusB( struct itimerval *timeA, struct itimerval *timeB )
+{
+ long secs = timeA->it_value.tv_sec - timeB->it_value.tv_sec;
+ long usecs = secs * 1000000;
+ usecs += (timeA->it_value.tv_usec - timeB->it_value.tv_usec);
+ return usecs;
+}
+
+static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+{
+ struct itimerval currentTime;
+ long insideCount;
+ long totalCount; /* Measure CPU utilization during this callback. */
+
+#define LOWPASS_COEFFICIENT_0 (0.95)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (pahsc == NULL)
+ return;
+ if (getitimer( ITIMER_REAL, &currentTime ) == 0 )
+ {
+ if (past->past_IfLastExitValid)
+ {
+ insideCount = SubtractTime_AminusB( &pahsc->pahsc_EntryTime, &currentTime );
+ pahsc->pahsc_InsideCountSum += insideCount;
+ totalCount = SubtractTime_AminusB( &pahsc->pahsc_LastExitTime, &currentTime );
+ pahsc->pahsc_TotalCountSum += totalCount;
+ /* DBUG(("insideCount = %d, totalCount = %d\n", insideCount, totalCount )); */
+ /* Low pass filter the result because sometimes we get called several times in a row. */
+ /* That can cause the TotalCount to be very low which can cause the usage to appear */
+ /* unnaturally high. So we must filter numerator and denominator separately!!! */
+ if (pahsc->pahsc_InsideCountSum > 0)
+ {
+ past->past_AverageInsideCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageInsideCount) +
+ (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_InsideCountSum));
+ past->past_AverageTotalCount = ((LOWPASS_COEFFICIENT_0 * past->past_AverageTotalCount) +
+ (LOWPASS_COEFFICIENT_1 * pahsc->pahsc_TotalCountSum));
+ past->past_Usage = past->past_AverageInsideCount / past->past_AverageTotalCount;
+ pahsc->pahsc_InsideCountSum = 0;
+ pahsc->pahsc_TotalCountSum = 0;
+ }
+ }
+ past->past_IfLastExitValid = 1;
+ }
+ pahsc->pahsc_LastExitTime.it_value.tv_sec = 100;
+ pahsc->pahsc_LastExitTime.it_value.tv_usec = 0;
+ setitimer( ITIMER_REAL, &pahsc->pahsc_LastExitTime, NULL );
+ past->past_IfLastExitValid = 1;
+} /*----------- END OF CPU UTILIZATION CODE (from pa_linux_oss/pa_linux_oss.c v15)--------------------*/
+
+
+/*--------------------------------------------------------------------------------------*/
+PaError translateSGIerror(void) /* Calls oserror(), may be used after an SGI AL-library */
+{ /* call to report via ERR_RPT(), yields a PaError-num. */
+ const char* a = "SGI AL "; /* (Not absolutely sure errno came from THIS thread! */
+ switch(oserror()) /* Read IRIX man-pages about the _SGI_MP_SOURCE macro.) */
+ {
+ case AL_BAD_OUT_OF_MEM:
+ ERR_RPT(("%sout of memory.\n", a));
+ return paInsufficientMemory; /* Known PaError. */
+ case AL_BAD_CONFIG:
+ ERR_RPT(("%sconfiguration invalid or NULL.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_CHANNELS:
+ ERR_RPT(("%schannels not 1,2 or 4.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_NO_PORTS:
+ ERR_RPT(("%sout of audio ports.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DEVICE:
+ ERR_RPT(("%swrong device number.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DEVICE_ACCESS:
+ ERR_RPT(("%swrong device access.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_DIRECTION:
+ ERR_RPT(("%sinvalid direction.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_SAMPFMT:
+ ERR_RPT(("%sdoesn't accept sampleformat.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_FLOATMAX:
+ ERR_RPT(("%smax float value is zero.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_WIDTH:
+ ERR_RPT(("%sunsupported samplewidth.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_QSIZE:
+ ERR_RPT(("%sinvalid queue size.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_PVBUFFER:
+ ERR_RPT(("%sPVbuffer null.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_BUFFERLENGTH_NEG:
+ ERR_RPT(("%snegative bufferlength.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_BUFFERLENGTH_ODD:
+ ERR_RPT(("%sodd bufferlength.\n", a));
+ return paHostError; /* Generic PaError. */
+ case AL_BAD_PARAM:
+ ERR_RPT(("%sparameter not valid for device.\n", a));
+ return paHostError; /* Generic PaError. */
+ default:
+ ERR_RPT(("%sunknown error.\n", a));
+ return paHostError; /* Generic PaError. */
+ }
+}
+
+/*------------------------------------------------------------------------------------------*/
+/* Tries to set various rates and formats and fill in the device info structure. */
+static PaError Pa_sgiQueryDevice(long ALdev, /* (AL_DEFAULT_DEVICE) */
+ PaDeviceID id, /* (DefaultI|ODeviceID()) */
+ char* name, /* (for example "SGI AL") */
+ internalPortAudioDevice* pad) /* Result written to pad. */
+{
+ int format;
+ long min, max; /* To catch hardware characteristics. */
+ ALseterrorhandler(0); /* 0 = turn off the default error handler. */
+ /*--------------------------------------------------------------------------------------*/
+ pad->pad_ALdevice = ALdev; /* Set the AL device number. */
+ pad->pad_DeviceID = id; /* Set the PA device number. */
+ if (strlen(name) > MAX_CHARS_DEVNAME) /* MAX_CHARS defined above. */
+ {
+ ERR_RPT(("Pa_QueryDevice(): name too long (%s).\n", name));
+ return paHostError;
+ }
+ strcpy(pad->pad_DeviceName, name); /* Write name-string. */
+ pad->pad_Info.name = pad->pad_DeviceName; /* Set pointer,..hmmm. */
+ /*--------------------------------- natively supported sample formats: -----------------*/
+ pad->pad_Info.nativeSampleFormats = paInt16; /* Later also include paFloat32 | ..| etc. */
+ /* Then also choose other CallConvertXX()! */
+ /*--------------------------------- number of available i/o channels: ------------------*/
+ if (ALgetminmax(ALdev, AL_INPUT_COUNT, &min, &max))
+ return translateSGIerror();
+ pad->pad_Info.maxInputChannels = max;
+ DBUG(("Pa_QueryDevice: maxInputChannels = %d\n", pad->pad_Info.maxInputChannels))
+ if (ALgetminmax(ALdev, AL_OUTPUT_COUNT, &min, &max))
+ return translateSGIerror();
+ pad->pad_Info.maxOutputChannels = max;
+ DBUG(("Pa_QueryDevice: maxOutputChannels = %d\n", pad->pad_Info.maxOutputChannels))
+ /*--------------------------------- supported samplerates: ----------------------*/
+ pad->pad_Info.numSampleRates = 7;
+ pad->pad_Info.sampleRates = pad->pad_SampleRates;
+ pad->pad_SampleRates[0] = (double)AL_RATE_8000; /* long -> double. */
+ pad->pad_SampleRates[1] = (double)AL_RATE_11025;
+ pad->pad_SampleRates[2] = (double)AL_RATE_16000;
+ pad->pad_SampleRates[3] = (double)AL_RATE_22050;
+ pad->pad_SampleRates[4] = (double)AL_RATE_32000;
+ pad->pad_SampleRates[5] = (double)AL_RATE_44100;
+ pad->pad_SampleRates[6] = (double)AL_RATE_48000;
+ if (ALgetminmax(ALdev, AL_INPUT_RATE, &min, &max)) /* Ask INPUT rate-max. */
+ return translateSGIerror(); /* double -> long. */
+ if (max != (long)(0.5 + pad->pad_SampleRates[6])) /* FP-compare not recommndd. */
+ goto weird;
+ if (ALgetminmax(ALdev, AL_OUTPUT_RATE, &min, &max)) /* Ask OUTPUT rate-max. */
+ return translateSGIerror();
+ if (max != (long)(0.5 + pad->pad_SampleRates[6]))
+ {
+weird: ERR_RPT(("Pa_sgiQueryDevice() did not confirm max samplerate (%ld)\n",max));
+ return paHostError; /* Or make it a warning and just carry on... */
+ }
+ /*-------------------------------------------------------------------------------*/
+ return paNoError;
+}
+
+
+/*--------------------------------------------------------------------------------*/
+int Pa_CountDevices() /* Name of this function suggests it only counts and */
+{ /* is NOT destructive, it however resets whole PA ! */
+ int numDevices = 0; /* Let 's not do that here. */
+ internalPortAudioDevice* currentDevice = sDeviceList; /* COPY GLOBAL VAR. */
+#if 0 /* Remains from linux_oss v15: Pa_Initialize(), on */
+ if (!currentDevice) /* its turn, calls PaHost_Init() via file pa_lib.c. */
+ Pa_Initialize(); /* Isn't that a bit too 'rude'? Don't be too */
+#endif /* friendly to clients that forgot to initialize PA. */
+ while (currentDevice) /* Slower but more elegant than the sNumDevices-way: */
+ {
+ numDevices++;
+ currentDevice = currentDevice->pad_Next;
+ }
+ return numDevices;
+}
+
+/*-------------------------------------------------------------------------------*/
+static internalPortAudioDevice *Pa_GetInternalDevice(PaDeviceID id)
+{
+ int numDevices = 0;
+ internalPortAudioDevice *res = (internalPortAudioDevice*)NULL;
+ internalPortAudioDevice *pad = sDeviceList; /* COPY GLOBAL VAR. */
+ while (pad) /* pad may be NULL, that's ok, return 0. */
+ { /* (Added ->pad_DeviceID field to the pad-struct, Pieter, 2001.) */
+ if (pad->pad_DeviceID == id) /* This the device we were looking for? */
+ res = pad; /* But keep on(!) counting so we don't */
+ numDevices++; /* have to call Pa_CountDevices() later. */
+ pad = pad->pad_Next; /* Advance to the next device or NULL. */
+ } /* No assumptions about order of ID's in */
+ if (!res) /* the list. */
+ ERR_RPT(("Pa_GetInternalDevice() could not find specified ID (%d).\n",id));
+ if ((id < 0) || (id >= numDevices))
+ {
+ ERR_RPT(("Pa_GetInternalDevice() supplied with an illegal ID (%d).\n",id));
+#if 1 /* Be strict, even when found, */
+ res = (internalPortAudioDevice*)NULL; /* do not accept illegal ID's. */
+#endif
+ }
+ return res;
+}
+
+/*----------------------------------------------------------------------*/
+const PaDeviceInfo* Pa_GetDeviceInfo(PaDeviceID id)
+{
+ PaDeviceInfo* res = (PaDeviceInfo*)NULL;
+ internalPortAudioDevice* pad = Pa_GetInternalDevice(id); /* Call. */
+ if (pad)
+ res = &pad->pad_Info; /* Not finding the specified ID is not */
+ if (!res) /* the same as &pad->pad_Info == NULL. */
+ ERR_RPT(("Pa_GetDeviceInfo() could not find it (ID=%d).\n", id));
+ return res; /* So (maybe) a second/third ERR_RPT(). */
+}
+
+/*------------------------------------------------*/
+PaDeviceID Pa_GetDefaultInputDeviceID(void)
+{
+ return 0; /* 0 is the default device ID. */
+}
+/*------------------------------------------------*/
+PaDeviceID Pa_GetDefaultOutputDeviceID(void)
+{
+ return 0;
+}
+
+/*-------------------------------------------------------------------------------------------------*/
+/* Build linked a list with all the available audio devices on this SGI machine (only 1 for now). */
+PaError PaHost_Init(void) /* Called by Pa_Initialize() from pa_lib.c. */
+{
+ internalPortAudioDevice* pad;
+ PaError r = paNoError;
+ int audioLibFileID; /* To test for the presence of audio. */
+
+ if (sDeviceList) /* Allow re-init, only warn, no error. */
+ {
+ ERR_RPT(("Warning: PaHost_Init() did not really re-init PA.\n"));
+ return r;
+ }
+ /*------------- ADD THE SGI DEFAULT DEVICE TO THE LIST: ---------------------------------------*/
+ audioLibFileID = open("/dev/hdsp/hdsp0master", O_RDONLY); /* Try to open Indigo style audio */
+ if (audioLibFileID < 0) /* IO port. On failure, machine */
+ { /* has no audio ability. */
+ ERR_RPT(("PaHost_Init(): This machine has no (Indigo-style) audio abilities.\n"));
+ return paHostError;
+ }
+ close(audioLibFileID); /* Allocate fast mem to hold device info. */
+ pad = PaHost_AllocateFastMemory(sizeof(internalPortAudioDevice));
+ if (pad == NULL)
+ return paInsufficientMemory;
+ memset(pad, 0, sizeof(internalPortAudioDevice)); /* "pad->pad_Next = NULL" is more elegant. */
+ r = Pa_sgiQueryDevice(AL_DEFAULT_DEVICE, /* Set AL device num (AL_DEFAULT_DEVICE). */
+ Pa_GetDefaultOutputDeviceID(),/* Set PA device num (or InputDeviceID()). */
+ "AL default", /* A suitable name. */
+ pad); /* Write args and queried info into pad. */
+ if (r != paNoError)
+ {
+ ERR_RPT(("Pa_QueryDevice for '%s' returned: %d\n", pad->pad_DeviceName, r));
+ PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice)); /* sDeviceList still NULL ! */
+ }
+ else
+ sDeviceList = pad; /* First element in linked list. pad->pad_Next already NULL. */
+ /*------------- QUERY AND ADD MORE POSSIBLE SGI DEVICES TO THE LINKED LIST: -------------------*/
+ /*---------------------------------------------------------------------------------------------*/
+ return r;
+}
+
+/*---------------------------------------------------------------------------------------------------*/
+static PaError Pa_SgiAudioProcess(internalPortAudioStream *past) /* Spawned by PaHost_StartEngine(). */
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+
+ if (!past)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (!pahsc)
+ return paInternalError;
+ past->past_IsActive = 1; /* Wasn't this already done by the calling parent?! */
+ DBUG(("entering thread.\n"));
+
+ while (!past->past_StopSoon) /* OR-ing StopSoon and StopNow here gives problems! */
+ {
+ /*---------------------------------------- INPUT: ------------------------------------*/
+ if (pahsc->pahsc_NativeInputBuffer) /* Then pahsc_ALportIN should also be there! */
+ {
+ while (ALgetfilled(pahsc->pahsc_ALportIN) < pahsc->pahsc_SamplesPerInputBuffer)
+ {
+ /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */
+ if (past->past_StopNow) /* Don't let ALreadsamps() block */
+ goto done;
+ }
+ if (ALreadsamps(pahsc->pahsc_ALportIN, (void*)pahsc->pahsc_NativeInputBuffer,
+ pahsc->pahsc_SamplesPerInputBuffer)) /* Number of samples instead */
+ { /* of number of frames. */
+ ERR_RPT(("ALreadsamps() failed.\n"));
+ result = paInternalError;
+ goto done;
+ }
+ }
+ /*---------------------------------------------------- USER CALLBACK ROUTINE: ----------*/
+ /* DBUG(("Calling Pa_CallConvertInt16()...\n")); */
+ Pa_StartUsageCalculation(past); /* Convert 16 bit native data to */
+ result = Pa_CallConvertInt16(past, /* user data and call user routine. */
+ pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_NativeOutputBuffer);
+ Pa_EndUsageCalculation(past);
+ if (result)
+ {
+ DBUG(("Pa_CallConvertInt16() returned %d, stopping...\n", result));
+ goto done; /* This is apparently NOT an error! */
+ } /* Just letting the userCallBack stop us. */
+ /*---------------------------------------- OUTPUT: ------------------------------------*/
+ if (pahsc->pahsc_NativeOutputBuffer) /* Then pahsc_ALportOUT should also be there! */
+ {
+ while (ALgetfillable(pahsc->pahsc_ALportOUT) < pahsc->pahsc_SamplesPerOutputBuffer)
+ {
+ /* Trying sginap(1); and usleep(); here... things get blocked under IRIX6.2. */
+ if (past->past_StopNow) /* Don't let ALwritesamps() block */
+ goto done;
+ }
+ if (ALwritesamps(pahsc->pahsc_ALportOUT, (void*)pahsc->pahsc_NativeOutputBuffer,
+ pahsc->pahsc_SamplesPerOutputBuffer))
+ {
+ ERR_RPT(("ALwritesamps() failed.\n"));
+ result = paInternalError;
+ goto done;
+ }
+ }
+ /*-------------------------------------------------------------------------------------*/
+ }
+done:
+ /* pahsc->pahsc_ThreadPID = -1; Hu? doesn't help!! (added by Pieter) */
+ past->past_IsActive = 0;
+ DBUG(("leaving thread.\n"));
+ return result;
+}
+
+
+/*--------------------------------------------------------------------------------------*/
+PaError PaHost_OpenStream(internalPortAudioStream *past)
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+ unsigned int minNumBuffers;
+ internalPortAudioDevice *padIN, *padOUT; /* For looking up native AL-numbers. */
+ ALconfig sgiALconfig = NULL; /* IRIX-datatype. */
+ long pvbuf[8]; /* To get/set hardware configs. */
+ long sr, ALqsize;
+ DBUG(("PaHost_OpenStream() called.\n")); /* Alloc FASTMEM and init host data. */
+ if (!past)
+ {
+ ERR_RPT(("Streampointer NULL!\n"));
+ result = paBadStreamPtr; goto done;
+ }
+ pahsc = (PaHostSoundControl*)PaHost_AllocateFastMemory(sizeof(PaHostSoundControl));
+ if (pahsc == NULL)
+ {
+ ERR_RPT(("FAST Memory allocation failed.\n")); /* Pass trough some ERR_RPT-exit- */
+ result = paInsufficientMemory; goto done; /* code (nothing will be freed). */
+ }
+ memset(pahsc, 0, sizeof(PaHostSoundControl));
+/* pahsc->pahsc_threadPID = -1; Should pahsc_threadPID be inited to */
+ past->past_DeviceData = (void*)pahsc; /* -1 instead of 0 ?? */
+ /*--------------------------------------------------- Allocate native buffers: --------*/
+ pahsc->pahsc_SamplesPerInputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */
+ past->past_NumInputChannels; /* audio-thread. */
+ pahsc->pahsc_BytesPerInputBuffer = pahsc->pahsc_SamplesPerInputBuffer * sizeof(short);
+ if (past->past_NumInputChannels > 0) /* Assumes short = 16 bits! */
+ {
+ pahsc->pahsc_NativeInputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerInputBuffer);
+ if( pahsc->pahsc_NativeInputBuffer == NULL )
+ {
+ ERR_RPT(("Fast memory allocation for input-buffer failed.\n"));
+ result = paInsufficientMemory; goto done;
+ }
+ }
+ pahsc->pahsc_SamplesPerOutputBuffer = past->past_FramesPerUserBuffer * /* Needed by the */
+ past->past_NumOutputChannels; /* audio-thread. */
+ pahsc->pahsc_BytesPerOutputBuffer = pahsc->pahsc_SamplesPerOutputBuffer * sizeof(short);
+ if (past->past_NumOutputChannels > 0) /* Assumes short = 16 bits! */
+ {
+ pahsc->pahsc_NativeOutputBuffer = (short*)PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerOutputBuffer);
+ if (pahsc->pahsc_NativeOutputBuffer == NULL)
+ {
+ ERR_RPT(("Fast memory allocation for output-buffer failed.\n"));
+ result = paInsufficientMemory; goto done;
+ }
+ }
+ /*------------------------------------------ Manipulate hardware if necessary and allowed: --*/
+ ALseterrorhandler(0); /* 0 = turn off the default error handler. */
+ pvbuf[0] = AL_INPUT_RATE;
+ pvbuf[2] = AL_INPUT_COUNT;
+ pvbuf[4] = AL_OUTPUT_RATE; /* TO FIX: rates may be logically, not always in Hz! */
+ pvbuf[6] = AL_OUTPUT_COUNT;
+ sr = (long)(past->past_SampleRate + 0.5); /* Common for input and output :-) */
+ if (past->past_NumInputChannels > 0) /* We need to lookup the corre- */
+ { /* sponding native AL-number(s). */
+ padIN = Pa_GetInternalDevice(past->past_InputDeviceID);
+ if (!padIN)
+ {
+ ERR_RPT(("Pa_GetInternalDevice() for input failed.\n"));
+ result = paHostError; goto done;
+ }
+ if (ALgetparams(padIN->pad_ALdevice, &pvbuf[0], 4)) /* Although input and output will both be on */
+ goto sgiError; /* the same AL-device, the AL-library might */
+ if (pvbuf[1] != sr) /* contain more than AL_DEFAULT_DEVICE in */
+ { /* Rate different from current harware-rate? the future. Therefore 2 seperate queries. */
+ if (pvbuf[3] > 0) /* Means, there's other clients using AL-input-ports */
+ {
+ ERR_RPT(("Sorry, not allowed to switch input-hardware to %ld Hz because \
+another process is currently using input at %ld kHz.\n", sr, pvbuf[1]));
+ result = paHostError; goto done;
+ }
+ pvbuf[1] = sr; /* Then set input-rate. */
+ if (ALsetparams(padIN->pad_ALdevice, &pvbuf[0], 2))
+ goto sgiError; /* WHETHER THIS SAMPLERATE WAS REALLY PRESENT IN OUR ARRAY OF RATES, */
+ } /* IS NOT CHECKED, AT LEAST NOT BY ME, WITHIN THIS FILE! Does PA do? */
+ }
+ if (past->past_NumOutputChannels > 0) /* CARE: padOUT/IN may NOT be NULL if Channels <= 0! */
+ { /* We use padOUT/IN later on, or at least 1 of both. */
+ padOUT = Pa_GetInternalDevice(past->past_OutputDeviceID);
+ if (!padOUT)
+ {
+ ERR_RPT(("Pa_GetInternalDevice() for output failed.\n"));
+ result = paHostError; goto done;
+ }
+ if (ALgetparams(padOUT->pad_ALdevice,&pvbuf[4], 4))
+ goto sgiError;
+ if ((past->past_NumOutputChannels > 0) && (pvbuf[5] != sr))
+ { /* Output needed and rate different from current harware-rate. */
+ if (pvbuf[7] > 0) /* Means, there's other clients using AL-output-ports */
+ {
+ ERR_RPT(("Sorry, not allowed to switch output-hardware to %ld Hz because \
+another process is currently using output at %ld kHz.\n", sr, pvbuf[5]));
+ result = paHostError; goto done; /* Will free again the inputbuffer */
+ } /* that was just created above. */
+ pvbuf[5] = sr; /* Then set output-rate. */
+ if (ALsetparams(padOUT->pad_ALdevice, &pvbuf[4], 2))
+ goto sgiError;
+ }
+ }
+ /*------------------------------------------ Construct an audio-port-configuration ----------*/
+ sgiALconfig = ALnewconfig(); /* Change the SGI-AL-default-settings. */
+ if (sgiALconfig == (ALconfig)0) /* sgiALconfig is released here after use! */
+ goto sgiError; /* See that sgiALconfig is NOT released! */
+ if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_TWOSCOMP)) /* Choose paInt16 as native i/o-format. */
+ goto sgiError;
+ if (ALsetwidth (sgiALconfig, AL_SAMPLE_16)) /* Only meaningful when sample format for */
+ goto sgiError; /* config is set to two's complement format. */
+ /************************ Future versions might (dynamically) switch to 32-bit floats? *******
+ if (ALsetsampfmt(sgiALconfig, AL_SAMPFMT_FLOAT)) (Then also call another CallConvert-func.)
+ goto sgiError;
+ if (ALsetfloatmax (sgiALconfig, 1.0)) Only meaningful when sample format for config
+ goto sgiError; is set to AL_SAMPFMT_FLOAT or AL_SAMPFMT_DOUBLE. */
+ /*---------- ?? --------------------*/
+ /* DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer )); */
+ minNumBuffers = Pa_GetMinNumBuffers(past->past_FramesPerUserBuffer, past->past_SampleRate);
+ past->past_NumUserBuffers = (minNumBuffers > past->past_NumUserBuffers) ?
+ minNumBuffers : past->past_NumUserBuffers;
+ /*------------------------------------------------ Set internal AL queuesize (in samples) ----*/
+ if (pahsc->pahsc_SamplesPerInputBuffer >= pahsc->pahsc_SamplesPerOutputBuffer)
+ ALqsize = (long)pahsc->pahsc_SamplesPerInputBuffer;
+ else /* Take the largest of the two amounts. */
+ ALqsize = (long)pahsc->pahsc_SamplesPerOutputBuffer;
+ ALqsize *= 4; /* 4 times as large as amount per transfer! */
+ if (ALsetqueuesize(sgiALconfig, ALqsize)) /* Or should we use past_NumUserBuffers here? */
+ goto sgiError; /* Using 2 times may give glitches... */
+ /* Have to work on ALsetqueuesize() above. */
+
+ /* Do ALsetchannels() later, apart per input and/or output. */
+ /*----------------------------------------------- OPEN 1 OR 2 AL-DEVICES: --------------------*/
+ if (past->past_OutputDeviceID == past->past_InputDeviceID) /* Who SETS these devive-numbers? */
+ {
+ if ((past->past_NumOutputChannels > 0) && (past->past_NumInputChannels > 0))
+ {
+ DBUG(("PaHost_OpenStream: opening both input and output channels.\n"));
+ /*------------------------- open output port: ----------------------------------*/
+ if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels)))
+ goto sgiError; /* Returns 0 on success, -1 on failure. */
+ pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig);
+ if (pahsc->pahsc_ALportOUT == (ALport)0)
+ goto sgiError;
+ /*------------------------- open input port: -----------------------------------*/
+ if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels)))
+ goto sgiError; /* Returns 0 on success, -1 on failure. */
+ pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig);
+ if (pahsc->pahsc_ALportIN == (ALport)0)
+ goto sgiError; /* For some reason the "patest_wire.c"-test crashes! */
+ } /* Probably due to too small buffersizes?.... */
+ else
+ {
+ ERR_RPT(("Cannot setup bidirectional stream between different devices.\n"));
+ result = paHostError;
+ goto done;
+ }
+ }
+ else /* (OutputDeviceID != InputDeviceID) */
+ {
+ if (past->past_NumOutputChannels > 0) /* WRITE-ONLY: */
+ {
+ /*------------------------- open output port: ----------------------------------*/
+ DBUG(("PaHost_OpenStream: opening %d output channel(s) on %s.\n",
+ past->past_NumOutputChannels, padOUT->pad_DeviceName));
+ if (ALsetchannels (sgiALconfig, (long)(past->past_NumOutputChannels)))
+ goto sgiError; /* Returns 0 on success, -1 on failure. */
+ pahsc->pahsc_ALportOUT = ALopenport("PA sgi out", "w", sgiALconfig);
+ if (pahsc->pahsc_ALportOUT == (ALport)0)
+ goto sgiError;
+ }
+ if (past->past_NumInputChannels > 0) /* READ-ONLY: */
+ {
+ /*------------------------- open input port: -----------------------------------*/
+ DBUG(("PaHost_OpenStream: opening %d input channel(s) on %s.\n",
+ past->past_NumInputChannels, padIN->pad_DeviceName));
+ if (ALsetchannels (sgiALconfig, (long)(past->past_NumInputChannels)))
+ goto sgiError; /* Returns 0 on success, -1 on failure. */
+ pahsc->pahsc_ALportIN = ALopenport("PA sgi in", "r", sgiALconfig);
+ if (pahsc->pahsc_ALportIN == (ALport)0)
+ goto sgiError;
+ }
+ }
+ DBUG(("PaHost_OpenStream() succeeded.\n"));
+ goto done; /* (no errors occured) */
+sgiError:
+ result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
+done:
+ if (sgiALconfig)
+ ALfreeconfig(sgiALconfig); /* We don't need that struct anymore. */
+ if (result != paNoError)
+ PaHost_CloseStream(past); /* Frees memory (only if really allocated!). */
+ return result;
+}
+
+/*-----------------------------------------------------*/
+PaError PaHost_StartOutput(internalPortAudioStream *past)
+{
+ return paNoError; /* Hmm, not implemented yet? */
+}
+PaError PaHost_StartInput(internalPortAudioStream *past)
+{
+ return paNoError;
+}
+
+/*------------------------------------------------------------------------------*/
+PaError PaHost_StartEngine(internalPortAudioStream *past)
+{
+ PaHostSoundControl *pahsc;
+ int hres;
+ PaError result = paNoError;
+
+ if (!past) /* Test argument. */
+ {
+ ERR_RPT(("PaHost_StartEngine(NULL)!\n"));
+ return paBadStreamPtr;
+ }
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (!pahsc)
+ {
+ ERR_RPT(("PaHost_StartEngine(arg): arg->past_DeviceData == NULL!\n"));
+ return paHostError;
+ }
+ past->past_StopSoon = 0; /* Assume SGI ALport is already opened! */
+ past->past_StopNow = 0;
+ past->past_IsActive = 1;
+ DBUG(("PaHost_StartEngine() called.\n"));
+ /* Use pthread_create() instead of __clone() because: */
+ /* - pthread_create also works for other UNIX systems like Solaris, */
+ /* - Java HotSpot VM crashes in pthread_setcanceltype() when using __clone(). */
+ hres = pthread_create(&(pahsc->pahsc_ThreadPID), /* SPAWN AUDIO-CHILD. */
+ NULL, /* pthread_attr_t * attr */
+ (void*)Pa_SgiAudioProcess,
+ past);
+ if (hres)
+ {
+ result = paHostError;
+ sPaHostError = hres;
+ ERR_RPT(("PaHost_StartEngine() failed to spawn audio-thread.\n"));
+ }
+ return result;
+}
+
+/*------------------------------------------------------------------------------*/
+PaError PaHost_StopEngine(internalPortAudioStream *past, int abort)
+{
+ int hres;
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+
+ DBUG(("PaHost_StopEngine() called.\n"));
+ if (!past)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl*)past->past_DeviceData;
+ if (pahsc == NULL)
+ return result; /* paNoError (already stopped, no err?). */
+ past->past_StopSoon = 1; /* Tell background thread to stop generating */
+ if (abort) /* more and to let current data play out. If */
+ past->past_StopNow = 1; /* aborting, tell backgrnd thread to stop NOW! */
+ if (pahsc->pahsc_ThreadPID != -1) /* Join thread to recover memory resources. */
+ {
+ DBUG(("pthread_join() called.\n"));
+ hres = pthread_join(pahsc->pahsc_ThreadPID, NULL);
+ if (hres)
+ {
+ result = paHostError;
+ sPaHostError = hres;
+ ERR_RPT(("PaHost_StopEngine() failed pthread_join().\n"));
+ }
+ pahsc->pahsc_ThreadPID = -1;
+ }
+ past->past_IsActive = 0;
+ return result;
+}
+
+/*---------------------------------------------------------------*/
+PaError PaHost_StopOutput(internalPortAudioStream *past, int abort)
+{
+ return paNoError; /* Not implemented yet? */
+}
+PaError PaHost_StopInput(internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+/*******************************************************************/
+PaError PaHost_CloseStream(internalPortAudioStream *past)
+{
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+
+ DBUG(("PaHost_CloseStream() called.\n"));
+ if (past == NULL)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (pahsc == NULL) /* If pahsc not NULL, past_DeviceData will be freed, and set to NULL. */
+ return result; /* This test prevents from freeing NULL-pointers. */
+
+ if (pahsc->pahsc_ALportIN)
+ {
+ if (ALcloseport(pahsc->pahsc_ALportIN))
+ result = translateSGIerror(); /* Translates SGI AL-code to PA-code and ERR_RPTs string. */
+ else /* But go on anyway... to release other stuff... */
+ pahsc->pahsc_ALportIN = (ALport)0;
+ }
+ if (pahsc->pahsc_ALportOUT)
+ {
+ if (ALcloseport(pahsc->pahsc_ALportOUT))
+ result = translateSGIerror();
+ else
+ pahsc->pahsc_ALportOUT = (ALport)0;
+ }
+ if (pahsc->pahsc_NativeInputBuffer)
+ {
+ PaHost_FreeFastMemory(pahsc->pahsc_NativeInputBuffer, pahsc->pahsc_BytesPerInputBuffer);
+ pahsc->pahsc_NativeInputBuffer = NULL;
+ }
+ if (pahsc->pahsc_NativeOutputBuffer)
+ {
+ PaHost_FreeFastMemory(pahsc->pahsc_NativeOutputBuffer, pahsc->pahsc_BytesPerOutputBuffer);
+ pahsc->pahsc_NativeOutputBuffer = NULL;
+ }
+ PaHost_FreeFastMemory(pahsc, sizeof(PaHostSoundControl));
+ past->past_DeviceData = NULL; /* PaHost_OpenStream() allocated FAST. */
+ return result;
+}
+
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+** set PA_MIN_LATENCY_MSEC=200
+** in the AUTOEXEC.BAT file and reboot.
+** If the environment variable is not set, then the latency will be
+** determined based on the OS. Windows NT has higher latency than Win95.
+*/
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
+{
+ return 2;
+}
+/* Hmmm, the note above isn't appropriate for SGI I'm afraid... */
+/* Do we HAVE to do it this way under IRIX???.... */
+/*--------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------*/
+PaError PaHost_Term(void) /* Frees all of the linked audio-devices. */
+{ /* Called by Pa_Terminate() from pa_lib.c. */
+ internalPortAudioDevice *pad = sDeviceList,
+ *nxt;
+ while (pad)
+ {
+ DBUG(("PaHost_Term: freeing %s\n", pad->pad_DeviceName));
+ nxt = pad->pad_Next;
+ PaHost_FreeFastMemory(pad, sizeof(internalPortAudioDevice));
+ pad = nxt; /* PaHost_Init allocated this FAST MEM.*/
+ }
+ sDeviceList = (internalPortAudioDevice*)NULL;
+ return 0; /* Got rid of sNumDevices=0; */
+}
+
+/***********************************************************************/
+void Pa_Sleep( long msec ) /* Sleep requested number of milliseconds. */
+{
+#if 0
+ struct timeval timeout;
+ timeout.tv_sec = msec / 1000;
+ timeout.tv_usec = (msec % 1000) * 1000;
+ select(0, NULL, NULL, NULL, &timeout);
+#else
+ long usecs = msec * 1000;
+ usleep( usecs );
+#endif
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Allocate memory that can be accessed in real-time. This may need to be held in physi- */
+/* cal memory so that it is not paged to virtual memory. This call MUST be balanced with */
+/* a call to PaHost_FreeFastMemory(). */
+void *PaHost_AllocateFastMemory(long numBytes)
+{
+ void *addr = malloc(numBytes);
+ if (addr)
+ memset(addr, 0, numBytes);
+ return addr;
+}
+
+/*---------------------------------------------------------------------------------------*/
+/* Free memory that could be accessed in real-time. This call MUST be balanced with a */
+/* call to PaHost_AllocateFastMemory(). */
+void PaHost_FreeFastMemory(void *addr, long numBytes)
+{
+ if (addr)
+ free(addr);
+}
+
+/*----------------------------------------------------------*/
+PaError PaHost_StreamActive (internalPortAudioStream *past)
+{
+ PaHostSoundControl *pahsc;
+ if (past == NULL)
+ return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if (pahsc == NULL)
+ return paInternalError;
+ return (PaError)(past->past_IsActive != 0);
+}
+
+/*-------------------------------------------------------------------*/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+/* FIXME - return actual frames played, not frames generated.
+** Need to query the output device somehow.
+*/
+ return past->past_FrameCount;
+}
diff --git a/pd/portaudio/pa_tests/debug_convert.c b/pd/portaudio/pa_tests/debug_convert.c
new file mode 100644
index 00000000..8e9dc6d1
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_convert.c
@@ -0,0 +1,131 @@
+/*
+ * $Id: debug_convert.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Convert tagged values.
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+//#define OUTPUT_DEVICE (11)
+#define NUM_SECONDS (8)
+#define SLEEP_DUR (800)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+
+#define NUM_BUFFERS (0)
+
+typedef struct
+{
+ unsigned int framesToGo;
+}
+paTestData;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ short *out = (short*)outputBuffer;
+ int i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( data->framesToGo < framesPerBuffer ) finished = 1;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = 0x0000 + i; /* left */
+ *out++ = 0x1000 + i; /* right */
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalSamps;
+ printf("PortAudio Test: output debug values\n" );
+ data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ printf("totalSamps = %d\n", totalSamps );
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE );
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ 2, /* stereo output */
+ paInt16, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
+ paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Is callback being called?\n");
+ for( i=0; i<((NUM_SECONDS+1)*1000); i+=SLEEP_DUR )
+ {
+ printf("data.framesToGo = %d\n", data.framesToGo ); fflush(stdout);
+ Pa_Sleep( SLEEP_DUR );
+ }
+ /* Stop sound until ENTER hit. */
+ printf("Call Pa_StopStream()\n");
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_dither_calc.c b/pd/portaudio/pa_tests/debug_dither_calc.c
new file mode 100644
index 00000000..d751ca39
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_dither_calc.c
@@ -0,0 +1,55 @@
+/*
+ * $Id: debug_dither_calc.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Test Dither calculations.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#include "pa_host.h"
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ long max,min;
+ int i;
+
+ for( i=0; i<10000; i++ )
+ {
+ long dither = PaConvert_TriangularDither();
+ // printf("dither = 0x%08X\n", dither );
+ if( dither < min ) min = dither;
+ else if( dither > max ) max = dither;
+ }
+ printf("min = 0x%08X = %d, max = 0x%08X = %d\n", min, min, max, max );
+}
diff --git a/pd/portaudio/pa_tests/debug_dual.c b/pd/portaudio/pa_tests/debug_dual.c
new file mode 100644
index 00000000..b90ef290
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_dual.c
@@ -0,0 +1,183 @@
+/*
+ * $Id: debug_dual.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_dual.c
+ * Try to open TWO streams on separate cards.
+ * Play a sine sweep using the Portable Audio api for several seconds.
+ * Hacked test for debugging PA.
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define DEV_ID_1 (13)
+#define DEV_ID_2 (15)
+#define NUM_SECONDS (8)
+#define SLEEP_DUR (800)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+#if 0
+#define MIN_LATENCY_MSEC (200)
+#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
+#else
+#define NUM_BUFFERS (0)
+#endif
+#define MIN_FREQ (100.0f)
+#define MAX_FREQ (4000.0f)
+#define FREQ_SCALAR (1.00002f)
+#define CalcPhaseIncrement(freq) (freq/SAMPLE_RATE)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (400)
+typedef struct
+{
+ float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation
+ float phase_increment;
+ float left_phase;
+ float right_phase;
+}
+paTestData;
+/* Convert phase between and 1.0 to sine value
+ * using linear interpolation.
+ */
+float LookupSine( paTestData *data, float phase );
+float LookupSine( paTestData *data, float phase )
+{
+ float fIndex = phase*TABLE_SIZE;
+ int index = (int) fIndex;
+ float fract = fIndex - index;
+ float lo = data->sine[index];
+ float hi = data->sine[index+1];
+ float val = lo + fract*(hi-lo);
+ return val;
+}
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = LookupSine(data, data->left_phase); /* left */
+ *out++ = LookupSine(data, data->right_phase); /* right */
+ data->left_phase += data->phase_increment;
+ if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f;
+ data->right_phase += (data->phase_increment * 1.5f); /* fifth above */
+ if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f;
+ /* sweep frequency then start over. */
+ data->phase_increment *= FREQ_SCALAR;
+ if( data->phase_increment > CalcPhaseIncrement(MAX_FREQ) ) data->phase_increment = CalcPhaseIncrement(MIN_FREQ);
+ }
+ return 0;
+}
+
+PaError TestStart( PortAudioStream **streamPtr, PaDeviceID devID,
+ paTestData *data );
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream1, *stream2;
+ PaError err;
+ paTestData DATA1, DATA2;
+ printf("PortAudio Test: DUAL sine sweep. ask for %d buffers\n", NUM_BUFFERS );
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = TestStart( &stream1, DEV_ID_1, &DATA1 );
+ if( err != paNoError ) goto error;
+ err = TestStart( &stream2, DEV_ID_2, &DATA2 );
+ if( err != paNoError ) goto error;
+ printf("Hit ENTER\n");
+ getchar();
+ err = Pa_StopStream( stream1 );
+ if( err != paNoError ) goto error;
+ err = Pa_StopStream( stream2 );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
+PaError TestStart( PortAudioStream **streamPtr, PaDeviceID devID, paTestData *data )
+{
+ PortAudioStream *stream;
+ PaError err;
+ int i;
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data->sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data->sine[TABLE_SIZE] = data->sine[0]; // set guard point
+ data->left_phase = data->right_phase = 0.0;
+ data->phase_increment = CalcPhaseIncrement(MIN_FREQ);
+ printf("PortAudio Test: output device = %d\n", devID );
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ devID,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
+ paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ *streamPtr = stream;
+ return 0;
+error:
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_multi_in.c b/pd/portaudio/pa_tests/debug_multi_in.c
new file mode 100644
index 00000000..ef1d4a19
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_multi_in.c
@@ -0,0 +1,179 @@
+/*
+ * $Id: debug_multi_in.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_multi_in.c
+ * Pass output from each of multiple channels
+ * to a stereo output using the Portable Audio api.
+ * Hacked test for debugging PA.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include "portaudio.h"
+//#define INPUT_DEVICE_NAME ("EWS88 MT Interleaved Rec")
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+//#define OUTPUT_DEVICE (18)
+#define SAMPLE_RATE (22050)
+#define FRAMES_PER_BUFFER (256)
+#define MIN_LATENCY_MSEC (400)
+#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+typedef struct
+{
+ int liveChannel;
+ int numChannels;
+}
+paTestData;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ float *in = (float*)inputBuffer;
+ int i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( in == NULL ) return 0;
+ for( i=0; i<(int)framesPerBuffer; i++ )
+ {
+ /* Copy one channel of input to output. */
+ *out++ = in[data->liveChannel];
+ *out++ = in[data->liveChannel];
+ in += data->numChannels;
+ }
+ return 0;
+}
+/*******************************************************************/
+int PaFindDeviceByName( const char *name )
+{
+ int i;
+ int numDevices;
+ const PaDeviceInfo *pdi;
+ int len = strlen( name );
+ PaDeviceID result = paNoDevice;
+ numDevices = Pa_CountDevices();
+ for( i=0; i<numDevices; i++ )
+ {
+ pdi = Pa_GetDeviceInfo( i );
+ if( strncmp( name, pdi->name, len ) == 0 )
+ {
+ result = i;
+ break;
+ }
+ }
+ return result;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ PaDeviceID inputDevice;
+ const PaDeviceInfo *pdi;
+ printf("PortAudio Test: input signal from each channel. %d buffers\n", NUM_BUFFERS );
+ data.liveChannel = 0;
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+#ifdef INPUT_DEVICE_NAME
+ printf("Try to use device: %s\n", INPUT_DEVICE_NAME );
+ inputDevice = PaFindDeviceByName(INPUT_DEVICE_NAME);
+ if( inputDevice == paNoDevice )
+ {
+ printf("Could not find %s. Using default instead.\n", INPUT_DEVICE_NAME );
+ inputDevice = Pa_GetDefaultInputDeviceID();
+ }
+#else
+ printf("Using default input device.\n");
+ inputDevice = Pa_GetDefaultInputDeviceID();
+#endif
+ pdi = Pa_GetDeviceInfo( inputDevice );
+ if( pdi == NULL )
+ {
+ printf("Could not get device info!\n");
+ goto error;
+ }
+ data.numChannels = pdi->maxInputChannels;
+ printf("Input Device name is %s\n", pdi->name );
+ printf("Input Device has %d channels.\n", pdi->maxInputChannels);
+ err = Pa_OpenStream(
+ &stream,
+ inputDevice,
+ pdi->maxInputChannels,
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ 2,
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ data.liveChannel = 0;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ for( i=0; i<data.numChannels; i++ )
+ {
+ data.liveChannel = i;
+ printf("Channel %d being sent to output. Hit ENTER for next channel.", i );
+ fflush(stdout);
+ getchar();
+ }
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( stream );
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_multi_out.c b/pd/portaudio/pa_tests/debug_multi_out.c
new file mode 100644
index 00000000..6ff64ac6
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_multi_out.c
@@ -0,0 +1,144 @@
+/*
+ * $Id: debug_multi_out.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_multi_out.c
+ * Play a different sine wave on each channels,
+ * using the Portable Audio api.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+#define FREQ_INCR (300.0 / SAMPLE_RATE)
+#define MAX_CHANNELS (64)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+typedef struct
+{
+ int numChannels;
+ double phases[MAX_CHANNELS];
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int frameIndex, channelIndex;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
+ {
+ for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
+ {
+ /* Output sine wave on every channel. */
+ *out++ = (float) sin(data->phases[channelIndex]);
+
+ /* Play each channel at a higher frequency. */
+ data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
+ if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
+ }
+ }
+
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ const PaDeviceInfo *pdi;
+ paTestData data = {0};
+ printf("PortAudio Test: output sine wave on each channel.\n" );
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE );
+ data.numChannels = pdi->maxOutputChannels;
+ if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS;
+ printf("Number of Channels = %d\n", data.numChannels );
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice, /* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ data.numChannels,
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Hit ENTER to stop sound.\n");
+ fflush(stdout);
+ getchar();
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_CloseStream( stream );
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_record.c b/pd/portaudio/pa_tests/debug_record.c
new file mode 100644
index 00000000..f82ea58c
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_record.c
@@ -0,0 +1,339 @@
+/*
+ * $Id: debug_record.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_record.c
+ * Record input into an array.
+ * Save array to a file.
+ * Based on patest_record.c but with various ugly debug hacks thrown in.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include "portaudio.h"
+#define SAMPLE_RATE (22050)
+#define NUM_SECONDS (10)
+#define SLEEP_DUR_MSEC (200)
+#define FRAMES_PER_BUFFER (1<<10)
+#define NUM_REC_BUFS (0)
+
+#if 1
+#define PA_SAMPLE_TYPE paFloat32
+typedef float SAMPLE;
+#else
+#define PA_SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+#endif
+
+typedef struct
+{
+ long frameIndex; /* Index into sample array. */
+ long maxFrameIndex;
+ long samplesPerFrame;
+ long numSamples;
+ SAMPLE *recordedSamples;
+}
+paTestData;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int recordCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = (SAMPLE*)inputBuffer;
+ SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
+ long framesToCalc;
+ unsigned long i;
+ int finished;
+ unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
+
+ (void) outputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ framesToCalc = framesLeft;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ finished = 0;
+ }
+ if( inputBuffer == NULL )
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = 0; /* left */
+ *wptr++ = 0; /* right */
+ }
+ }
+ else
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ }
+ data->frameIndex += framesToCalc;
+ return finished;
+}
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int playCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
+ SAMPLE *wptr = (SAMPLE*)outputBuffer;
+ unsigned long i;
+ int finished;
+ unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;
+ if( outputBuffer == NULL ) return 0;
+ (void) inputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ /* final buffer... */
+ for( i=0; i<framesLeft; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = 0; /* left */
+ *wptr++ = 0; /* right */
+ }
+ data->frameIndex += framesLeft;
+ finished = 1;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ data->frameIndex += framesPerBuffer;
+ finished = 0;
+ }
+ return finished;
+}
+
+/****************************************************************/
+PaError TestRecording( paTestData *dataPtr )
+{
+ PortAudioStream *stream;
+ PaError err;
+ int i;
+
+ /* Record some audio. */
+ err = Pa_OpenStream(
+ &stream,
+ Pa_GetDefaultInputDeviceID(),
+ dataPtr->samplesPerFrame, /* stereo input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ paNoDevice,
+ 0,
+ PA_SAMPLE_TYPE,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ recordCallback,
+ dataPtr );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Now recording!\n"); fflush(stdout);
+ for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
+ {
+ if( Pa_StreamActive( stream ) <= 0)
+ {
+ printf("Stream inactive!\n");
+ break;
+ }
+ if( dataPtr->maxFrameIndex <= dataPtr->frameIndex )
+ {
+ printf("Buffer recording complete.\n");
+ break;
+ }
+ Pa_Sleep(100);
+ printf("index = %d\n", dataPtr->frameIndex ); fflush(stdout);
+ }
+
+ printf("Finished loop. Close stream.\n"); fflush(stdout);
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Done.\n"); fflush(stdout);
+ {
+ SAMPLE max = 0;
+ SAMPLE posVal;
+ int i;
+ for( i=0; i<dataPtr->numSamples; i++ )
+ {
+ posVal = dataPtr->recordedSamples[i];
+ if( posVal < 0 ) posVal = -posVal;
+ if( posVal > max ) max = posVal;
+ }
+ printf("Largest recorded sample = %d\n", max );
+ }
+ /* Write recorded data to a file. */
+#if 0
+ {
+ FILE *fid;
+ fid = fopen("recorded.raw", "wb");
+ if( fid == NULL )
+ {
+ printf("Could not open file.");
+ }
+ else
+ {
+ fwrite( dataPtr->recordedSamples, dataPtr->samplesPerFrame * sizeof(SAMPLE), totalFrames, fid );
+ fclose( fid );
+ printf("Wrote data to 'recorded.raw'\n");
+ }
+ }
+#endif
+
+error:
+ return err;
+}
+
+/****************************************************************/
+PaError TestPlayback( paTestData *dataPtr )
+{
+ PortAudioStream *stream;
+ PaError err;
+ int i;
+
+ /* Playback recorded data. */
+ dataPtr->frameIndex = 0;
+ printf("Begin playback.\n"); fflush(stdout);
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* NO input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ Pa_GetDefaultOutputDeviceID(),
+ dataPtr->samplesPerFrame, /* stereo output */
+ PA_SAMPLE_TYPE,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ playCallback,
+ dataPtr );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for playback to finish.\n"); fflush(stdout);
+ for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
+ {
+ Pa_Sleep(100);
+ printf("index = %d\n", dataPtr->frameIndex );
+ }
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+error:
+ return err;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ paTestData data;
+ long totalFrames;
+ long numBytes;
+ long i;
+ printf("patest_record.c\n"); fflush(stdout);
+
+ data.frameIndex = 0;
+ data.samplesPerFrame = 2;
+ data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE;
+
+ printf("totalFrames = %d\n", totalFrames ); fflush(stdout);
+ data.numSamples = totalFrames * data.samplesPerFrame;
+
+ numBytes = data.numSamples * sizeof(SAMPLE);
+ data.recordedSamples = (SAMPLE *) malloc( numBytes );
+ if( data.recordedSamples == NULL )
+ {
+ printf("Could not allocate record array.\n");
+ exit(1);
+ }
+ for( i=0; i<data.numSamples; i++ ) data.recordedSamples[i] = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ for( i=0; i<2; i++ )
+ {
+ err = TestRecording( &data );
+ if( err != paNoError ) goto error;
+
+ err = TestPlayback( &data );
+ if( err != paNoError ) goto error;
+ }
+
+ free( data.recordedSamples );
+ Pa_Terminate();
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ if( err == paHostError )
+ {
+ fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() );
+ }
+ return -1;
+}
diff --git a/pd/portaudio/pa_tests/debug_record_reuse.c b/pd/portaudio/pa_tests/debug_record_reuse.c
new file mode 100644
index 00000000..4f4fb53d
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_record_reuse.c
@@ -0,0 +1,351 @@
+/*
+ * $Id: debug_record_reuse.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_record_reuse.c
+ * Record input into an array.
+ * Save array to a file.
+ * Based on patest_record.c but with various ugly debug hacks thrown in.
+ * Loop twice and reuse same streams.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include "portaudio.h"
+#define SAMPLE_RATE (22050)
+#define NUM_SECONDS (4)
+#define SLEEP_DUR_MSEC (200)
+#define FRAMES_PER_BUFFER (256)
+#define NUM_REC_BUFS (0)
+
+#if 1
+#define PA_SAMPLE_TYPE paFloat32
+typedef float SAMPLE;
+#else
+#define PA_SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+#endif
+
+typedef struct
+{
+ long frameIndex; /* Index into sample array. */
+ long maxFrameIndex;
+ long samplesPerFrame;
+ long numSamples;
+ PortAudioStream *outputStream;
+ PortAudioStream *inputStream;
+ SAMPLE *recordedSamples;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int recordCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = (SAMPLE*)inputBuffer;
+ SAMPLE *wptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
+ long framesToCalc;
+ unsigned long i;
+ int finished;
+ unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
+
+ (void) outputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ framesToCalc = framesLeft;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ finished = 0;
+ }
+ if( inputBuffer == NULL )
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = 0; /* left */
+ *wptr++ = 0; /* right */
+ }
+ }
+ else
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ }
+ data->frameIndex += framesToCalc;
+ return finished;
+}
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int playCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = &data->recordedSamples[data->frameIndex * data->samplesPerFrame];
+ SAMPLE *wptr = (SAMPLE*)outputBuffer;
+ unsigned long i;
+ int finished;
+ unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;
+ if( outputBuffer == NULL ) return 0;
+ (void) inputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ /* final buffer... */
+ for( i=0; i<framesLeft; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = 0; /* left */
+ *wptr++ = 0; /* right */
+ }
+ data->frameIndex += framesLeft;
+ finished = 1;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ *wptr++ = *rptr++; /* right */
+ }
+ data->frameIndex += framesPerBuffer;
+ finished = 0;
+ }
+ return finished;
+}
+
+/****************************************************************/
+PaError TestRecording( paTestData *dataPtr )
+{
+ PaError err;
+ int i;
+ int lastIndex = 0;
+
+/* Open input stream if not already open. */
+ if( dataPtr->inputStream == NULL )
+ {
+ /* Record some audio. */
+ err = Pa_OpenStream(
+ &dataPtr->inputStream,
+ Pa_GetDefaultInputDeviceID(),
+ dataPtr->samplesPerFrame, /* stereo input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ paNoDevice,
+ 0,
+ PA_SAMPLE_TYPE,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ recordCallback,
+ dataPtr );
+ if( err != paNoError ) goto error;
+ }
+
+ dataPtr->frameIndex = 0;
+
+ err = Pa_StartStream( dataPtr->inputStream );
+ if( err != paNoError ) goto error;
+
+ printf("Now recording!\n"); fflush(stdout);
+ for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
+ {
+ int frameIndex, delta;
+ Pa_Sleep(SLEEP_DUR_MSEC);
+
+ frameIndex = dataPtr->frameIndex;
+ if( Pa_StreamActive( dataPtr->inputStream ) <= 0)
+ {
+ printf("Stream inactive!\n");
+ break;
+ }
+ if( dataPtr->maxFrameIndex <= frameIndex )
+ {
+ printf("Buffer recording complete.\n");
+ break;
+ }
+
+ delta = frameIndex - lastIndex;
+ lastIndex = frameIndex;
+ printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout);
+ }
+
+ err = Pa_StopStream( dataPtr->inputStream );
+ if( err != paNoError ) goto error;
+
+ printf("Done.\n"); fflush(stdout);
+
+error:
+ return err;
+}
+
+/****************************************************************/
+PaError TestPlayback( paTestData *dataPtr )
+{
+ PaError err;
+ int i;
+ int lastIndex = 0;
+
+ /* Playback recorded data. */
+ dataPtr->frameIndex = 0;
+ printf("Begin playback.\n"); fflush(stdout);
+
+/* Open output stream if not already open. */
+ if( dataPtr->outputStream == NULL )
+ {
+ err = Pa_OpenStream(
+ &dataPtr->outputStream,
+ paNoDevice,
+ 0, /* NO input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ Pa_GetDefaultOutputDeviceID(),
+ dataPtr->samplesPerFrame, /* stereo output */
+ PA_SAMPLE_TYPE,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ playCallback,
+ dataPtr );
+ if( err != paNoError ) goto error;
+ }
+
+ err = Pa_StartStream( dataPtr->outputStream );
+ if( err != paNoError ) goto error;
+
+ printf("Waiting for playback to finish.\n"); fflush(stdout);
+ for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
+ {
+ int frameIndex, delta;
+ Pa_Sleep(SLEEP_DUR_MSEC);
+ frameIndex = dataPtr->frameIndex;
+ delta = frameIndex - lastIndex;
+ lastIndex = frameIndex;
+ printf("index = %d, delta = %d\n", frameIndex, delta ); fflush(stdout);
+ }
+
+ err = Pa_StopStream( dataPtr->outputStream );
+ if( err != paNoError ) goto error;
+
+error:
+ return err;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ paTestData data = { 0 };
+ long totalFrames;
+ long numBytes;
+ long i;
+ printf("patest_record.c\n"); fflush(stdout);
+
+/* Set up test data structure and sample array. */
+ data.frameIndex = 0;
+ data.samplesPerFrame = 2;
+ data.maxFrameIndex = totalFrames = NUM_SECONDS*SAMPLE_RATE;
+
+ printf("totalFrames = %d\n", totalFrames ); fflush(stdout);
+ data.numSamples = totalFrames * data.samplesPerFrame;
+
+ numBytes = data.numSamples * sizeof(SAMPLE);
+ data.recordedSamples = (SAMPLE *) malloc( numBytes );
+ if( data.recordedSamples == NULL )
+ {
+ printf("Could not allocate record array.\n");
+ exit(1);
+ }
+ for( i=0; i<data.numSamples; i++ ) data.recordedSamples[i] = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+/* Record and playback multiple times. */
+ for( i=0; i<2; i++ )
+ {
+ err = TestRecording( &data );
+ if( err != paNoError ) goto error;
+
+ err = TestPlayback( &data );
+ if( err != paNoError ) goto error;
+ }
+
+/* Clean up. */
+ err = Pa_CloseStream( data.inputStream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( data.outputStream );
+ if( err != paNoError ) goto error;
+
+ if( err != paNoError ) goto error;
+
+ free( data.recordedSamples );
+ Pa_Terminate();
+
+ printf("Test complete.\n"); fflush(stdout);
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ if( err == paHostError )
+ {
+ fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() );
+ }
+ return -1;
+}
diff --git a/pd/portaudio/pa_tests/debug_sine.c b/pd/portaudio/pa_tests/debug_sine.c
new file mode 100644
index 00000000..93d74160
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_sine.c
@@ -0,0 +1,192 @@
+/*
+ * $Id: debug_sine.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_sine.c
+ * Play a sine sweep using the Portable Audio api for several seconds.
+ * Hacked test for debugging PA.
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+//#define OUTPUT_DEVICE (11)
+#define NUM_SECONDS (8)
+#define SLEEP_DUR (800)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+#if 0
+#define MIN_LATENCY_MSEC (200)
+#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
+#else
+#define NUM_BUFFERS (0)
+#endif
+#define MIN_FREQ (100.0f)
+#define MAX_FREQ (4000.0f)
+#define FREQ_SCALAR (1.00002f)
+#define CalcPhaseIncrement(freq) (freq/SAMPLE_RATE)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (400)
+typedef struct
+{
+ float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation
+ float phase_increment;
+ float left_phase;
+ float right_phase;
+ unsigned int framesToGo;
+}
+paTestData;
+/* Convert phase between and 1.0 to sine value
+ * using linear interpolation.
+ */
+float LookupSine( paTestData *data, float phase );
+float LookupSine( paTestData *data, float phase )
+{
+ float fIndex = phase*TABLE_SIZE;
+ int index = (int) fIndex;
+ float fract = fIndex - index;
+ float lo = data->sine[index];
+ float hi = data->sine[index+1];
+ float val = lo + fract*(hi-lo);
+ return val;
+}
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int framesToCalc;
+ int i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( data->framesToGo < framesPerBuffer )
+ {
+ framesToCalc = data->framesToGo;
+ data->framesToGo = 0;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ data->framesToGo -= framesPerBuffer;
+ }
+
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *out++ = LookupSine(data, data->left_phase); /* left */
+ *out++ = LookupSine(data, data->right_phase); /* right */
+ data->left_phase += data->phase_increment;
+ if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f;
+ data->right_phase += (data->phase_increment * 1.5f); /* fifth above */
+ if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f;
+ /* sweep frequency then start over. */
+ data->phase_increment *= FREQ_SCALAR;
+ if( data->phase_increment > CalcPhaseIncrement(MAX_FREQ) ) data->phase_increment = CalcPhaseIncrement(MIN_FREQ);
+ }
+ /* zero remainder of final buffer */
+ for( ; i<(int)framesPerBuffer; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalSamps;
+ printf("PortAudio Test: output sine sweep. ask for %d buffers\n", NUM_BUFFERS );
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.sine[TABLE_SIZE] = data.sine[0]; // set guard point
+ data.left_phase = data.right_phase = 0.0;
+ data.phase_increment = CalcPhaseIncrement(MIN_FREQ);
+ data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ printf("totalSamps = %d\n", totalSamps );
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE );
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
+ paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Is callback being called?\n");
+ for( i=0; i<((NUM_SECONDS+1)*1000); i+=SLEEP_DUR )
+ {
+ printf("data.framesToGo = %d\n", data.framesToGo ); fflush(stdout);
+ Pa_Sleep( SLEEP_DUR );
+ }
+ /* Stop sound until ENTER hit. */
+ printf("Call Pa_StopStream()\n");
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_sine_amp.c b/pd/portaudio/pa_tests/debug_sine_amp.c
new file mode 100644
index 00000000..b6b21865
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_sine_amp.c
@@ -0,0 +1,157 @@
+/*
+ * $Id: debug_sine_amp.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Play a different sine wave on each channels,
+ * using the Portable Audio api.
+ * Allos amplitude to be set interactively.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+#define FREQ_INCR (300.0 / SAMPLE_RATE)
+#define MAX_CHANNELS (64)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+typedef struct
+{
+ int numChannels;
+ double phases[MAX_CHANNELS];
+ float amplitude;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int frameIndex, channelIndex;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
+ {
+ for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
+ {
+ /* Output sine wave on every channel. */
+ *out++ = (float) ( data->amplitude * sin(data->phases[channelIndex]) );
+
+ /* Play each channel at a higher frequency. */
+ data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
+ if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
+ }
+ }
+
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ char pad[256];
+ PortAudioStream *stream;
+ PaError err;
+ const PaDeviceInfo *pdi;
+ paTestData data = {0};
+ printf("PortAudio Test: output sine wave on each channel.\n" );
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE );
+ data.numChannels = pdi->maxOutputChannels;
+ if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS;
+ printf("Number of Channels = %d\n", data.numChannels );
+ data.amplitude = 1.0;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice, /* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ data.numChannels,
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ do
+ {
+ printf("Current amplitude = %f\n", data.amplitude );
+ printf("Enter new amplitude or 'q' to quit.\n");
+ fflush(stdout);
+ gets( pad );
+ if( pad[0] != 'q' )
+ {
+ // I tried to use atof but it seems to be broken on Mac OS X 10.1
+ float amp;
+ sscanf( pad, "%f", &amp );
+ data.amplitude = amp;
+ }
+ } while( pad[0] != 'q' );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_CloseStream( stream );
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_sine_formats.c b/pd/portaudio/pa_tests/debug_sine_formats.c
new file mode 100644
index 00000000..3f75fa2e
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_sine_formats.c
@@ -0,0 +1,202 @@
+/*
+ * $Id: debug_sine_formats.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sine_formats.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ * Test various data formats.
+ *
+ * Author: Phil Burk
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (10)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+
+#define LEFT_FREQ (SAMPLE_RATE/512.0) /* So we hit 1.0 */
+#define RIGHT_FREQ (500.0)
+
+#define AMPLITUDE (1.0)
+
+/* Select ONE format for testing. */
+#define TEST_UINT8 (1)
+#define TEST_INT8 (0)
+#define TEST_INT16 (0)
+#define TEST_FLOAT32 (0)
+
+#if TEST_UINT8
+#define TEST_FORMAT paUInt8
+typedef unsigned char SAMPLE_t;
+#define SAMPLE_ZERO (0x80)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
+#define FORMAT_NAME "Unsigned 8 Bit"
+
+#elif TEST_INT8
+#define TEST_FORMAT paInt8
+typedef char SAMPLE_t;
+#define SAMPLE_ZERO (0)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
+#define FORMAT_NAME "Signed 8 Bit"
+
+#elif TEST_INT16
+#define TEST_FORMAT paInt16
+typedef short SAMPLE_t;
+#define SAMPLE_ZERO (0)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x)))
+#define FORMAT_NAME "Signed 16 Bit"
+
+#elif TEST_FLOAT32
+#define TEST_FORMAT paFloat32
+typedef float SAMPLE_t;
+#define SAMPLE_ZERO (0.0)
+#define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x))
+#define FORMAT_NAME "Float 32 Bit"
+#endif
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+
+typedef struct
+{
+ double left_phase;
+ double right_phase;
+ unsigned int framesToGo;
+}
+paTestData;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE_t *out = (SAMPLE_t *)outputBuffer;
+ SAMPLE_t sample;
+ int i;
+ int framesToCalc;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( data->framesToGo < framesPerBuffer )
+ {
+ framesToCalc = data->framesToGo;
+ data->framesToGo = 0;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ data->framesToGo -= framesPerBuffer;
+ }
+
+ for( i=0; i<framesToCalc; i++ )
+ {
+ data->left_phase += (LEFT_FREQ / SAMPLE_RATE);
+ if( data->left_phase > 1.0) data->left_phase -= 1.0;
+ sample = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. ))); /**/
+ *out++ = sample;
+/* *out++ = sample; /**/
+/* *out++ = 0; /**/
+
+ data->right_phase += (RIGHT_FREQ / SAMPLE_RATE);
+ if( data->right_phase > 1.0) data->right_phase -= 1.0;
+ *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. ))); /**/
+/* *out++ = 0; /* */
+ }
+ /* zero remainder of final buffer */
+ for( ; i<(int)framesPerBuffer; i++ )
+ {
+ *out++ = SAMPLE_ZERO; /* left */
+ *out++ = SAMPLE_ZERO; /* right */
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int totalSamps;
+
+ printf("PortAudio Test: output " FORMAT_NAME "\n");
+
+
+ data.left_phase = data.right_phase = 0.0;
+ data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ TEST_FORMAT,
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ TEST_FORMAT,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS );
+ while( Pa_StreamActive( stream ) ) Pa_Sleep(10);
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+
+ printf("PortAudio Test Finished: " FORMAT_NAME "\n");
+
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/debug_srate.c b/pd/portaudio/pa_tests/debug_srate.c
new file mode 100644
index 00000000..b3e3b70f
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_srate.c
@@ -0,0 +1,265 @@
+/*
+ * $Id: debug_srate.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * debug_record_reuse.c
+ * Record input into an array.
+ * Save array to a file.
+ * Based on patest_record.c but with various ugly debug hacks thrown in.
+ * Loop twice and reuse same streams.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include "portaudio.h"
+
+#define EWS88MT_12_REC (1)
+#define EWS88MT_12_PLAY (10)
+#define SBLIVE_REC (2)
+#define SBLIVE_PLAY (11)
+
+#if 0
+#define INPUT_DEVICE_ID Pa_GetDefaultInputDeviceID()
+#define OUTPUT_DEVICE_ID Pa_GetDefaultOutputDeviceID()
+#else
+#define INPUT_DEVICE_ID (EWS88MT_12_REC)
+#define OUTPUT_DEVICE_ID (SBLIVE_PLAY)
+#endif
+
+#define INPUT_SAMPLE_RATE (22050.0)
+#define OUTPUT_SAMPLE_RATE (22050.0)
+#define NUM_SECONDS (4)
+#define SLEEP_DUR_MSEC (1000)
+#define FRAMES_PER_BUFFER (64)
+#define NUM_REC_BUFS (0)
+#define SAMPLES_PER_FRAME (2)
+
+#define PA_SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+
+typedef struct
+{
+ long frameIndex; /* Index into sample array. */
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int recordCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData *) userData;
+ (void) outputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( inputBuffer != NULL )
+ {
+ data->frameIndex += framesPerBuffer;
+ }
+ return 0;
+}
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int playCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData *) userData;
+ (void) inputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( outputBuffer != NULL )
+ {
+ data->frameIndex += framesPerBuffer;
+ }
+ return 0;
+}
+
+/****************************************************************/
+PaError MeasureStreamRate( PortAudioStream *stream, paTestData *dataPtr, double *ratePtr )
+{
+ PaError err;
+ int i;
+ int totalFrames = 0;
+ int totalMSec = 0;
+
+ dataPtr->frameIndex = 0;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ for( i=0; i<(NUM_SECONDS*1000/SLEEP_DUR_MSEC); i++ )
+ {
+ int delta, endIndex;
+
+ int startIndex = dataPtr->frameIndex;
+ Pa_Sleep(SLEEP_DUR_MSEC);
+ endIndex = dataPtr->frameIndex;
+
+ delta = endIndex - startIndex;
+ totalFrames += delta;
+ totalMSec += SLEEP_DUR_MSEC;
+
+ printf("index = %d, delta = %d\n", endIndex, delta ); fflush(stdout);
+ }
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ *ratePtr = (totalFrames * 1000.0) / totalMSec;
+
+error:
+ return err;
+}
+
+void ReportRate( double measuredRate, double expectedRate )
+{
+ double error;
+
+ error = (measuredRate - expectedRate) / expectedRate;
+ error = (error < 0 ) ? -error : error;
+
+ printf("Measured rate = %6.1f, expected rate = %6.1f\n",
+ measuredRate, expectedRate );
+ if( error > 0.1 )
+ {
+ printf("ERROR: unexpected rate! --------------------- ERROR!\n");
+ }
+ else
+ {
+ printf("SUCCESS: rate within tolerance!\n");
+ }
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ paTestData data = { 0 };
+ long i;
+ double rate;
+ const PaDeviceInfo *pdi;
+
+ PortAudioStream *outputStream;
+ PortAudioStream *inputStream;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+
+ pdi = Pa_GetDeviceInfo( INPUT_DEVICE_ID );
+ printf("Input device = %s\n", pdi->name );
+ pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE_ID );
+ printf("Output device = %s\n", pdi->name );
+
+/* Open input stream. */
+ err = Pa_OpenStream(
+ &inputStream,
+ INPUT_DEVICE_ID,
+ SAMPLES_PER_FRAME, /* stereo input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ paNoDevice,
+ 0,
+ PA_SAMPLE_TYPE,
+ NULL,
+ INPUT_SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ NUM_REC_BUFS, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ recordCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &outputStream,
+ paNoDevice,
+ 0, /* NO input */
+ PA_SAMPLE_TYPE,
+ NULL,
+ OUTPUT_DEVICE_ID,
+ SAMPLES_PER_FRAME, /* stereo output */
+ PA_SAMPLE_TYPE,
+ NULL,
+ OUTPUT_SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ playCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+/* Record and playback multiple times. */
+ for( i=0; i<2; i++ )
+ {
+ printf("Measuring INPUT ------------------------- \n");
+ err = MeasureStreamRate( inputStream, &data, &rate );
+ if( err != paNoError ) goto error;
+ ReportRate( rate, INPUT_SAMPLE_RATE );
+
+ printf("Measuring OUTPUT ------------------------- \n");
+ err = MeasureStreamRate( outputStream, &data, &rate );
+ if( err != paNoError ) goto error;
+ ReportRate( rate, OUTPUT_SAMPLE_RATE );
+ }
+
+/* Clean up. */
+ err = Pa_CloseStream( inputStream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( outputStream );
+ if( err != paNoError ) goto error;
+
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+
+ printf("Test complete.\n"); fflush(stdout);
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ if( err == paHostError )
+ {
+ fprintf( stderr, "Host Error number: %d\n", Pa_GetHostError() );
+ }
+ return -1;
+}
diff --git a/pd/portaudio/pa_tests/debug_test1.c b/pd/portaudio/pa_tests/debug_test1.c
new file mode 100644
index 00000000..05370b00
--- /dev/null
+++ b/pd/portaudio/pa_tests/debug_test1.c
@@ -0,0 +1,114 @@
+/*
+ * $Id: debug_test1.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ patest1.c
+ Ring modulate the audio input with a 441hz sine wave for 20 seconds
+ using the Portable Audio api
+ Author: Ross Bencina <rossb@audiomulch.com>
+ Modifications:
+ April 5th, 2001 - PLB - Check for NULL inputBuffer.
+*/
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+typedef struct
+{
+ float sine[100];
+ int phase;
+ int sampsToGo;
+}
+patest1data;
+static int patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long bufferFrames,
+ PaTimestamp outTime, void *userData )
+{
+ patest1data *data = (patest1data*)userData;
+ float *in = (float*)inputBuffer;
+ float *out = (float*)outputBuffer;
+ int framesToCalc = bufferFrames;
+ unsigned long i;
+ int finished = 0;
+ if(inputBuffer == NULL) return 0;
+ if( data->sampsToGo < bufferFrames )
+ {
+ finished = 1;
+ }
+ for( i=0; i<bufferFrames; i++ )
+ {
+ *out++ = *in++;
+ *out++ = *in++;
+ if( data->phase >= 100 )
+ data->phase = 0;
+ }
+ data->sampsToGo -= bufferFrames;
+ /* zero remainder of final buffer if not already done */
+ for( ; i<bufferFrames; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+ return finished;
+}
+int main(int argc, char* argv[]);
+int main(int argc, char* argv[])
+{
+ PaStream *stream;
+ PaError err;
+ patest1data data;
+ int i;
+ int inputDevice = Pa_GetDefaultInputDeviceID();
+ int outputDevice = Pa_GetDefaultOutputDeviceID();
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<100; i++ )
+ data.sine[i] = sin( ((double)i/100.) * M_PI * 2. );
+ data.phase = 0;
+ data.sampsToGo = 44100 * 4; // 20 seconds
+ /* initialise portaudio subsytem */
+ Pa_Initialize();
+ err = Pa_OpenStream(
+ &stream,
+ inputDevice,
+ 2, /* stereo input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ outputDevice,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ 44100.,
+ // 22050, /* half second buffers */
+ // 4, /* four buffers */
+ 512, /* half second buffers */
+ 0, /* four buffers */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patest1Callback,
+ &data );
+ if( err == paNoError )
+ {
+ err = Pa_StartStream( stream );
+ // printf( "Press any key to end.\n" );
+ // getc( stdin ); //wait for input before exiting
+ // Pa_AbortStream( stream );
+
+ printf( "Waiting for stream to complete...\n" );
+
+ while( Pa_StreamActive( stream ) )
+ Pa_Sleep(1000); /* sleep until playback has finished */
+
+ err = Pa_CloseStream( stream );
+ }
+ else
+ {
+ fprintf( stderr, "An error occured while opening the portaudio stream\n" );
+ if( err == paHostError )
+ fprintf( stderr, "Host error number: %d\n", Pa_GetHostError() );
+ else
+ fprintf( stderr, "Error number: %d\n", err );
+ }
+ Pa_Terminate();
+ printf( "bye\n" );
+
+ return 0;
+}
diff --git a/pd/portaudio/pa_tests/pa_devs.c b/pd/portaudio/pa_tests/pa_devs.c
new file mode 100644
index 00000000..983699d1
--- /dev/null
+++ b/pd/portaudio/pa_tests/pa_devs.c
@@ -0,0 +1,199 @@
+/*
+ * $Id: pa_devs.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * pa_devs.c
+ * List available devices.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+/*******************************************************************/
+static void PrintSupportedStandardSampleRates(
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters )
+{
+ static double standardSampleRates[] = {
+ 8000.0, 9600.0, 11025.0, 12000.0, 16000.0, 22050.0, 24000.0, 32000.0,
+ 44100.0, 48000.0, 88200.0, 96000.0, -1 /* negative terminated list */
+ };
+ int i, printCount;
+ PaError err;
+
+ printCount = 0;
+ for( i=0; standardSampleRates[i] > 0; i++ )
+ {
+ err = Pa_IsFormatSupported( inputParameters, outputParameters, standardSampleRates[i] );
+ if( err == paFormatIsSupported )
+ {
+ if( printCount == 0 )
+ {
+ printf( "\t%8.2f", standardSampleRates[i] );
+ printCount = 1;
+ }
+ else if( printCount == 4 )
+ {
+ printf( ",\n\t%8.2f", standardSampleRates[i] );
+ printCount = 1;
+ }
+ else
+ {
+ printf( ", %8.2f", standardSampleRates[i] );
+ ++printCount;
+ }
+ }
+ }
+ if( !printCount )
+ printf( "None\n" );
+ else
+ printf( "\n" );
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i, numDevices, defaultDisplayed;
+ const PaDeviceInfo *deviceInfo;
+ PaStreamParameters inputParameters, outputParameters;
+ PaError err;
+
+
+ Pa_Initialize();
+
+ printf( "PortAudio version number = %d\nPortAudio version text = '%s'\n",
+ Pa_GetVersion(), Pa_GetVersionText() );
+
+
+ numDevices = Pa_CountDevices();
+ if( numDevices < 0 )
+ {
+ printf( "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
+ err = numDevices;
+ goto error;
+ }
+
+ printf( "Number of devices = %d\n", numDevices );
+ for( i=0; i<numDevices; i++ )
+ {
+ deviceInfo = Pa_GetDeviceInfo( i );
+ printf( "--------------------------------------- device #%d\n", i );
+
+ /* Mark global and API specific default devices */
+ defaultDisplayed = 0;
+ if( i == Pa_GetDefaultInputDevice() )
+ {
+ printf( "[ Default Input" );
+ defaultDisplayed = 1;
+ }
+ else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultInputDevice )
+ {
+ const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
+ printf( "[ Default %s Input", hostInfo->name );
+ defaultDisplayed = 1;
+ }
+
+ if( i == Pa_GetDefaultOutputDevice() )
+ {
+ printf( (defaultDisplayed ? "," : "[") );
+ printf( " Default Output" );
+ defaultDisplayed = 1;
+ }
+ else if( i == Pa_GetHostApiInfo( deviceInfo->hostApi )->defaultOutputDevice )
+ {
+ const PaHostApiInfo *hostInfo = Pa_GetHostApiInfo( deviceInfo->hostApi );
+ printf( (defaultDisplayed ? "," : "[") );
+ printf( " Default %s Output", hostInfo->name );
+ defaultDisplayed = 1;
+ }
+
+ if( defaultDisplayed )
+ printf( " ]\n" );
+
+ /* print device info fields */
+ printf( "Name = %s\n", deviceInfo->name );
+ printf( "Host API = %s\n", Pa_GetHostApiInfo( deviceInfo->hostApi )->name );
+ printf( "Max inputs = %d", deviceInfo->maxInputChannels );
+ printf( ", Max outputs = %d\n", deviceInfo->maxOutputChannels );
+
+ printf( "Default low input latency = %8.3f\n", deviceInfo->defaultLowInputLatency );
+ printf( "Default low output latency = %8.3f\n", deviceInfo->defaultLowOutputLatency );
+ printf( "Default high input latency = %8.3f\n", deviceInfo->defaultHighInputLatency );
+ printf( "Default high output latency = %8.3f\n", deviceInfo->defaultHighOutputLatency );
+
+ printf( "Default sample rate = %8.2f\n", deviceInfo->defaultSampleRate );
+
+ /* poll for standard sample rates */
+ inputParameters.device = i;
+ inputParameters.channelCount = deviceInfo->maxInputChannels;
+ inputParameters.sampleFormat = paInt16;
+ inputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+
+ outputParameters.device = i;
+ outputParameters.channelCount = deviceInfo->maxOutputChannels;
+ outputParameters.sampleFormat = paInt16;
+ outputParameters.suggestedLatency = 0; /* ignored by Pa_IsFormatSupported() */
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ if( inputParameters.channelCount > 0 )
+ {
+ printf("Supported standard sample rates\n for half-duplex 16 bit %d channel input = \n",
+ inputParameters.channelCount );
+ PrintSupportedStandardSampleRates( &inputParameters, NULL );
+ }
+
+ if( outputParameters.channelCount > 0 )
+ {
+ printf("Supported standard sample rates\n for half-duplex 16 bit %d channel output = \n",
+ outputParameters.channelCount );
+ PrintSupportedStandardSampleRates( NULL, &outputParameters );
+ }
+
+ if( inputParameters.channelCount > 0 && outputParameters.channelCount > 0 )
+ {
+ printf("Supported standard sample rates\n for full-duplex 16 bit %d channel input, %d channel output = \n",
+ inputParameters.channelCount, outputParameters.channelCount );
+ PrintSupportedStandardSampleRates( &inputParameters, &outputParameters );
+ }
+ }
+
+ Pa_Terminate();
+
+ printf("----------------------------------------------\n");
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/pa_fuzz.c b/pd/portaudio/pa_tests/pa_fuzz.c
new file mode 100644
index 00000000..1ec88785
--- /dev/null
+++ b/pd/portaudio/pa_tests/pa_fuzz.c
@@ -0,0 +1,168 @@
+/*
+ * $Id: pa_fuzz.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * pa_fuzz.c
+ * Distort input like a fuzz boz.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+/*
+** Note that many of the older ISA sound cards on PCs do NOT support
+** full duplex audio (simultaneous record and playback).
+** And some only support full duplex at lower sample rates.
+*/
+#define SAMPLE_RATE (44100)
+#define PA_SAMPLE_TYPE paFloat32
+#define FRAMES_PER_BUFFER (64)
+
+typedef float SAMPLE;
+
+float CubicAmplifier( float input );
+static int fuzzCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData );
+
+/* Non-linear amplifier with soft distortion curve. */
+float CubicAmplifier( float input )
+{
+ float output, temp;
+ if( input < 0.0 )
+ {
+ temp = input + 1.0f;
+ output = (temp * temp * temp) - 1.0f;
+ }
+ else
+ {
+ temp = input - 1.0f;
+ output = (temp * temp * temp) + 1.0f;
+ }
+
+ return output;
+}
+#define FUZZ(x) CubicAmplifier(CubicAmplifier(CubicAmplifier(CubicAmplifier(x))))
+
+static int gNumNoInputs = 0;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int fuzzCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData )
+{
+ SAMPLE *out = (SAMPLE*)outputBuffer;
+ SAMPLE *in = (SAMPLE*)inputBuffer;
+ unsigned int i;
+ (void) timeInfo; /* Prevent unused variable warnings. */
+ (void) statusFlags;
+ (void) userData;
+
+ if( inputBuffer == NULL )
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = 0; /* left - silent */
+ *out++ = 0; /* right - silent */
+ }
+ gNumNoInputs += 1;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = FUZZ(*in++); /* left - distorted */
+ *out++ = *in++; /* right - clean */
+ }
+ }
+
+ return paContinue;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStreamParameters inputParameters, outputParameters;
+ PaStream *stream;
+ PaError err;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+
+ inputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */
+ inputParameters.channelCount = 2; /* stereo input */
+ inputParameters.sampleFormat = PA_SAMPLE_TYPE;
+ inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
+ inputParameters.hostApiSpecificStreamInfo = NULL;
+
+ outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
+ outputParameters.channelCount = 2; /* stereo output */
+ outputParameters.sampleFormat = PA_SAMPLE_TYPE;
+ outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ err = Pa_OpenStream(
+ &stream,
+ &inputParameters,
+ &outputParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ 0, // paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ fuzzCallback,
+ NULL );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Hit ENTER to stop program.\n");
+ getchar();
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Finished. gNumNoInputs = %d\n", gNumNoInputs );
+ Pa_Terminate();
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
diff --git a/pd/portaudio/pa_tests/pa_minlat.c b/pd/portaudio/pa_tests/pa_minlat.c
new file mode 100644
index 00000000..736445a7
--- /dev/null
+++ b/pd/portaudio/pa_tests/pa_minlat.c
@@ -0,0 +1,176 @@
+/*
+ * $Id: pa_minlat.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * paminlat.c
+ * Experiment with different numbers of buffers to determine the
+ * minimum latency for a computer.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TWOPI (M_PI * 2.0)
+
+#define DEFAULT_BUFFER_SIZE (32)
+
+typedef struct
+{
+ double left_phase;
+ double right_phase;
+}
+paTestData;
+
+/* Very simple synthesis routine to generate two sine waves. */
+static int paminlatCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned int i;
+ double left_phaseInc = 0.02;
+ double right_phaseInc = 0.06;
+
+ double left_phase = data->left_phase;
+ double right_phase = data->right_phase;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ left_phase += left_phaseInc;
+ if( left_phase > TWOPI ) left_phase -= TWOPI;
+ *out++ = (float) sin( left_phase );
+
+ right_phase += right_phaseInc;
+ if( right_phase > TWOPI ) right_phase -= TWOPI;
+ *out++ = (float) sin( right_phase );
+ }
+
+ data->left_phase = left_phase;
+ data->right_phase = right_phase;
+ return 0;
+}
+void main( int argc, char **argv );
+void main( int argc, char **argv )
+{
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int go;
+ int outLatency = 0;
+ int minLatency = DEFAULT_BUFFER_SIZE * 2;
+ int framesPerBuffer;
+ double sampleRate = 44100.0;
+ char str[256];
+ printf("pa_minlat - Determine minimum latency for your computer.\n");
+ printf(" usage: pa_minlat {userBufferSize}\n");
+ printf(" for example: pa_minlat 64\n");
+ printf("Adjust your stereo until you hear a smooth tone in each speaker.\n");
+ printf("Then try to find the smallest number of frames that still sounds smooth.\n");
+ printf("Note that the sound will stop momentarily when you change the number of buffers.\n");
+
+ /* Get bufferSize from command line. */
+ framesPerBuffer = ( argc > 1 ) ? atol( argv[1] ) : DEFAULT_BUFFER_SIZE;
+ printf("Frames per buffer = %d\n", framesPerBuffer );
+
+ data.left_phase = data.right_phase = 0.0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ outLatency = sampleRate * 200.0 / 1000.0; // 200 msec
+
+ /* Try different numBuffers in a loop. */
+ go = 1;
+ while( go )
+ {
+
+ printf("Latency = %d frames = %6.1f msec.\n", outLatency,
+ (outLatency * 1000.0 / sampleRate) );
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ 0,
+ NULL,
+ Pa_GetDefaultOutputDevice(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ outLatency,
+ NULL,
+ sampleRate,
+ framesPerBuffer,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ paminlatCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ if( stream == NULL ) goto error;
+
+ /* Start audio. */
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ /* Ask user for a new nlatency. */
+ printf("\nMove windows around to see if the sound glitches.\n");
+ printf("Latency currently %d, enter new number, or 'q' to quit: ", outLatency );
+ gets( str );
+ if( str[0] == 'q' ) go = 0;
+ else
+ {
+ outLatency = atol( str );
+ if( outLatency < minLatency )
+ {
+ printf( "Latency below minimum of %d! Set to minimum!!!\n", minLatency );
+ outLatency = minLatency;
+ }
+ }
+ /* Stop sound until ENTER hit. */
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ }
+ printf("A good setting for latency would be somewhat higher than\n");
+ printf("the minimum latency that worked.\n");
+ printf("PortAudio: Test finished.\n");
+ Pa_Terminate();
+ return;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+}
diff --git a/pd/portaudio/pa_tests/paqa_devs.c b/pd/portaudio/pa_tests/paqa_devs.c
new file mode 100644
index 00000000..904a6082
--- /dev/null
+++ b/pd/portaudio/pa_tests/paqa_devs.c
@@ -0,0 +1,317 @@
+/*
+ * $Id: paqa_devs.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * paqa_devs.c
+ * Self Testing Quality Assurance app for PortAudio
+ * Try to open each device and run through all the
+ * possible configurations.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#include "pa_trace.h"
+/****************************************** Definitions ***********/
+#define MODE_INPUT (0)
+#define MODE_OUTPUT (1)
+typedef struct PaQaData
+{
+ unsigned long framesLeft;
+ int numChannels;
+ int bytesPerSample;
+ int mode;
+ short sawPhase;
+ PaSampleFormat format;
+}
+PaQaData;
+/****************************************** Prototypes ***********/
+static void TestDevices( int mode );
+static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate,
+ int numChannels );
+static int TestAdvance( int mode, PaDeviceID deviceID, double sampleRate,
+ int numChannels, PaSampleFormat format );
+static int QaCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+/****************************************** Globals ***********/
+static int gNumPassed = 0;
+static int gNumFailed = 0;
+/****************************************** Macros ***********/
+/* Print ERROR if it fails. Tally success or failure. */
+/* Odd do-while wrapper seems to be needed for some compilers. */
+#define EXPECT(_exp) \
+ do \
+ { \
+ if ((_exp)) {\
+ /* printf("SUCCESS for %s\n", #_exp ); */ \
+ gNumPassed++; \
+ } \
+ else { \
+ printf("ERROR - 0x%x - %s for %s\n", result, \
+ ((result == 0) ? "-" : Pa_GetErrorText(result)), \
+ #_exp ); \
+ gNumFailed++; \
+ goto error; \
+ } \
+ } while(0)
+/*******************************************************************/
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int QaCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ unsigned long i;
+ short phase;
+ PaQaData *data = (PaQaData *) userData;
+ (void) inputBuffer;
+ (void) outTime;
+
+ /* Play simle sawtooth wave. */
+ if( data->mode == MODE_OUTPUT )
+ {
+ phase = data->sawPhase;
+ switch( data->format )
+ {
+ case paFloat32:
+ {
+ float *out = (float *) outputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ phase += 0x123;
+ *out++ = (float) (phase * (1.0 / 32768.0));
+ if( data->numChannels == 2 )
+ {
+ *out++ = (float) (phase * (1.0 / 32768.0));
+ }
+ }
+ }
+ break;
+
+ case paInt32:
+ {
+ int *out = (int *) outputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ phase += 0x123;
+ *out++ = ((int) phase ) << 16;
+ if( data->numChannels == 2 )
+ {
+ *out++ = ((int) phase ) << 16;
+ }
+ }
+ }
+ break;
+ case paInt16:
+ {
+ short *out = (short *) outputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ phase += 0x123;
+ *out++ = phase;
+ if( data->numChannels == 2 )
+ {
+ *out++ = phase;
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ unsigned char *out = (unsigned char *) outputBuffer;
+ unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample;
+ for( i=0; i<numBytes; i++ )
+ {
+ *out++ = 0;
+ }
+ }
+ break;
+ }
+ data->sawPhase = phase;
+ }
+ /* Are we through yet? */
+ if( data->framesLeft > framesPerBuffer )
+ {
+ AddTraceMessage("QaCallback: running. framesLeft", data->framesLeft );
+ data->framesLeft -= framesPerBuffer;
+ return 0;
+ }
+ else
+ {
+ AddTraceMessage("QaCallback: DONE! framesLeft", data->framesLeft );
+ data->framesLeft = 0;
+ return 1;
+ }
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError result;
+ EXPECT( ((result=Pa_Initialize()) == 0) );
+ printf("Test OUTPUT ---------------\n");
+ TestDevices( MODE_OUTPUT );
+ printf("Test INPUT ---------------\n");
+ TestDevices( MODE_INPUT );
+error:
+ Pa_Terminate();
+ printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed );
+}
+/*******************************************************************
+* Try each output device, through its full range of capabilities. */
+static void TestDevices( int mode )
+{
+ int id,jc,kr;
+ int maxChannels;
+ const PaDeviceInfo *pdi;
+ int numDevices = Pa_CountDevices();
+ /* Iterate through all devices. */
+ for( id=0; id<numDevices; id++ )
+ {
+ pdi = Pa_GetDeviceInfo( id );
+ /* Try 1 to maxChannels on each device. */
+ maxChannels = ( mode == MODE_INPUT ) ? pdi->maxInputChannels : pdi->maxOutputChannels;
+ for( jc=1; jc<=maxChannels; jc++ )
+ {
+ printf("Name = %s\n", pdi->name );
+ /* Try each legal sample rate. */
+ if( pdi->numSampleRates == -1 )
+ {
+ double low, high;
+ low = pdi->sampleRates[0];
+ high = pdi->sampleRates[1];
+ if( low < 8000.0 ) low = 8000.0;
+ TestFormats( mode, id, low, jc );
+#define TESTSR(sr) {if(((sr)>=low) && ((sr)<=high)) TestFormats( mode, id, (sr), jc ); }
+
+ TESTSR(11025.0);
+ TESTSR(22050.0);
+ TESTSR(44100.0);
+ TestFormats( mode, id, high, jc );
+ }
+ else
+ {
+ for( kr=0; kr<pdi->numSampleRates; kr++ )
+ {
+ TestFormats( mode, id, pdi->sampleRates[kr], jc );
+ }
+ }
+ }
+ }
+}
+/*******************************************************************/
+static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate,
+ int numChannels )
+{
+ TestAdvance( mode, deviceID, sampleRate, numChannels, paFloat32 ); /* */
+ TestAdvance( mode, deviceID, sampleRate, numChannels, paInt16 ); /* */
+ TestAdvance( mode, deviceID, sampleRate, numChannels, paInt32 ); /* */
+ /* TestAdvance( mode, deviceID, sampleRate, numChannels, paInt24 ); */
+}
+/*******************************************************************/
+static int TestAdvance( int mode, PaDeviceID deviceID, double sampleRate,
+ int numChannels, PaSampleFormat format )
+{
+ PortAudioStream *stream = NULL;
+ PaError result;
+ PaQaData myData;
+#define FRAMES_PER_BUFFER (64)
+ printf("------ TestAdvance: %s, device = %d, rate = %g, numChannels = %d, format = %d -------\n",
+ ( mode == MODE_INPUT ) ? "INPUT" : "OUTPUT",
+ deviceID, sampleRate, numChannels, format);
+ /* Setup data for synthesis thread. */
+ myData.framesLeft = (unsigned long) (sampleRate * 100); /* 100 seconds */
+ myData.numChannels = numChannels;
+ myData.mode = mode;
+ myData.format = format;
+ switch( format )
+ {
+ case paFloat32:
+ case paInt32:
+ case paInt24:
+ myData.bytesPerSample = 4;
+ break;
+ case paPackedInt24:
+ myData.bytesPerSample = 3;
+ break;
+ default:
+ myData.bytesPerSample = 2;
+ break;
+ }
+ EXPECT( ((result = Pa_OpenStream(
+ &stream,
+ ( mode == MODE_INPUT ) ? deviceID : paNoDevice,
+ ( mode == MODE_INPUT ) ? numChannels : 0,
+ format,
+ NULL,
+ ( mode == MODE_OUTPUT ) ? deviceID : paNoDevice,
+ ( mode == MODE_OUTPUT ) ? numChannels : 0,
+ format,
+ NULL,
+ sampleRate,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ QaCallback,
+ &myData )
+ ) == 0) );
+ if( stream )
+ {
+ PaTimestamp oldStamp, newStamp;
+ unsigned long oldFrames;
+ int minDelay = ( mode == MODE_INPUT ) ? 1000 : 400;
+ int minNumBuffers = Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );
+ int msec = (int) ((minNumBuffers * 3 * 1000.0 * FRAMES_PER_BUFFER) / sampleRate);
+ if( msec < minDelay ) msec = minDelay;
+ printf("msec = %d\n", msec); /**/
+ EXPECT( ((result=Pa_StartStream( stream )) == 0) );
+ /* Check to make sure PortAudio is advancing timeStamp. */
+ result = paNoError;
+ oldStamp = Pa_StreamTime(stream);
+ Pa_Sleep(msec);
+ newStamp = Pa_StreamTime(stream);
+ printf("oldStamp = %g,newStamp = %g\n", oldStamp, newStamp ); /**/
+ EXPECT( (oldStamp < newStamp) );
+ /* Check to make sure callback is decrementing framesLeft. */
+ oldFrames = myData.framesLeft;
+ Pa_Sleep(msec);
+ printf("oldFrames = %d, myData.framesLeft = %d\n", oldFrames, myData.framesLeft ); /**/
+ EXPECT( (oldFrames > myData.framesLeft) );
+ EXPECT( ((result=Pa_CloseStream( stream )) == 0) );
+ stream = NULL;
+ }
+error:
+ if( stream != NULL ) Pa_CloseStream( stream );
+ return result;
+}
diff --git a/pd/portaudio/pa_tests/paqa_errs.c b/pd/portaudio/pa_tests/paqa_errs.c
new file mode 100644
index 00000000..d0738602
--- /dev/null
+++ b/pd/portaudio/pa_tests/paqa_errs.c
@@ -0,0 +1,330 @@
+/*
+ * $Id: paqa_errs.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * paqa_devs.c
+ * Self Testing Quality Assurance app for PortAudio
+ * Do lots of bad things to test error reporting.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+/****************************************** Definitions ***********/
+#define MODE_INPUT (0)
+#define MODE_OUTPUT (1)
+#define FRAMES_PER_BUFFER (64)
+#define SAMPLE_RATE (44100.0)
+#define NUM_BUFFERS (0)
+typedef struct PaQaData
+{
+ unsigned long framesLeft;
+ int numChannels;
+ int bytesPerSample;
+ int mode;
+}
+PaQaData;
+/****************************************** Prototypes ***********/
+static void TestDevices( int mode );
+static void TestFormats( int mode, PaDeviceID deviceID, double sampleRate,
+ int numChannels );
+static int TestBadOpens( void );
+static int TestBadActions( void );
+static int QaCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+/****************************************** Globals ***********/
+static int gNumPassed = 0;
+static int gNumFailed = 0;
+/****************************************** Macros ***********/
+/* Print ERROR if it fails. Tally success or failure. */
+/* Odd do-while wrapper seems to be needed for some compilers. */
+#define EXPECT(_exp) \
+ do \
+ { \
+ if ((_exp)) {\
+ gNumPassed++; \
+ } \
+ else { \
+ printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \
+ gNumFailed++; \
+ goto error; \
+ } \
+ } while(0)
+#define HOPEFOR(_exp) \
+ do \
+ { \
+ if ((_exp)) {\
+ gNumPassed++; \
+ } \
+ else { \
+ printf("\nERROR - 0x%x - %s for %s\n", result, Pa_GetErrorText(result), #_exp ); \
+ gNumFailed++; \
+ } \
+ } while(0)
+/*******************************************************************/
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int QaCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ unsigned long i;
+ unsigned char *out = (unsigned char *) outputBuffer;
+ PaQaData *data = (PaQaData *) userData;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+ (void) outTime;
+
+ /* Zero out buffer so we don't hear terrible noise. */
+ if( data->mode == MODE_OUTPUT )
+ {
+ unsigned long numBytes = framesPerBuffer * data->numChannels * data->bytesPerSample;
+ for( i=0; i<numBytes; i++ )
+ {
+ *out++ = 0;
+ }
+ }
+ /* Are we through yet? */
+ if( data->framesLeft > framesPerBuffer )
+ {
+ data->framesLeft -= framesPerBuffer;
+ return 0;
+ }
+ else
+ {
+ data->framesLeft = 0;
+ return 1;
+ }
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError result;
+ EXPECT( ((result=Pa_Initialize()) == 0) );
+ TestBadOpens();
+ TestBadActions();
+error:
+ Pa_Terminate();
+ printf("QA Report: %d passed, %d failed.\n", gNumPassed, gNumFailed );
+ return 0;
+}
+/*******************************************************************/
+static int TestBadOpens( void )
+{
+ PortAudioStream *stream = NULL;
+ PaError result;
+ PaQaData myData;
+ /* Setup data for synthesis thread. */
+ myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */
+ myData.numChannels = 1;
+ myData.mode = MODE_OUTPUT;
+ HOPEFOR( (/* No devices specified. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ paNoDevice, 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidDeviceId) );
+ HOPEFOR( ( /* Out of range input device specified. */
+ (result = Pa_OpenStream(
+ &stream,
+ Pa_CountDevices(), 0, paFloat32, NULL,
+ paNoDevice, 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidDeviceId) );
+
+ HOPEFOR( ( /* Out of range output device specified. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_CountDevices(), 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidDeviceId) );
+ HOPEFOR( ( /* Zero input channels. */
+ (result = Pa_OpenStream(
+ &stream,
+ Pa_GetDefaultInputDeviceID(), 0, paFloat32, NULL,
+ paNoDevice, 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidChannelCount) );
+ HOPEFOR( ( /* Zero output channels. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidChannelCount) );
+ HOPEFOR( ( /* Nonzero input channels but no device. */
+ (result = Pa_OpenStream(
+ &stream,
+ Pa_GetDefaultInputDeviceID(), 2, paFloat32, NULL,
+ paNoDevice, 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidChannelCount) );
+
+ HOPEFOR( ( /* Nonzero output channels but no device. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 2, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidChannelCount) );
+ HOPEFOR( ( /* NULL stream pointer. */
+ (result = Pa_OpenStream(
+ NULL,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paBadStreamPtr) );
+ HOPEFOR( ( /* Low sample rate. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ 1.0, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidSampleRate) );
+ HOPEFOR( ( /* High sample rate. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ 10000000.0, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidSampleRate) );
+ HOPEFOR( ( /* NULL callback. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ NULL,
+ &myData )
+ ) == paNullCallback) );
+ HOPEFOR( ( /* Bad flag. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ (1<<3),
+ QaCallback,
+ &myData )
+ ) == paInvalidFlag) );
+
+#if 0 /* FIXME - this is legal for some implementations. */
+ HOPEFOR( ( /* Use input device as output device. */
+ (result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultInputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidDeviceId) );
+
+ HOPEFOR( ( /* Use output device as input device. */
+ (result = Pa_OpenStream(
+ &stream,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ paNoDevice, 0, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == paInvalidDeviceId) );
+#endif
+
+ if( stream != NULL ) Pa_CloseStream( stream );
+ return result;
+}
+/*******************************************************************/
+static int TestBadActions( void )
+{
+ PortAudioStream *stream = NULL;
+ PaError result;
+ PaQaData myData;
+ /* Setup data for synthesis thread. */
+ myData.framesLeft = (unsigned long) (SAMPLE_RATE * 100); /* 100 seconds */
+ myData.numChannels = 1;
+ myData.mode = MODE_OUTPUT;
+ /* Default output. */
+ EXPECT( ((result = Pa_OpenStream(
+ &stream,
+ paNoDevice, 0, paFloat32, NULL,
+ Pa_GetDefaultOutputDeviceID(), 2, paFloat32, NULL,
+ SAMPLE_RATE, FRAMES_PER_BUFFER, NUM_BUFFERS,
+ paClipOff,
+ QaCallback,
+ &myData )
+ ) == 0) );
+ HOPEFOR( ((result = Pa_StartStream( NULL )) == paBadStreamPtr) );
+ HOPEFOR( ((result = Pa_StopStream( NULL )) == paBadStreamPtr) );
+ HOPEFOR( ((result = Pa_StreamActive( NULL )) == paBadStreamPtr) );
+ HOPEFOR( ((result = Pa_CloseStream( NULL )) == paBadStreamPtr) );
+ HOPEFOR( ((result = (PaError)Pa_StreamTime( NULL )) != 0) );
+ HOPEFOR( ((result = (PaError)Pa_GetCPULoad( NULL )) != 0) );
+error:
+ if( stream != NULL ) Pa_CloseStream( stream );
+ return result;
+}
diff --git a/pd/portaudio/pa_tests/patest1.c b/pd/portaudio/pa_tests/patest1.c
new file mode 100644
index 00000000..1f969436
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest1.c
@@ -0,0 +1,119 @@
+/*
+ $Id: patest1.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ patest1.c
+ Ring modulate the audio input with a sine wave for 20 seconds
+ using the Portable Audio api
+ Author: Ross Bencina <rossb@audiomulch.com>
+ Modifications:
+ April 5th, 2001 - PLB - Check for NULL inputBuffer.
+*/
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+typedef struct
+{
+ float sine[100];
+ int phase;
+ int sampsToGo;
+}
+patest1data;
+static int patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long bufferFrames,
+ PaTime outTime, void *userData )
+{
+ patest1data *data = (patest1data*)userData;
+ float *in = (float*)inputBuffer;
+ float *out = (float*)outputBuffer;
+ int framesToCalc = bufferFrames;
+ unsigned long i;
+ int finished = 0;
+ /* Check to see if any input data is available. */
+ if(inputBuffer == NULL) return 0;
+ if( data->sampsToGo < bufferFrames )
+ {
+ framesToCalc = data->sampsToGo;
+ finished = 1;
+ }
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *out++ = *in++ * data->sine[data->phase]; /* left */
+ *out++ = *in++ * data->sine[data->phase++]; /* right */
+ if( data->phase >= 100 )
+ data->phase = 0;
+ }
+ data->sampsToGo -= framesToCalc;
+ /* zero remainder of final buffer if not already done */
+ for( ; i<bufferFrames; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+ return finished;
+}
+int main(int argc, char* argv[]);
+int main(int argc, char* argv[])
+{
+ PaStream *stream;
+ PaError err;
+ patest1data data;
+ int i;
+ int inputDevice = Pa_GetDefaultInputDevice();
+ int outputDevice = Pa_GetDefaultOutputDevice();
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<100; i++ )
+ data.sine[i] = sin( ((double)i/100.) * M_PI * 2. );
+ data.phase = 0;
+ data.sampsToGo = 44100 * 20; // 20 seconds
+ /* initialise portaudio subsytem */
+ Pa_Initialize();
+ err = Pa_OpenStream(
+ &stream,
+ inputDevice,
+ 2, /* stereo input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ outputDevice,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ 44100.,
+ 512, /* small buffers */
+ 0, /* let PA determine number of buffers */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patest1Callback,
+ &data );
+ if( err == paNoError )
+ {
+ err = Pa_StartStream( stream );
+ printf( "Press any key to end.\n" );
+ getc( stdin ); //wait for input before exiting
+ Pa_AbortStream( stream );
+
+ printf( "Waiting for stream to complete...\n" );
+
+ while( Pa_IsStreamActive( stream ) )
+ Pa_Sleep(1000); /* sleep until playback has finished */
+
+ err = Pa_CloseStream( stream );
+ }
+ else
+ {
+ fprintf( stderr, "An error occured while opening the portaudio stream\n" );
+ if( err == paHostError )
+ {
+ fprintf( stderr, "Host error number: %d\n", Pa_GetHostError() );
+ }
+ else
+ {
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error text: %s\n", Pa_GetErrorText( err ) );
+ }
+ }
+ Pa_Terminate();
+ printf( "bye\n" );
+
+ return 0;
+}
diff --git a/pd/portaudio/pa_tests/patest_buffer.c b/pd/portaudio/pa_tests/patest_buffer.c
new file mode 100644
index 00000000..dbc55913
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_buffer.c
@@ -0,0 +1,181 @@
+/*
+ * $Id: patest_buffer.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_buffer.c
+ * Test opening streams with different buffer sizes.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (1)
+#define SAMPLE_RATE (44100)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+
+#define BUFFER_TABLE 9
+long buffer_table[] = {200,256,500,512,600, 723, 1000, 1024, 2345};
+
+typedef struct
+{
+ short sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+ unsigned int sampsToGo;
+}
+paTestData;
+PaError TestOnce( int buffersize );
+
+static int patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ short *out = (short*)outputBuffer;
+ unsigned int i;
+ int finished = 0;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+ (void) outTime;
+
+ if( data->sampsToGo < framesPerBuffer )
+ {
+ /* final buffer... */
+
+ for( i=0; i<data->sampsToGo; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ /* zero remainder of final buffer */
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+
+ finished = 1;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ data->sampsToGo -= framesPerBuffer;
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i;
+ PaError err;
+ printf("Test opening streams with different buffer sizes\n\n");
+
+ for (i = 0 ; i < BUFFER_TABLE; i++)
+ {
+ printf("Buffer size %d\n", buffer_table[i]);
+ err = TestOnce(buffer_table[i]);
+ if( err < 0 ) return 0;
+
+ }
+}
+
+
+PaError TestOnce( int buffersize )
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalSamps;
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (short) (32767.0 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ));
+ }
+ data.left_phase = data.right_phase = 0;
+ data.sampsToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paInt16, /* sample format */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paInt16, /* sample format */
+ NULL,
+ SAMPLE_RATE,
+ buffersize, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patest1Callback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for sound to finish.\n");
+ Pa_Sleep(1000);
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ return paNoError;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_clip.c b/pd/portaudio/pa_tests/patest_clip.c
new file mode 100644
index 00000000..c19bf3fe
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_clip.c
@@ -0,0 +1,156 @@
+/*
+ * $Id: patest_clip.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_clip.c
+ * Play a sine wave using the Portable Audio api for several seconds
+ * at an amplitude that would require clipping.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (4)
+#define SAMPLE_RATE (44100)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+typedef struct paTestData
+{
+ float sine[TABLE_SIZE];
+ float amplitude;
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+PaError PlaySine( paTestData *data, unsigned long flags, float amplitude );
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int sineCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ float amplitude = data->amplitude;
+ unsigned int i;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+ (void) outTime;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = amplitude * data->sine[data->left_phase]; /* left */
+ *out++ = amplitude * data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ paTestData DATA;
+ int i;
+ printf("PortAudio Test: output sine wave with and without clipping.\n");
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ DATA.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ printf("\nHalf amplitude. Should sound like sine wave.\n"); fflush(stdout);
+ err = PlaySine( &DATA, paClipOff | paDitherOff, 0.5f );
+ if( err < 0 ) goto error;
+ printf("\nFull amplitude. Should sound like sine wave.\n"); fflush(stdout);
+ err = PlaySine( &DATA, paClipOff | paDitherOff, 0.999f );
+ if( err < 0 ) goto error;
+ printf("\nOver range with clipping and dithering turned OFF. Should sound very nasty.\n");
+ fflush(stdout);
+ err = PlaySine( &DATA, paClipOff | paDitherOff, 1.1f );
+ if( err < 0 ) goto error;
+ printf("\nOver range with clipping and dithering turned ON. Should sound smoother than previous.\n");
+ fflush(stdout);
+ err = PlaySine( &DATA, paNoFlag, 1.1f );
+ if( err < 0 ) goto error;
+ printf("\nOver range with paClipOff but dithering ON.\n"
+ "That forces clipping ON so it should sound the same as previous.\n");
+ fflush(stdout);
+ err = PlaySine( &DATA, paClipOff, 1.1f );
+ if( err < 0 ) goto error;
+ return 0;
+error:
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return 1;
+}
+/*****************************************************************************/
+PaError PlaySine( paTestData *data, unsigned long flags, float amplitude )
+{
+ PortAudioStream *stream;
+ PaError err;
+ data->left_phase = data->right_phase = 0;
+ data->amplitude = amplitude;
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ 1024,
+ 0, /* number of buffers, if zero then use default minimum */
+ flags, /* we won't output out of range samples so don't bother clipping them */
+ sineCallback,
+ data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Sleep( NUM_SECONDS * 1000 );
+ printf("CPULoad = %8.6f\n", Pa_GetCPULoad( stream ) );
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ return paNoError;
+error:
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_dither.c b/pd/portaudio/pa_tests/patest_dither.c
new file mode 100644
index 00000000..2ab11e7b
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_dither.c
@@ -0,0 +1,152 @@
+/*
+ * $Id: patest_dither.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_dither.c
+ * Attempt to hear difference between dithered and non-dithered signal.
+ * This only has an effect if the native format is 16 bit.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (4)
+#define SAMPLE_RATE (44100)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+typedef struct paTestData
+{
+ float sine[TABLE_SIZE];
+ float amplitude;
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+PaError PlaySine( paTestData *data, PaStreamFlags flags, float amplitude );
+static int sineCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int sineCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ float amplitude = data->amplitude;
+ unsigned int i;
+ (void) outTime;
+ (void) inputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = amplitude * data->sine[data->left_phase]; /* left */
+ *out++ = amplitude * data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ paTestData DATA;
+ int i;
+ float amplitude = 32.0 / (1<<15);
+ printf("PortAudio Test: output EXTREMELY QUIET sine wave with and without dithering.\n");
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ DATA.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ printf("\nNo treatment..\n"); fflush(stdout);
+ err = PlaySine( &DATA, paClipOff | paDitherOff, amplitude );
+ if( err < 0 ) goto error;
+ printf("\nClip.\n");
+ fflush(stdout);
+ err = PlaySine( &DATA, paDitherOff, amplitude );
+ if( err < 0 ) goto error;
+ printf("\nClip and Dither.\n");
+ fflush(stdout);
+ err = PlaySine( &DATA, paNoFlag, amplitude );
+ if( err < 0 ) goto error;
+ return 0;
+error:
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
+/*****************************************************************************/
+PaError PlaySine( paTestData *data, PaStreamFlags flags, float amplitude )
+{
+ PortAudioStream *stream;
+ PaError err;
+ data->left_phase = data->right_phase = 0;
+ data->amplitude = amplitude;
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ 1024,
+ 0, /* number of buffers, if zero then use default minimum */
+ flags, /* we won't output out of range samples so don't bother clipping them */
+ sineCallback,
+ (void *)data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Sleep( NUM_SECONDS * 1000 );
+ printf("CPULoad = %8.6f\n", Pa_GetCPULoad( stream ) );
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ return paNoError;
+error:
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_hang.c b/pd/portaudio/pa_tests/patest_hang.c
new file mode 100644
index 00000000..b97727ba
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_hang.c
@@ -0,0 +1,151 @@
+/*
+ * $Id: patest_hang.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Play a sine then hang audio callback to test watchdog.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (1024)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TWOPI (M_PI * 2.0)
+
+typedef struct paTestData
+{
+ int sleepFor;
+ double phase;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+ int finished = 0;
+ double phaseInc = 0.02;
+ double phase = data->phase;
+
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ phase += phaseInc;
+ if( phase > TWOPI ) phase -= TWOPI;
+ /* This is not a very efficient way to calc sines. */
+ *out++ = (float) sin( phase ); /* mono */
+ }
+
+ if( data->sleepFor > 0 )
+ {
+ Pa_Sleep( data->sleepFor );
+ }
+
+ data->phase = phase;
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ int i;
+ paTestData data = {0};
+
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n",
+ SAMPLE_RATE, FRAMES_PER_BUFFER );
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 1, /* mono output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+/* Gradually increase sleep time. */
+ for( i=0; i<10000; i+= 1000 )
+ {
+ printf("Sleep for %d milliseconds in audio callback.\n", i );
+ data.sleepFor = i;
+ Pa_Sleep( ((i<1000) ? 1000 : i) );
+ }
+
+ printf("Suffer for 10 seconds.\n");
+ Pa_Sleep( 10000 );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_latency.c b/pd/portaudio/pa_tests/patest_latency.c
new file mode 100644
index 00000000..261a005c
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_latency.c
@@ -0,0 +1,176 @@
+/*
+ * $Id: patest_latency.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Hear the latency caused by big buffers.
+ * Play a sine wave and change frequency based on letter input.
+ *
+ * Author: Phil Burk <philburk@softsynth.com>, and Darren Gibbs
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDeviceID())
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (64)
+
+#if 0
+#define MIN_LATENCY_MSEC (2000)
+#define NUM_BUFFERS ((MIN_LATENCY_MSEC * SAMPLE_RATE) / (FRAMES_PER_BUFFER * 1000))
+#else
+#define NUM_BUFFERS (0)
+#endif
+
+#define MIN_FREQ (100.0f)
+#define CalcPhaseIncrement(freq) ((freq)/SAMPLE_RATE)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (400)
+typedef struct
+{
+ float sine[TABLE_SIZE + 1]; // add one for guard point for interpolation
+ float phase_increment;
+ float left_phase;
+ float right_phase;
+}
+paTestData;
+float LookupSine( paTestData *data, float phase );
+/* Convert phase between and 1.0 to sine value
+ * using linear interpolation.
+ */
+float LookupSine( paTestData *data, float phase )
+{
+ float fIndex = phase*TABLE_SIZE;
+ int index = (int) fIndex;
+ float fract = fIndex - index;
+ float lo = data->sine[index];
+ float hi = data->sine[index+1];
+ float val = lo + fract*(hi-lo);
+ return val;
+}
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = LookupSine(data, data->left_phase); /* left */
+ *out++ = LookupSine(data, data->right_phase); /* right */
+ data->left_phase += data->phase_increment;
+ if( data->left_phase >= 1.0f ) data->left_phase -= 1.0f;
+ data->right_phase += (data->phase_increment * 1.5f); /* fifth above */
+ if( data->right_phase >= 1.0f ) data->right_phase -= 1.0f;
+ }
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int done = 0;
+ printf("PortAudio Test: enter letter then hit ENTER. numBuffers = %d\n", NUM_BUFFERS );
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = 0.90f * (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.sine[TABLE_SIZE] = data.sine[0]; // set guard point
+ data.left_phase = data.right_phase = 0.0;
+ data.phase_increment = CalcPhaseIncrement(MIN_FREQ);
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ printf("PortAudio Test: output device = %d\n", OUTPUT_DEVICE );
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ OUTPUT_DEVICE,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ NUM_BUFFERS, /* number of buffers, if zero then use default minimum */
+ paClipOff|paDitherOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Play ASCII keyboard. Hit 'q' to stop. (Use RETURN key on Mac)\n");
+ fflush(stdout);
+ while ( !done )
+ {
+ float freq;
+ int index;
+ char c;
+ do
+ {
+ c = getchar();
+ }
+ while( c < ' '); /* Strip white space and control chars. */
+
+ if( c == 'q' ) done = 1;
+ index = c % 26;
+ freq = MIN_FREQ + (index * 40.0);
+ data.phase_increment = CalcPhaseIncrement(freq);
+ }
+ printf("Call Pa_StopStream()\n");
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_leftright.c b/pd/portaudio/pa_tests/patest_leftright.c
new file mode 100644
index 00000000..d23c8b2c
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_leftright.c
@@ -0,0 +1,168 @@
+/*
+ * $Id: patest_leftright.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_leftright.c
+ * Play different tone sine waves that alternate between left and right channel.
+ * The low tone should be on the left channel.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (8)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (512)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+ int toggle;
+ int countDown;
+}
+paTestData;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ if( data->toggle )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = 0; /* right */
+ }
+ else
+ {
+ *out++ = 0; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ }
+
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+
+ if( data->countDown < 0 )
+ {
+ data->countDown = SAMPLE_RATE;
+ data->toggle = !data->toggle;
+ }
+ data->countDown -= framesPerBuffer;
+
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int timeout;
+
+ printf("Play different tone sine waves that alternate between left and right channel.\n");
+ printf("The low tone should be on the left channel.\n");
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = data.toggle = 0;
+ data.countDown = SAMPLE_RATE;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Play for several seconds.\n");
+ timeout = NUM_SECONDS * 4;
+ while( timeout > 0 )
+ {
+ Pa_Sleep( 300 );
+ timeout -= 1;
+ }
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_longsine.c b/pd/portaudio/pa_tests/patest_longsine.c
new file mode 100644
index 00000000..cc48c44a
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_longsine.c
@@ -0,0 +1,137 @@
+/*
+ * $Id: patest_longsine.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_longsine.c
+ * Play a sine wave using the Portable Audio api until ENTER hit.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define SAMPLE_RATE (44100)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned int i;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ return 0;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ printf("PortAudio Test: output sine wave.\n");
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ 256, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Hit ENTER to stop program.\n");
+ getchar();
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+
+ printf("Test finished.\n");
+ return err;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_many.c b/pd/portaudio/pa_tests/patest_many.c
new file mode 100644
index 00000000..f42efb52
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_many.c
@@ -0,0 +1,194 @@
+/*
+ * $Id: patest_many.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_many.c
+ * Start and stop the PortAudio Driver multiple times.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (1)
+#define SAMPLE_RATE (44100)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+typedef struct
+{
+ short sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+ unsigned int sampsToGo;
+}
+paTestData;
+PaError TestOnce( void );
+static int patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patest1Callback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ short *out = (short*)outputBuffer;
+ unsigned int i;
+ int finished = 0;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+ (void) outTime;
+
+ if( data->sampsToGo < framesPerBuffer )
+ {
+ /* final buffer... */
+
+ for( i=0; i<data->sampsToGo; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ /* zero remainder of final buffer */
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+
+ finished = 1;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ data->sampsToGo -= framesPerBuffer;
+ }
+ return finished;
+}
+/*******************************************************************/
+#ifdef MACINTOSH
+int main(void);
+int main(void)
+{
+ int i;
+ PaError err;
+ int numLoops = 10;
+ printf("Loop %d times.\n", numLoops );
+ for( i=0; i<numLoops; i++ )
+ {
+ printf("Loop %d out of %d.\n", i+1, numLoops );
+ err = TestOnce();
+ if( err < 0 ) return 0;
+ }
+}
+#else
+int main(int argc, char **argv);
+int main(int argc, char **argv)
+{
+ PaError err;
+ int i, numLoops = 10;
+ if( argc > 1 )
+ {
+ numLoops = atoi(argv[1]);
+ }
+ for( i=0; i<numLoops; i++ )
+ {
+ printf("Loop %d out of %d.\n", i+1, numLoops );
+ err = TestOnce();
+ if( err < 0 ) return 1;
+ }
+ printf("Test complete.\n");
+ return 0;
+}
+#endif
+PaError TestOnce( void )
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalSamps;
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (short) (32767.0 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ));
+ }
+ data.left_phase = data.right_phase = 0;
+ data.sampsToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paInt16, /* sample format */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paInt16, /* sample format */
+ NULL,
+ SAMPLE_RATE,
+ 1024, /* frames per buffer */
+ 8, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patest1Callback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for sound to finish.\n");
+ Pa_Sleep(1000);
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ return paNoError;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_maxsines.c b/pd/portaudio/pa_tests/patest_maxsines.c
new file mode 100644
index 00000000..9fcd7ba8
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_maxsines.c
@@ -0,0 +1,197 @@
+/*
+ * $Id: patest_maxsines.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_maxsines.c
+ * How many sine waves can we calculate and play in less than 80% CPU Load.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define MAX_SINES (500)
+#define MAX_USAGE (0.8)
+#define SAMPLE_RATE (44100)
+#define FREQ_TO_PHASE_INC(freq) (freq/(float)SAMPLE_RATE)
+
+#define MIN_PHASE_INC FREQ_TO_PHASE_INC(200.0f)
+#define MAX_PHASE_INC (MIN_PHASE_INC * (1 << 5))
+
+#define FRAMES_PER_BUFFER (512)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TWOPI (M_PI * 2.0)
+
+#define TABLE_SIZE (512)
+
+typedef struct paTestData
+{
+ int numSines;
+ float sine[TABLE_SIZE + 1]; /* add one for guard point for interpolation */
+ float phases[MAX_SINES];
+}
+paTestData;
+
+/* Convert phase between and 1.0 to sine value
+ * using linear interpolation.
+ */
+float LookupSine( paTestData *data, float phase );
+float LookupSine( paTestData *data, float phase )
+{
+ float fIndex = phase*TABLE_SIZE;
+ int index = (int) fIndex;
+ float fract = fIndex - index;
+ float lo = data->sine[index];
+ float hi = data->sine[index+1];
+ float val = lo + fract*(hi-lo);
+ return val;
+}
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ float outSample;
+ float scaler;
+ int numForScale;
+ unsigned long i;
+ int j;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+/* Detemine amplitude scaling factor */
+ numForScale = data->numSines;
+ if( numForScale < 8 ) numForScale = 8; /* prevent pops at beginning */
+ scaler = 1.0f / numForScale;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ float output = 0.0;
+ float phaseInc = MIN_PHASE_INC;
+ float phase;
+ for( j=0; j<data->numSines; j++ )
+ {
+ /* Advance phase of next oscillator. */
+ phase = data->phases[j];
+ phase += phaseInc;
+ if( phase >= 1.0 ) phase -= 1.0;
+
+ output += LookupSine(data, phase);
+ data->phases[j] = phase;
+
+ phaseInc *= 1.02f;
+ if( phaseInc > MAX_PHASE_INC ) phaseInc = MIN_PHASE_INC;
+ }
+
+ outSample = (float) (output * scaler);
+ *out++ = outSample; /* Left */
+ *out++ = outSample; /* Right */
+ }
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i;
+ PaStream *stream;
+ PaError err;
+ paTestData data = {0};
+ double load;
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.sine[TABLE_SIZE] = data.sine[0]; /* set guard point */
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32,
+ 0, /* default latency */
+ NULL,
+ Pa_GetDefaultOutputDevice(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ 0, /* default latency */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+/* Play an increasing number of sine waves until we hit MAX_USAGE */
+ do
+ {
+ data.numSines++;
+ Pa_Sleep( 200 );
+
+ load = Pa_GetStreamCpuLoad( stream );
+ printf("numSines = %d, CPU load = %f\n", data.numSines, load );
+ fflush( stdout );
+ }
+ while( (load < MAX_USAGE) && (data.numSines < MAX_SINES) );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_multi_sine.c b/pd/portaudio/pa_tests/patest_multi_sine.c
new file mode 100644
index 00000000..2b78e932
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_multi_sine.c
@@ -0,0 +1,175 @@
+/*
+ * $Id: patest_multi_sine.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_multi_out.c
+ * Play a different sine wave on each channels,
+ * using the Portable Audio api.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDevice())
+//#define NON_INTERLEAVED
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (0) // take what we get(256)
+#define FREQ_INCR (300.0 / SAMPLE_RATE)
+#define MAX_CHANNELS (64)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+typedef struct
+{
+ int numChannels;
+ double phases[MAX_CHANNELS];
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ float **outputs = (float**)outputBuffer;
+
+#ifdef NON_INTERLEAVED
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int frameIndex, channelIndex;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
+ {
+ for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
+ {
+ /* Output sine wave on every channel. */
+ outputs[channelIndex][frameIndex] = (float) sin(data->phases[channelIndex]);
+
+ /* Play each channel at a higher frequency. */
+ data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
+ if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
+ }
+ }
+
+#else /* interleaved version */
+
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ int frameIndex, channelIndex;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( frameIndex=0; frameIndex<(int)framesPerBuffer; frameIndex++ )
+ {
+ for( channelIndex=0; channelIndex<data->numChannels; channelIndex++ )
+ {
+ /* Output sine wave on every channel. */
+ *out++ = (float) sin(data->phases[channelIndex]);
+
+ /* Play each channel at a higher frequency. */
+ data->phases[channelIndex] += FREQ_INCR * (4 + channelIndex);
+ if( data->phases[channelIndex] >= (2.0 * M_PI) ) data->phases[channelIndex] -= (2.0 * M_PI);
+ }
+ }
+#endif /* NON_INTERLEAVED */
+ return 0;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream *stream;
+ PaError err;
+ const PaDeviceInfo *pdi;
+ paTestData data = {0};
+ printf("PortAudio Test: output sine wave on each channel.\n" );
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ pdi = Pa_GetDeviceInfo( OUTPUT_DEVICE );
+ data.numChannels = pdi->maxOutputChannels;
+ if( data.numChannels > MAX_CHANNELS ) data.numChannels = MAX_CHANNELS;
+ printf("Number of Channels = %d\n", data.numChannels );
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice, /* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ 0, /* default input latency */
+ NULL,
+ OUTPUT_DEVICE,
+ data.numChannels,
+#ifdef NON_INTERLEAVED
+ paFloat32 | paNonInterleaved, /* 32 bit floating point output */
+#else
+ paFloat32,
+#endif
+ 0, /* default output latency */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Hit ENTER to stop sound.\n");
+ getchar();
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_CloseStream( stream );
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_pink.c b/pd/portaudio/pa_tests/patest_pink.c
new file mode 100644
index 00000000..7a3e29cd
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_pink.c
@@ -0,0 +1,245 @@
+/*
+ * $Id: patest_pink.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ patest_pink.c
+ Generate Pink Noise using Gardner method.
+ Optimization suggested by James McCartney uses a tree
+ to select which random value to replace.
+ x x x x x x x x x x x x x x x x
+ x x x x x x x x
+ x x x x
+ x x
+ x
+ Tree is generated by counting trailing zeros in an increasing index.
+ When the index is zero, no random number is selected.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define PINK_MAX_RANDOM_ROWS (30)
+#define PINK_RANDOM_BITS (24)
+#define PINK_RANDOM_SHIFT ((sizeof(long)*8)-PINK_RANDOM_BITS)
+typedef struct
+{
+ long pink_Rows[PINK_MAX_RANDOM_ROWS];
+ long pink_RunningSum; /* Used to optimize summing of generators. */
+ int pink_Index; /* Incremented each sample. */
+ int pink_IndexMask; /* Index wrapped by ANDing with this mask. */
+ float pink_Scalar; /* Used to scale within range of -1.0 to +1.0 */
+}
+PinkNoise;
+/* Prototypes */
+static unsigned long GenerateRandomNumber( void );
+void InitializePinkNoise( PinkNoise *pink, int numRows );
+float GeneratePinkNoise( PinkNoise *pink );
+/************************************************************/
+/* Calculate pseudo-random 32 bit number based on linear congruential method. */
+static unsigned long GenerateRandomNumber( void )
+{
+ /* Change this seed for different random sequences. */
+ static unsigned long randSeed = 22222;
+ randSeed = (randSeed * 196314165) + 907633515;
+ return randSeed;
+}
+/************************************************************/
+/* Setup PinkNoise structure for N rows of generators. */
+void InitializePinkNoise( PinkNoise *pink, int numRows )
+{
+ int i;
+ long pmax;
+ pink->pink_Index = 0;
+ pink->pink_IndexMask = (1<<numRows) - 1;
+ /* Calculate maximum possible signed random value. Extra 1 for white noise always added. */
+ pmax = (numRows + 1) * (1<<(PINK_RANDOM_BITS-1));
+ pink->pink_Scalar = 1.0f / pmax;
+ /* Initialize rows. */
+ for( i=0; i<numRows; i++ ) pink->pink_Rows[i] = 0;
+ pink->pink_RunningSum = 0;
+}
+#define PINK_MEASURE
+#ifdef PINK_MEASURE
+float pinkMax = -999.0;
+float pinkMin = 999.0;
+#endif
+/* Generate Pink noise values between -1.0 and +1.0 */
+float GeneratePinkNoise( PinkNoise *pink )
+{
+ long newRandom;
+ long sum;
+ float output;
+ /* Increment and mask index. */
+ pink->pink_Index = (pink->pink_Index + 1) & pink->pink_IndexMask;
+ /* If index is zero, don't update any random values. */
+ if( pink->pink_Index != 0 )
+ {
+ /* Determine how many trailing zeros in PinkIndex. */
+ /* This algorithm will hang if n==0 so test first. */
+ int numZeros = 0;
+ int n = pink->pink_Index;
+ while( (n & 1) == 0 )
+ {
+ n = n >> 1;
+ numZeros++;
+ }
+ /* Replace the indexed ROWS random value.
+ * Subtract and add back to RunningSum instead of adding all the random
+ * values together. Only one changes each time.
+ */
+ pink->pink_RunningSum -= pink->pink_Rows[numZeros];
+ newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
+ pink->pink_RunningSum += newRandom;
+ pink->pink_Rows[numZeros] = newRandom;
+ }
+
+ /* Add extra white noise value. */
+ newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT;
+ sum = pink->pink_RunningSum + newRandom;
+ /* Scale to range of -1.0 to 0.9999. */
+ output = pink->pink_Scalar * sum;
+#ifdef PINK_MEASURE
+ /* Check Min/Max */
+ if( output > pinkMax ) pinkMax = output;
+ else if( output < pinkMin ) pinkMin = output;
+#endif
+ return output;
+}
+/*******************************************************************/
+#define PINK_TEST
+#ifdef PINK_TEST
+/* Context for callback routine. */
+typedef struct
+{
+ PinkNoise leftPink;
+ PinkNoise rightPink;
+ unsigned int sampsToGo;
+}
+paTestData;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ int finished;
+ int i;
+ int numFrames;
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ (void) inputBuffer; /* Prevent "unused variable" warnings. */
+ (void) outTime;
+
+ /* Are we almost at end. */
+ if( data->sampsToGo < framesPerBuffer )
+ {
+ numFrames = data->sampsToGo;
+ finished = 1;
+ }
+ else
+ {
+ numFrames = framesPerBuffer;
+ finished = 0;
+ }
+ for( i=0; i<numFrames; i++ )
+ {
+ *out++ = GeneratePinkNoise( &data->leftPink );
+ *out++ = GeneratePinkNoise( &data->rightPink );
+ }
+ data->sampsToGo -= numFrames;
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int totalSamps;
+ /* Initialize two pink noise signals with different numbers of rows. */
+ InitializePinkNoise( &data.leftPink, 12 );
+ InitializePinkNoise( &data.rightPink, 16 );
+ /* Look at a few values. */
+ {
+ int i;
+ float pink;
+ for( i=0; i<20; i++ )
+ {
+ pink = GeneratePinkNoise( &data.leftPink );
+ printf("Pink = %f\n", pink );
+ }
+ }
+ data.sampsToGo = totalSamps = 8*44100; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ /* Open a stereo PortAudio stream so we can hear the result. */
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ 44100.,
+ 2048, /* 46 msec buffers */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for sound to finish.\n");
+ while( Pa_StreamActive( stream ) )
+ {
+ Pa_Sleep(100); /* SPIN! */
+ }
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+#ifdef PINK_MEASURE
+ printf("Pink min = %f, max = %f\n", pinkMin, pinkMax );
+#endif
+ Pa_Terminate();
+ return 0;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return 0;
+}
+#endif /* PINK_TEST */
diff --git a/pd/portaudio/pa_tests/patest_record.c b/pd/portaudio/pa_tests/patest_record.c
new file mode 100644
index 00000000..59471aaf
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_record.c
@@ -0,0 +1,327 @@
+/*
+ * $Id: patest_record.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_record.c
+ * Record input into an array.
+ * Save array to a file.
+ * Playback recorded data.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "portaudio.h"
+
+/* #define SAMPLE_RATE (17932) /* Test failure to open with this value. */
+#define SAMPLE_RATE (44100)
+#define NUM_SECONDS (5)
+#define NUM_CHANNELS (2)
+/* #define DITHER_FLAG (paDitherOff) /**/
+#define DITHER_FLAG (0) /**/
+
+/* Select sample format. */
+#if 1
+#define PA_SAMPLE_TYPE paFloat32
+typedef float SAMPLE;
+#define SAMPLE_SILENCE (0.0f)
+#elif 1
+#define PA_SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+#define SAMPLE_SILENCE (0)
+#elif 0
+#define PA_SAMPLE_TYPE paInt8
+typedef char SAMPLE;
+#define SAMPLE_SILENCE (0)
+#else
+#define PA_SAMPLE_TYPE paUInt8
+typedef unsigned char SAMPLE;
+#define SAMPLE_SILENCE (128)
+
+#endif
+
+typedef struct
+{
+ int frameIndex; /* Index into sample array. */
+ int maxFrameIndex;
+ SAMPLE *recordedSamples;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int recordCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = (SAMPLE*)inputBuffer;
+ SAMPLE *wptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
+ long framesToCalc;
+ long i;
+ int finished;
+ unsigned long framesLeft = data->maxFrameIndex - data->frameIndex;
+
+ (void) outputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ framesToCalc = framesLeft;
+ finished = paComplete;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ finished = paContinue;
+ }
+
+ if( inputBuffer == NULL )
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = SAMPLE_SILENCE; /* left */
+ if( NUM_CHANNELS == 2 ) *wptr++ = SAMPLE_SILENCE; /* right */
+ }
+ }
+ else
+ {
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
+ }
+ }
+ data->frameIndex += framesToCalc;
+ return finished;
+}
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int playCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE *rptr = &data->recordedSamples[data->frameIndex * NUM_CHANNELS];
+ SAMPLE *wptr = (SAMPLE*)outputBuffer;
+ unsigned int i;
+ int finished;
+ unsigned int framesLeft = data->maxFrameIndex - data->frameIndex;
+ (void) inputBuffer; /* Prevent unused variable warnings. */
+ (void) outTime;
+
+ if( framesLeft < framesPerBuffer )
+ {
+ /* final buffer... */
+ for( i=0; i<framesLeft; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
+ }
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = 0; /* left */
+ if( NUM_CHANNELS == 2 ) *wptr++ = 0; /* right */
+ }
+ data->frameIndex += framesLeft;
+ finished = paComplete;
+ }
+ else
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *wptr++ = *rptr++; /* left */
+ if( NUM_CHANNELS == 2 ) *wptr++ = *rptr++; /* right */
+ }
+ data->frameIndex += framesPerBuffer;
+ finished = paContinue;
+ }
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalFrames;
+ int numSamples;
+ int numBytes;
+ SAMPLE max, average, val;
+ printf("patest_record.c\n"); fflush(stdout);
+
+ data.maxFrameIndex = totalFrames = NUM_SECONDS * SAMPLE_RATE; /* Record for a few seconds. */
+ data.frameIndex = 0;
+ numSamples = totalFrames * NUM_CHANNELS;
+
+ numBytes = numSamples * sizeof(SAMPLE);
+ data.recordedSamples = (SAMPLE *) malloc( numBytes );
+ if( data.recordedSamples == NULL )
+ {
+ printf("Could not allocate record array.\n");
+ exit(1);
+ }
+ for( i=0; i<numSamples; i++ ) data.recordedSamples[i] = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ /* Record some audio. -------------------------------------------- */
+ err = Pa_OpenStream(
+ &stream,
+ Pa_GetDefaultInputDevice(),
+ NUM_CHANNELS, /* stereo input */
+ PA_SAMPLE_TYPE,
+ 0, /* default latency */
+ NULL,
+ paNoDevice,
+ 0,
+ PA_SAMPLE_TYPE,
+ 0, /* default latency */
+ NULL,
+ SAMPLE_RATE,
+ 1024, /* frames per buffer */
+ 0, //paDitherOff, /* flags */
+ recordCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Now recording!!\n"); fflush(stdout);
+
+ while( Pa_IsStreamActive( stream ) )
+ {
+ Pa_Sleep(1000);
+ printf("index = %d\n", data.frameIndex ); fflush(stdout);
+ }
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ /* Measure maximum peak amplitude. */
+ max = 0;
+ average = 0;
+ for( i=0; i<numSamples; i++ )
+ {
+ val = data.recordedSamples[i];
+ if( val < 0 ) val = -val; /* ABS */
+ if( val > max )
+ {
+ max = val;
+ }
+ average += val;
+ }
+
+ average = average / numSamples;
+
+ if( PA_SAMPLE_TYPE == paFloat32 )
+ {
+ printf("sample max amplitude = %f\n", max );
+ printf("sample average = %f\n", average );
+ }
+ else
+ {
+ printf("sample max amplitude = %d\n", max );
+ printf("sample average = %d\n", average );
+ }
+
+ /* Write recorded data to a file. */
+#if 0
+ {
+ FILE *fid;
+ fid = fopen("recorded.raw", "wb");
+ if( fid == NULL )
+ {
+ printf("Could not open file.");
+ }
+ else
+ {
+ fwrite( data.recordedSamples, NUM_CHANNELS * sizeof(SAMPLE), totalFrames, fid );
+ fclose( fid );
+ printf("Wrote data to 'recorded.raw'\n");
+ }
+ }
+#endif
+
+ /* Playback recorded data. -------------------------------------------- */
+ data.frameIndex = 0;
+ printf("Begin playback.\n"); fflush(stdout);
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,
+ 0, /* NO input */
+ PA_SAMPLE_TYPE,
+ 0, /* default latency */
+ NULL,
+ Pa_GetDefaultOutputDevice(),
+ NUM_CHANNELS, /* stereo output */
+ PA_SAMPLE_TYPE,
+ 0, /* default latency */
+ NULL,
+ SAMPLE_RATE,
+ 1024, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ playCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ if( stream )
+ {
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for playback to finish.\n"); fflush(stdout);
+
+ while( Pa_IsStreamActive( stream ) ) Pa_Sleep(100);
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Done.\n"); fflush(stdout);
+ }
+ free( data.recordedSamples );
+
+ Pa_Terminate();
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
diff --git a/pd/portaudio/pa_tests/patest_ringmix.c b/pd/portaudio/pa_tests/patest_ringmix.c
new file mode 100644
index 00000000..34c66381
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_ringmix.c
@@ -0,0 +1,41 @@
+/* $Id: patest_ringmix.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $ */
+
+#include "stdio.h"
+#include "portaudio.h"
+/* This will be called asynchronously by the PortAudio engine. */
+static int myCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer, PaTimestamp outTime, void *userData )
+{
+ float *out = (float *) outputBuffer;
+ float *in = (float *) inputBuffer;
+ float leftInput, rightInput;
+ unsigned int i;
+ if( inputBuffer == NULL ) return 0;
+ /* Read input buffer, process data, and fill output buffer. */
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ leftInput = *in++; /* Get interleaved samples from input buffer. */
+ rightInput = *in++;
+ *out++ = leftInput * rightInput; /* ring modulation */
+ *out++ = 0.5f * (leftInput + rightInput); /* mix */
+ }
+ return 0;
+}
+/* Open a PortAudioStream to input and output audio data. */
+int main(void)
+{
+ PortAudioStream *stream;
+ Pa_Initialize();
+ Pa_OpenDefaultStream(
+ &stream,
+ 2, 2, /* stereo input and output */
+ paFloat32, 44100.0,
+ 64, 0, /* 64 frames per buffer, let PA determine numBuffers */
+ myCallback, NULL );
+ Pa_StartStream( stream );
+ Pa_Sleep( 10000 ); /* Sleep for 10 seconds while processing. */
+ Pa_StopStream( stream );
+ Pa_CloseStream( stream );
+ Pa_Terminate();
+ return 0;
+}
diff --git a/pd/portaudio/pa_tests/patest_saw.c b/pd/portaudio/pa_tests/patest_saw.c
new file mode 100644
index 00000000..da1851ed
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_saw.c
@@ -0,0 +1,118 @@
+/*
+ * $Id: patest_saw.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_saw.c
+ * Play a simple sawtooth wave.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (4)
+#define SAMPLE_RATE (44100)
+typedef struct
+{
+ float left_phase;
+ float right_phase;
+}
+paTestData;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ /* Cast data passed through stream to our structure. */
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned int i;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->left_phase; /* left */
+ *out++ = data->right_phase; /* right */
+ /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
+ data->left_phase += 0.01f;
+ /* When signal reaches top, drop back down. */
+ if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
+ /* higher pitch so we can distinguish left and right. */
+ data->right_phase += 0.03f;
+ if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
+ }
+ return 0;
+}
+/*******************************************************************/
+static paTestData data;
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ printf("PortAudio Test: output sawtooth wave.\n");
+ /* Initialize our data for use by callback. */
+ data.left_phase = data.right_phase = 0.0;
+ /* Initialize library before making any other calls. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ /* Open an audio I/O stream. */
+ err = Pa_OpenDefaultStream(
+ &stream,
+ 0, /* no input channels */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ SAMPLE_RATE,
+ 256, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ /* Sleep for several seconds. */
+ Pa_Sleep(NUM_SECONDS*1000);
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_sine.c b/pd/portaudio/pa_tests/patest_sine.c
new file mode 100644
index 00000000..1bebb90e
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_sine.c
@@ -0,0 +1,152 @@
+/*
+ * $Id: patest_sine.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sine.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (5)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (64)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+
+ (void) timeInfo; /* Prevent unused variable warnings. */
+ (void) statusFlags;
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+
+ return paContinue;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStreamParameters outputParameters;
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+
+
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
+ outputParameters.channelCount = 2; /* stereo output */
+ outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
+ outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ err = Pa_OpenStream(
+ &stream,
+ NULL, /* no input */
+ &outputParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Play for %d seconds.\n", NUM_SECONDS );
+ Pa_Sleep( NUM_SECONDS * 1000 );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+ printf("Test finished.\n");
+
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_sine8.c b/pd/portaudio/pa_tests/patest_sine8.c
new file mode 100644
index 00000000..f3ef9ebb
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_sine8.c
@@ -0,0 +1,184 @@
+/*
+ * $Id: patest_sine8.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sine8.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ * Test 8 bit data.
+ *
+ * Author: Ross Bencina <rossb@audiomulch.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define NUM_SECONDS (8)
+#define SAMPLE_RATE (44100)
+#define TEST_UNSIGNED (1)
+#if TEST_UNSIGNED
+#define TEST_FORMAT paUInt8
+#else
+#define TEST_FORMAT paInt8
+#endif
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (200)
+typedef struct
+{
+#if TEST_UNSIGNED
+ unsigned char sine[TABLE_SIZE];
+#else
+ char sine[TABLE_SIZE];
+#endif
+ int left_phase;
+ int right_phase;
+ unsigned int framesToGo;
+}
+paTestData;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ char *out = (char*)outputBuffer;
+ int i;
+ int framesToCalc;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( data->framesToGo < framesPerBuffer )
+ {
+ framesToCalc = data->framesToGo;
+ data->framesToGo = 0;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ data->framesToGo -= framesPerBuffer;
+ }
+
+ for( i=0; i<framesToCalc; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+ /* zero remainder of final buffer */
+ for( ; i<(int)framesPerBuffer; i++ )
+ {
+#if TEST_UNSIGNED
+ *out++ = (unsigned char) 0x80; /* left */
+ *out++ = (unsigned char) 0x80; /* right */
+#else
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+#endif
+
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ int totalSamps;
+#if TEST_UNSIGNED
+ printf("PortAudio Test: output UNsigned 8 bit sine wave.\n");
+#else
+ printf("PortAudio Test: output signed 8 bit sine wave.\n");
+#endif
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (char) (127.0 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. ));
+#if TEST_UNSIGNED
+ data.sine[i] += (unsigned char) 0x80;
+#endif
+
+ }
+ data.left_phase = data.right_phase = 0;
+ data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ TEST_FORMAT,
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ TEST_FORMAT,
+ NULL,
+ SAMPLE_RATE,
+ 256, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ /* Watch until sound is halfway finished. */
+ while( Pa_StreamTime( stream ) < (totalSamps/2) ) Pa_Sleep(10);
+ /* Stop sound until ENTER hit. */
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Pause for 2 seconds.\n");
+ Pa_Sleep( 2000 );
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Waiting for sound to finish.\n");
+ while( Pa_StreamActive( stream ) ) Pa_Sleep(10);
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_sine_formats.c b/pd/portaudio/pa_tests/patest_sine_formats.c
new file mode 100644
index 00000000..74e12022
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_sine_formats.c
@@ -0,0 +1,196 @@
+/*
+ * $Id: patest_sine_formats.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sine_formats.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ * Test various data formats.
+ *
+ * Author: Phil Burk
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (10)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (512)
+#define LEFT_FREQ (SAMPLE_RATE/256.0) /* So we hit 1.0 */
+#define RIGHT_FREQ (500.0)
+#define AMPLITUDE (1.0)
+
+/* Select ONE format for testing. */
+#define TEST_UINT8 (0)
+#define TEST_INT8 (0)
+#define TEST_INT16 (1)
+#define TEST_FLOAT32 (0)
+
+#if TEST_UINT8
+#define TEST_FORMAT paUInt8
+typedef unsigned char SAMPLE_t;
+#define SAMPLE_ZERO (0x80)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
+#define FORMAT_NAME "Unsigned 8 Bit"
+
+#elif TEST_INT8
+#define TEST_FORMAT paInt8
+typedef char SAMPLE_t;
+#define SAMPLE_ZERO (0)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(127.0 * (x)))
+#define FORMAT_NAME "Signed 8 Bit"
+
+#elif TEST_INT16
+#define TEST_FORMAT paInt16
+typedef short SAMPLE_t;
+#define SAMPLE_ZERO (0)
+#define DOUBLE_TO_SAMPLE(x) (SAMPLE_ZERO + (SAMPLE_t)(32767 * (x)))
+#define FORMAT_NAME "Signed 16 Bit"
+
+#elif TEST_FLOAT32
+#define TEST_FORMAT paFloat32
+typedef float SAMPLE_t;
+#define SAMPLE_ZERO (0.0)
+#define DOUBLE_TO_SAMPLE(x) ((SAMPLE_t)(x))
+#define FORMAT_NAME "Float 32 Bit"
+#endif
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+
+typedef struct
+{
+ double left_phase;
+ double right_phase;
+ unsigned int framesToGo;
+}
+paTestData;
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ SAMPLE_t *out = (SAMPLE_t *)outputBuffer;
+ int i;
+ int framesToCalc;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ if( data->framesToGo < framesPerBuffer )
+ {
+ framesToCalc = data->framesToGo;
+ data->framesToGo = 0;
+ finished = 1;
+ }
+ else
+ {
+ framesToCalc = framesPerBuffer;
+ data->framesToGo -= framesPerBuffer;
+ }
+
+ for( i=0; i<framesToCalc; i++ )
+ {
+ data->left_phase += (LEFT_FREQ / SAMPLE_RATE);
+ if( data->left_phase > 1.0) data->left_phase -= 1.0;
+ *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->left_phase * M_PI * 2. )));
+
+ data->right_phase += (RIGHT_FREQ / SAMPLE_RATE);
+ if( data->right_phase > 1.0) data->right_phase -= 1.0;
+ *out++ = DOUBLE_TO_SAMPLE( AMPLITUDE * sin( (data->right_phase * M_PI * 2. )));
+ }
+ /* zero remainder of final buffer */
+ for( ; i<(int)framesPerBuffer; i++ )
+ {
+ *out++ = SAMPLE_ZERO; /* left */
+ *out++ = SAMPLE_ZERO; /* right */
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int totalSamps;
+
+ printf("PortAudio Test: output " FORMAT_NAME "\n");
+
+
+ data.left_phase = data.right_phase = 0.0;
+ data.framesToGo = totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ TEST_FORMAT,
+ 0, /* default latency */
+ NULL,
+ Pa_GetDefaultOutputDevice(), /* default output device */
+ 2, /* stereo output */
+ TEST_FORMAT,
+ 0, /* default latency */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Waiting %d seconds for sound to finish.\n", NUM_SECONDS );
+ while( Pa_IsStreamActive( stream ) ) Pa_Sleep(10);
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+
+ printf("PortAudio Test Finished: " FORMAT_NAME "\n");
+
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_sine_time.c b/pd/portaudio/pa_tests/patest_sine_time.c
new file mode 100644
index 00000000..c849af0a
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_sine_time.c
@@ -0,0 +1,194 @@
+/*
+ * $Id: patest_sine_time.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sine_time.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ * Pausing in the middle.
+ * use the Pa_GetStreamTime() and Pa_IsStreamActive() calls.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#include "pa_util.h"
+#define NUM_SECONDS (8)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (64)
+#define NUM_BUFFERS (0)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TWOPI (M_PI * 2.0)
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ double left_phase;
+ double right_phase;
+ volatile PaTimestamp outTime;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned int i;
+
+ double left_phaseInc = 0.02;
+ double right_phaseInc = 0.06;
+
+ double left_phase = data->left_phase;
+ double right_phase = data->right_phase;
+
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+ data->outTime = outTime;\
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ left_phase += left_phaseInc;
+ if( left_phase > TWOPI ) left_phase -= TWOPI;
+ *out++ = (float) sin( left_phase );
+
+ right_phase += right_phaseInc;
+ if( right_phase > TWOPI ) right_phase -= TWOPI;
+ *out++ = (float) sin( right_phase );
+ }
+
+ data->left_phase = left_phase;
+ data->right_phase = right_phase;
+
+ return paContinue;
+}
+/*******************************************************************/
+static void ReportStreamTime( PaStream *stream, paTestData *data );
+static void ReportStreamTime( PaStream *stream, paTestData *data )
+{
+ PaTimestamp streamTime, latency, outTime;
+
+ streamTime = Pa_GetStreamTime( stream );
+ outTime = data->outTime;
+ if( outTime < 0.0 )
+ {
+ printf("Stream time = %8.1f\n", streamTime );
+ }
+ else
+ {
+ latency = outTime - streamTime;
+ printf("Stream time = %8.1f, outTime = %8.1f, latency = %8.1f\n",
+ streamTime, outTime, latency );
+ }
+ fflush(stdout);
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream *stream;
+ PaError err;
+ paTestData DATA;
+ int totalSamps;
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+ DATA.left_phase = DATA.right_phase = 0;
+ totalSamps = NUM_SECONDS * SAMPLE_RATE; /* Play for a few seconds. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ 0, /* default latency */
+ NULL,
+ Pa_GetDefaultOutputDevice(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ 0, /* default latency */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &DATA );
+ if( err != paNoError ) goto error;
+
+ /* Watch until sound is halfway finished. */
+ printf("Play for %d seconds.\n", NUM_SECONDS/2 ); fflush(stdout);
+
+ DATA.outTime = -1.0; // mark time for callback as undefined
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+ do
+ {
+ ReportStreamTime( stream, &DATA );
+ Pa_Sleep(100);
+ } while( Pa_GetStreamTime( stream ) < (totalSamps/2) );
+
+ /* Stop sound until ENTER hit. */
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+ printf("Pause for 2 seconds.\n"); fflush(stdout);
+ Pa_Sleep( 2000 );
+
+ DATA.outTime = -1.0; // mark time for callback as undefined
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Play until sound is finished.\n"); fflush(stdout);
+ do
+ {
+ ReportStreamTime( stream, &DATA );
+ Pa_Sleep(100);
+ } while( Pa_GetStreamTime( stream ) < (totalSamps/2) );
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_start_stop.c b/pd/portaudio/pa_tests/patest_start_stop.c
new file mode 100644
index 00000000..0e183708
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_start_stop.c
@@ -0,0 +1,160 @@
+/*
+ * $Id: patest_start_stop.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_start_stop.c
+ * Play a sine wave using the Portable Audio api for several seconds.
+ * Start and stop the stream multiple times.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (3)
+#define NUM_LOOPS (4)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (400)
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo* timeInfo,
+ PaStreamCallbackFlags statusFlags,
+ void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+
+ (void) timeInfo; /* Prevent unused variable warnings. */
+ (void) statusFlags;
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+
+ return paContinue;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStreamParameters outputParameters;
+ PaStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+
+
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = 0;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
+ outputParameters.channelCount = 2; /* stereo output */
+ outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
+ outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ err = Pa_OpenStream(
+ &stream,
+ NULL, /* no input */
+ &outputParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+
+ for( i=0; i<NUM_LOOPS; i++ )
+ {
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Play for %d seconds.\n", NUM_SECONDS );
+ Pa_Sleep( NUM_SECONDS * 1000 );
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Stopped.\n" );
+ Pa_Sleep( 1000 );
+ }
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+ printf("Test finished.\n");
+
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_stop.c b/pd/portaudio/pa_tests/patest_stop.c
new file mode 100644
index 00000000..54e72ff7
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_stop.c
@@ -0,0 +1,288 @@
+/*
+ * $Id: patest_stop.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_stop.c
+ *
+ * Test the three ways of stopping audio:
+ * calling Pa_StopStream(),
+ * calling Pa_AbortStream(),
+ * and returning a 1 from the callback function.
+ *
+ * A long latency is set up so that you can hear the difference.
+ * Then a simple 8 note sequence is repeated twice.
+ * The program will print what you should hear.
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDevice())
+#define SLEEP_DUR (200)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (256)
+#define LATENCY_MSEC (3000)
+#define FRAMES_PER_NOTE (SAMPLE_RATE/2)
+#define MAX_REPEATS (2)
+#define FUNDAMENTAL (400.0f / SAMPLE_RATE)
+#define NOTE_0 (FUNDAMENTAL * 1.0f / 1.0f)
+#define NOTE_1 (FUNDAMENTAL * 5.0f / 4.0f)
+#define NOTE_2 (FUNDAMENTAL * 4.0f / 3.0f)
+#define NOTE_3 (FUNDAMENTAL * 3.0f / 2.0f)
+#define NOTE_4 (FUNDAMENTAL * 2.0f / 1.0f)
+#define MODE_FINISH (0)
+#define MODE_STOP (1)
+#define MODE_ABORT (2)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TABLE_SIZE (400)
+typedef struct
+{
+ float waveform[TABLE_SIZE + 1]; // add one for guard point for interpolation
+ float phase_increment;
+ float phase;
+ float *tune;
+ int notesPerTune;
+ int frameCounter;
+ int noteCounter;
+ int repeatCounter;
+ PaTimestamp outTime;
+ int stopMode;
+ int done;
+}
+paTestData;
+/************* Prototypes *****************************/
+int TestStopMode( paTestData *data );
+float LookupWaveform( paTestData *data, float phase );
+/******************************************************
+ * Convert phase between 0.0 and 1.0 to waveform value
+ * using linear interpolation.
+ */
+float LookupWaveform( paTestData *data, float phase )
+{
+ float fIndex = phase*TABLE_SIZE;
+ int index = (int) fIndex;
+ float fract = fIndex - index;
+ float lo = data->waveform[index];
+ float hi = data->waveform[index+1];
+ float val = lo + fract*(hi-lo);
+ return val;
+}
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ float value;
+ unsigned int i = 0;
+ int finished = paContinue;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ data->outTime = outTime;
+ if( !data->done )
+ {
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ /* Are we done with this note? */
+ if( data->frameCounter >= FRAMES_PER_NOTE )
+ {
+ data->noteCounter += 1;
+ data->frameCounter = 0;
+ /* Are we done with this tune? */
+ if( data->noteCounter >= data->notesPerTune )
+ {
+ data->noteCounter = 0;
+ data->repeatCounter += 1;
+ /* Are we totally done? */
+ if( data->repeatCounter >= MAX_REPEATS )
+ {
+ data->done = 1;
+ if( data->stopMode == MODE_FINISH )
+ {
+ finished = paComplete;
+ break;
+ }
+ }
+ }
+ data->phase_increment = data->tune[data->noteCounter];
+ }
+ value = LookupWaveform(data, data->phase);
+ *out++ = value; /* left */
+ *out++ = value; /* right */
+ data->phase += data->phase_increment;
+ if( data->phase >= 1.0f ) data->phase -= 1.0f;
+
+ data->frameCounter += 1;
+ }
+ }
+ /* zero remainder of final buffer */
+ for( ; i<framesPerBuffer; i++ )
+ {
+ *out++ = 0; /* left */
+ *out++ = 0; /* right */
+ }
+ return finished;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ paTestData DATA;
+ int i;
+ float simpleTune[] = { NOTE_0, NOTE_1, NOTE_2, NOTE_3, NOTE_4, NOTE_3, NOTE_2, NOTE_1 };
+ printf("PortAudio Test: play song and test stopping. ask for %d latency\n", LATENCY_MSEC );
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ DATA.waveform[i] = (float) (
+ (0.2 * sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. )) +
+ (0.2 * sin( ((double)(3*i)/(double)TABLE_SIZE) * M_PI * 2. )) +
+ (0.1 * sin( ((double)(5*i)/(double)TABLE_SIZE) * M_PI * 2. ))
+ );
+ }
+ DATA.waveform[TABLE_SIZE] = DATA.waveform[0]; // set guard point
+ DATA.tune = &simpleTune[0];
+ DATA.notesPerTune = sizeof(simpleTune) / sizeof(float);
+ printf("Test MODE_FINISH - callback returns 1.\n");
+ printf("Should hear entire %d note tune repeated twice.\n", DATA.notesPerTune);
+ DATA.stopMode = MODE_FINISH;
+ if( TestStopMode( &DATA ) != paNoError )
+ {
+ printf("Test of MODE_FINISH failed!\n");
+ goto error;
+ }
+ printf("Test MODE_STOP - stop when song is done.\n");
+ printf("Should hear entire %d note tune repeated twice.\n", DATA.notesPerTune);
+ DATA.stopMode = MODE_STOP;
+ if( TestStopMode( &DATA ) != paNoError )
+ {
+ printf("Test of MODE_STOP failed!\n");
+ goto error;
+ }
+
+ printf("Test MODE_ABORT - abort immediately.\n");
+ printf("Should hear last repetition cut short by %d msec.\n", LATENCY_MSEC);
+ DATA.stopMode = MODE_ABORT;
+ if( TestStopMode( &DATA ) != paNoError )
+ {
+ printf("Test of MODE_ABORT failed!\n");
+ goto error;
+ }
+ return 0;
+error:
+ return 1;
+}
+
+int TestStopMode( paTestData *data )
+{
+ PaStream *stream;
+ PaError err;
+ data->done = 0;
+ data->phase = 0.0;
+ data->frameCounter = 0;
+ data->noteCounter = 0;
+ data->repeatCounter = 0;
+ data->phase_increment = data->tune[data->noteCounter];
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ 0,
+ NULL,
+ OUTPUT_DEVICE,
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ LATENCY_MSEC,
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ if( data->stopMode == MODE_FINISH )
+ {
+ while( Pa_IsStreamActive( stream ) )
+ {
+ /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime,
+ data->noteCounter, data->repeatCounter );
+ fflush(stdout); /**/
+ Pa_Sleep( SLEEP_DUR );
+ }
+ }
+ else
+ {
+ while( data->repeatCounter < MAX_REPEATS )
+ {
+ /*printf("outTime = %g, note# = %d, repeat# = %d\n", data->outTime,
+ data->noteCounter, data->repeatCounter );
+ fflush(stdout); /**/
+ Pa_Sleep( SLEEP_DUR );
+ }
+ }
+
+ if( data->stopMode == MODE_ABORT )
+ {
+ printf("Call Pa_AbortStream()\n");
+ err = Pa_AbortStream( stream );
+ }
+ else
+ {
+ printf("Call Pa_StopStream()\n");
+ err = Pa_StopStream( stream );
+ }
+ if( err != paNoError ) goto error;
+
+ printf("Call Pa_CloseStream()\n"); fflush(stdout);
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_sync.c b/pd/portaudio/pa_tests/patest_sync.c
new file mode 100644
index 00000000..46854eb6
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_sync.c
@@ -0,0 +1,257 @@
+/*
+ * $Id: patest_sync.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * patest_sync.c
+ * Test time stamping and synchronization of audio and video.
+ * A high latency is used so we can hear the difference in time.
+ * Random durations are used so we know we are hearing the right beep
+ * and not the one before or after.
+ *
+ * Sequence of events:
+ * Foreground requests a beep.
+ * Background randomly schedules a beep.
+ * Foreground waits for the beep to be heard based on PaUtil_GetTime().
+ * Foreground outputs video (printf) in sync with audio.
+ * Repeat.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+#include "pa_util.h"
+#define NUM_BEEPS (6)
+#define SAMPLE_RATE (44100)
+#define SAMPLE_PERIOD (1.0/44100.0)
+#define FRAMES_PER_BUFFER (256)
+#define BEEP_DURATION (400)
+#define LATENCY_MSEC (2000)
+#define SLEEP_MSEC (10)
+#define TIMEOUT_MSEC (15000)
+
+#define STATE_BKG_IDLE (0)
+#define STATE_BKG_PENDING (1)
+#define STATE_BKG_BEEPING (2)
+typedef struct
+{
+ float left_phase;
+ float right_phase;
+ int state;
+ int requestBeep; /* Set by foreground, cleared by background. */
+ PaTime beepTime;
+ int beepCount;
+ double latency; /* For debugging. */
+}
+paTestData;
+
+static unsigned long GenerateRandomNumber( void );
+/************************************************************/
+/* Calculate pseudo-random 32 bit number based on linear congruential method. */
+static unsigned long GenerateRandomNumber( void )
+{
+ static unsigned long randSeed = 99887766; /* Change this for different random sequences. */
+ randSeed = (randSeed * 196314165) + 907633515;
+ return randSeed;
+}
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ const PaStreamCallbackTimeInfo *timeInfo,
+ PaStreamCallbackFlags statusFlags, void *userData )
+{
+ /* Cast data passed through stream to our structure. */
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned int i;
+ (void) inputBuffer;
+
+ data->latency = timeInfo->outputBufferDacTime - timeInfo->currentTime;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ switch( data->state )
+ {
+ case STATE_BKG_IDLE:
+ /* Schedule beep at some random time in the future. */
+ if( data->requestBeep )
+ {
+ int random = GenerateRandomNumber() >> 14;
+ data->beepTime = timeInfo->outputBufferDacTime + (( (double)(random + SAMPLE_RATE)) * SAMPLE_PERIOD );
+ data->state = STATE_BKG_PENDING;
+ }
+ *out++ = 0.0; /* left */
+ *out++ = 0.0; /* right */
+ break;
+
+ case STATE_BKG_PENDING:
+ if( (timeInfo->outputBufferDacTime + (i*SAMPLE_PERIOD)) >= data->beepTime )
+ {
+ data->state = STATE_BKG_BEEPING;
+ data->beepCount = BEEP_DURATION;
+ data->left_phase = data->right_phase = 0.0;
+ }
+ *out++ = 0.0; /* left */
+ *out++ = 0.0; /* right */
+ break;
+
+ case STATE_BKG_BEEPING:
+ if( data->beepCount <= 0 )
+ {
+ data->state = STATE_BKG_IDLE;
+ data->requestBeep = 0;
+ *out++ = 0.0; /* left */
+ *out++ = 0.0; /* right */
+ }
+ else
+ {
+ /* Play sawtooth wave. */
+ *out++ = data->left_phase; /* left */
+ *out++ = data->right_phase; /* right */
+ /* Generate simple sawtooth phaser that ranges between -1.0 and 1.0. */
+ data->left_phase += 0.01f;
+ /* When signal reaches top, drop back down. */
+ if( data->left_phase >= 1.0f ) data->left_phase -= 2.0f;
+ /* higher pitch so we can distinguish left and right. */
+ data->right_phase += 0.03f;
+ if( data->right_phase >= 1.0f ) data->right_phase -= 2.0f;
+ }
+ data->beepCount -= 1;
+ break;
+
+ default:
+ data->state = STATE_BKG_IDLE;
+ break;
+ }
+ }
+ return 0;
+}
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaStream *stream;
+ PaError err;
+ paTestData DATA;
+ int i, timeout;
+ PaTime previousTime;
+ PaStreamParameters outputParameters;
+ printf("PortAudio Test: you should see BEEP at the same time you hear it.\n");
+ printf("Wait for a few seconds random delay between BEEPs.\n");
+ printf("BEEP %d times.\n", NUM_BEEPS );
+ /* Initialize our DATA for use by callback. */
+ DATA.left_phase = DATA.right_phase = 0.0;
+ DATA.state = STATE_BKG_IDLE;
+ DATA.requestBeep = 0;
+ /* Initialize library before making any other calls. */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ outputParameters.device = Pa_GetDefaultOutputDevice();
+ outputParameters.channelCount = 2;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+ outputParameters.sampleFormat = paFloat32;
+ outputParameters.suggestedLatency = (double)LATENCY_MSEC / 1000;
+
+ /* Open an audio I/O stream. */
+ err = Pa_OpenStream(
+ &stream,
+ NULL, /* no input */
+ &outputParameters,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &DATA );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("started\n");
+ fflush(stdout);
+
+ previousTime = Pa_GetStreamTime( stream );
+ for( i=0; i<NUM_BEEPS; i++ )
+ {
+ /* Request a beep from background. */
+ DATA.requestBeep = 1;
+
+ /* Wait for background to acknowledge request. */
+ timeout = TIMEOUT_MSEC;
+ while( (DATA.requestBeep == 1) && (timeout-- > 0 ) ) Pa_Sleep(SLEEP_MSEC);
+ if( timeout <= 0 )
+ {
+ fprintf( stderr, "Timed out waiting for background to acknowledge request.\n" );
+ goto error;
+ }
+ printf("calc beep for %9.3f, latency = %6.3f\n", DATA.beepTime, DATA.latency );
+ fflush(stdout);
+
+ /* Wait for scheduled beep time. */
+ timeout = TIMEOUT_MSEC + (10000/SLEEP_MSEC);
+ while( (Pa_GetStreamTime( stream ) < DATA.beepTime) && (timeout-- > 0 ) )
+ {
+ Pa_Sleep(SLEEP_MSEC);
+ }
+ if( timeout <= 0 )
+ {
+ fprintf( stderr, "Timed out waiting for time. Now = %9.3f, Beep for %9.3f.\n",
+ PaUtil_GetTime(), DATA.beepTime );
+ goto error;
+ }
+
+ /* Beep should be sounding now so print synchronized BEEP. */
+ printf("hear \"BEEP\" at %9.3f, delta = %9.3f\n",
+ Pa_GetStreamTime( stream ), (DATA.beepTime - previousTime) );
+ fflush(stdout);
+
+ previousTime = DATA.beepTime;
+ }
+
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_toomanysines.c b/pd/portaudio/pa_tests/patest_toomanysines.c
new file mode 100644
index 00000000..2fbb8433
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_toomanysines.c
@@ -0,0 +1,172 @@
+/*
+ * $Id: patest_toomanysines.c,v 1.1.1.1 2003-05-09 16:03:56 ggeiger Exp $
+ * Play more sine waves than we can handle in real time as a stress test,
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define MAX_SINES (500)
+#define MAX_LOAD (1.2)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (512)
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+#define TWOPI (M_PI * 2.0)
+
+typedef struct paTestData
+{
+ int numSines;
+ double phases[MAX_SINES];
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+ int j;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ float output = 0.0;
+ double phaseInc = 0.02;
+ double phase;
+ for( j=0; j<data->numSines; j++ )
+ {
+ /* Advance phase of next oscillator. */
+ phase = data->phases[j];
+ phase += phaseInc;
+ if( phase > TWOPI ) phase -= TWOPI;
+
+ phaseInc *= 1.02;
+ if( phaseInc > 0.5 ) phaseInc *= 0.5;
+
+ /* This is not a very efficient way to calc sines. */
+ output += (float) sin( phase );
+ data->phases[j] = phase;
+ }
+
+
+ *out++ = (float) (output / data->numSines);
+ }
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ int numStress;
+ paTestData data = {0};
+ double load;
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d. MAX_LOAD = %f\n",
+ SAMPLE_RATE, FRAMES_PER_BUFFER, MAX_LOAD );
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 1, /* mono output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER, /* frames per buffer */
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ /* Determine number of sines required to get to 50% */
+ do
+ {
+ data.numSines++;
+ Pa_Sleep( 100 );
+
+ load = Pa_GetCPULoad( stream );
+ printf("numSines = %d, CPU load = %f\n", data.numSines, load );
+ }
+ while( load < 0.5 );
+
+ /* Calculate target stress value then ramp up to that level*/
+ numStress = (int) (2.0 * data.numSines * MAX_LOAD );
+ for( ; data.numSines < numStress; data.numSines++ )
+ {
+ Pa_Sleep( 200 );
+ load = Pa_GetCPULoad( stream );
+ printf("STRESSING: numSines = %d, CPU load = %f\n", data.numSines, load );
+ }
+
+ printf("Suffer for 5 seconds.\n");
+ Pa_Sleep( 5000 );
+
+ printf("Stop stream.\n");
+ err = Pa_StopStream( stream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_underflow.c b/pd/portaudio/pa_tests/patest_underflow.c
new file mode 100644
index 00000000..3f02c5a4
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_underflow.c
@@ -0,0 +1,151 @@
+/*
+ * $Id: patest_underflow.c,v 1.1.1.1 2003-05-09 16:03:57 ggeiger Exp $
+ * patest_underflow.c
+ * Simulate an output buffer underflow condition.
+ * Tests whether the stream can be stopped when underflowing buffers.
+ *
+ * Authors:
+ * Ross Bencina <rossb@audiomulch.com>
+ * Phil Burk <philburk@softsynth.com>
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define NUM_SECONDS (20)
+#define SAMPLE_RATE (44100)
+#define FRAMES_PER_BUFFER (2048)
+#define MSEC_PER_BUFFER ( (FRAMES_PER_BUFFER * 1000) / SAMPLE_RATE )
+
+#ifndef M_PI
+#define M_PI (3.14159265)
+#endif
+
+#define TABLE_SIZE (200)
+typedef struct
+{
+ float sine[TABLE_SIZE];
+ int left_phase;
+ int right_phase;
+ int sleepTime;
+}
+paTestData;
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+static int patestCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ paTestData *data = (paTestData*)userData;
+ float *out = (float*)outputBuffer;
+ unsigned long i;
+ int finished = 0;
+ (void) outTime; /* Prevent unused variable warnings. */
+ (void) inputBuffer;
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out++ = data->sine[data->left_phase]; /* left */
+ *out++ = data->sine[data->right_phase]; /* right */
+ data->left_phase += 1;
+ if( data->left_phase >= TABLE_SIZE ) data->left_phase -= TABLE_SIZE;
+ data->right_phase += 3; /* higher pitch so we can distinguish left and right. */
+ if( data->right_phase >= TABLE_SIZE ) data->right_phase -= TABLE_SIZE;
+ }
+
+ /* Cause underflow to occur. */
+ if( data->sleepTime > 0 ) Pa_Sleep( data->sleepTime );
+ data->sleepTime += 1;
+
+ return finished;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PortAudioStream *stream;
+ PaError err;
+ paTestData data;
+ int i;
+ printf("PortAudio Test: output sine wave. SR = %d, BufSize = %d\n", SAMPLE_RATE, FRAMES_PER_BUFFER);
+ /* initialise sinusoidal wavetable */
+ for( i=0; i<TABLE_SIZE; i++ )
+ {
+ data.sine[i] = (float) sin( ((double)i/(double)TABLE_SIZE) * M_PI * 2. );
+ }
+ data.left_phase = data.right_phase = data.sleepTime = 0;
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+ err = Pa_OpenStream(
+ &stream,
+ paNoDevice,/* default input device */
+ 0, /* no input */
+ paFloat32, /* 32 bit floating point input */
+ NULL,
+ Pa_GetDefaultOutputDeviceID(), /* default output device */
+ 2, /* stereo output */
+ paFloat32, /* 32 bit floating point output */
+ NULL,
+ SAMPLE_RATE,
+ FRAMES_PER_BUFFER,
+ 0, /* number of buffers, if zero then use default minimum */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ patestCallback,
+ &data );
+ if( err != paNoError ) goto error;
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ while( data.sleepTime < (2 * MSEC_PER_BUFFER) )
+ {
+ printf("SleepTime = %d\n", data.sleepTime );
+ Pa_Sleep( data.sleepTime );
+ }
+
+ printf("Try to stop stream.\n");
+ err = Pa_StopStream( stream ); /* */
+ err = Pa_AbortStream( stream ); /* */
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+ Pa_Terminate();
+ printf("Test finished.\n");
+ return err;
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
diff --git a/pd/portaudio/pa_tests/patest_wire.c b/pd/portaudio/pa_tests/patest_wire.c
new file mode 100644
index 00000000..51531395
--- /dev/null
+++ b/pd/portaudio/pa_tests/patest_wire.c
@@ -0,0 +1,277 @@
+/*
+ * $Id: patest_wire.c,v 1.1.1.1 2003-05-09 16:03:57 ggeiger Exp $
+ * patest_wire.c
+ *
+ * Pass input directly to output.
+ * Note that some HW devices, for example many ISA audio cards
+ * on PCs, do NOT support full duplex! For a PC, you normally need
+ * a PCI based audio card such as the SBLive.
+ *
+ * Author: Phil Burk http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <math.h>
+#include "portaudio.h"
+
+#define SAMPLE_RATE (44100)
+
+typedef struct WireConfig_s
+{
+ int isInputInterleaved;
+ int isOutputInterleaved;
+ int numInputChannels;
+ int numOutputChannels;
+ int framesPerCallback;
+} WireConfig_t;
+
+#define USE_FLOAT_INPUT (1)
+#define USE_FLOAT_OUTPUT (1)
+
+#define INPUT_LATENCY_MSEC (0)
+#define INPUT_LATENCY_FRAMES ((INPUT_LATENCY_MSEC * SAMPLE_RATE) / 1000)
+#define OUTPUT_LATENCY_MSEC (0)
+#define OUTPUT_LATENCY_FRAMES ((OUTPUT_LATENCY_MSEC * SAMPLE_RATE) / 1000)
+
+
+#if USE_FLOAT_INPUT
+ #define INPUT_FORMAT paFloat32
+ typedef float INPUT_SAMPLE;
+#else
+ #define INPUT_FORMAT paInt16
+ typedef short INPUT_SAMPLE;
+#endif
+
+#if USE_FLOAT_OUTPUT
+ #define OUTPUT_FORMAT paFloat32
+ typedef float OUTPUT_SAMPLE;
+#else
+ #define OUTPUT_FORMAT paInt16
+ typedef short OUTPUT_SAMPLE;
+#endif
+
+double gInOutScaler = 1.0;
+#define CONVERT_IN_TO_OUT(in) ((OUTPUT_SAMPLE) ((in) * gInOutScaler))
+
+#define INPUT_DEVICE (Pa_GetDefaultInputDevice())
+#define OUTPUT_DEVICE (Pa_GetDefaultOutputDevice())
+
+static PaError TestConfiguration( WireConfig_t *config );
+
+static int wireCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+/* This routine will be called by the PortAudio engine when audio is needed.
+** It may be called at interrupt level on some machines so don't do anything
+** that could mess up the system like calling malloc() or free().
+*/
+
+static int wireCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ INPUT_SAMPLE *in;
+ OUTPUT_SAMPLE *out;
+ int inStride;
+ int outStride;
+
+ int inDone = 0;
+ int outDone = 0;
+ WireConfig_t *config = (WireConfig_t *) userData;
+ unsigned int i;
+ int inChannel, outChannel;
+ (void) outTime;
+
+ /* This may get called with NULL inputBuffer during initial setup. */
+ if( inputBuffer == NULL) return 0;
+
+ inChannel=0, outChannel=0;
+ while( !(inDone && outDone) )
+ {
+ if( config->isInputInterleaved )
+ {
+ in = ((INPUT_SAMPLE*)inputBuffer) + inChannel;
+ inStride = config->numInputChannels;
+ }
+ else
+ {
+ in = ((INPUT_SAMPLE**)inputBuffer)[inChannel];
+ inStride = 1;
+ }
+
+ if( config->isOutputInterleaved )
+ {
+ out = ((OUTPUT_SAMPLE*)outputBuffer) + outChannel;
+ outStride = config->numOutputChannels;
+ }
+ else
+ {
+ out = ((OUTPUT_SAMPLE**)outputBuffer)[outChannel];
+ outStride = 1;
+ }
+
+ for( i=0; i<framesPerBuffer; i++ )
+ {
+ *out = CONVERT_IN_TO_OUT( *in );
+ out += outStride;
+ in += inStride;
+ }
+
+ if(inChannel < (config->numInputChannels - 1)) inChannel++;
+ else inDone = 1;
+ if(outChannel < (config->numOutputChannels - 1)) outChannel++;
+ else outDone = 1;
+ }
+ return 0;
+}
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ PaError err;
+ WireConfig_t CONFIG;
+ WireConfig_t *config = &CONFIG;
+ int configIndex = 0;;
+
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ printf("Please connect audio signal to input and listen for it on output!\n");
+ printf("input format = %d\n", INPUT_FORMAT );
+ printf("output format = %d\n", OUTPUT_FORMAT );
+ printf("input device ID = %d\n", INPUT_DEVICE );
+ printf("output device ID = %d\n", OUTPUT_DEVICE );
+
+ if( INPUT_FORMAT == OUTPUT_FORMAT )
+ {
+ gInOutScaler = 1.0;
+ }
+ else if( (INPUT_FORMAT == paInt16) && (OUTPUT_FORMAT == paFloat32) )
+ {
+ gInOutScaler = 1.0/32768.0;
+ }
+ else if( (INPUT_FORMAT == paFloat32) && (OUTPUT_FORMAT == paInt16) )
+ {
+ gInOutScaler = 32768.0;
+ }
+
+ for( config->isInputInterleaved = 0; config->isInputInterleaved < 2; config->isInputInterleaved++ )
+ {
+ for( config->isOutputInterleaved = 0; config->isOutputInterleaved < 2; config->isOutputInterleaved++ )
+ {
+ for( config->numInputChannels = 1; config->numInputChannels < 3; config->numInputChannels++ )
+ {
+ for( config->numOutputChannels = 1; config->numOutputChannels < 3; config->numOutputChannels++ )
+ {
+ for( config->framesPerCallback = 0; config->framesPerCallback < 65; config->framesPerCallback += 64 )
+ {
+ printf("-----------------------------------------------\n" );
+ printf("Configuration #%d\n", configIndex++ );
+ err = TestConfiguration( config );
+ // give user a chance to bail out
+ if( err == 1 )
+ {
+ err = paNoError;
+ goto done;
+ }
+ else if( err != paNoError ) goto error;
+ }
+ }
+ }
+ }
+ }
+
+done:
+ Pa_Terminate();
+
+ printf("Full duplex sound test complete.\n"); fflush(stdout);
+
+ printf("Hit ENTER to quit.\n"); fflush(stdout);
+ getchar();
+
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ printf("Hit ENTER to quit.\n"); fflush(stdout);
+ getchar();
+ return -1;
+}
+
+static PaError TestConfiguration( WireConfig_t *config )
+{
+ int c;
+ PaError err;
+ PaStream *stream;
+ printf("input %sinterleaved!\n", (config->isInputInterleaved ? " " : "NOT ") );
+ printf("output %sinterleaved!\n", (config->isOutputInterleaved ? " " : "NOT ") );
+ printf("input channels = %d\n", config->numInputChannels );
+ printf("output channels = %d\n", config->numOutputChannels );
+ printf("framesPerCallback = %d\n", config->framesPerCallback );
+
+ err = Pa_OpenStream(
+ &stream,
+ INPUT_DEVICE,
+ config->numInputChannels,
+ INPUT_FORMAT | (config->isInputInterleaved ? 0 : paNonInterleaved),
+ INPUT_LATENCY_FRAMES, /* input latency */
+ NULL,
+ OUTPUT_DEVICE,
+ config->numOutputChannels,
+ OUTPUT_FORMAT | (config->isOutputInterleaved ? 0 : paNonInterleaved),
+ OUTPUT_LATENCY_FRAMES, /* output latency */
+ NULL,
+ SAMPLE_RATE,
+ config->framesPerCallback, /* frames per buffer */
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ wireCallback,
+ config ); /* user data */
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( stream );
+ if( err != paNoError ) goto error;
+
+ printf("Hit ENTER for next configuration, or 'q' to quit.\n"); fflush(stdout);
+ c = getchar();
+
+ printf("Closing stream.\n");
+ err = Pa_CloseStream( stream );
+ if( err != paNoError ) goto error;
+
+ if( c == 'q' ) return 1;
+
+error:
+ return err;
+}
diff --git a/pd/portaudio/pa_unix/pa_unix_hostapis.c b/pd/portaudio/pa_unix/pa_unix_hostapis.c
new file mode 100644
index 00000000..4d10ef93
--- /dev/null
+++ b/pd/portaudio/pa_unix/pa_unix_hostapis.c
@@ -0,0 +1,60 @@
+/*
+ * $Id: pa_unix_hostapis.c,v 1.1.2.4 2003/02/10 01:06:09 dmazzoni Exp $
+ * Portable Audio I/O Library UNIX initialization table
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "pa_hostapi.h"
+
+PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+
+
+PaUtilHostApiInitializer *paHostApiInitializers[] =
+ {
+#ifdef PA_USE_OSS
+ PaOSS_Initialize,
+#endif
+
+#ifdef PA_USE_ALSA
+ PaAlsa_Initialize,
+#endif
+
+#ifdef PA_USE_JACK
+ PaJack_Initialize,
+#endif
+
+
+ 0 /* NULL terminated array */
+ };
+
+int paDefaultHostApiIndex = 0;
+
+
diff --git a/pd/portaudio/pa_unix/pa_unix_hostapis.o b/pd/portaudio/pa_unix/pa_unix_hostapis.o
new file mode 100644
index 00000000..e8d68536
--- /dev/null
+++ b/pd/portaudio/pa_unix/pa_unix_hostapis.o
Binary files differ
diff --git a/pd/portaudio/pa_unix/pa_unix_util.c b/pd/portaudio/pa_unix/pa_unix_util.c
new file mode 100644
index 00000000..826d4e7c
--- /dev/null
+++ b/pd/portaudio/pa_unix/pa_unix_util.c
@@ -0,0 +1,102 @@
+/*
+ * $Id: pa_unix_util.c,v 1.1.2.1 2002/07/31 04:22:56 joshua Exp $
+ * Portable Audio I/O Library
+ * UNIX platform-specific support functions
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "pa_util.h"
+
+
+/*
+ Track memory allocations to avoid leaks.
+ */
+
+#if PA_TRACK_MEMORY
+static int numAllocations_ = 0;
+#endif
+
+
+void *PaUtil_AllocateMemory( long size )
+{
+ void *result = malloc( size );
+
+#if PA_TRACK_MEMORY
+ if( result != NULL ) numAllocations_ += 1;
+#endif
+ return result;
+}
+
+
+void PaUtil_FreeMemory( void *block )
+{
+ if( block != NULL )
+ {
+ free( block );
+#if PA_TRACK_MEMORY
+ numAllocations_ -= 1;
+#endif
+
+ }
+}
+
+
+int PaUtil_CountCurrentlyAllocatedBlocks( void )
+{
+#if PA_TRACK_MEMORY
+ return numAllocations_;
+#else
+ return 0;
+#endif
+}
+
+
+void Pa_Sleep( long msec )
+{
+ usleep( msec * 1000 );
+}
+
+
+static int usePerformanceCounter_;
+static double microsecondsPerTick_;
+
+void PaUtil_InitializeClock( void )
+{
+ /* TODO */
+}
+
+
+double PaUtil_GetTime( void )
+{
+ /* TODO */
+ return (0);
+}
diff --git a/pd/portaudio/pa_unix/pa_unix_util.o b/pd/portaudio/pa_unix/pa_unix_util.o
new file mode 100644
index 00000000..52868e5f
--- /dev/null
+++ b/pd/portaudio/pa_unix/pa_unix_util.o
Binary files differ
diff --git a/pd/portaudio/pa_unix_oss/Makefile b/pd/portaudio/pa_unix_oss/Makefile
new file mode 100644
index 00000000..f5015631
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/Makefile
@@ -0,0 +1,43 @@
+# Make PortAudio for Linux
+
+LIBS = -lm -lpthread
+
+CDEFINES = -I../pa_common
+CFLAGS = -g -Wall
+PASRC = ../pa_common/pa_lib.c pa_unix_oss.c
+PAINC = ../pa_common/portaudio.h
+
+# Tests that work.
+TESTC = $(PASRC) ../pa_tests/patest_sine.c
+#TESTC = $(PASRC) ../pa_tests/patest_longsine.c
+#TESTC = $(PASRC) ../pa_tests/patest_sine_time.c
+#TESTC = $(PASRC) ../pa_tests/patest_maxsines.c
+#TESTC = $(PASRC) ../pa_tests/patest_toomanysines.c
+#TESTC = $(PASRC) ../pa_tests/patest_underflow.c
+#TESTC = $(PASRC) ../pa_tests/patest_hang.c
+#TESTC = $(PASRC) ../pa_tests/patest_sync.c
+#TESTC = $(PASRC) ../pa_tests/patest_pink.c
+#TESTC = $(PASRC) ../pa_tests/patest_leftright.c
+#TESTC = $(PASRC) ../pa_tests/patest_clip.c
+#TESTC = $(PASRC) ../pa_tests/patest_dither.c
+#TESTC = $(PASRC) ../pa_tests/pa_devs.c
+#TESTC = $(PASRC) ../pa_tests/patest_many.c
+#TESTC = $(PASRC) ../pa_tests/patest_record.c
+#TESTC = $(PASRC) ../pa_tests/pa_fuzz.c
+#TESTC = $(PASRC) ../pa_tests/patest_wire.c
+#TESTC = $(PASRC) ../pa_tests/paqa_devs.c
+
+# Tests that do not yet work.
+# OSS doesn't let us make obscenely huge buffers so the test will seem to fail. But its OK.
+#TESTC = $(PASRC) ../pa_tests/patest_stop.c
+
+TESTH = $(PAINC)
+
+all: patest
+
+patest: $(TESTC) $(TESTH) Makefile
+ gcc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest
+
+run: patest
+ ./patest
+
diff --git a/pd/portaudio/pa_unix_oss/Makefile_freebsd b/pd/portaudio/pa_unix_oss/Makefile_freebsd
new file mode 100644
index 00000000..fc8b14db
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/Makefile_freebsd
@@ -0,0 +1,36 @@
+# Make PortAudio for FreeBSD
+
+LIBS = -lm -pthread
+
+CDEFINES = -I../pa_common
+CFLAGS = -g
+PASRC = ../pa_common/pa_lib.c pa_freebsd.c
+PAINC = ../pa_common/portaudio.h
+
+# Tests that work.
+#TESTC = $(PASRC) ../pa_tests/patest_sine.c
+TESTC = $(PASRC) ../pa_tests/patest_sine_time.c
+#TESTC = $(PASRC) ../pa_tests/patest_stop.c
+#TESTC = $(PASRC) ../pa_tests/patest_sync.c
+#TESTC = $(PASRC) ../pa_tests/patest_pink.c
+#TESTC = $(PASRC) ../pa_tests/patest_leftright.c
+#TESTC = $(PASRC) ../pa_tests/patest_clip.c
+#TESTC = $(PASRC) ../pa_tests/patest_dither.c
+#TESTC = $(PASRC) ../pa_tests/pa_devs.c
+#TESTC = $(PASRC) ../pa_tests/patest_many.c
+#TESTC = $(PASRC) ../pa_tests/patest_record.c
+#TESTC = $(PASRC) ../pa_tests/patest_wire.c
+#TESTC = $(PASRC) ../pa_tests/paqa_devs.c
+
+# Tests that do not yet work.
+
+TESTH = $(PAINC)
+
+all: patest
+
+patest: $(TESTC) $(TESTH) Makefile
+ gcc $(CFLAGS) $(TESTC) $(CDEFINES) $(LIBS) -o patest
+
+run: patest
+ ./patest
+
diff --git a/pd/portaudio/pa_unix_oss/low_latency_tip.txt b/pd/portaudio/pa_unix_oss/low_latency_tip.txt
new file mode 100644
index 00000000..2d982b79
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/low_latency_tip.txt
Binary files differ
diff --git a/pd/portaudio/pa_unix_oss/pa_unix_oss.c b/pd/portaudio/pa_unix_oss/pa_unix_oss.c
new file mode 100644
index 00000000..2e51b245
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/pa_unix_oss.c
@@ -0,0 +1,1187 @@
+/*
+ * $Id
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ * OSS implementation by:
+ * Douglas Repetto
+ * Phil Burk
+ * Dominic Mazzoni
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#ifdef __linux__
+# include <linux/soundcard.h>
+# define DEVICE_NAME_BASE "/dev/dsp"
+#else
+# include <machine/soundcard.h> /* JH20010905 */
+# define DEVICE_NAME_BASE "/dev/audio"
+#endif
+
+#include "portaudio.h"
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
+
+/* TODO: add error text handling
+#define PA_UNIX_OSS_ERROR( errorCode, errorText ) \
+ PaUtil_SetLastHostErrorInfo( paInDevelopment, errorCode, errorText )
+*/
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define DBUG(x) /* PRINT(x) */
+
+/* PaOSSHostApiRepresentation - host api datastructure specific to this implementation */
+
+typedef struct
+{
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
+
+ PaUtilAllocationGroup *allocations;
+
+ PaHostApiIndex hostApiIndex;
+}
+PaOSSHostApiRepresentation;
+
+typedef struct PaOSS_DeviceList {
+ PaDeviceInfo *deviceInfo;
+ struct PaOSS_DeviceList *next;
+}
+PaOSS_DeviceList;
+
+/* prototypes for functions declared in this file */
+
+PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData );
+static PaError CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+static signed long GetStreamReadAvailable( PaStream* stream );
+static signed long GetStreamWriteAvailable( PaStream* stream );
+static PaError BuildDeviceList( PaOSSHostApiRepresentation *hostApi );
+
+
+PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ PaOSSHostApiRepresentation *ossHostApi;
+
+ DBUG(("PaOSS_Initialize\n"));
+
+ ossHostApi = (PaOSSHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaOSSHostApiRepresentation) );
+ if( !ossHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ ossHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !ossHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ *hostApi = &ossHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paOSS;
+ (*hostApi)->info.name = "OSS";
+ ossHostApi->hostApiIndex = hostApiIndex;
+
+ BuildDeviceList( ossHostApi );
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &ossHostApi->callbackStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite,
+ PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &ossHostApi->blockingStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+
+ return result;
+
+error:
+ if( ossHostApi )
+ {
+ if( ossHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( ossHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( ossHostApi );
+ }
+ return result;
+}
+
+#ifndef AFMT_S16_NE
+#define AFMT_S16_NE Get_AFMT_S16_NE()
+/*********************************************************************
+ * Some versions of OSS do not define AFMT_S16_NE. So check CPU.
+ * PowerPC is Big Endian. X86 is Little Endian.
+ */
+static int Get_AFMT_S16_NE( void )
+{
+ long testData = 1;
+ char *ptr = (char *) &testData;
+ int isLittle = ( *ptr == 1 ); /* Does address point to least significant byte? */
+ return isLittle ? AFMT_S16_LE : AFMT_S16_BE;
+}
+#endif
+
+PaError PaOSS_SetFormat(const char *callingFunctionName, int deviceHandle,
+ char *deviceName, int inputChannelCount, int outputChannelCount,
+ double *sampleRate)
+{
+ int format;
+ int rate;
+ int temp;
+
+ /* Attempt to set format to 16-bit */
+
+ format = AFMT_S16_NE;
+ if (ioctl(deviceHandle, SNDCTL_DSP_SETFMT, &format) == -1) {
+ DBUG(("%s: could not set format: %s\n", callingFunctionName, deviceName ));
+ return paSampleFormatNotSupported;
+ }
+ if (format != AFMT_S16_NE) {
+ DBUG(("%s: device does not support AFMT_S16_NE: %s\n", callingFunctionName, deviceName ));
+ return paSampleFormatNotSupported;
+ }
+
+ /* try to set the number of channels */
+
+ if (inputChannelCount > 0) {
+ temp = inputChannelCount;
+
+ if( ioctl(deviceHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 ) {
+ DBUG(("%s: Couldn't set device %s to %d channels\n", callingFunctionName, deviceName, inputChannelCount ));
+ return paSampleFormatNotSupported;
+ }
+ }
+
+ if (outputChannelCount > 0) {
+ temp = outputChannelCount;
+
+ if( ioctl(deviceHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 ) {
+ DBUG(("%s: Couldn't set device %s to %d channels\n", callingFunctionName, deviceName, outputChannelCount ));
+ return paSampleFormatNotSupported;
+ }
+ }
+
+ /* try to set the sample rate */
+
+ rate = (int)(*sampleRate);
+ if (ioctl(deviceHandle, SNDCTL_DSP_SPEED, &rate) == -1)
+ {
+ DBUG(("%s: Device %s, couldn't set sample rate to %d\n",
+ callingFunctionName, deviceName, (int)*sampleRate ));
+ return paInvalidSampleRate;
+ }
+
+ /* reject if there's no sample rate within 1% of the one requested */
+ if ((fabs(*sampleRate - rate) / *sampleRate) > 0.01)
+ {
+ DBUG(("%s: Device %s, wanted %d, closest sample rate was %d\n",
+ callingFunctionName, deviceName, (int)*sampleRate, rate ));
+ return paInvalidSampleRate;
+ }
+
+ *sampleRate = rate;
+
+ return paNoError;
+}
+
+static PaError PaOSS_QueryDevice(char *deviceName, PaDeviceInfo *deviceInfo)
+{
+ PaError result = paNoError;
+ int tempDevHandle;
+ int numChannels, maxNumChannels;
+ int sampleRate;
+ int format;
+
+ /* douglas:
+ we have to do this querying in a slightly different order. apparently
+ some sound cards will give you different info based on their settins.
+ e.g. a card might give you stereo at 22kHz but only mono at 44kHz.
+ the correct order for OSS is: format, channels, sample rate
+ */
+
+ if ( (tempDevHandle = open(deviceName,O_WRONLY|O_NONBLOCK)) == -1 )
+ {
+ DBUG(("PaOSS_QueryDevice: could not open %s\n", deviceName ));
+ return paDeviceUnavailable;
+ }
+
+ /* Attempt to set format to 16-bit */
+ format = AFMT_S16_NE;
+ if (ioctl(tempDevHandle, SNDCTL_DSP_SETFMT, &format) == -1) {
+ DBUG(("PaOSS_QueryDevice: could not set format: %s\n", deviceName ));
+ result = paSampleFormatNotSupported;
+ goto error;
+ }
+ if (format != AFMT_S16_NE) {
+ DBUG(("PaOSS_QueryDevice: device does not support AFMT_S16_NE: %s\n", deviceName ));
+ result = paSampleFormatNotSupported;
+ goto error;
+ }
+
+ /* Negotiate for the maximum number of channels for this device. PLB20010927
+ * Consider up to 16 as the upper number of channels.
+ * Variable maxNumChannels should contain the actual upper limit after the call.
+ * Thanks to John Lazzaro and Heiko Purnhagen for suggestions.
+ */
+ maxNumChannels = 0;
+ for( numChannels = 1; numChannels <= 16; numChannels++ )
+ {
+ int temp = numChannels;
+ DBUG(("PaOSS_QueryDevice: use SNDCTL_DSP_CHANNELS, numChannels = %d\n", numChannels ))
+ if(ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp) < 0 )
+ {
+ /* ioctl() failed so bail out if we already have stereo */
+ if( numChannels > 2 ) break;
+ }
+ else
+ {
+ /* ioctl() worked but bail out if it does not support numChannels.
+ * We don't want to leave gaps in the numChannels supported.
+ */
+ if( (numChannels > 2) && (temp != numChannels) ) break;
+ DBUG(("PaOSS_QueryDevice: temp = %d\n", temp ))
+ if( temp > maxNumChannels ) maxNumChannels = temp; /* Save maximum. */
+ }
+ }
+
+ /* The above negotiation may fail for an old driver so try this older technique. */
+ if( maxNumChannels < 1 )
+ {
+ int stereo = 1;
+ if(ioctl(tempDevHandle, SNDCTL_DSP_STEREO, &stereo) < 0)
+ {
+ maxNumChannels = 1;
+ }
+ else
+ {
+ maxNumChannels = (stereo) ? 2 : 1;
+ }
+ DBUG(("PaOSS_QueryDevice: use SNDCTL_DSP_STEREO, maxNumChannels = %d\n", maxNumChannels ))
+ }
+
+ DBUG(("PaOSS_QueryDevice: maxNumChannels = %d\n", maxNumChannels))
+
+ deviceInfo->maxOutputChannels = maxNumChannels;
+ /* FIXME - for now, assume maxInputChannels = maxOutputChannels.
+ * Eventually do separate queries for O_WRONLY and O_RDONLY
+ */
+ deviceInfo->maxInputChannels = deviceInfo->maxOutputChannels;
+
+ /* During channel negotiation, the last ioctl() may have failed. This can
+ * also cause sample rate negotiation to fail. Hence the following, to return
+ * to a supported number of channels. SG20011005 */
+ {
+ int temp = maxNumChannels;
+ if( temp > 2 ) temp = 2; /* use most reasonable default value */
+ ioctl(tempDevHandle, SNDCTL_DSP_CHANNELS, &temp);
+ }
+
+ /* Get supported sample rate closest to 44100 Hz */
+ sampleRate = 44100;
+ if (ioctl(tempDevHandle, SNDCTL_DSP_SPEED, &sampleRate) == -1)
+ {
+ result = paUnanticipatedHostError;
+ goto error;
+ }
+
+ deviceInfo->defaultSampleRate = sampleRate;
+
+ deviceInfo->structVersion = 2;
+
+ /* TODO */
+ deviceInfo->defaultLowInputLatency = 128.0 / sampleRate;
+ deviceInfo->defaultLowOutputLatency = 128.0 / sampleRate;
+ deviceInfo->defaultHighInputLatency = 16384.0 / sampleRate;
+ deviceInfo->defaultHighOutputLatency = 16384.0 / sampleRate;
+
+ result = paNoError;
+
+error:
+ /* We MUST close the handle here or we won't be able to reopen it later!!! */
+ close(tempDevHandle);
+
+ return result;
+}
+
+static PaError BuildDeviceList( PaOSSHostApiRepresentation *ossApi )
+{
+ PaUtilHostApiRepresentation *commonApi = &ossApi->inheritedHostApiRep;
+ PaOSS_DeviceList *head = NULL, *tail = NULL, *entry;
+ int i;
+ int numDevices;
+
+ /* Find devices by calling PaOSS_QueryDevice on each
+ potential device names. When we find a valid one,
+ add it to a linked list. */
+
+ for(i=0; i<10; i++) {
+ char deviceName[32];
+ PaDeviceInfo deviceInfo;
+ int testResult;
+
+ if (i==0)
+ sprintf(deviceName, "%s", DEVICE_NAME_BASE);
+ else
+ sprintf(deviceName, "%s%d", DEVICE_NAME_BASE, i);
+
+ DBUG(("PaOSS BuildDeviceList: trying device %s\n", deviceName ));
+ testResult = PaOSS_QueryDevice(deviceName, &deviceInfo);
+ DBUG(("PaOSS BuildDeviceList: PaOSS_QueryDevice returned %d\n", testResult ));
+
+ if (testResult == paNoError) {
+ DBUG(("PaOSS BuildDeviceList: Adding device %s to list\n", deviceName));
+ deviceInfo.hostApi = ossApi->hostApiIndex;
+ deviceInfo.name = PaUtil_GroupAllocateMemory(
+ ossApi->allocations, strlen(deviceName)+1);
+ strcpy((char *)deviceInfo.name, deviceName);
+ entry = (PaOSS_DeviceList *)PaUtil_AllocateMemory(sizeof(PaOSS_DeviceList));
+ entry->deviceInfo = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ ossApi->allocations, sizeof(PaDeviceInfo) );
+ entry->next = NULL;
+ memcpy(entry->deviceInfo, &deviceInfo, sizeof(PaDeviceInfo));
+ if (tail)
+ tail->next = entry;
+ else {
+ head = entry;
+ tail = entry;
+ }
+ }
+ }
+
+ /* Make an array of PaDeviceInfo pointers out of the linked list */
+
+ numDevices = 0;
+ entry = head;
+ while(entry) {
+ numDevices++;
+ entry = entry->next;
+ }
+
+ DBUG(("PaOSS BuildDeviceList: Total number of devices found: %d\n", numDevices));
+
+ commonApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ ossApi->allocations, sizeof(PaDeviceInfo*) *numDevices );
+
+ entry = head;
+ i = 0;
+ while(entry) {
+ commonApi->deviceInfos[i] = entry->deviceInfo;
+ i++;
+ entry = entry->next;
+ }
+
+ commonApi->info.deviceCount = numDevices;
+ commonApi->info.defaultInputDevice = 0;
+ commonApi->info.defaultOutputDevice = 0;
+
+ return paNoError;
+}
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
+
+ if( ossHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( ossHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( ossHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( ossHostApi );
+}
+
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
+{
+ PaDeviceIndex device;
+ PaDeviceInfo *deviceInfo;
+ PaError result = paNoError;
+ char *deviceName;
+ int inputChannelCount, outputChannelCount;
+ int tempDevHandle = 0;
+ int flags;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ if (inputChannelCount == 0 && outputChannelCount == 0)
+ return paInvalidChannelCount;
+
+ /* if full duplex, make sure that they're the same device */
+
+ if (inputChannelCount > 0 && outputChannelCount > 0 &&
+ inputParameters->device != outputParameters->device)
+ return paInvalidDevice;
+
+ /* if full duplex, also make sure that they're the same number of channels */
+
+ if (inputChannelCount > 0 && outputChannelCount > 0 &&
+ inputChannelCount != outputChannelCount)
+ return paInvalidChannelCount;
+
+ /* open the device so we can do more tests */
+
+ if (inputChannelCount > 0) {
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi);
+ if (result != paNoError)
+ return result;
+ }
+ else {
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi);
+ if (result != paNoError)
+ return result;
+ }
+
+ deviceInfo = hostApi->deviceInfos[device];
+ deviceName = (char *)deviceInfo->name;
+
+ flags = O_NONBLOCK;
+ if (inputChannelCount > 0 && outputChannelCount > 0)
+ flags |= O_RDWR;
+ else if (inputChannelCount > 0)
+ flags |= O_RDONLY;
+ else
+ flags |= O_WRONLY;
+
+ if ( (tempDevHandle = open(deviceInfo->name, flags)) == -1 )
+ {
+ DBUG(("PaOSS IsFormatSupported: could not open %s\n", deviceName ));
+ return paDeviceUnavailable;
+ }
+
+ /* PaOSS_SetFormat will do the rest of the checking for us */
+
+ if ((result = PaOSS_SetFormat("PaOSS IsFormatSupported", tempDevHandle,
+ deviceName, inputChannelCount, outputChannelCount,
+ &sampleRate)) != paNoError)
+ {
+ goto error;
+ }
+
+ /* everything succeeded! */
+
+ close(tempDevHandle);
+
+ return paFormatIsSupported;
+
+ error:
+ if (tempDevHandle)
+ close(tempDevHandle);
+
+ return paSampleFormatNotSupported;
+}
+
+/* PaOSSStream - a stream data structure specifically for this implementation */
+
+typedef struct PaOSSStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ int deviceHandle;
+
+ int stopSoon;
+ int stopNow;
+ int isActive;
+
+ int inputChannelCount;
+ int outputChannelCount;
+
+ pthread_t thread;
+
+ void *inputBuffer;
+ void *outputBuffer;
+
+ int lastPosPtr;
+ double lastStreamBytes;
+
+ int framesProcessed;
+
+ double sampleRate;
+
+ unsigned long framesPerHostCallback;
+}
+PaOSSStream;
+
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaOSSHostApiRepresentation *ossHostApi = (PaOSSHostApiRepresentation*)hostApi;
+ PaOSSStream *stream = 0;
+ PaDeviceIndex device;
+ PaDeviceInfo *deviceInfo;
+ audio_buf_info bufinfo;
+ int bytesPerHostBuffer;
+ int flags;
+ int deviceHandle = 0;
+ char *deviceName;
+ unsigned long framesPerHostBuffer;
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat = paInt16, outputSampleFormat = paInt16;
+ PaSampleFormat hostInputSampleFormat = paInt16, hostOutputSampleFormat = paInt16;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16, inputSampleFormat );
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16, outputSampleFormat );
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ if( inputChannelCount == 0 && outputChannelCount == 0 )
+ {
+ DBUG(("Both inputChannelCount and outputChannelCount are zero!\n"));
+ return paUnanticipatedHostError;
+ }
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
+
+ /*
+ * open the device and set parameters here
+ */
+
+ if (inputChannelCount == 0 && outputChannelCount == 0)
+ return paInvalidChannelCount;
+
+ /* if full duplex, make sure that they're the same device */
+
+ if (inputChannelCount > 0 && outputChannelCount > 0 &&
+ inputParameters->device != outputParameters->device)
+ return paInvalidDevice;
+
+ /* if full duplex, also make sure that they're the same number of channels */
+
+ if (inputChannelCount > 0 && outputChannelCount > 0 &&
+ inputChannelCount != outputChannelCount)
+ return paInvalidChannelCount;
+
+ if (inputChannelCount > 0) {
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, inputParameters->device, hostApi);
+ if (result != paNoError)
+ return result;
+ }
+ else {
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex(&device, outputParameters->device, hostApi);
+ if (result != paNoError)
+ return result;
+ }
+
+ deviceInfo = hostApi->deviceInfos[device];
+ deviceName = (char *)deviceInfo->name;
+
+ flags = O_NONBLOCK;
+ if (inputChannelCount > 0 && outputChannelCount > 0)
+ flags |= O_RDWR;
+ else if (inputChannelCount > 0)
+ flags |= O_RDONLY;
+ else
+ flags |= O_WRONLY;
+
+ /* open first in nonblocking mode, in case it's busy... */
+ if ( (deviceHandle = open(deviceInfo->name, flags)) == -1 )
+ {
+ DBUG(("PaOSS OpenStream: could not open %s\n", deviceName ));
+ return paDeviceUnavailable;
+ }
+
+ /* if that succeeded, immediately open it again in blocking mode */
+ close(deviceHandle);
+ flags -= O_NONBLOCK;
+ if ( (deviceHandle = open(deviceInfo->name, flags)) == -1 )
+ {
+ DBUG(("PaOSS OpenStream: could not open %s in blocking mode\n", deviceName ));
+ return paDeviceUnavailable;
+ }
+
+ if ((result = PaOSS_SetFormat("PaOSS OpenStream", deviceHandle,
+ deviceName, inputChannelCount, outputChannelCount,
+ &sampleRate)) != paNoError)
+ {
+ goto error;
+ }
+
+ /* Compute number of frames per host buffer - if we can't retrieve the
+ * value, use the user's value instead
+ */
+
+ if ( ioctl(deviceHandle, SNDCTL_DSP_GETBLKSIZE, &bytesPerHostBuffer) == 0)
+ {
+ framesPerHostBuffer = bytesPerHostBuffer / 2 / (inputChannelCount>0? inputChannelCount: outputChannelCount);
+ }
+ else
+ framesPerHostBuffer = framesPerBuffer;
+
+ /* Allocate stream and fill in structure */
+
+ stream = (PaOSSStream*)PaUtil_AllocateMemory( sizeof(PaOSSStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( streamCallback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &ossHostApi->callbackStreamInterface, streamCallback, userData );
+ }
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &ossHostApi->blockingStreamInterface, streamCallback, userData );
+ }
+
+ stream->streamRepresentation.streamInfo.inputLatency = 0.;
+ stream->streamRepresentation.streamInfo.outputLatency = 0.;
+
+ if (inputChannelCount > 0) {
+ if (ioctl( deviceHandle, SNDCTL_DSP_GETISPACE, &bufinfo) == 0)
+ stream->streamRepresentation.streamInfo.inputLatency =
+ (bufinfo.fragsize * bufinfo.fragstotal) / sampleRate;
+ }
+
+ if (outputChannelCount > 0) {
+ if (ioctl( deviceHandle, SNDCTL_DSP_GETOSPACE, &bufinfo) == 0)
+ stream->streamRepresentation.streamInfo.outputLatency =
+ (bufinfo.fragsize * bufinfo.fragstotal) / sampleRate;
+ }
+
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+ /* we assume a fixed host buffer size in this example, but the buffer processor
+ can also support bounded and unknown host buffer sizes by passing
+ paUtilBoundedHostBufferSize or paUtilUnknownHostBufferSize instead of
+ paUtilFixedHostBufferSize below. */
+
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ inputChannelCount, inputSampleFormat, hostInputSampleFormat,
+ outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer,
+ framesPerHostBuffer, paUtilFixedHostBufferSize,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+
+ stream->framesPerHostCallback = framesPerHostBuffer;
+
+ stream->stopSoon = 0;
+ stream->stopNow = 0;
+ stream->isActive = 0;
+ stream->thread = 0;
+ stream->lastPosPtr = 0;
+ stream->lastStreamBytes = 0;
+ stream->sampleRate = sampleRate;
+ stream->framesProcessed = 0;
+ stream->deviceHandle = deviceHandle;
+
+ if (inputChannelCount > 0)
+ stream->inputBuffer = PaUtil_AllocateMemory( 2 * framesPerHostBuffer * inputChannelCount );
+ else
+ stream->inputBuffer = NULL;
+
+ if (outputChannelCount > 0)
+ stream->outputBuffer = PaUtil_AllocateMemory( 2 * framesPerHostBuffer * outputChannelCount );
+ else
+ stream->outputBuffer = NULL;
+
+ stream->inputChannelCount = inputChannelCount;
+ stream->outputChannelCount = outputChannelCount;
+
+ *s = (PaStream*)stream;
+
+ result = paNoError;
+
+ return result;
+
+error:
+ if( stream )
+ PaUtil_FreeMemory( stream );
+
+ if( deviceHandle )
+ close( deviceHandle );
+
+ return result;
+}
+
+static void *PaOSS_AudioThreadProc(void *userData)
+{
+ PaOSSStream *stream = (PaOSSStream*)userData;
+
+ DBUG(("PaOSS AudioThread: %d in, %d out\n", stream->inputChannelCount, stream->outputChannelCount));
+
+ while( (stream->stopNow == 0) && (stream->stopSoon == 0) ) {
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* TODO: IMPLEMENT ME */
+ int callbackResult;
+ unsigned long framesProcessed;
+ int bytesRequested;
+ int bytesRead, bytesWritten;
+ int delta;
+ int result;
+ count_info info;
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo );
+
+ /*
+ depending on whether the host buffers are interleaved, non-interleaved
+ or a mixture, you will want to call PaUtil_SetInterleaved*Channels(),
+ PaUtil_SetNonInterleaved*Channel() or PaUtil_Set*Channel() here.
+ */
+
+ if ( stream->inputChannelCount > 0 )
+ {
+ bytesRequested = stream->framesPerHostCallback * 2 * stream->inputChannelCount;
+ bytesRead = read( stream->deviceHandle, stream->inputBuffer, bytesRequested );
+
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, bytesRead/(2*stream->inputChannelCount));
+ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor,
+ 0, /* first channel of inputBuffer is channel 0 */
+ stream->inputBuffer,
+ 0 ); /* 0 - use inputChannelCount passed to init buffer processor */
+ }
+
+ if ( stream->outputChannelCount > 0 )
+ {
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
+ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor,
+ 0, /* first channel of outputBuffer is channel 0 */
+ stream->outputBuffer,
+ 0 ); /* 0 - use outputChannelCount passed to init buffer processor */
+ }
+
+ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+
+ if( callbackResult == paContinue )
+ {
+ /* nothing special to do */
+ }
+ else if( callbackResult == paAbort )
+ {
+ /* once finished, call the finished callback */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+
+ return NULL; /* return from the loop */
+ }
+ else if ( callbackResult == paComplete )
+ {
+ /* User callback has asked us to stop with paComplete or other non-zero value */
+
+ /* once finished, call the finished callback */
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+
+ stream->stopSoon = 1;
+ }
+
+ if ( stream->outputChannelCount > 0 ) {
+ /* write output samples AFTER we've checked the callback result code */
+
+ bytesRequested = stream->framesPerHostCallback * 2 * stream->outputChannelCount;
+ bytesWritten = write( stream->deviceHandle, stream->outputBuffer, bytesRequested );
+
+ /* TODO: handle bytesWritten != bytesRequested (slippage?) */
+ }
+
+ /* Update current stream time (using a double so that
+ we don't wrap around like info.bytes does) */
+ if( stream->outputChannelCount > 0 )
+ result = ioctl( stream->deviceHandle, SNDCTL_DSP_GETOPTR, &info);
+ else
+ result = ioctl( stream->deviceHandle, SNDCTL_DSP_GETIPTR, &info);
+
+ if (result == 0) {
+ delta = ( info.bytes - stream->lastPosPtr ) & 0x000FFFFF;
+ stream->lastStreamBytes += delta;
+ stream->lastPosPtr = info.bytes;
+ }
+
+ stream->framesProcessed += stream->framesPerHostCallback;
+ }
+
+ return NULL;
+}
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ close(stream->deviceHandle);
+
+ if ( stream->inputBuffer )
+ PaUtil_FreeMemory( stream->inputBuffer );
+ if ( stream->outputBuffer )
+ PaUtil_FreeMemory( stream->outputBuffer );
+
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaOSSStream *stream = (PaOSSStream*)s;
+ int presult;
+
+ stream->isActive = 1;
+ stream->lastPosPtr = 0;
+ stream->lastStreamBytes = 0;
+ stream->framesProcessed = 0;
+
+ DBUG(("PaOSS StartStream\n"));
+
+ presult = pthread_create(&stream->thread,
+ NULL /*pthread_attr_t * attr*/,
+ (void*)PaOSS_AudioThreadProc, (void *)stream);
+
+ return result;
+}
+
+
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ stream->stopSoon = 1;
+ pthread_join( stream->thread, NULL );
+ stream->stopSoon = 0;
+ stream->stopNow = 0;
+ stream->isActive = 0;
+
+ DBUG(("PaOSS StopStream: Stopped stream\n"));
+
+ return result;
+}
+
+
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ stream->stopNow = 1;
+ pthread_join( stream->thread, NULL );
+ stream->stopSoon = 0;
+ stream->stopNow = 0;
+ stream->isActive = 0;
+
+ DBUG(("PaOSS AbortStream: Stopped stream\n"));
+
+ return result;
+}
+
+
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ return (!stream->isActive);
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ return (stream->isActive);
+}
+
+
+static PaTime GetStreamTime( PaStream *s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+ count_info info;
+ int delta;
+
+ if( stream->outputChannelCount > 0 ) {
+ if (ioctl( stream->deviceHandle, SNDCTL_DSP_GETOPTR, &info) == 0) {
+ delta = ( info.bytes - stream->lastPosPtr ) & 0x000FFFFF;
+ return ( stream->lastStreamBytes + delta) / ( stream->outputChannelCount * 2 ) / stream->sampleRate;
+ }
+ }
+ else {
+ if (ioctl( stream->deviceHandle, SNDCTL_DSP_GETIPTR, &info) == 0) {
+ delta = (info.bytes - stream->lastPosPtr) & 0x000FFFFF;
+ return ( stream->lastStreamBytes + delta) / ( stream->inputChannelCount * 2 ) / stream->sampleRate;
+ }
+ }
+
+ /* the ioctl failed, but we can still give a coarse estimate */
+
+ return stream->framesProcessed / stream->sampleRate;
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
+/*
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
+
+
+static PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+ int bytesRequested, bytesRead;
+
+ bytesRequested = frames * 2 * stream->inputChannelCount;
+ bytesRead = read( stream->deviceHandle, stream->inputBuffer, bytesRequested );
+
+ if ( bytesRequested != bytesRead )
+ return paUnanticipatedHostError;
+ else
+ return paNoError;
+}
+
+
+static PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+ int bytesRequested, bytesWritten;
+
+ bytesRequested = frames * 2 * stream->outputChannelCount;
+ bytesWritten = write( stream->deviceHandle, buffer, bytesRequested );
+
+ if ( bytesRequested != bytesWritten )
+ return paUnanticipatedHostError;
+ else
+ return paNoError;
+}
+
+
+static signed long GetStreamReadAvailable( PaStream* s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+ audio_buf_info info;
+
+ if ( ioctl(stream->deviceHandle, SNDCTL_DSP_GETISPACE, &info) == 0)
+ {
+ int bytesAvailable = info.fragments * info.fragsize;
+ return ( bytesAvailable / 2 / stream->inputChannelCount );
+ }
+ else
+ return 0; /* TODO: is this right for "don't know"? */
+}
+
+
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+ PaOSSStream *stream = (PaOSSStream*)s;
+
+ audio_buf_info info;
+
+ if ( ioctl(stream->deviceHandle, SNDCTL_DSP_GETOSPACE, &info) == 0)
+ {
+ int bytesAvailable = info.fragments * info.fragsize;
+ return ( bytesAvailable / 2 / stream->outputChannelCount );
+ }
+ else
+ return 0; /* TODO: is this right for "don't know"? */
+}
+
diff --git a/pd/portaudio/pa_unix_oss/pa_unix_oss.o b/pd/portaudio/pa_unix_oss/pa_unix_oss.o
new file mode 100644
index 00000000..604f9798
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/pa_unix_oss.o
Binary files differ
diff --git a/pd/portaudio/pa_unix_oss/recplay.c b/pd/portaudio/pa_unix_oss/recplay.c
new file mode 100644
index 00000000..9d4c78cf
--- /dev/null
+++ b/pd/portaudio/pa_unix_oss/recplay.c
@@ -0,0 +1,114 @@
+/*
+ * recplay.c
+ * Phil Burk
+ * Minimal record and playback test.
+ *
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#ifndef __STDC__
+/* #include <getopt.h> */
+#endif /* __STDC__ */
+#include <fcntl.h>
+#ifdef __STDC__
+#include <string.h>
+#else /* __STDC__ */
+#include <strings.h>
+#endif /* __STDC__ */
+#include <sys/soundcard.h>
+
+#define NUM_BYTES (64*1024)
+#define BLOCK_SIZE (4*1024)
+
+#define AUDIO "/dev/dsp"
+
+char buffer[NUM_BYTES];
+
+int audioDev = 0;
+
+main (int argc, char *argv[])
+{
+ int numLeft;
+ char *ptr;
+ int num;
+ int samplesize;
+
+ /********** RECORD ********************/
+ /* Open audio device. */
+ audioDev = open (AUDIO, O_RDONLY, 0);
+ if (audioDev == -1)
+ {
+ perror (AUDIO);
+ exit (-1);
+ }
+
+ /* Set to 16 bit samples. */
+ samplesize = 16;
+ ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize);
+ if (samplesize != 16)
+ {
+ perror("Unable to set the sample size.");
+ exit(-1);
+ }
+
+ /* Record in blocks */
+ printf("Begin recording.\n");
+ numLeft = NUM_BYTES;
+ ptr = buffer;
+ while( numLeft >= BLOCK_SIZE )
+ {
+ if ( (num = read (audioDev, ptr, BLOCK_SIZE)) < 0 )
+ {
+ perror (AUDIO);
+ exit (-1);
+ }
+ else
+ {
+ printf("Read %d bytes\n", num);
+ ptr += num;
+ numLeft -= num;
+ }
+ }
+
+ close( audioDev );
+
+ /********** PLAYBACK ********************/
+ /* Open audio device for writing. */
+ audioDev = open (AUDIO, O_WRONLY, 0);
+ if (audioDev == -1)
+ {
+ perror (AUDIO);
+ exit (-1);
+ }
+
+ /* Set to 16 bit samples. */
+ samplesize = 16;
+ ioctl(audioDev, SNDCTL_DSP_SAMPLESIZE, &samplesize);
+ if (samplesize != 16)
+ {
+ perror("Unable to set the sample size.");
+ exit(-1);
+ }
+
+ /* Play in blocks */
+ printf("Begin playing.\n");
+ numLeft = NUM_BYTES;
+ ptr = buffer;
+ while( numLeft >= BLOCK_SIZE )
+ {
+ if ( (num = write (audioDev, ptr, BLOCK_SIZE)) < 0 )
+ {
+ perror (AUDIO);
+ exit (-1);
+ }
+ else
+ {
+ printf("Wrote %d bytes\n", num);
+ ptr += num;
+ numLeft -= num;
+ }
+ }
+
+ close( audioDev );
+}
diff --git a/pd/portaudio/pa_win/pa_win_hostapis.c b/pd/portaudio/pa_win/pa_win_hostapis.c
new file mode 100644
index 00000000..2b518512
--- /dev/null
+++ b/pd/portaudio/pa_win/pa_win_hostapis.c
@@ -0,0 +1,63 @@
+/*
+ * $Id: pa_win_hostapis.c,v 1.1.2.6 2002/10/26 05:32:35 rossbencina Exp $
+ * Portable Audio I/O Library Windows initialization table
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include "pa_hostapi.h"
+
+PaError PaSkeleton_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+PaError PaAsio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+
+
+PaUtilHostApiInitializer *paHostApiInitializers[] =
+ {
+
+#ifndef PA_NO_WMME
+ PaWinMme_Initialize,
+#endif
+
+#ifndef PA_NO_DS
+ PaWinDs_Initialize,
+#endif
+
+#ifndef PA_NO_ASIO
+ PaAsio_Initialize,
+#endif
+
+ PaSkeleton_Initialize, /* just for testing */
+
+ 0 /* NULL terminated array */
+ };
+
+
+int paDefaultHostApiIndex = 0;
+
diff --git a/pd/portaudio/pa_win/pa_win_util.c b/pd/portaudio/pa_win/pa_win_util.c
new file mode 100644
index 00000000..f92d1e35
--- /dev/null
+++ b/pd/portaudio/pa_win/pa_win_util.c
@@ -0,0 +1,128 @@
+/*
+ * $Id: pa_win_util.c,v 1.1.2.5 2002/10/18 18:36:57 rossbencina Exp $
+ * Portable Audio I/O Library
+ * Win32 platform-specific support functions
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#include <windows.h>
+#include <mmsystem.h> /* for timeGetTime() */
+
+#include "pa_util.h"
+
+
+/*
+ Track memory allocations to avoid leaks.
+ */
+
+#if PA_TRACK_MEMORY
+static int numAllocations_ = 0;
+#endif
+
+
+void *PaUtil_AllocateMemory( long size )
+{
+ void *result = GlobalAlloc( GPTR, size );
+
+#if PA_TRACK_MEMORY
+ if( result != NULL ) numAllocations_ += 1;
+#endif
+ return result;
+}
+
+
+void PaUtil_FreeMemory( void *block )
+{
+ if( block != NULL )
+ {
+ GlobalFree( block );
+#if PA_TRACK_MEMORY
+ numAllocations_ -= 1;
+#endif
+
+ }
+}
+
+
+int PaUtil_CountCurrentlyAllocatedBlocks( void )
+{
+#if PA_TRACK_MEMORY
+ return numAllocations_;
+#else
+ return 0;
+#endif
+}
+
+
+void Pa_Sleep( long msec )
+{
+ Sleep( msec );
+}
+
+static int usePerformanceCounter_;
+static double secondsPerTick_;
+
+void PaUtil_InitializeClock( void )
+{
+ LARGE_INTEGER ticksPerSecond;
+
+ if( QueryPerformanceFrequency( &ticksPerSecond ) != 0 )
+ {
+ usePerformanceCounter_ = 1;
+ secondsPerTick_ = 1.0 / (double)ticksPerSecond.QuadPart;
+ }
+ else
+ {
+ usePerformanceCounter_ = 0;
+ }
+}
+
+
+double PaUtil_GetTime( void )
+{
+ LARGE_INTEGER time;
+
+ if( usePerformanceCounter_ )
+ {
+ /* FIXME:
+ according to this knowledge-base article, QueryPerformanceCounter
+ can skip forward by seconds!
+ http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323&
+
+ it may be better to use the rtdsc instruction using inline asm,
+ however then a method is needed to calculate a ticks/seconds ratio.
+ */
+ QueryPerformanceCounter( &time );
+ return time.QuadPart * secondsPerTick_;
+ }
+ else
+ {
+ return timeGetTime() * .001;
+ }
+}
diff --git a/pd/portaudio/pa_win/pa_x86_plain_converters.c b/pd/portaudio/pa_win/pa_x86_plain_converters.c
new file mode 100644
index 00000000..98442a8c
--- /dev/null
+++ b/pd/portaudio/pa_win/pa_x86_plain_converters.c
@@ -0,0 +1,1167 @@
+#include "pa_x86_plain_converters.h"
+
+#include "pa_converters.h"
+#include "pa_dither.h"
+
+/*
+ plain intel assemby versions of standard pa converter functions.
+
+ the main reason these versions are faster than the equivalent C versions
+ is that float -> int casting is expensive in C on x86 because the rounding
+ mode needs to be changed for every cast. these versions only set
+ the rounding mode once outside the loop.
+
+ small additional speed gains are made by the way that clamping is
+ implemented.
+
+TODO:
+ o- inline dither code
+ o- implement Dither only (no-clip) versions
+ o- implement int8 and uint8 versions
+ o- test thouroughly
+
+ o- the packed 24 bit functions could benefit from unrolling and avoiding
+ byte and word sized register access.
+*/
+
+/* -------------------------------------------------------------------------- */
+
+/*
+#define PA_CLIP_( val, min, max )\
+ { val = ((val) < (min)) ? (min) : (((val) > (max)) ? (max) : (val)); }
+*/
+
+/*
+ the following notes were used to determine whether a floating point
+ value should be saturated (ie >1 or <-1) by loading it into an integer
+ register. these should be rewritten so that they make sense.
+
+ an ieee floating point value
+
+ 1.xxxxxxxxxxxxxxxxxxxx?
+
+
+ is less than or equal to 1 and greater than or equal to -1 either:
+
+ if the mantissa is 0 and the unbiased exponent is 0
+
+ OR
+
+ if the unbiased exponent < 0
+
+ this translates to:
+
+ if the mantissa is 0 and the biased exponent is 7F
+
+ or
+
+ if the biased exponent is less than 7F
+
+
+ therefore the value is greater than 1 or less than -1 if
+
+ the mantissa is not 0 and the biased exponent is 7F
+
+ or
+
+ if the biased exponent is greater than 7F
+
+
+ in other words, if we mask out the sign bit, the value is
+ greater than 1 or less than -1 if its integer representation is greater than:
+
+ 0 01111111 0000 0000 0000 0000 0000 000
+
+ 0011 1111 1000 0000 0000 0000 0000 0000 => 0x3F800000
+*/
+
+/* -------------------------------------------------------------------------- */
+
+static const short fpuControlWord_ = 0x033F; /*round to nearest, 64 bit precision, all exceptions masked*/
+static const double int32Scaler_ = 0x7FFFFFFF;
+static const double ditheredInt32Scaler_ = 0x7FFFFFFE;
+static const double int24Scaler_ = 0x7FFFFF;
+static const double ditheredInt24Scaler_ = 0x7FFFFE;
+static const double int16Scaler_ = 0x7FFF;
+static const double ditheredInt16Scaler_ = 0x7FFE;
+
+#define PA_DITHER_BITS_ (15)
+/* Multiply by PA_FLOAT_DITHER_SCALE_ to get a float between -2.0 and +1.99999 */
+#define PA_FLOAT_DITHER_SCALE_ (1.0 / ((1<<PA_DITHER_BITS_)-1))
+static const float const_float_dither_scale_ = PA_FLOAT_DITHER_SCALE_;
+#define PA_DITHER_SHIFT_ ((32 - PA_DITHER_BITS_) + 1)
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void)ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+ // REVIEW
+ double scaled = *src * 0x7FFFFFFF;
+ *dest = (signed long) scaled;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ (void) ditherGenerator; /* unused parameter */
+
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32 and int32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int32Scaler_ // stack: (int)0x7FFFFFFF
+
+ Float32_To_Int32_loop:
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFFFFFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFFFF, (int)0x7FFFFFFF
+ /*
+ note: we could store to a temporary qword here which would cause
+ wraparound distortion instead of int indefinite 0x10. that would
+ be more work, and given that not enabling clipping is only advisable
+ when you know that your signal isn't going to clip it isn't worth it.
+ */
+ fistp dword ptr [edi] // pop st(0) into dest, stack: (int)0x7FFFFFFF
+
+ add edi, ebx // increment destination ptr
+ //lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int32_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+ (void) ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+ // REVIEW
+ double scaled = *src * 0x7FFFFFFF;
+ PA_CLIP_( scaled, -2147483648., 2147483647. );
+ *dest = (signed long) scaled;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32 and int32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int32Scaler_ // stack: (int)0x7FFFFFFF
+
+ Float32_To_Int32_Clip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int32_Clip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFFFFFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFFFF, (int)0x7FFFFFFF
+ fistp dword ptr [edi] // pop st(0) into dest, stack: (int)0x7FFFFFFF
+ jmp Float32_To_Int32_Clip_stored
+
+ Float32_To_Int32_Clip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add edx, 0x7FFFFFFF // convert to maximum range integers
+ mov dword ptr [edi], edx
+
+ Float32_To_Int32_Clip_stored:
+
+ //add edi, ebx // increment destination ptr
+ lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int32_Clip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int32_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+ /*
+ float *src = (float*)sourceBuffer;
+ signed long *dest = (signed long*)destinationBuffer;
+
+ while( count-- )
+ {
+ // REVIEW
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ // 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;
+
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+ */
+
+ short savedFpuControlWord;
+
+ // spill storage:
+ signed long sourceByteStride;
+ signed long highpassedDither;
+
+ // dither state:
+ unsigned long ditherPrevious = ditherGenerator->previous;
+ unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
+ unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32 and int32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld ditheredInt32Scaler_ // stack: int scaler
+
+ Float32_To_Int32_DitherClip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int32_DitherClip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, int scaler
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler
+
+ /*
+ // call PaUtil_GenerateFloatTriangularDither with C calling convention
+ mov sourceByteStride, eax // save eax
+ mov sourceEnd, ecx // save ecx
+ push ditherGenerator // pass ditherGenerator parameter on stack
+ call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler
+ pop edx // clear parameter off stack
+ mov ecx, sourceEnd // restore ecx
+ mov eax, sourceByteStride // restore eax
+ */
+
+ // generate dither
+ mov sourceByteStride, eax // save eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed1
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov ditherRandSeed1, eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed2
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov edx, ditherRandSeed1
+ shr edx, PA_DITHER_SHIFT_
+ mov ditherRandSeed2, eax
+ shr eax, PA_DITHER_SHIFT_
+ //add eax, edx // eax -> current
+ lea eax, [eax+edx]
+ mov edx, ditherPrevious
+ neg edx
+ lea edx, [eax+edx] // highpass = current - previous
+ mov highpassedDither, edx
+ mov ditherPrevious, eax // previous = current
+ mov eax, sourceByteStride // restore eax
+ fild highpassedDither
+ fmul const_float_dither_scale_
+ // end generate dither, dither signal in st(0)
+
+ faddp st(1), st(0) // stack: dither + value*(int scaler), int scaler
+ fistp dword ptr [edi] // pop st(0) into dest, stack: int scaler
+ jmp Float32_To_Int32_DitherClip_stored
+
+ Float32_To_Int32_DitherClip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add edx, 0x7FFFFFFF // convert to maximum range integers
+ mov dword ptr [edi], edx
+
+ Float32_To_Int32_DitherClip_stored:
+
+ //add edi, ebx // increment destination ptr
+ lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int32_DitherClip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+
+ ditherGenerator->previous = ditherPrevious;
+ ditherGenerator->randSeed1 = ditherRandSeed1;
+ ditherGenerator->randSeed2 = ditherRandSeed2;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ (void) ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+ // convert to 32 bit and drop the low 8 bits
+ double scaled = *src * 0x7FFFFFFF;
+ temp = (signed long) scaled;
+
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ signed long tempInt32;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov edx, 3 // sizeof int24
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int24Scaler_ // stack: (int)0x7FFFFF
+
+ Float32_To_Int24_loop:
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFFFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFF, (int)0x7FFFFF
+ fistp tempInt32 // pop st(0) into tempInt32, stack: (int)0x7FFFFF
+ mov edx, tempInt32
+
+ mov byte ptr [edi], DL
+ shr edx, 8
+ //mov byte ptr [edi+1], DL
+ //mov byte ptr [edi+2], DH
+ mov word ptr [edi+1], DX
+
+ //add edi, ebx // increment destination ptr
+ lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int24_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ (void) ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+ // convert to 32 bit and drop the low 8 bits
+ double scaled = *src * 0x7FFFFFFF;
+ PA_CLIP_( scaled, -2147483648., 2147483647. );
+ temp = (signed long) scaled;
+
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ signed long tempInt32;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov edx, 3 // sizeof int24
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int24Scaler_ // stack: (int)0x7FFFFF
+
+ Float32_To_Int24_Clip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int24_Clip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFFFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFFFF, (int)0x7FFFFF
+ fistp tempInt32 // pop st(0) into tempInt32, stack: (int)0x7FFFFF
+ mov edx, tempInt32
+ jmp Float32_To_Int24_Clip_store
+
+ Float32_To_Int24_Clip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add edx, 0x7FFFFF // convert to maximum range integers
+
+ Float32_To_Int24_Clip_store:
+
+ mov byte ptr [edi], DL
+ shr edx, 8
+ //mov byte ptr [edi+1], DL
+ //mov byte ptr [edi+2], DH
+ mov word ptr [edi+1], DX
+
+ //add edi, ebx // increment destination ptr
+ lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int24_Clip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int24_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ unsigned char *dest = (unsigned char*)destinationBuffer;
+ signed long temp;
+
+ while( count-- )
+ {
+ // convert to 32 bit and drop the low 8 bits
+
+ // FIXME: the dither amplitude here appears to be too small by 8 bits
+ double dither = PaUtil_GenerateFloatTriangularDither( ditherGenerator );
+ // use smaller scaler to prevent overflow when we add the dither
+ double dithered = ((double)*src * (2147483646.0)) + dither;
+ PA_CLIP_( dithered, -2147483648., 2147483647. );
+
+ temp = (signed long) dithered;
+
+ dest[0] = (unsigned char)(temp >> 8);
+ dest[1] = (unsigned char)(temp >> 16);
+ dest[2] = (unsigned char)(temp >> 24);
+
+ src += sourceStride;
+ dest += destinationStride * 3;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ // spill storage:
+ signed long sourceByteStride;
+ signed long highpassedDither;
+
+ // dither state:
+ unsigned long ditherPrevious = ditherGenerator->previous;
+ unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
+ unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
+
+ signed long tempInt32;
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi
+
+ mov edi, destinationBuffer
+
+ mov edx, 3 // sizeof int24
+ mov ebx, destinationStride
+ imul ebx, edx
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld ditheredInt24Scaler_ // stack: int scaler
+
+ Float32_To_Int24_DitherClip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int24_DitherClip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, int scaler
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler
+
+ /*
+ // call PaUtil_GenerateFloatTriangularDither with C calling convention
+ mov sourceByteStride, eax // save eax
+ mov sourceEnd, ecx // save ecx
+ push ditherGenerator // pass ditherGenerator parameter on stack
+ call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler
+ pop edx // clear parameter off stack
+ mov ecx, sourceEnd // restore ecx
+ mov eax, sourceByteStride // restore eax
+ */
+
+ // generate dither
+ mov sourceByteStride, eax // save eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed1
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov ditherRandSeed1, eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed2
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov edx, ditherRandSeed1
+ shr edx, PA_DITHER_SHIFT_
+ mov ditherRandSeed2, eax
+ shr eax, PA_DITHER_SHIFT_
+ //add eax, edx // eax -> current
+ lea eax, [eax+edx]
+ mov edx, ditherPrevious
+ neg edx
+ lea edx, [eax+edx] // highpass = current - previous
+ mov highpassedDither, edx
+ mov ditherPrevious, eax // previous = current
+ mov eax, sourceByteStride // restore eax
+ fild highpassedDither
+ fmul const_float_dither_scale_
+ // end generate dither, dither signal in st(0)
+
+ faddp st(1), st(0) // stack: dither * value*(int scaler), int scaler
+ fistp tempInt32 // pop st(0) into tempInt32, stack: int scaler
+ mov edx, tempInt32
+ jmp Float32_To_Int24_DitherClip_store
+
+ Float32_To_Int24_DitherClip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add edx, 0x7FFFFF // convert to maximum range integers
+
+ Float32_To_Int24_DitherClip_store:
+
+ mov byte ptr [edi], DL
+ shr edx, 8
+ //mov byte ptr [edi+1], DL
+ //mov byte ptr [edi+2], DH
+ mov word ptr [edi+1], DX
+
+ //add edi, ebx // increment destination ptr
+ lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int24_DitherClip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+
+ ditherGenerator->previous = ditherPrevious;
+ ditherGenerator->randSeed1 = ditherRandSeed1;
+ ditherGenerator->randSeed2 = ditherRandSeed2;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+
+ short samp = (short) (*src * (32767.0f));
+ *dest = samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx // source byte stride
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi // source end ptr = count * source byte stride + source ptr
+
+ mov edi, destinationBuffer
+
+ mov edx, 2 // sizeof int16
+ mov ebx, destinationStride
+ imul ebx, edx // destination byte stride
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int16Scaler_ // stack: (int)0x7FFF
+
+ Float32_To_Int16_loop:
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFF, (int)0x7FFF
+ fistp word ptr [edi] // store scaled int into dest, stack: (int)0x7FFF
+
+ add edi, ebx // increment destination ptr
+ //lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int16_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16_Clip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+ long samp = (signed long) (*src * (32767.0f));
+ PA_CLIP_( samp, -0x8000, 0x7FFF );
+ *dest = (signed short) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ (void) ditherGenerator; /* unused parameter */
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx // source byte stride
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi // source end ptr = count * source byte stride + source ptr
+
+ mov edi, destinationBuffer
+
+ mov edx, 2 // sizeof int16
+ mov ebx, destinationStride
+ imul ebx, edx // destination byte stride
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld int16Scaler_ // stack: (int)0x7FFF
+
+ Float32_To_Int16_Clip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int16_Clip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, (int)0x7FFF
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*0x7FFF, (int)0x7FFF
+ fistp word ptr [edi] // store scaled int into dest, stack: (int)0x7FFF
+ jmp Float32_To_Int16_Clip_stored
+
+ Float32_To_Int16_Clip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add dx, 0x7FFF // convert to maximum range integers
+ mov word ptr [edi], dx // store clamped into into dest
+
+ Float32_To_Int16_Clip_stored:
+
+ add edi, ebx // increment destination ptr
+ //lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int16_Clip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void Float32_To_Int16_DitherClip(
+ void *destinationBuffer, signed int destinationStride,
+ void *sourceBuffer, signed int sourceStride,
+ unsigned int count, PaUtilTriangularDitherGenerator *ditherGenerator )
+{
+/*
+ float *src = (float*)sourceBuffer;
+ signed short *dest = (signed short*)destinationBuffer;
+ (void)ditherGenerator; // unused parameter
+
+ while( count-- )
+ {
+
+ 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;
+ PA_CLIP_( samp, -0x8000, 0x7FFF );
+ *dest = (signed short) samp;
+
+ src += sourceStride;
+ dest += destinationStride;
+ }
+*/
+
+ short savedFpuControlWord;
+
+ // spill storage:
+ signed long sourceByteStride;
+ signed long highpassedDither;
+
+ // dither state:
+ unsigned long ditherPrevious = ditherGenerator->previous;
+ unsigned long ditherRandSeed1 = ditherGenerator->randSeed1;
+ unsigned long ditherRandSeed2 = ditherGenerator->randSeed2;
+
+ __asm{
+ // esi -> source ptr
+ // eax -> source byte stride
+ // edi -> destination ptr
+ // ebx -> destination byte stride
+ // ecx -> source end ptr
+ // edx -> temp
+
+ mov esi, sourceBuffer
+
+ mov edx, 4 // sizeof float32
+ mov eax, sourceStride
+ imul eax, edx // source byte stride
+
+ mov ecx, count
+ imul ecx, eax
+ add ecx, esi // source end ptr = count * source byte stride + source ptr
+
+ mov edi, destinationBuffer
+
+ mov edx, 2 // sizeof int16
+ mov ebx, destinationStride
+ imul ebx, edx // destination byte stride
+
+ fwait
+ fstcw savedFpuControlWord
+ fldcw fpuControlWord_
+
+ fld ditheredInt16Scaler_ // stack: int scaler
+
+ Float32_To_Int16_DitherClip_loop:
+
+ mov edx, dword ptr [esi] // load floating point value into integer register
+
+ and edx, 0x7FFFFFFF // mask off sign
+ cmp edx, 0x3F800000 // greater than 1.0 or less than -1.0
+
+ jg Float32_To_Int16_DitherClip_clamp
+
+ // load unscaled value into st(0)
+ fld dword ptr [esi] // stack: value, int scaler
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ fmul st(0), st(1) // st(0) *= st(1), stack: value*(int scaler), int scaler
+
+ /*
+ // call PaUtil_GenerateFloatTriangularDither with C calling convention
+ mov sourceByteStride, eax // save eax
+ mov sourceEnd, ecx // save ecx
+ push ditherGenerator // pass ditherGenerator parameter on stack
+ call PaUtil_GenerateFloatTriangularDither // stack: dither, value*(int scaler), int scaler
+ pop edx // clear parameter off stack
+ mov ecx, sourceEnd // restore ecx
+ mov eax, sourceByteStride // restore eax
+ */
+
+ // generate dither
+ mov sourceByteStride, eax // save eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed1
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov ditherRandSeed1, eax
+ mov edx, 196314165
+ mov eax, ditherRandSeed2
+ mul edx // eax:edx = eax * 196314165
+ //add eax, 907633515
+ lea eax, [eax+907633515]
+ mov edx, ditherRandSeed1
+ shr edx, PA_DITHER_SHIFT_
+ mov ditherRandSeed2, eax
+ shr eax, PA_DITHER_SHIFT_
+ //add eax, edx // eax -> current
+ lea eax, [eax+edx] // current = randSeed1>>x + randSeed2>>x
+ mov edx, ditherPrevious
+ neg edx
+ lea edx, [eax+edx] // highpass = current - previous
+ mov highpassedDither, edx
+ mov ditherPrevious, eax // previous = current
+ mov eax, sourceByteStride // restore eax
+ fild highpassedDither
+ fmul const_float_dither_scale_
+ // end generate dither, dither signal in st(0)
+
+ faddp st(1), st(0) // stack: dither * value*(int scaler), int scaler
+ fistp word ptr [edi] // store scaled int into dest, stack: int scaler
+ jmp Float32_To_Int16_DitherClip_stored
+
+ Float32_To_Int16_DitherClip_clamp:
+ mov edx, dword ptr [esi] // load floating point value into integer register
+ shr edx, 31 // move sign bit into bit 0
+ add esi, eax // increment source ptr
+ //lea esi, [esi+eax]
+ add dx, 0x7FFF // convert to maximum range integers
+ mov word ptr [edi], dx // store clamped into into dest
+
+ Float32_To_Int16_DitherClip_stored:
+
+ add edi, ebx // increment destination ptr
+ //lea edi, [edi+ebx]
+
+ cmp esi, ecx // has src ptr reached end?
+ jne Float32_To_Int16_DitherClip_loop
+
+ ffree st(0)
+ fincstp
+
+ fwait
+ fnclex
+ fldcw savedFpuControlWord
+ }
+
+ ditherGenerator->previous = ditherPrevious;
+ ditherGenerator->randSeed1 = ditherRandSeed1;
+ ditherGenerator->randSeed2 = ditherRandSeed2;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void PaUtil_InitializeX86PlainConverters( void )
+{
+ paConverters.Float32_To_Int32 = Float32_To_Int32;
+ paConverters.Float32_To_Int32_Clip = Float32_To_Int32_Clip;
+ paConverters.Float32_To_Int32_DitherClip = Float32_To_Int32_DitherClip;
+
+ paConverters.Float32_To_Int24 = Float32_To_Int24;
+ paConverters.Float32_To_Int24_Clip = Float32_To_Int24_Clip;
+ paConverters.Float32_To_Int24_DitherClip = Float32_To_Int24_DitherClip;
+
+ paConverters.Float32_To_Int16 = Float32_To_Int16;
+ paConverters.Float32_To_Int16_Clip = Float32_To_Int16_Clip;
+ paConverters.Float32_To_Int16_DitherClip = Float32_To_Int16_DitherClip;
+}
+
+/* -------------------------------------------------------------------------- */
diff --git a/pd/portaudio/pa_win/pa_x86_plain_converters.h b/pd/portaudio/pa_win/pa_x86_plain_converters.h
new file mode 100644
index 00000000..b93a291c
--- /dev/null
+++ b/pd/portaudio/pa_win/pa_x86_plain_converters.h
@@ -0,0 +1,19 @@
+#ifndef PA_X86_PLAIN_CONVERTERS_H
+#define PA_X86_PLAIN_CONVERTERS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+/**
+ Install optimised converter functions suitable for all IA32 processors
+*/
+void PaUtil_InitializeX86PlainConverters( void );
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_X86_PLAIN_CONVERTERS_H */
diff --git a/pd/portaudio/pa_win_ds/dsound_wrapper.c b/pd/portaudio/pa_win_ds/dsound_wrapper.c
new file mode 100644
index 00000000..ac8c927d
--- /dev/null
+++ b/pd/portaudio/pa_win_ds/dsound_wrapper.c
@@ -0,0 +1,604 @@
+/*
+ * $Id: dsound_wrapper.c,v 1.1.1.1.2.5 2002/07/01 00:49:41 philburk Exp $
+ * Simplified DirectSound interface.
+ *
+ * Author: Phil Burk & Robert Marsanyi
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * For more information see: http://www.softsynth.com/portaudio/
+ * DirectSound Implementation
+ * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#define INITGUID // Needed to build IID_IDirectSoundNotify. See objbase.h for info.
+#include <objbase.h>
+#include <unknwn.h>
+#include "dsound_wrapper.h"
+#include "pa_trace.h"
+
+/************************************************************************************/
+DSoundEntryPoints dswDSoundEntryPoints = { 0, 0, 0, 0, 0, 0, 0 };
+/************************************************************************************/
+static HRESULT WINAPI DummyDirectSoundCreate(LPGUID lpcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter)
+{
+ (void)lpcGuidDevice; /* unused parameter */
+ (void)ppDS; /* unused parameter */
+ (void)pUnkOuter; /* unused parameter */
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDirectSoundEnumerateW(LPDSENUMCALLBACKW lpDSEnumCallback, LPVOID lpContext)
+{
+ (void)lpDSEnumCallback; /* unused parameter */
+ (void)lpContext; /* unused parameter */
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDirectSoundEnumerateA(LPDSENUMCALLBACKA lpDSEnumCallback, LPVOID lpContext)
+{
+ (void)lpDSEnumCallback; /* unused parameter */
+ (void)lpContext; /* unused parameter */
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDirectSoundCaptureCreate(LPGUID lpcGUID, LPDIRECTSOUNDCAPTURE *lplpDSC, LPUNKNOWN pUnkOuter)
+{
+ (void)lpcGUID; /* unused parameter */
+ (void)lplpDSC; /* unused parameter */
+ (void)pUnkOuter; /* unused parameter */
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDirectSoundCaptureEnumerateW(LPDSENUMCALLBACKW lpDSCEnumCallback, LPVOID lpContext)
+{
+ (void)lpDSCEnumCallback; /* unused parameter */
+ (void)lpContext; /* unused parameter */
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI DummyDirectSoundCaptureEnumerateA(LPDSENUMCALLBACKA lpDSCEnumCallback, LPVOID lpContext)
+{
+ (void)lpDSCEnumCallback; /* unused parameter */
+ (void)lpContext; /* unused parameter */
+ return E_NOTIMPL;
+}
+/************************************************************************************/
+void DSW_InitializeDSoundEntryPoints(void)
+{
+ dswDSoundEntryPoints.hInstance_ = LoadLibrary("dsound.dll");
+ if( dswDSoundEntryPoints.hInstance_ != NULL )
+ {
+ dswDSoundEntryPoints.DirectSoundCreate =
+ (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCreate" );
+ if( dswDSoundEntryPoints.DirectSoundCreate == NULL )
+ dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
+
+ dswDSoundEntryPoints.DirectSoundEnumerateW =
+ (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundEnumerateW" );
+ if( dswDSoundEntryPoints.DirectSoundEnumerateW == NULL )
+ dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
+
+ dswDSoundEntryPoints.DirectSoundEnumerateA =
+ (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundEnumerateA" );
+ if( dswDSoundEntryPoints.DirectSoundEnumerateA == NULL )
+ dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
+
+ dswDSoundEntryPoints.DirectSoundCaptureCreate =
+ (HRESULT (WINAPI *)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureCreate" );
+ if( dswDSoundEntryPoints.DirectSoundCaptureCreate == NULL )
+ dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
+
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateW =
+ (HRESULT (WINAPI *)(LPDSENUMCALLBACKW, LPVOID))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateW" );
+ if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateW == NULL )
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
+
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateA =
+ (HRESULT (WINAPI *)(LPDSENUMCALLBACKA, LPVOID))
+ GetProcAddress( dswDSoundEntryPoints.hInstance_, "DirectSoundCaptureEnumerateA" );
+ if( dswDSoundEntryPoints.DirectSoundCaptureEnumerateA == NULL )
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
+ }
+ else
+ {
+ /* initialize with dummy entry points to make live easy when ds isn't present */
+ dswDSoundEntryPoints.DirectSoundCreate = DummyDirectSoundCreate;
+ dswDSoundEntryPoints.DirectSoundEnumerateW = DummyDirectSoundEnumerateW;
+ dswDSoundEntryPoints.DirectSoundEnumerateA = DummyDirectSoundEnumerateA;
+ dswDSoundEntryPoints.DirectSoundCaptureCreate = DummyDirectSoundCaptureCreate;
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = DummyDirectSoundCaptureEnumerateW;
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = DummyDirectSoundCaptureEnumerateA;
+ }
+}
+/************************************************************************************/
+void DSW_TerminateDSoundEntryPoints(void)
+{
+ if( dswDSoundEntryPoints.hInstance_ != NULL )
+ {
+ FreeLibrary( dswDSoundEntryPoints.hInstance_ );
+ dswDSoundEntryPoints.hInstance_ = NULL;
+ /* ensure that we crash reliably if the entry points arent initialised */
+ dswDSoundEntryPoints.DirectSoundCreate = 0;
+ dswDSoundEntryPoints.DirectSoundEnumerateW = 0;
+ dswDSoundEntryPoints.DirectSoundEnumerateA = 0;
+ dswDSoundEntryPoints.DirectSoundCaptureCreate = 0;
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateW = 0;
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerateA = 0;
+ }
+}
+/************************************************************************************/
+void DSW_Term( DSoundWrapper *dsw )
+{
+ // Cleanup the sound buffers
+ if (dsw->dsw_OutputBuffer)
+ {
+ IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
+ IDirectSoundBuffer_Release( dsw->dsw_OutputBuffer );
+ dsw->dsw_OutputBuffer = NULL;
+ }
+
+ if (dsw->dsw_InputBuffer)
+ {
+ IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
+ IDirectSoundCaptureBuffer_Release( dsw->dsw_InputBuffer );
+ dsw->dsw_InputBuffer = NULL;
+ }
+
+ if (dsw->dsw_pDirectSoundCapture)
+ {
+ IDirectSoundCapture_Release( dsw->dsw_pDirectSoundCapture );
+ dsw->dsw_pDirectSoundCapture = NULL;
+ }
+
+ if (dsw->dsw_pDirectSound)
+ {
+ IDirectSound_Release( dsw->dsw_pDirectSound );
+ dsw->dsw_pDirectSound = NULL;
+ }
+}
+/************************************************************************************/
+HRESULT DSW_Init( DSoundWrapper *dsw )
+{
+ memset( dsw, 0, sizeof(DSoundWrapper) );
+ return 0;
+}
+/************************************************************************************/
+HRESULT DSW_InitOutputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
+{
+ // Create the DS object
+ HRESULT hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &dsw->dsw_pDirectSound, NULL );
+ if( hr != DS_OK ) return hr;
+ return hr;
+}
+
+/************************************************************************************/
+HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bytesPerBuffer )
+{
+ DWORD dwDataLen;
+ DWORD playCursor;
+ HRESULT result;
+ LPDIRECTSOUNDBUFFER pPrimaryBuffer;
+ HWND hWnd;
+ HRESULT hr;
+ WAVEFORMATEX wfFormat;
+ DSBUFFERDESC primaryDesc;
+ DSBUFFERDESC secondaryDesc;
+ unsigned char* pDSBuffData;
+ LARGE_INTEGER counterFrequency;
+
+ dsw->dsw_OutputSize = bytesPerBuffer;
+ dsw->dsw_OutputRunning = FALSE;
+ dsw->dsw_OutputUnderflows = 0;
+ dsw->dsw_FramesWritten = 0;
+ dsw->dsw_BytesPerOutputFrame = nChannels * sizeof(short);
+
+ // We were using getForegroundWindow() but sometimes the ForegroundWindow may not be the
+ // applications's window. Also if that window is closed before the Buffer is closed
+ // then DirectSound can crash. (Thanks for Scott Patterson for reporting this.)
+ // So we will use GetDesktopWindow() which was suggested by Miller Puckette.
+ // hWnd = GetForegroundWindow();
+ hWnd = GetDesktopWindow();
+
+ // Set cooperative level to DSSCL_EXCLUSIVE so that we can get 16 bit output, 44.1 KHz.
+ // Exclusize also prevents unexpected sounds from other apps during a performance.
+ if ((hr = IDirectSound_SetCooperativeLevel( dsw->dsw_pDirectSound,
+ hWnd, DSSCL_EXCLUSIVE)) != DS_OK)
+ {
+ return hr;
+ }
+
+ // -----------------------------------------------------------------------
+ // Create primary buffer and set format just so we can specify our custom format.
+ // Otherwise we would be stuck with the default which might be 8 bit or 22050 Hz.
+ // Setup the primary buffer description
+ ZeroMemory(&primaryDesc, sizeof(DSBUFFERDESC));
+ primaryDesc.dwSize = sizeof(DSBUFFERDESC);
+ primaryDesc.dwFlags = DSBCAPS_PRIMARYBUFFER; // all panning, mixing, etc done by synth
+ primaryDesc.dwBufferBytes = 0;
+ primaryDesc.lpwfxFormat = NULL;
+ // Create the buffer
+ if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,
+ &primaryDesc, &pPrimaryBuffer, NULL)) != DS_OK) return result;
+ // Define the buffer format
+ wfFormat.wFormatTag = WAVE_FORMAT_PCM;
+ wfFormat.nChannels = nChannels;
+ wfFormat.nSamplesPerSec = nFrameRate;
+ wfFormat.wBitsPerSample = 8 * sizeof(short);
+ wfFormat.nBlockAlign = wfFormat.nChannels * wfFormat.wBitsPerSample / 8;
+ wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
+ wfFormat.cbSize = 0; /* No extended format info. */
+ // Set the primary buffer's format
+ if((result = IDirectSoundBuffer_SetFormat( pPrimaryBuffer, &wfFormat)) != DS_OK) return result;
+
+ // ----------------------------------------------------------------------
+ // Setup the secondary buffer description
+ ZeroMemory(&secondaryDesc, sizeof(DSBUFFERDESC));
+ secondaryDesc.dwSize = sizeof(DSBUFFERDESC);
+ secondaryDesc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
+ secondaryDesc.dwBufferBytes = bytesPerBuffer;
+ secondaryDesc.lpwfxFormat = &wfFormat;
+ // Create the secondary buffer
+ if ((result = IDirectSound_CreateSoundBuffer( dsw->dsw_pDirectSound,
+ &secondaryDesc, &dsw->dsw_OutputBuffer, NULL)) != DS_OK) return result;
+ // Lock the DS buffer
+ if ((result = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, 0, dsw->dsw_OutputSize, (LPVOID*)&pDSBuffData,
+ &dwDataLen, NULL, 0, 0)) != DS_OK) return result;
+ // Zero the DS buffer
+ ZeroMemory(pDSBuffData, dwDataLen);
+ // Unlock the DS buffer
+ if ((result = IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, pDSBuffData, dwDataLen, NULL, 0)) != DS_OK) return result;
+ if( QueryPerformanceFrequency( &counterFrequency ) )
+ {
+ int framesInBuffer = bytesPerBuffer / (nChannels * sizeof(short));
+ dsw->dsw_CounterTicksPerBuffer.QuadPart = (counterFrequency.QuadPart * framesInBuffer) / nFrameRate;
+ }
+ else
+ {
+ dsw->dsw_CounterTicksPerBuffer.QuadPart = 0;
+ }
+ // Let DSound set the starting write position because if we set it to zero, it looks like the
+ // buffer is full to begin with. This causes a long pause before sound starts when using large buffers.
+ hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &dsw->dsw_WriteOffset );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ dsw->dsw_FramesWritten = dsw->dsw_WriteOffset / dsw->dsw_BytesPerOutputFrame;
+ /* printf("DSW_InitOutputBuffer: playCursor = %d, writeCursor = %d\n", playCursor, dsw->dsw_WriteOffset ); */
+ return DS_OK;
+}
+
+/************************************************************************************/
+HRESULT DSW_StartOutput( DSoundWrapper *dsw )
+{
+ HRESULT hr;
+ QueryPerformanceCounter( &dsw->dsw_LastPlayTime );
+ dsw->dsw_LastPlayCursor = 0;
+ dsw->dsw_FramesPlayed = 0;
+ hr = IDirectSoundBuffer_SetCurrentPosition( dsw->dsw_OutputBuffer, 0 );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ // Start the buffer playback in a loop.
+ if( dsw->dsw_OutputBuffer != NULL )
+ {
+ hr = IDirectSoundBuffer_Play( dsw->dsw_OutputBuffer, 0, 0, DSBPLAY_LOOPING );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ dsw->dsw_OutputRunning = TRUE;
+ }
+
+ return 0;
+}
+/************************************************************************************/
+HRESULT DSW_StopOutput( DSoundWrapper *dsw )
+{
+ // Stop the buffer playback
+ if( dsw->dsw_OutputBuffer != NULL )
+ {
+ dsw->dsw_OutputRunning = FALSE;
+ return IDirectSoundBuffer_Stop( dsw->dsw_OutputBuffer );
+ }
+ else return 0;
+}
+
+/************************************************************************************/
+HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilledPtr )
+{
+ HRESULT hr;
+ DWORD playCursor;
+ DWORD writeCursor;
+ long bytesFilled;
+ // Query to see where play position is.
+ // We don't need the writeCursor but sometimes DirectSound doesn't handle NULLS correctly
+ // so let's pass a pointer just to be safe.
+ hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ bytesFilled = dsw->dsw_WriteOffset - playCursor;
+ if( bytesFilled < 0 ) bytesFilled += dsw->dsw_OutputSize; // unwrap offset
+ *bytesFilledPtr = bytesFilled;
+ return hr;
+}
+
+/************************************************************************************
+ * Determine how much space can be safely written to in DS buffer.
+ * Detect underflows and overflows.
+ * Does not allow writing into safety gap maintained by DirectSound.
+ */
+HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty )
+{
+ HRESULT hr;
+ DWORD playCursor;
+ DWORD writeCursor;
+ long numBytesEmpty;
+ long playWriteGap;
+ // Query to see how much room is in buffer.
+ hr = IDirectSoundBuffer_GetCurrentPosition( dsw->dsw_OutputBuffer, &playCursor, &writeCursor );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ // Determine size of gap between playIndex and WriteIndex that we cannot write into.
+ playWriteGap = writeCursor - playCursor;
+ if( playWriteGap < 0 ) playWriteGap += dsw->dsw_OutputSize; // unwrap
+ /* DirectSound doesn't have a large enough playCursor so we cannot detect wrap-around. */
+ /* Attempt to detect playCursor wrap-around and correct it. */
+ if( dsw->dsw_OutputRunning && (dsw->dsw_CounterTicksPerBuffer.QuadPart != 0) )
+ {
+ /* How much time has elapsed since last check. */
+ LARGE_INTEGER currentTime;
+ LARGE_INTEGER elapsedTime;
+ long bytesPlayed;
+ long bytesExpected;
+ long buffersWrapped;
+ QueryPerformanceCounter( &currentTime );
+ elapsedTime.QuadPart = currentTime.QuadPart - dsw->dsw_LastPlayTime.QuadPart;
+ dsw->dsw_LastPlayTime = currentTime;
+ /* How many bytes does DirectSound say have been played. */
+ bytesPlayed = playCursor - dsw->dsw_LastPlayCursor;
+ if( bytesPlayed < 0 ) bytesPlayed += dsw->dsw_OutputSize; // unwrap
+ dsw->dsw_LastPlayCursor = playCursor;
+ /* Calculate how many bytes we would have expected to been played by now. */
+ bytesExpected = (long) ((elapsedTime.QuadPart * dsw->dsw_OutputSize) / dsw->dsw_CounterTicksPerBuffer.QuadPart);
+ buffersWrapped = (bytesExpected - bytesPlayed) / dsw->dsw_OutputSize;
+ if( buffersWrapped > 0 )
+ {
+ playCursor += (buffersWrapped * dsw->dsw_OutputSize);
+ bytesPlayed += (buffersWrapped * dsw->dsw_OutputSize);
+ }
+ /* Maintain frame output cursor. */
+ dsw->dsw_FramesPlayed += (bytesPlayed / dsw->dsw_BytesPerOutputFrame);
+ }
+ numBytesEmpty = playCursor - dsw->dsw_WriteOffset;
+ if( numBytesEmpty < 0 ) numBytesEmpty += dsw->dsw_OutputSize; // unwrap offset
+ /* Have we underflowed? */
+ if( numBytesEmpty > (dsw->dsw_OutputSize - playWriteGap) )
+ {
+ if( dsw->dsw_OutputRunning )
+ {
+ dsw->dsw_OutputUnderflows += 1;
+ }
+ dsw->dsw_WriteOffset = writeCursor;
+ numBytesEmpty = dsw->dsw_OutputSize - playWriteGap;
+ }
+ *bytesEmpty = numBytesEmpty;
+ return hr;
+}
+
+/************************************************************************************/
+HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw )
+{
+ HRESULT hr;
+ LPBYTE lpbuf1 = NULL;
+ LPBYTE lpbuf2 = NULL;
+ DWORD dwsize1 = 0;
+ DWORD dwsize2 = 0;
+ long bytesEmpty;
+ hr = DSW_QueryOutputSpace( dsw, &bytesEmpty ); // updates dsw_FramesPlayed
+ if (hr != DS_OK) return hr;
+ if( bytesEmpty == 0 ) return DS_OK;
+ // Lock free space in the DS
+ hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, bytesEmpty, (void **) &lpbuf1, &dwsize1,
+ (void **) &lpbuf2, &dwsize2, 0);
+ if (hr == DS_OK)
+ {
+ // Copy the buffer into the DS
+ ZeroMemory(lpbuf1, dwsize1);
+ if(lpbuf2 != NULL)
+ {
+ ZeroMemory(lpbuf2, dwsize2);
+ }
+ // Update our buffer offset and unlock sound buffer
+ dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
+ IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
+ dsw->dsw_FramesWritten += bytesEmpty / dsw->dsw_BytesPerOutputFrame;
+ }
+ return hr;
+}
+
+/************************************************************************************/
+HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes )
+{
+ HRESULT hr;
+ LPBYTE lpbuf1 = NULL;
+ LPBYTE lpbuf2 = NULL;
+ DWORD dwsize1 = 0;
+ DWORD dwsize2 = 0;
+ // Lock free space in the DS
+ hr = IDirectSoundBuffer_Lock( dsw->dsw_OutputBuffer, dsw->dsw_WriteOffset, numBytes, (void **) &lpbuf1, &dwsize1,
+ (void **) &lpbuf2, &dwsize2, 0);
+ if (hr == DS_OK)
+ {
+ // Copy the buffer into the DS
+ CopyMemory(lpbuf1, buf, dwsize1);
+ if(lpbuf2 != NULL)
+ {
+ CopyMemory(lpbuf2, buf+dwsize1, dwsize2);
+ }
+ // Update our buffer offset and unlock sound buffer
+ dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + dwsize1 + dwsize2) % dsw->dsw_OutputSize;
+ IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
+ dsw->dsw_FramesWritten += numBytes / dsw->dsw_BytesPerOutputFrame;
+ }
+ return hr;
+}
+
+/************************************************************************************/
+DWORD DSW_GetOutputStatus( DSoundWrapper *dsw )
+{
+ DWORD status;
+ if (IDirectSoundBuffer_GetStatus( dsw->dsw_OutputBuffer, &status ) != DS_OK)
+ return( DSERR_INVALIDPARAM );
+ else
+ return( status );
+}
+
+/* These routines are used to support audio input.
+ * Do NOT compile these calls when using NT4 because it does
+ * not support the entry points.
+ */
+/************************************************************************************/
+HRESULT DSW_InitInputDevice( DSoundWrapper *dsw, LPGUID lpGUID )
+{
+ HRESULT hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &dsw->dsw_pDirectSoundCapture, NULL );
+ if( hr != DS_OK ) return hr;
+ return hr;
+}
+/************************************************************************************/
+HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate, int nChannels, int bytesPerBuffer )
+{
+ DSCBUFFERDESC captureDesc;
+ WAVEFORMATEX wfFormat;
+ HRESULT result;
+
+ dsw->dsw_BytesPerInputFrame = nChannels * sizeof(short);
+
+ // Define the buffer format
+ wfFormat.wFormatTag = WAVE_FORMAT_PCM;
+ wfFormat.nChannels = nChannels;
+ wfFormat.nSamplesPerSec = nFrameRate;
+ wfFormat.wBitsPerSample = 8 * sizeof(short);
+ wfFormat.nBlockAlign = wfFormat.nChannels * (wfFormat.wBitsPerSample / 8);
+ wfFormat.nAvgBytesPerSec = wfFormat.nSamplesPerSec * wfFormat.nBlockAlign;
+ wfFormat.cbSize = 0; /* No extended format info. */
+ dsw->dsw_InputSize = bytesPerBuffer;
+ // ----------------------------------------------------------------------
+ // Setup the secondary buffer description
+ ZeroMemory(&captureDesc, sizeof(DSCBUFFERDESC));
+ captureDesc.dwSize = sizeof(DSCBUFFERDESC);
+ captureDesc.dwFlags = 0;
+ captureDesc.dwBufferBytes = bytesPerBuffer;
+ captureDesc.lpwfxFormat = &wfFormat;
+ // Create the capture buffer
+ if ((result = IDirectSoundCapture_CreateCaptureBuffer( dsw->dsw_pDirectSoundCapture,
+ &captureDesc, &dsw->dsw_InputBuffer, NULL)) != DS_OK) return result;
+ dsw->dsw_ReadOffset = 0; // reset last read position to start of buffer
+ return DS_OK;
+}
+
+/************************************************************************************/
+HRESULT DSW_StartInput( DSoundWrapper *dsw )
+{
+ // Start the buffer playback
+ if( dsw->dsw_InputBuffer != NULL )
+ {
+ return IDirectSoundCaptureBuffer_Start( dsw->dsw_InputBuffer, DSCBSTART_LOOPING );
+ }
+ else return 0;
+}
+
+/************************************************************************************/
+HRESULT DSW_StopInput( DSoundWrapper *dsw )
+{
+ // Stop the buffer playback
+ if( dsw->dsw_InputBuffer != NULL )
+ {
+ return IDirectSoundCaptureBuffer_Stop( dsw->dsw_InputBuffer );
+ }
+ else return 0;
+}
+
+/************************************************************************************/
+HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled )
+{
+ HRESULT hr;
+ DWORD capturePos;
+ DWORD readPos;
+ long filled;
+ // Query to see how much data is in buffer.
+ // We don't need the capture position but sometimes DirectSound doesn't handle NULLS correctly
+ // so let's pass a pointer just to be safe.
+ hr = IDirectSoundCaptureBuffer_GetCurrentPosition( dsw->dsw_InputBuffer, &capturePos, &readPos );
+ if( hr != DS_OK )
+ {
+ return hr;
+ }
+ filled = readPos - dsw->dsw_ReadOffset;
+ if( filled < 0 ) filled += dsw->dsw_InputSize; // unwrap offset
+ *bytesFilled = filled;
+ return hr;
+}
+
+/************************************************************************************/
+HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes )
+{
+ HRESULT hr;
+ LPBYTE lpbuf1 = NULL;
+ LPBYTE lpbuf2 = NULL;
+ DWORD dwsize1 = 0;
+ DWORD dwsize2 = 0;
+ // Lock free space in the DS
+ hr = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer, dsw->dsw_ReadOffset, numBytes, (void **) &lpbuf1, &dwsize1,
+ (void **) &lpbuf2, &dwsize2, 0);
+ if (hr == DS_OK)
+ {
+ // Copy from DS to the buffer
+ CopyMemory( buf, lpbuf1, dwsize1);
+ if(lpbuf2 != NULL)
+ {
+ CopyMemory( buf+dwsize1, lpbuf2, dwsize2);
+ }
+ // Update our buffer offset and unlock sound buffer
+ dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + dwsize1 + dwsize2) % dsw->dsw_InputSize;
+ IDirectSoundCaptureBuffer_Unlock ( dsw->dsw_InputBuffer, lpbuf1, dwsize1, lpbuf2, dwsize2);
+ }
+ return hr;
+}
+
diff --git a/pd/portaudio/pa_win_ds/dsound_wrapper.h b/pd/portaudio/pa_win_ds/dsound_wrapper.h
new file mode 100644
index 00000000..e9ce4c6b
--- /dev/null
+++ b/pd/portaudio/pa_win_ds/dsound_wrapper.h
@@ -0,0 +1,129 @@
+#ifndef __DSOUND_WRAPPER_H
+#define __DSOUND_WRAPPER_H
+/*
+ * $Id: dsound_wrapper.h,v 1.1.1.1.2.5 2002/07/03 01:43:56 rossbencina Exp $
+ * Simplified DirectSound interface.
+ *
+ * Author: Phil Burk & Robert Marsanyi
+ *
+ * For PortAudio Portable Real-Time Audio Library
+ * For more information see: http://www.softsynth.com/portaudio/
+ * DirectSound Implementation
+ * Copyright (c) 1999-2000 Phil Burk & Robert Marsanyi
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* on Borland compilers, WIN32 doesn't seem to be defined by default, which
+ breaks DSound.h. Adding the define here fixes the problem. - rossb. */
+#ifdef __BORLANDC__
+#if !defined(WIN32)
+#define WIN32
+#endif
+#endif
+
+#include <DSound.h>
+#if !defined(BOOL)
+#define BOOL short
+#endif
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+typedef struct
+{
+ HINSTANCE hInstance_;
+
+ HRESULT (WINAPI *DirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
+ HRESULT (WINAPI *DirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
+ HRESULT (WINAPI *DirectSoundEnumerateA)(LPDSENUMCALLBACKA, LPVOID);
+
+ HRESULT (WINAPI *DirectSoundCaptureCreate)(LPGUID, LPDIRECTSOUNDCAPTURE *, LPUNKNOWN);
+ HRESULT (WINAPI *DirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID);
+ HRESULT (WINAPI *DirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA, LPVOID);
+}DSoundEntryPoints;
+
+extern DSoundEntryPoints dswDSoundEntryPoints;
+
+void DSW_InitializeDSoundEntryPoints(void);
+void DSW_TerminateDSoundEntryPoints(void);
+
+#define DSW_NUM_POSITIONS (4)
+#define DSW_NUM_EVENTS (5)
+#define DSW_TERMINATION_EVENT (DSW_NUM_POSITIONS)
+
+typedef struct
+{
+/* Output */
+ LPDIRECTSOUND dsw_pDirectSound;
+ LPDIRECTSOUNDBUFFER dsw_OutputBuffer;
+ DWORD dsw_WriteOffset; /* last write position */
+ INT dsw_OutputSize;
+ INT dsw_BytesPerOutputFrame;
+ /* Try to detect play buffer underflows. */
+ LARGE_INTEGER dsw_CounterTicksPerBuffer; /* counter ticks it should take to play a full buffer */
+ LARGE_INTEGER dsw_LastPlayTime;
+ UINT dsw_LastPlayCursor;
+ UINT dsw_OutputUnderflows;
+ BOOL dsw_OutputRunning;
+ /* use double which lets us can play for several thousand years with enough precision */
+ double dsw_FramesWritten;
+ double dsw_FramesPlayed;
+/* Input */
+ INT dsw_BytesPerInputFrame;
+ LPDIRECTSOUNDCAPTURE dsw_pDirectSoundCapture;
+ LPDIRECTSOUNDCAPTUREBUFFER dsw_InputBuffer;
+ UINT dsw_ReadOffset; /* last read position */
+ UINT dsw_InputSize;
+} DSoundWrapper;
+
+HRESULT DSW_Init( DSoundWrapper *dsw );
+void DSW_Term( DSoundWrapper *dsw );
+HRESULT DSW_InitOutputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate,
+ int nChannels, int bufSize );
+HRESULT DSW_StartOutput( DSoundWrapper *dsw );
+HRESULT DSW_StopOutput( DSoundWrapper *dsw );
+DWORD DSW_GetOutputStatus( DSoundWrapper *dsw );
+HRESULT DSW_WriteBlock( DSoundWrapper *dsw, char *buf, long numBytes );
+HRESULT DSW_ZeroEmptySpace( DSoundWrapper *dsw );
+HRESULT DSW_QueryOutputSpace( DSoundWrapper *dsw, long *bytesEmpty );
+HRESULT DSW_Enumerate( DSoundWrapper *dsw );
+
+HRESULT DSW_InitInputBuffer( DSoundWrapper *dsw, unsigned long nFrameRate,
+ int nChannels, int bufSize );
+HRESULT DSW_StartInput( DSoundWrapper *dsw );
+HRESULT DSW_StopInput( DSoundWrapper *dsw );
+HRESULT DSW_ReadBlock( DSoundWrapper *dsw, char *buf, long numBytes );
+HRESULT DSW_QueryInputFilled( DSoundWrapper *dsw, long *bytesFilled );
+HRESULT DSW_QueryOutputFilled( DSoundWrapper *dsw, long *bytesFilled );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __DSOUND_WRAPPER_H */
diff --git a/pd/portaudio/pa_win_ds/pa_dsound.c b/pd/portaudio/pa_win_ds/pa_dsound.c
new file mode 100644
index 00000000..8fa343cf
--- /dev/null
+++ b/pd/portaudio/pa_win_ds/pa_dsound.c
@@ -0,0 +1,1021 @@
+/*
+ * $Id: pa_dsound.c,v 1.1.1.1 2003-05-09 16:03:58 ggeiger Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.softsynth.com/portaudio/
+ * DirectSound Implementation
+ *
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+/* Modifications
+ * 7/19/01 Mike Berry - casts for compiling with __MWERKS__ CodeWarrior
+ * 9/27/01 Phil Burk - use number of frames instead of real-time for CPULoad calculation.
+ * 4/19/02 Phil Burk - Check for Win XP for system latency calculation.
+ */
+/* Compiler flags:
+ SUPPORT_AUDIO_CAPTURE - define this flag if you want to SUPPORT_AUDIO_CAPTURE
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef __MWERKS__
+#include <malloc.h>
+#include <memory.h>
+#endif //__MWERKS__
+#include <math.h>
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+#include "dsound_wrapper.h"
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+#define PA_USE_HIGH_LATENCY (0)
+#if PA_USE_HIGH_LATENCY
+#define PA_WIN_9X_LATENCY (500)
+#define PA_WIN_NT_LATENCY (600)
+#else
+#define PA_WIN_9X_LATENCY (140)
+#define PA_WIN_NT_LATENCY (280)
+#endif
+
+#define PA_WIN_WDM_LATENCY (120)
+
+/* Trigger an underflow for testing purposes. Should normally be (0). */
+#define PA_SIMULATE_UNDERFLOW (0)
+#if PA_SIMULATE_UNDERFLOW
+static gUnderCallbackCounter = 0;
+#define UNDER_START_GAP (10)
+#define UNDER_STOP_GAP (UNDER_START_GAP + 4)
+#endif
+
+/************************************************* Definitions ********/
+typedef struct internalPortAudioStream internalPortAudioStream;
+typedef struct internalPortAudioDevice
+{
+ GUID pad_GUID;
+ GUID *pad_lpGUID;
+ double pad_SampleRates[10]; /* for pointing to from pad_Info FIXME?!*/
+ PaDeviceInfo pad_Info;
+}
+internalPortAudioDevice;
+
+/* Define structure to contain all DirectSound and Windows specific data. */
+typedef struct PaHostSoundControl
+{
+ DSoundWrapper pahsc_DSoundWrapper;
+ MMRESULT pahsc_TimerID;
+ BOOL pahsc_IfInsideCallback; /* Test for reentrancy. */
+ short *pahsc_NativeBuffer;
+ unsigned int pahsc_BytesPerBuffer; /* native buffer size in bytes */
+ double pahsc_ValidFramesWritten;
+ int pahsc_FramesPerDSBuffer;
+ /* For measuring CPU utilization. */
+ LARGE_INTEGER pahsc_EntryCount;
+ double pahsc_InverseTicksPerUserBuffer;
+}
+PaHostSoundControl;
+
+/************************************************* Shared Data ********/
+/* FIXME - put Mutex around this shared data. */
+static int sNumDevices = 0;
+static int sDeviceIndex = 0;
+static internalPortAudioDevice *sDevices = NULL;
+static int sDefaultInputDeviceID = paNoDevice;
+static int sDefaultOutputDeviceID = paNoDevice;
+static int sEnumerationError;
+static int sPaHostError = 0;
+/************************************************* Prototypes **********/
+static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id );
+static BOOL CALLBACK Pa_EnumProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext );
+static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext );
+static Pa_QueryDevices( void );
+static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg,
+ DWORD dwUser, DWORD dw1, DWORD dw2);
+
+/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
+static void Pa_StartUsageCalculation( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+ /* Query system timer for usage analysis and to prevent overuse of CPU. */
+ QueryPerformanceCounter( &pahsc->pahsc_EntryCount );
+}
+
+static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+{
+ LARGE_INTEGER CurrentCount = { 0, 0 };
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+ /*
+ ** Measure CPU utilization during this callback. Note that this calculation
+ ** assumes that we had the processor the whole time.
+ */
+#define LOWPASS_COEFFICIENT_0 (0.9)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+ if( QueryPerformanceCounter( &CurrentCount ) )
+ {
+ LONGLONG InsideCount = CurrentCount.QuadPart - pahsc->pahsc_EntryCount.QuadPart;
+ double newUsage = InsideCount * pahsc->pahsc_InverseTicksPerUserBuffer;
+ past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
+ (LOWPASS_COEFFICIENT_1 * newUsage);
+ }
+}
+
+/****************************************** END CPU UTILIZATION *******/
+static PaError Pa_QueryDevices( void )
+{
+ int numBytes;
+ sDefaultInputDeviceID = paNoDevice;
+ sDefaultOutputDeviceID = paNoDevice;
+ /* Enumerate once just to count devices. */
+ sNumDevices = 0; // for default device
+ DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, NULL );
+#if SUPPORT_AUDIO_CAPTURE
+ DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, NULL );
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ /* Allocate structures to hold device info. */
+ numBytes = sNumDevices * sizeof(internalPortAudioDevice);
+ sDevices = (internalPortAudioDevice *)PaHost_AllocateFastMemory( numBytes ); /* MEM */
+ if( sDevices == NULL ) return paInsufficientMemory;
+ /* Enumerate again to fill in structures. */
+ sDeviceIndex = 0;
+ sEnumerationError = 0;
+ DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_EnumProc, (void *)0 );
+#if SUPPORT_AUDIO_CAPTURE
+ if( sEnumerationError != paNoError ) return sEnumerationError;
+ sEnumerationError = 0;
+ DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_EnumProc, (void *)1 );
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ return sEnumerationError;
+}
+/************************************************************************************/
+long Pa_GetHostError()
+{
+ return sPaHostError;
+}
+/************************************************************************************
+** Just count devices so we know how much memory to allocate.
+*/
+static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext )
+{
+ sNumDevices++;
+ return TRUE;
+}
+/************************************************************************************
+** Extract capabilities info from each device.
+*/
+static BOOL CALLBACK Pa_EnumProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext )
+{
+ HRESULT hr;
+ LPDIRECTSOUND lpDirectSound;
+#if SUPPORT_AUDIO_CAPTURE
+ LPDIRECTSOUNDCAPTURE lpDirectSoundCapture;
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ int isInput = (int) lpContext; /* Passed from Pa_CountDevices() */
+ internalPortAudioDevice *pad;
+
+ if( sDeviceIndex >= sNumDevices )
+ {
+ sEnumerationError = paInternalError;
+ return FALSE;
+ }
+ pad = &sDevices[sDeviceIndex];
+ /* Copy GUID to static array. Set pointer. */
+ if( lpGUID == NULL )
+ {
+ pad->pad_lpGUID = NULL;
+ }
+ else
+ {
+ memcpy( &pad->pad_GUID, lpGUID, sizeof(GUID) );
+ pad->pad_lpGUID = &pad->pad_GUID;
+ }
+ pad->pad_Info.sampleRates = pad->pad_SampleRates; /* Point to array. */
+ /* Allocate room for descriptive name. */
+ if( lpszDesc != NULL )
+ {
+ int len = strlen(lpszDesc);
+ pad->pad_Info.name = (char *)malloc( len+1 );
+ if( pad->pad_Info.name == NULL )
+ {
+ sEnumerationError = paInsufficientMemory;
+ return FALSE;
+ }
+ memcpy( (void *) pad->pad_Info.name, lpszDesc, len+1 );
+ }
+#if SUPPORT_AUDIO_CAPTURE
+ if( isInput )
+ {
+ /********** Input ******************************/
+ DSCCAPS caps;
+ if( lpGUID == NULL ) sDefaultInputDeviceID = sDeviceIndex;
+ hr = DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL );
+ if( hr != DS_OK )
+ {
+ pad->pad_Info.maxInputChannels = 0;
+ DBUG(("Cannot create Capture for %s. Result = 0x%x\n", lpszDesc, hr ));
+ }
+ else
+ {
+ /* Query device characteristics. */
+ caps.dwSize = sizeof(caps);
+ IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps );
+ /* printf("caps.dwFormats = 0x%x\n", caps.dwFormats ); */
+ pad->pad_Info.maxInputChannels = caps.dwChannels;
+ /* Determine sample rates from flags. */
+ if( caps.dwChannels == 2 )
+ {
+ int index = 0;
+ if( caps.dwFormats & WAVE_FORMAT_1S16) pad->pad_SampleRates[index++] = 11025.0;
+ if( caps.dwFormats & WAVE_FORMAT_2S16) pad->pad_SampleRates[index++] = 22050.0;
+ if( caps.dwFormats & WAVE_FORMAT_4S16) pad->pad_SampleRates[index++] = 44100.0;
+ pad->pad_Info.numSampleRates = index;
+ }
+ else if( caps.dwChannels == 1 )
+ {
+ int index = 0;
+ if( caps.dwFormats & WAVE_FORMAT_1M16) pad->pad_SampleRates[index++] = 11025.0;
+ if( caps.dwFormats & WAVE_FORMAT_2M16) pad->pad_SampleRates[index++] = 22050.0;
+ if( caps.dwFormats & WAVE_FORMAT_4M16) pad->pad_SampleRates[index++] = 44100.0;
+ pad->pad_Info.numSampleRates = index;
+ }
+ else pad->pad_Info.numSampleRates = 0;
+ IDirectSoundCapture_Release( lpDirectSoundCapture );
+ }
+ }
+ else
+#endif /* SUPPORT_AUDIO_CAPTURE */
+
+ {
+ /********** Output ******************************/
+ DSCAPS caps;
+ if( lpGUID == NULL ) sDefaultOutputDeviceID = sDeviceIndex;
+ /* Create interfaces for each object. */
+ hr = DirectSoundCreate( lpGUID, &lpDirectSound, NULL );
+ if( hr != DS_OK )
+ {
+ pad->pad_Info.maxOutputChannels = 0;
+ DBUG(("Cannot create dsound for %s. Result = 0x%x\n", lpszDesc, hr ));
+ }
+ else
+ {
+ /* Query device characteristics. */
+ caps.dwSize = sizeof(caps);
+ IDirectSound_GetCaps( lpDirectSound, &caps );
+ pad->pad_Info.maxOutputChannels = ( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
+ /* Get sample rates. */
+ pad->pad_SampleRates[0] = (double) caps.dwMinSecondarySampleRate;
+ pad->pad_SampleRates[1] = (double) caps.dwMaxSecondarySampleRate;
+ if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) pad->pad_Info.numSampleRates = -1;
+ else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate )
+ {
+ if( caps.dwMinSecondarySampleRate == 0 )
+ {
+ /*
+ ** On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !!
+ ** But it supports continuous sampling.
+ ** So fake range of rates, and hope it really supports it.
+ */
+ pad->pad_SampleRates[0] = 11025.0f;
+ pad->pad_SampleRates[1] = 48000.0f;
+ pad->pad_Info.numSampleRates = -1; /* continuous range */
+
+ DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex ));
+ }
+ else
+ {
+ pad->pad_Info.numSampleRates = 1;
+ }
+ }
+ else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) )
+ {
+ /* The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000.
+ ** But we know that they really support a range of rates!
+ ** So when we see a ridiculous set of rates, assume it is a range.
+ */
+ pad->pad_Info.numSampleRates = -1;
+ DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex ));
+ }
+ else pad->pad_Info.numSampleRates = 2;
+ IDirectSound_Release( lpDirectSound );
+ }
+ }
+ pad->pad_Info.nativeSampleFormats = paInt16;
+ sDeviceIndex++;
+ return( TRUE );
+}
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ if( sNumDevices <= 0 ) Pa_Initialize();
+ return sNumDevices;
+}
+static internalPortAudioDevice *Pa_GetInternalDevice( PaDeviceID id )
+{
+ if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
+ return &sDevices[id];
+}
+/*************************************************************************/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ internalPortAudioDevice *pad;
+ if( (id < 0) || ( id >= Pa_CountDevices()) ) return NULL;
+ pad = Pa_GetInternalDevice( id );
+ return &pad->pad_Info ;
+}
+static PaError Pa_MaybeQueryDevices( void )
+{
+ if( sNumDevices == 0 )
+ {
+ return Pa_QueryDevices();
+ }
+ return 0;
+}
+/*************************************************************************
+** Returns recommended device ID.
+** On the PC, the recommended device can be specified by the user by
+** setting an environment variable. For example, to use device #1.
+**
+** set PA_RECOMMENDED_OUTPUT_DEVICE=1
+**
+** The user should first determine the available device ID by using
+** the supplied application "pa_devs".
+*/
+#define PA_ENV_BUF_SIZE (32)
+#define PA_REC_IN_DEV_ENV_NAME ("PA_RECOMMENDED_INPUT_DEVICE")
+#define PA_REC_OUT_DEV_ENV_NAME ("PA_RECOMMENDED_OUTPUT_DEVICE")
+static PaDeviceID PaHost_GetEnvDefaultDeviceID( char *envName )
+{
+ DWORD hresult;
+ char envbuf[PA_ENV_BUF_SIZE];
+ PaDeviceID recommendedID = paNoDevice;
+ /* Let user determine default device by setting environment variable. */
+ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE );
+ if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
+ {
+ recommendedID = atoi( envbuf );
+ }
+ return recommendedID;
+}
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
+{
+ PaError result;
+ result = PaHost_GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME );
+ if( result < 0 )
+ {
+ result = Pa_MaybeQueryDevices();
+ if( result < 0 ) return result;
+ result = sDefaultInputDeviceID;
+ }
+ return result;
+}
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
+{
+ PaError result;
+ result = PaHost_GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME );
+ if( result < 0 )
+ {
+ result = Pa_MaybeQueryDevices();
+ if( result < 0 ) return result;
+ result = sDefaultOutputDeviceID;
+ }
+ return result;
+}
+/**********************************************************************
+** Make sure that we have queried the device capabilities.
+*/
+PaError PaHost_Init( void )
+{
+#if PA_SIMULATE_UNDERFLOW
+ PRINT(("WARNING - Underflow Simulation Enabled - Expect a Big Glitch!!!\n"));
+#endif
+ return Pa_MaybeQueryDevices();
+}
+static PaError Pa_TimeSlice( internalPortAudioStream *past )
+{
+ PaError result = 0;
+ long bytesEmpty = 0;
+ long bytesFilled = 0;
+ long bytesToXfer = 0;
+ long numChunks;
+ HRESULT hresult;
+ PaHostSoundControl *pahsc;
+ short *nativeBufPtr;
+ past->past_NumCallbacks += 1;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+ /* How much input data is available? */
+#if SUPPORT_AUDIO_CAPTURE
+ if( past->past_NumInputChannels > 0 )
+ {
+ DSW_QueryInputFilled( &pahsc->pahsc_DSoundWrapper, &bytesFilled );
+ bytesToXfer = bytesFilled;
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ /* How much output room is available? */
+ if( past->past_NumOutputChannels > 0 )
+ {
+ DSW_QueryOutputSpace( &pahsc->pahsc_DSoundWrapper, &bytesEmpty );
+ bytesToXfer = bytesEmpty;
+ }
+ AddTraceMessage( "bytesEmpty ", bytesEmpty );
+ /* Choose smallest value if both are active. */
+ if( (past->past_NumInputChannels > 0) && (past->past_NumOutputChannels > 0) )
+ {
+ bytesToXfer = ( bytesFilled < bytesEmpty ) ? bytesFilled : bytesEmpty;
+ }
+ /* printf("bytesFilled = %d, bytesEmpty = %d, bytesToXfer = %d\n",
+ bytesFilled, bytesEmpty, bytesToXfer);
+ */
+ /* Quantize to multiples of a buffer. */
+ numChunks = bytesToXfer / pahsc->pahsc_BytesPerBuffer;
+ if( numChunks > (long)(past->past_NumUserBuffers/2) )
+ {
+ numChunks = (long)past->past_NumUserBuffers/2;
+ }
+ else if( numChunks < 0 )
+ {
+ numChunks = 0;
+ }
+ AddTraceMessage( "numChunks ", numChunks );
+ nativeBufPtr = pahsc->pahsc_NativeBuffer;
+ if( numChunks > 0 )
+ {
+ while( numChunks-- > 0 )
+ {
+ /* Measure usage based on time to process one user buffer. */
+ Pa_StartUsageCalculation( past );
+#if SUPPORT_AUDIO_CAPTURE
+ /* Get native data from DirectSound. */
+ if( past->past_NumInputChannels > 0 )
+ {
+ hresult = DSW_ReadBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer );
+ if( hresult < 0 )
+ {
+ ERR_RPT(("DirectSound ReadBlock failed, hresult = 0x%x\n",hresult));
+ sPaHostError = hresult;
+ break;
+ }
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ /* Convert 16 bit native data to user data and call user routine. */
+ result = Pa_CallConvertInt16( past, nativeBufPtr, nativeBufPtr );
+ if( result != 0) break;
+ /* Pass native data to DirectSound. */
+ if( past->past_NumOutputChannels > 0 )
+ {
+ /* static short DEBUGHACK = 0;
+ DEBUGHACK += 0x0049;
+ nativeBufPtr[0] = DEBUGHACK; /* Make buzz to see if DirectSound still running. */
+ hresult = DSW_WriteBlock( &pahsc->pahsc_DSoundWrapper, (char *) nativeBufPtr, pahsc->pahsc_BytesPerBuffer );
+ if( hresult < 0 )
+ {
+ ERR_RPT(("DirectSound WriteBlock failed, result = 0x%x\n",hresult));
+ sPaHostError = hresult;
+ break;
+ }
+ }
+ Pa_EndUsageCalculation( past );
+ }
+ }
+ return result;
+}
+/*******************************************************************/
+static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+ internalPortAudioStream *past;
+ PaHostSoundControl *pahsc;
+#if PA_SIMULATE_UNDERFLOW
+ gUnderCallbackCounter++;
+ if( (gUnderCallbackCounter >= UNDER_START_GAP) &&
+ (gUnderCallbackCounter <= UNDER_STOP_GAP) )
+ {
+ if( gUnderCallbackCounter == UNDER_START_GAP)
+ {
+ AddTraceMessage("Begin stall: gUnderCallbackCounter =======", gUnderCallbackCounter );
+ }
+ if( gUnderCallbackCounter == UNDER_STOP_GAP)
+ {
+ AddTraceMessage("End stall: gUnderCallbackCounter =======", gUnderCallbackCounter );
+ }
+ return;
+ }
+#endif
+ past = (internalPortAudioStream *) dwUser;
+ if( past == NULL ) return;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+ if( !pahsc->pahsc_IfInsideCallback && past->past_IsActive )
+ {
+ if( past->past_StopNow )
+ {
+ past->past_IsActive = 0;
+ }
+ else if( past->past_StopSoon )
+ {
+ DSoundWrapper *dsw = &pahsc->pahsc_DSoundWrapper;
+ if( past->past_NumOutputChannels > 0 )
+ {
+ DSW_ZeroEmptySpace( dsw );
+ AddTraceMessage("Pa_TimerCallback: waiting - written ", (int) dsw->dsw_FramesWritten );
+ AddTraceMessage("Pa_TimerCallback: waiting - played ", (int) dsw->dsw_FramesPlayed );
+ /* clear past_IsActive when all sound played */
+ if( dsw->dsw_FramesPlayed >= past->past_FrameCount )
+ {
+ past->past_IsActive = 0;
+ }
+ }
+ else
+ {
+ past->past_IsActive = 0;
+ }
+ }
+ else
+ {
+ pahsc->pahsc_IfInsideCallback = 1;
+ if( Pa_TimeSlice( past ) != 0) /* Call time slice independant of timing method. */
+ {
+ past->past_StopSoon = 1;
+ }
+ pahsc->pahsc_IfInsideCallback = 0;
+ }
+ }
+}
+/*******************************************************************/
+PaError PaHost_OpenStream( internalPortAudioStream *past )
+{
+ HRESULT hr;
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+ int numBytes, maxChannels;
+ unsigned int minNumBuffers;
+ internalPortAudioDevice *pad;
+ DSoundWrapper *dsw;
+ /* Allocate and initialize host data. */
+ pahsc = (PaHostSoundControl *) PaHost_AllocateFastMemory(sizeof(PaHostSoundControl)); /* MEM */
+ if( pahsc == NULL )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ memset( pahsc, 0, sizeof(PaHostSoundControl) );
+ past->past_DeviceData = (void *) pahsc;
+ pahsc->pahsc_TimerID = 0;
+ dsw = &pahsc->pahsc_DSoundWrapper;
+ DSW_Init( dsw );
+ /* Allocate native buffer. */
+ maxChannels = ( past->past_NumOutputChannels > past->past_NumInputChannels ) ?
+ past->past_NumOutputChannels : past->past_NumInputChannels;
+ pahsc->pahsc_BytesPerBuffer = past->past_FramesPerUserBuffer * maxChannels * sizeof(short);
+ if( maxChannels > 0 )
+ {
+ pahsc->pahsc_NativeBuffer = (short *) PaHost_AllocateFastMemory(pahsc->pahsc_BytesPerBuffer); /* MEM */
+ if( pahsc->pahsc_NativeBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ }
+ else
+ {
+ result = paInvalidChannelCount;
+ goto error;
+ }
+
+ DBUG(("PaHost_OpenStream: pahsc_MinFramesPerHostBuffer = %d\n", pahsc->pahsc_MinFramesPerHostBuffer ));
+ minNumBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
+ past->past_NumUserBuffers = ( minNumBuffers > past->past_NumUserBuffers ) ? minNumBuffers : past->past_NumUserBuffers;
+ numBytes = pahsc->pahsc_BytesPerBuffer * past->past_NumUserBuffers;
+ if( numBytes < DSBSIZE_MIN )
+ {
+ result = paBufferTooSmall;
+ goto error;
+ }
+ if( numBytes > DSBSIZE_MAX )
+ {
+ result = paBufferTooBig;
+ goto error;
+ }
+ pahsc->pahsc_FramesPerDSBuffer = past->past_FramesPerUserBuffer * past->past_NumUserBuffers;
+ {
+ int msecLatency = (int) ((pahsc->pahsc_FramesPerDSBuffer * 1000) / past->past_SampleRate);
+ PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", pahsc->pahsc_FramesPerDSBuffer, msecLatency ));
+ }
+ /* ------------------ OUTPUT */
+ if( (past->past_OutputDeviceID >= 0) && (past->past_NumOutputChannels > 0) )
+ {
+ DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", past->past_OutputDeviceID));
+ pad = Pa_GetInternalDevice( past->past_OutputDeviceID );
+ hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL );
+ /* If this fails, then try each output device until we find one that works. */
+ if( hr != DS_OK )
+ {
+ int i;
+ ERR_RPT(("Creation of requested Audio Output device '%s' failed.\n",
+ ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) ));
+ for( i=0; i<Pa_CountDevices(); i++ )
+ {
+ pad = Pa_GetInternalDevice( i );
+ if( pad->pad_Info.maxOutputChannels >= past->past_NumOutputChannels )
+ {
+ DBUG(("Try device '%s' instead.\n", pad->pad_Info.name ));
+ hr = DirectSoundCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSound, NULL );
+ if( hr == DS_OK )
+ {
+ ERR_RPT(("Using device '%s' instead.\n", pad->pad_Info.name ));
+ break;
+ }
+ }
+ }
+ }
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n"));
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+ hr = DSW_InitOutputBuffer( dsw,
+ (unsigned long) (past->past_SampleRate + 0.5),
+ past->past_NumOutputChannels, numBytes );
+ DBUG(("DSW_InitOutputBuffer() returns %x\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+ past->past_FrameCount = pahsc->pahsc_DSoundWrapper.dsw_FramesWritten;
+ }
+#if SUPPORT_AUDIO_CAPTURE
+ /* ------------------ INPUT */
+ if( (past->past_InputDeviceID >= 0) && (past->past_NumInputChannels > 0) )
+ {
+ pad = Pa_GetInternalDevice( past->past_InputDeviceID );
+ hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL );
+ /* If this fails, then try each input device until we find one that works. */
+ if( hr != DS_OK )
+ {
+ int i;
+ ERR_RPT(("Creation of requested Audio Capture device '%s' failed.\n",
+ ((pad->pad_lpGUID == NULL) ? "Default" : pad->pad_Info.name) ));
+ for( i=0; i<Pa_CountDevices(); i++ )
+ {
+ pad = Pa_GetInternalDevice( i );
+ if( pad->pad_Info.maxInputChannels >= past->past_NumInputChannels )
+ {
+ PRINT(("Try device '%s' instead.\n", pad->pad_Info.name ));
+ hr = DirectSoundCaptureCreate( pad->pad_lpGUID, &dsw->dsw_pDirectSoundCapture, NULL );
+ if( hr == DS_OK ) break;
+ }
+ }
+ }
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n"));
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+ hr = DSW_InitInputBuffer( dsw,
+ (unsigned long) (past->past_SampleRate + 0.5),
+ past->past_NumInputChannels, numBytes );
+ DBUG(("DSW_InitInputBuffer() returns %x\n", hr));
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr));
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ /* Calculate scalar used in CPULoad calculation. */
+ {
+ LARGE_INTEGER frequency;
+ if( QueryPerformanceFrequency( &frequency ) == 0 )
+ {
+ pahsc->pahsc_InverseTicksPerUserBuffer = 0.0;
+ }
+ else
+ {
+ pahsc->pahsc_InverseTicksPerUserBuffer = past->past_SampleRate /
+ ( (double)frequency.QuadPart * past->past_FramesPerUserBuffer );
+ DBUG(("pahsc_InverseTicksPerUserBuffer = %g\n", pahsc->pahsc_InverseTicksPerUserBuffer ));
+ }
+ }
+ return result;
+error:
+ PaHost_CloseStream( past );
+ return result;
+}
+/*************************************************************************/
+PaError PaHost_StartOutput( internalPortAudioStream *past )
+{
+ HRESULT hr;
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ /* Give user callback a chance to pre-fill buffer. */
+ result = Pa_TimeSlice( past );
+ if( result != paNoError ) return result; // FIXME - what if finished?
+ hr = DSW_StartOutput( &pahsc->pahsc_DSoundWrapper );
+ DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+error:
+ return result;
+}
+/*************************************************************************/
+PaError PaHost_StartInput( internalPortAudioStream *past )
+{
+ PaError result = paNoError;
+#if SUPPORT_AUDIO_CAPTURE
+ HRESULT hr;
+ PaHostSoundControl *pahsc;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ hr = DSW_StartInput( &pahsc->pahsc_DSoundWrapper );
+ DBUG(("Pa_StartStream: DSW_StartInput returned = 0x%X.\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paHostError;
+ sPaHostError = hr;
+ goto error;
+ }
+error:
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ return result;
+}
+/*************************************************************************/
+PaError PaHost_StartEngine( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ PaError result = paNoError;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ past->past_StopNow = 0;
+ past->past_StopSoon = 0;
+ past->past_IsActive = 1;
+ /* Create timer that will wake us up so we can fill the DSound buffer. */
+ {
+ int msecPerBuffer;
+ int resolution;
+ int bufsPerInterrupt = past->past_NumUserBuffers/4;
+ if( bufsPerInterrupt < 1 ) bufsPerInterrupt = 1;
+ msecPerBuffer = 1000 * (bufsPerInterrupt * past->past_FramesPerUserBuffer) / (int) past->past_SampleRate;
+ if( msecPerBuffer < 10 ) msecPerBuffer = 10;
+ else if( msecPerBuffer > 100 ) msecPerBuffer = 100;
+ resolution = msecPerBuffer/4;
+ pahsc->pahsc_TimerID = timeSetEvent( msecPerBuffer, resolution, (LPTIMECALLBACK) Pa_TimerCallback,
+ (DWORD) past, TIME_PERIODIC );
+ }
+ if( pahsc->pahsc_TimerID == 0 )
+ {
+ past->past_IsActive = 0;
+ result = paHostError;
+ sPaHostError = 0;
+ goto error;
+ }
+error:
+ return result;
+}
+/*************************************************************************/
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+{
+ int timeoutMsec;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ if( abort ) past->past_StopNow = 1;
+ past->past_StopSoon = 1;
+ /* Set timeout at 20% beyond maximum time we might wait. */
+ timeoutMsec = (int) (1200.0 * pahsc->pahsc_FramesPerDSBuffer / past->past_SampleRate);
+ while( past->past_IsActive && (timeoutMsec > 0) )
+ {
+ Sleep(10);
+ timeoutMsec -= 10;
+ }
+ if( pahsc->pahsc_TimerID != 0 )
+ {
+ timeKillEvent(pahsc->pahsc_TimerID); /* Stop callback timer. */
+ pahsc->pahsc_TimerID = 0;
+ }
+ return paNoError;
+}
+/*************************************************************************/
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
+{
+#if SUPPORT_AUDIO_CAPTURE
+ HRESULT hr;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ (void) abort;
+ hr = DSW_StopInput( &pahsc->pahsc_DSoundWrapper );
+ DBUG(("DSW_StopInput() result is %x\n", hr));
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ return paNoError;
+}
+/*************************************************************************/
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+{
+ HRESULT hr;
+ PaHostSoundControl *pahsc;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ (void) abort;
+ hr = DSW_StopOutput( &pahsc->pahsc_DSoundWrapper );
+ DBUG(("DSW_StopOutput() result is %x\n", hr));
+ return paNoError;
+}
+/*******************************************************************/
+PaError PaHost_CloseStream( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ DSW_Term( &pahsc->pahsc_DSoundWrapper );
+ if( pahsc->pahsc_NativeBuffer )
+ {
+ PaHost_FreeFastMemory( pahsc->pahsc_NativeBuffer, pahsc->pahsc_BytesPerBuffer ); /* MEM */
+ pahsc->pahsc_NativeBuffer = NULL;
+ }
+ PaHost_FreeFastMemory( pahsc, sizeof(PaHostSoundControl) ); /* MEM */
+ past->past_DeviceData = NULL;
+ return paNoError;
+}
+
+/* Set minimal latency based on whether NT or Win95.
+ * NT has higher latency.
+ */
+static int PaHost_GetMinSystemLatency( void )
+{
+ int minLatencyMsec;
+ /* Set minimal latency based on whether NT or other OS.
+ * NT has higher latency.
+ */
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof( osvi );
+ GetVersionEx( &osvi );
+ DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId ));
+ DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion ));
+ DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion ));
+ /* Check for NT */
+ if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
+ {
+ minLatencyMsec = PA_WIN_NT_LATENCY;
+ }
+ else if(osvi.dwMajorVersion >= 5)
+ {
+ minLatencyMsec = PA_WIN_WDM_LATENCY;
+ }
+ else
+ {
+ minLatencyMsec = PA_WIN_9X_LATENCY;
+ }
+ return minLatencyMsec;
+}
+
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+**
+** set PA_MIN_LATENCY_MSEC=200
+**
+** in the AUTOEXEC.BAT file and reboot.
+** If the environment variable is not set, then the latency will be determined
+** based on the OS. Windows NT has higher latency than Win95.
+*/
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate )
+{
+ char envbuf[PA_ENV_BUF_SIZE];
+ DWORD hresult;
+ int minLatencyMsec = 0;
+ double msecPerBuffer = (1000.0 * framesPerBuffer) / sampleRate;
+ int minBuffers;
+ /* Let user determine minimal latency by setting environment variable. */
+ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE );
+ if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
+ {
+ minLatencyMsec = atoi( envbuf );
+ }
+ else
+ {
+ minLatencyMsec = PaHost_GetMinSystemLatency();
+#if PA_USE_HIGH_LATENCY
+ PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));
+#endif
+
+ }
+ minBuffers = (int) (1.0 + ((double)minLatencyMsec / msecPerBuffer));
+ if( minBuffers < 2 ) minBuffers = 2;
+ return minBuffers;
+}
+/*************************************************************************/
+PaError PaHost_Term( void )
+{
+ int i;
+ /* Free names allocated during enumeration. */
+ for( i=0; i<sNumDevices; i++ )
+ {
+ if( sDevices[i].pad_Info.name != NULL )
+ {
+ free( (void *) sDevices[i].pad_Info.name );
+ sDevices[i].pad_Info.name = NULL;
+ }
+ }
+ if( sDevices != NULL )
+ {
+ PaHost_FreeFastMemory( sDevices, sNumDevices * sizeof(internalPortAudioDevice) ); /* MEM */
+ sDevices = NULL;
+ sNumDevices = 0;
+ }
+ return 0;
+}
+void Pa_Sleep( long msec )
+{
+ Sleep( msec );
+}
+/*************************************************************************
+ * Allocate memory that can be accessed in real-time.
+ * This may need to be held in physical memory so that it is not
+ * paged to virtual memory.
+ * This call MUST be balanced with a call to PaHost_FreeFastMemory().
+ * Memory will be set to zero.
+ */
+void *PaHost_AllocateFastMemory( long numBytes )
+{
+ void *addr = GlobalAlloc( GPTR, numBytes ); /* FIXME - do we need physical memory? Use VirtualLock() */ /* MEM */
+ return addr;
+}
+/*************************************************************************
+ * Free memory that could be accessed in real-time.
+ * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
+ */
+void PaHost_FreeFastMemory( void *addr, long numBytes )
+{
+ if( addr != NULL ) GlobalFree( addr ); /* MEM */
+}
+/***********************************************************************/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+ return (PaError) (past->past_IsActive);
+}
+/*************************************************************************/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ DSoundWrapper *dsw;
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ PaHostSoundControl *pahsc;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ dsw = &pahsc->pahsc_DSoundWrapper;
+ return dsw->dsw_FramesPlayed;
+}
diff --git a/pd/portaudio/pa_win_ds/pa_win_ds.c b/pd/portaudio/pa_win_ds/pa_win_ds.c
new file mode 100644
index 00000000..b23a407e
--- /dev/null
+++ b/pd/portaudio/pa_win_ds/pa_win_ds.c
@@ -0,0 +1,1441 @@
+/*
+ * $Id: pa_win_ds.c,v 1.1.2.29 2002/12/03 06:30:40 rossbencina Exp $
+ * Portable Audio I/O Library DirectSound implementation
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/** @file
+
+ @todo implement underflow/overflow streamCallback statusFlags, paNeverDropInput.
+
+ @todo implement host api specific extension to set i/o buffer sizes in frames
+
+ @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.)
+
+ @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
+
+ @todo audit handling of DirectSound result codes - in many cases we could convert a HRESULT into
+ a native portaudio error code. Standard DirectSound result codes are documented at msdn.
+
+ @todo implement IsFormatSupported
+
+ @todo implement PaDeviceInfo.defaultSampleRate;
+*/
+
+#include <stdio.h>
+#include <string.h> /* strlen() */
+
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
+
+#include "dsound_wrapper.h"
+
+/* TODO
+O- fix "patest_stop.c"
+O- Handle buffer underflow, overflow, etc.
+*/
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+#define PA_USE_HIGH_LATENCY (0)
+#if PA_USE_HIGH_LATENCY
+#define PA_WIN_9X_LATENCY (500)
+#define PA_WIN_NT_LATENCY (600)
+#else
+#define PA_WIN_9X_LATENCY (140)
+#define PA_WIN_NT_LATENCY (280)
+#endif
+
+#define PA_WIN_WDM_LATENCY (120)
+
+#define SECONDS_PER_MSEC (0.001)
+#define MSEC_PER_SECOND (1000)
+
+/* prototypes for functions declared in this file */
+
+PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+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 CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+static signed long GetStreamReadAvailable( PaStream* stream );
+static signed long GetStreamWriteAvailable( PaStream* stream );
+
+
+/* FIXME: should convert hr to a string */
+#define PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr ) \
+ PaUtil_SetLastHostErrorInfo( paDirectSound, hr, "DirectSound error" )
+
+/************************************************* DX Prototypes **********/
+static BOOL CALLBACK Pa_EnumOutputProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext );
+static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext );
+
+/************************************************************************************/
+/********************** Structures **************************************************/
+/************************************************************************************/
+/* PaWinDsHostApiRepresentation - host api datastructure specific to this implementation */
+
+typedef struct PaWinDsDeviceInfo
+{
+ GUID GUID;
+ GUID *lpGUID;
+ double sampleRates[3];
+} PaWinDsDeviceInfo;
+
+typedef struct
+{
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
+
+ PaUtilAllocationGroup *allocations;
+
+ /* implementation specific data goes here */
+ PaWinDsDeviceInfo *winDsDeviceInfos;
+ PaError enumerationError;
+
+} PaWinDsHostApiRepresentation;
+
+/* PaWinDsStream - a stream data structure specifically for this implementation */
+
+typedef struct PaWinDsStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+/* DirectSound specific data. */
+ DSoundWrapper directSoundWrapper;
+ MMRESULT timerID;
+ BOOL ifInsideCallback; /* Test for reentrancy. */
+ int framesPerDSBuffer;
+ double framesWritten;
+ double secondsPerHostByte; /* Used to optimize latency calculation for outTime */
+
+/* FIXME - move all below to PaUtilStreamRepresentation */
+ volatile int isStarted;
+ volatile int isActive;
+ volatile int stopProcessing; /* stop thread once existing buffers have been returned */
+ volatile int abortProcessing; /* stop thread immediately */
+} PaWinDsStream;
+
+
+/************************************************************************************
+** Just count devices so we know how much memory to allocate.
+*/
+static BOOL CALLBACK Pa_CountDevProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext )
+{
+ int *counterPtr = (int *)lpContext;
+ *counterPtr += 1;
+ return TRUE;
+}
+
+/************************************************************************************
+** Extract capabilities info from each device.
+*/
+static BOOL CALLBACK Pa_EnumOutputProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext )
+{
+ HRESULT hr;
+ DSCAPS caps;
+ LPDIRECTSOUND lpDirectSound;
+ PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation *) lpContext;
+ PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep;
+ int index = hostApi->info.deviceCount;
+ PaDeviceInfo *deviceInfo = hostApi->deviceInfos[index];
+ PaWinDsDeviceInfo *winDsDeviceInfo = &winDsHostApi->winDsDeviceInfos[index];
+ int deviceOK = TRUE;
+
+ /* Copy GUID to static array. Set pointer. */
+ if( lpGUID == NULL )
+ {
+ winDsDeviceInfo->lpGUID = NULL;
+ }
+ else
+ {
+ winDsDeviceInfo->lpGUID = &winDsDeviceInfo->GUID;
+ memcpy( &winDsDeviceInfo->GUID, lpGUID, sizeof(GUID) );
+ }
+
+
+ /********** Output ******************************/
+
+ /* Create interfaces for each object. */
+ hr = dswDSoundEntryPoints.DirectSoundCreate( lpGUID, &lpDirectSound, NULL );
+ if( hr != DS_OK )
+ {
+ deviceInfo->maxOutputChannels = 0;
+ DBUG(("Cannot create dsound for %s. Result = 0x%x\n", lpszDesc, hr ));
+ deviceOK = FALSE;
+ }
+ else
+ {
+ /* Query device characteristics. */
+ caps.dwSize = sizeof(caps);
+ IDirectSound_GetCaps( lpDirectSound, &caps );
+
+#ifndef PA_NO_WMME
+ if( caps.dwFlags & DSCAPS_EMULDRIVER )
+ {
+ /* If WMME supported, then reject Emulated drivers because they are lousy. */
+ deviceOK = FALSE;
+ }
+#endif
+
+ if( deviceOK )
+ {
+ /* Mono or stereo device? */
+ deviceInfo->maxOutputChannels = ( caps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
+
+ deviceInfo->defaultSampleRate = 0.; /* @todo IMPLEMENT ME */
+
+ /* Get sample rates. */
+ /*
+ winDsDeviceInfo->sampleRates[0] = (double) caps.dwMinSecondarySampleRate;
+ winDsDeviceInfo->sampleRates[1] = (double) caps.dwMaxSecondarySampleRate;
+ if( caps.dwFlags & DSCAPS_CONTINUOUSRATE ) deviceInfo->numSampleRates = -1;
+ else if( caps.dwMinSecondarySampleRate == caps.dwMaxSecondarySampleRate )
+ {
+ if( caps.dwMinSecondarySampleRate == 0 )
+ {
+ //
+ // On my Thinkpad 380Z, DirectSoundV6 returns min-max=0 !!
+ // But it supports continuous sampling.
+ // So fake range of rates, and hope it really supports it.
+ //
+ winDsDeviceInfo->sampleRates[0] = 11025.0f;
+ winDsDeviceInfo->sampleRates[1] = 48000.0f;
+ deviceInfo->numSampleRates = -1; // continuous range
+
+ DBUG(("PA - Reported rates both zero. Setting to fake values for device #%d\n", sDeviceIndex ));
+ }
+ else
+ {
+ deviceInfo->numSampleRates = 1;
+ }
+ }
+ else if( (caps.dwMinSecondarySampleRate < 1000.0) && (caps.dwMaxSecondarySampleRate > 50000.0) )
+ {
+ // The EWS88MT drivers lie, lie, lie. The say they only support two rates, 100 & 100000.
+ // But we know that they really support a range of rates!
+ // So when we see a ridiculous set of rates, assume it is a range.
+ //
+ deviceInfo->numSampleRates = -1;
+ DBUG(("PA - Sample rate range used instead of two odd values for device #%d\n", sDeviceIndex ));
+ }
+ else deviceInfo->numSampleRates = 2;
+ */
+ }
+
+ IDirectSound_Release( lpDirectSound );
+ }
+
+ if( deviceOK )
+ {
+ if( lpGUID == NULL ) hostApi->info.defaultOutputDevice = index;
+
+ /* Allocate room for descriptive name. */
+ if( lpszDesc != NULL )
+ {
+ char *deviceName;
+ int len = strlen(lpszDesc);
+ deviceName = (char*)PaUtil_GroupAllocateMemory( winDsHostApi->allocations, len + 1 );
+ if( !deviceName )
+ {
+ winDsHostApi->enumerationError = paInsufficientMemory;
+ return FALSE;
+ }
+ memcpy( (void *) deviceName, lpszDesc, len+1 );
+ deviceInfo->name = deviceName;
+ }
+
+ hostApi->info.deviceCount++;
+ }
+
+ return( TRUE );
+}
+
+
+/************************************************************************************
+** Extract capabilities info from each device.
+*/
+static BOOL CALLBACK Pa_EnumInputProc(LPGUID lpGUID,
+ LPCTSTR lpszDesc,
+ LPCTSTR lpszDrvName,
+ LPVOID lpContext )
+{
+ HRESULT hr;
+ DSCCAPS caps;
+ LPDIRECTSOUNDCAPTURE lpDirectSoundCapture;
+ PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation *) lpContext;
+ PaUtilHostApiRepresentation *hostApi = &winDsHostApi->inheritedHostApiRep;
+ int index = hostApi->info.deviceCount;
+ PaDeviceInfo *deviceInfo = hostApi->deviceInfos[index];
+ PaWinDsDeviceInfo *winDsDeviceInfo = &winDsHostApi->winDsDeviceInfos[index];
+ int deviceOK = TRUE;
+
+ /* Copy GUID to static array. Set pointer. */
+ if( lpGUID == NULL )
+ {
+ winDsDeviceInfo->lpGUID = NULL;
+ }
+ else
+ {
+ winDsDeviceInfo->lpGUID = &winDsDeviceInfo->GUID;
+ memcpy( &winDsDeviceInfo->GUID, lpGUID, sizeof(GUID) );
+ }
+
+ /********** Input ******************************/
+
+ hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( lpGUID, &lpDirectSoundCapture, NULL );
+ if( hr != DS_OK )
+ {
+ deviceInfo->maxInputChannels = 0;
+ DBUG(("Cannot create Capture for %s. Result = 0x%x\n", lpszDesc, hr ));
+ deviceOK = FALSE;
+ }
+ else
+ {
+ /* Query device characteristics. */
+ caps.dwSize = sizeof(caps);
+ IDirectSoundCapture_GetCaps( lpDirectSoundCapture, &caps );
+
+ /* printf("caps.dwFormats = 0x%x\n", caps.dwFormats ); */
+ deviceInfo->maxInputChannels = caps.dwChannels;
+ /* Determine sample rates from flags. */
+ /*
+ if( caps.dwChannels == 2 )
+ {
+ int index = 0;
+ if( caps.dwFormats & WAVE_FORMAT_1S16) winDsDeviceInfo->sampleRates[index++] = 11025.0;
+ if( caps.dwFormats & WAVE_FORMAT_2S16) winDsDeviceInfo->sampleRates[index++] = 22050.0;
+ if( caps.dwFormats & WAVE_FORMAT_4S16) winDsDeviceInfo->sampleRates[index++] = 44100.0;
+ deviceInfo->numSampleRates = index;
+ }
+ else if( caps.dwChannels == 1 )
+ {
+ int index = 0;
+ if( caps.dwFormats & WAVE_FORMAT_1M16) winDsDeviceInfo->sampleRates[index++] = 11025.0;
+ if( caps.dwFormats & WAVE_FORMAT_2M16) winDsDeviceInfo->sampleRates[index++] = 22050.0;
+ if( caps.dwFormats & WAVE_FORMAT_4M16) winDsDeviceInfo->sampleRates[index++] = 44100.0;
+ deviceInfo->numSampleRates = index;
+ }
+ else
+ {
+ deviceInfo->numSampleRates = 0;
+ deviceOK = FALSE;
+ }
+ */
+ IDirectSoundCapture_Release( lpDirectSoundCapture );
+ }
+
+ if( deviceOK )
+ {
+ /* Allocate room for descriptive name. */
+ if( lpszDesc != NULL )
+ {
+ char *deviceName;
+ int len = strlen(lpszDesc);
+ deviceName = (char*)PaUtil_GroupAllocateMemory( winDsHostApi->allocations, len + 1 );
+ if( !deviceName )
+ {
+ winDsHostApi->enumerationError = paInsufficientMemory;
+ return FALSE;
+ }
+ memcpy( (void *) deviceName, lpszDesc, len+1 );
+ deviceInfo->name = deviceName;
+ }
+
+ if( lpGUID == NULL ) hostApi->info.defaultInputDevice = index;
+
+ hostApi->info.deviceCount++;
+ }
+
+ return TRUE;
+}
+
+
+/***********************************************************************************/
+PaError PaWinDs_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ int i, deviceCount;
+ PaWinDsHostApiRepresentation *winDsHostApi;
+ PaDeviceInfo *deviceInfoArray;
+
+ DSW_InitializeDSoundEntryPoints();
+
+ winDsHostApi = (PaWinDsHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinDsHostApiRepresentation) );
+ if( !winDsHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ winDsHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !winDsHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ *hostApi = &winDsHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paDirectSound;
+ (*hostApi)->info.name = "Windows DirectSound";
+
+ (*hostApi)->info.deviceCount = 0;
+ (*hostApi)->info.defaultInputDevice = paNoDevice;
+ (*hostApi)->info.defaultOutputDevice = paNoDevice;
+
+ deviceCount = 0;
+/* DSound - enumerate devices to count them. */
+ dswDSoundEntryPoints.DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, &deviceCount );
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_CountDevProc, &deviceCount );
+
+ if( deviceCount > 0 )
+ {
+ /* allocate array for pointers to PaDeviceInfo structs */
+ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ winDsHostApi->allocations, sizeof(PaDeviceInfo*) * deviceCount );
+ if( !(*hostApi)->deviceInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* allocate all PaDeviceInfo structs in a contiguous block */
+ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ winDsHostApi->allocations, sizeof(PaDeviceInfo) * deviceCount );
+ if( !deviceInfoArray )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* allocate all DSound specific info structs in a contiguous block */
+ winDsHostApi->winDsDeviceInfos = (PaWinDsDeviceInfo*)PaUtil_GroupAllocateMemory(
+ winDsHostApi->allocations, sizeof(PaWinDsDeviceInfo) * deviceCount );
+ if( !winDsHostApi->winDsDeviceInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i=0; i < deviceCount; ++i )
+ {
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[i];
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+ deviceInfo->name = 0;
+
+ deviceInfo->defaultLowInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultLowOutputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighOutputLatency = 0.; /* @todo IMPLEMENT ME */
+
+ (*hostApi)->deviceInfos[i] = deviceInfo;
+ }
+
+ /* DSound - Enumerate again to fill in structures. */
+ winDsHostApi->enumerationError = 0;
+ dswDSoundEntryPoints.DirectSoundEnumerate( (LPDSENUMCALLBACK)Pa_EnumOutputProc, (void *)winDsHostApi );
+ if( winDsHostApi->enumerationError != paNoError ) return winDsHostApi->enumerationError;
+
+ winDsHostApi->enumerationError = 0;
+ dswDSoundEntryPoints.DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK)Pa_EnumInputProc, (void *)winDsHostApi );
+ if( winDsHostApi->enumerationError != paNoError ) return winDsHostApi->enumerationError;
+ }
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &winDsHostApi->callbackStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &winDsHostApi->blockingStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+
+ return result;
+
+error:
+ if( winDsHostApi )
+ {
+ if( winDsHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( winDsHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( winDsHostApi );
+ }
+ return result;
+}
+
+
+/***********************************************************************************/
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
+
+ /*
+ IMPLEMENT ME:
+ - clean up any resourced not handled by the allocation group
+ */
+
+ if( winDsHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( winDsHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( winDsHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( winDsHostApi );
+
+ DSW_TerminateDSoundEntryPoints();
+}
+
+
+/* Set minimal latency based on whether NT or Win95.
+ * NT has higher latency.
+ */
+static int PaWinDS_GetMinSystemLatency( void )
+{
+ int minLatencyMsec;
+ /* Set minimal latency based on whether NT or other OS.
+ * NT has higher latency.
+ */
+ OSVERSIONINFO osvi;
+ osvi.dwOSVersionInfoSize = sizeof( osvi );
+ GetVersionEx( &osvi );
+ DBUG(("PA - PlatformId = 0x%x\n", osvi.dwPlatformId ));
+ DBUG(("PA - MajorVersion = 0x%x\n", osvi.dwMajorVersion ));
+ DBUG(("PA - MinorVersion = 0x%x\n", osvi.dwMinorVersion ));
+ /* Check for NT */
+ if( (osvi.dwMajorVersion == 4) && (osvi.dwPlatformId == 2) )
+ {
+ minLatencyMsec = PA_WIN_NT_LATENCY;
+ }
+ else if(osvi.dwMajorVersion >= 5)
+ {
+ minLatencyMsec = PA_WIN_WDM_LATENCY;
+ }
+ else
+ {
+ minLatencyMsec = PA_WIN_9X_LATENCY;
+ }
+ return minLatencyMsec;
+}
+
+/***********************************************************************************/
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
+{
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ /*
+ IMPLEMENT ME:
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+ */
+
+ return paFormatIsSupported;
+}
+
+
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Latency can be optionally set by user by setting
+** an environment variable. For example, to set latency to 200 msec, put:
+**
+** set PA_MIN_LATENCY_MSEC=200
+**
+** in the AUTOEXEC.BAT file and reboot.
+** If the environment variable is not set, then the latency will be determined
+** based on the OS. Windows NT has higher latency than Win95.
+*/
+#define PA_LATENCY_ENV_NAME ("PA_MIN_LATENCY_MSEC")
+#define PA_ENV_BUF_SIZE (32)
+
+static int PaWinDs_GetMinLatencyFrames( double sampleRate )
+{
+ char envbuf[PA_ENV_BUF_SIZE];
+ DWORD hresult;
+ int minLatencyMsec = 0;
+
+ /* Let user determine minimal latency by setting environment variable. */
+ hresult = GetEnvironmentVariable( PA_LATENCY_ENV_NAME, envbuf, PA_ENV_BUF_SIZE );
+ if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE) )
+ {
+ minLatencyMsec = atoi( envbuf );
+ }
+ else
+ {
+ minLatencyMsec = PaWinDS_GetMinSystemLatency();
+#if PA_USE_HIGH_LATENCY
+ PRINT(("PA - Minimum Latency set to %d msec!\n", minLatencyMsec ));
+#endif
+
+ }
+
+ return (int) (minLatencyMsec * sampleRate * SECONDS_PER_MSEC);
+}
+
+/***********************************************************************************/
+/* see pa_hostapi.h for a list of validity guarantees made about OpenStream parameters */
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaWinDsHostApiRepresentation *winDsHostApi = (PaWinDsHostApiRepresentation*)hostApi;
+ PaWinDsStream *stream = 0;
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+ PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
+ unsigned long suggestedInputLatencyFrames, suggestedOutputLatencyFrames;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+ suggestedInputLatencyFrames = inputParameters->suggestedLatency * sampleRate;
+
+ /* IDEA: the following 3 checks could be performed by default by pa_front
+ unless some flag indicated otherwise */
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate hostApiSpecificStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ inputChannelCount = 0;
+ suggestedInputLatencyFrames = 0;
+ }
+
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+ suggestedOutputLatencyFrames = outputParameters->suggestedLatency * sampleRate;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate hostApiSpecificStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ outputChannelCount = 0;
+ suggestedOutputLatencyFrames = 0;
+ }
+
+
+ /*
+ IMPLEMENT ME:
+
+ ( the following two checks are taken care of by PaUtil_InitializeBufferProcessor() )
+
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+
+ - alter sampleRate to a close allowable rate if possible / necessary
+
+ - validate suggestedInputLatency and suggestedOutputLatency parameters,
+ use default values where necessary
+ */
+
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
+
+
+ stream = (PaWinDsStream*)PaUtil_AllocateMemory( sizeof(PaWinDsStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( streamCallback )
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &winDsHostApi->callbackStreamInterface, streamCallback, userData );
+ }
+ else
+ {
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &winDsHostApi->blockingStreamInterface, streamCallback, userData );
+ }
+
+ stream->streamRepresentation.streamInfo.inputLatency = 0.; /* FIXME: not initialised anywhere else */
+ stream->streamRepresentation.streamInfo.outputLatency = 0.;
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+
+ if( inputParameters )
+ {
+ /* IMPLEMENT ME - establish which host formats are available */
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputParameters->sampleFormat );
+ }
+
+ if( outputParameters )
+ {
+ /* IMPLEMENT ME - establish which host formats are available */
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputParameters->sampleFormat );
+ }
+
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ inputChannelCount, inputSampleFormat, hostInputSampleFormat,
+ outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer,
+ framesPerBuffer, /* ignored in paUtilVariableHostBufferSizePartialUsageAllowed mode. */
+ /* This next mode is required because DS can split the host buffer when it wraps around. */
+ paUtilVariableHostBufferSizePartialUsageAllowed,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+
+/* DirectSound specific initialization */
+ {
+ HRESULT hr;
+ int bytesPerDirectSoundBuffer;
+ DSoundWrapper *dsw;
+ int userLatencyFrames;
+ int minLatencyFrames;
+
+ stream->timerID = 0;
+ dsw = &stream->directSoundWrapper;
+ DSW_Init( dsw );
+
+ /* Get system minimum latency. */
+ minLatencyFrames = PaWinDs_GetMinLatencyFrames( sampleRate );
+
+ /* Let user override latency by passing latency parameter. */
+ userLatencyFrames = (suggestedInputLatencyFrames > suggestedOutputLatencyFrames)
+ ? suggestedInputLatencyFrames
+ : suggestedOutputLatencyFrames;
+ if( userLatencyFrames > 0 ) minLatencyFrames = userLatencyFrames;
+
+ /* Calculate stream->framesPerDSBuffer depending on framesPerBuffer */
+ if( framesPerBuffer == paFramesPerBufferUnspecified )
+ {
+ /* App support variable framesPerBuffer */
+ stream->framesPerDSBuffer = minLatencyFrames;
+
+ stream->streamRepresentation.streamInfo.outputLatency = (double)(minLatencyFrames - 1) / sampleRate;
+ }
+ else
+ {
+ /* Round up to number of buffers needed to guarantee that latency. */
+ int numUserBuffers = (minLatencyFrames + framesPerBuffer - 1) / framesPerBuffer;
+ if( numUserBuffers < 1 ) numUserBuffers = 1;
+ numUserBuffers += 1; /* So we have latency worth of buffers ahead of current buffer. */
+ stream->framesPerDSBuffer = framesPerBuffer * numUserBuffers;
+
+ stream->streamRepresentation.streamInfo.outputLatency = (double)(framesPerBuffer * (numUserBuffers-1)) / sampleRate;
+ }
+
+ {
+ /* @todo REVIEW: this calculation seems incorrect to me - rossb. */
+ int msecLatency = (int) ((stream->framesPerDSBuffer * MSEC_PER_SECOND) / sampleRate);
+ PRINT(("PortAudio on DirectSound - Latency = %d frames, %d msec\n", stream->framesPerDSBuffer, msecLatency ));
+ }
+
+
+ /* ------------------ OUTPUT */
+ if( outputParameters )
+ {
+ PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ outputParameters->device ];
+ DBUG(("PaHost_OpenStream: deviceID = 0x%x\n", outputDevice));
+
+ bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * outputParameters->channelCount * sizeof(short);
+ if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )
+ {
+ result = paBufferTooSmall;
+ goto error;
+ }
+ else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )
+ {
+ result = paBufferTooBig;
+ goto error;
+ }
+
+
+ hr = dswDSoundEntryPoints.DirectSoundCreate( winDsHostApi->winDsDeviceInfos[outputParameters->device].lpGUID,
+ &dsw->dsw_pDirectSound, NULL );
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DirectSoundCreate() failed!\n"));
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ hr = DSW_InitOutputBuffer( dsw,
+ (unsigned long) (sampleRate + 0.5),
+ outputParameters->channelCount, bytesPerDirectSoundBuffer );
+ DBUG(("DSW_InitOutputBuffer() returns %x\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ /* Calculate value used in latency calculation to avoid real-time divides. */
+ stream->secondsPerHostByte = 1.0 /
+ (stream->bufferProcessor.bytesPerHostOutputSample *
+ outputChannelCount * sampleRate);
+ }
+
+ /* ------------------ INPUT */
+ if( inputParameters )
+ {
+ PaDeviceInfo *deviceInfo = hostApi->deviceInfos[ inputParameters->device ];
+
+ bytesPerDirectSoundBuffer = stream->framesPerDSBuffer * inputParameters->channelCount * sizeof(short);
+ if( bytesPerDirectSoundBuffer < DSBSIZE_MIN )
+ {
+ result = paBufferTooSmall;
+ goto error;
+ }
+ else if( bytesPerDirectSoundBuffer > DSBSIZE_MAX )
+ {
+ result = paBufferTooBig;
+ goto error;
+ }
+
+ hr = dswDSoundEntryPoints.DirectSoundCaptureCreate( winDsHostApi->winDsDeviceInfos[inputParameters->device].lpGUID,
+ &dsw->dsw_pDirectSoundCapture, NULL );
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DirectSoundCaptureCreate() failed!\n"));
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ hr = DSW_InitInputBuffer( dsw,
+ (unsigned long) (sampleRate + 0.5),
+ inputParameters->channelCount, bytesPerDirectSoundBuffer );
+ DBUG(("DSW_InitInputBuffer() returns %x\n", hr));
+ if( hr != DS_OK )
+ {
+ ERR_RPT(("PortAudio: DSW_InitInputBuffer() returns %x\n", hr));
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ }
+
+ }
+
+ *s = (PaStream*)stream;
+
+ return result;
+
+error:
+ if( stream )
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+/***********************************************************************************/
+static PaError Pa_TimeSlice( PaWinDsStream *stream )
+{
+ PaError result = 0; /* FIXME: this should be declared int and this function should also return that type (same as stream callback return type)*/
+ DSoundWrapper *dsw;
+ long numFrames = 0;
+ long bytesEmpty = 0;
+ long bytesFilled = 0;
+ long bytesToXfer = 0;
+ long framesToXfer = 0;
+ long numInFramesReady = 0;
+ long numOutFramesReady = 0;
+ long bytesProcessed;
+ HRESULT hresult;
+ double outputLatency = 0;
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* @todo implement inputBufferAdcTime */
+/* Input */
+ LPBYTE lpInBuf1 = NULL;
+ LPBYTE lpInBuf2 = NULL;
+ DWORD dwInSize1 = 0;
+ DWORD dwInSize2 = 0;
+/* Output */
+ LPBYTE lpOutBuf1 = NULL;
+ LPBYTE lpOutBuf2 = NULL;
+ DWORD dwOutSize1 = 0;
+ DWORD dwOutSize2 = 0;
+
+ dsw = &stream->directSoundWrapper;
+
+ /* How much input data is available? */
+ if( stream->bufferProcessor.inputChannelCount > 0 )
+ {
+ DSW_QueryInputFilled( dsw, &bytesFilled );
+ framesToXfer = numInFramesReady = bytesFilled / dsw->dsw_BytesPerInputFrame;
+ outputLatency = ((double)bytesFilled) * stream->secondsPerHostByte;
+ }
+
+ /* How much output room is available? */
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ DSW_QueryOutputSpace( dsw, &bytesEmpty );
+ framesToXfer = numOutFramesReady = bytesEmpty / dsw->dsw_BytesPerOutputFrame;
+ }
+
+ if( (numInFramesReady > 0) && (numOutFramesReady > 0) )
+ {
+ framesToXfer = (numOutFramesReady < numInFramesReady) ? numOutFramesReady : numInFramesReady;
+ }
+
+ if( framesToXfer > 0 )
+ {
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ /* The outputBufferDacTime parameter should indicates the time at which
+ the first sample of the output buffer is heard at the DACs. */
+ timeInfo.currentTime = PaUtil_GetTime();
+ timeInfo.outputBufferDacTime = timeInfo.currentTime + outputLatency;
+
+
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo );
+
+ /* Input */
+ if( stream->bufferProcessor.inputChannelCount > 0 )
+ {
+ bytesToXfer = framesToXfer * dsw->dsw_BytesPerInputFrame;
+ hresult = IDirectSoundCaptureBuffer_Lock ( dsw->dsw_InputBuffer,
+ dsw->dsw_ReadOffset, bytesToXfer,
+ (void **) &lpInBuf1, &dwInSize1,
+ (void **) &lpInBuf2, &dwInSize2, 0);
+ if (hresult != DS_OK)
+ {
+ ERR_RPT(("DirectSound IDirectSoundCaptureBuffer_Lock failed, hresult = 0x%x\n",hresult));
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );
+ goto error2;
+ }
+
+ numFrames = dwInSize1 / dsw->dsw_BytesPerInputFrame;
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, numFrames );
+ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf1, 0 );
+ /* Is input split into two regions. */
+ if( dwInSize2 > 0 )
+ {
+ numFrames = dwInSize2 / dsw->dsw_BytesPerInputFrame;
+ PaUtil_Set2ndInputFrameCount( &stream->bufferProcessor, numFrames );
+ PaUtil_Set2ndInterleavedInputChannels( &stream->bufferProcessor, 0, lpInBuf2, 0 );
+ }
+ }
+
+ /* Output */
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ bytesToXfer = framesToXfer * dsw->dsw_BytesPerOutputFrame;
+ hresult = IDirectSoundBuffer_Lock ( dsw->dsw_OutputBuffer,
+ dsw->dsw_WriteOffset, bytesToXfer,
+ (void **) &lpOutBuf1, &dwOutSize1,
+ (void **) &lpOutBuf2, &dwOutSize2, 0);
+ if (hresult != DS_OK)
+ {
+ ERR_RPT(("DirectSound IDirectSoundBuffer_Lock failed, hresult = 0x%x\n",hresult));
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hresult );
+ goto error1;
+ }
+
+ numFrames = dwOutSize1 / dsw->dsw_BytesPerOutputFrame;
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, numFrames );
+ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf1, 0 );
+
+ /* Is output split into two regions. */
+ if( dwOutSize2 > 0 )
+ {
+ numFrames = dwOutSize2 / dsw->dsw_BytesPerOutputFrame;
+ PaUtil_Set2ndOutputFrameCount( &stream->bufferProcessor, numFrames );
+ PaUtil_Set2ndInterleavedOutputChannels( &stream->bufferProcessor, 0, lpOutBuf2, 0 );
+ }
+ }
+
+ numFrames = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &result );
+ stream->framesWritten += numFrames;
+
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ /* Update our buffer offset and unlock sound buffer */
+ bytesProcessed = numFrames * dsw->dsw_BytesPerOutputFrame;
+ dsw->dsw_WriteOffset = (dsw->dsw_WriteOffset + bytesProcessed) % dsw->dsw_OutputSize;
+ IDirectSoundBuffer_Unlock( dsw->dsw_OutputBuffer, lpOutBuf1, dwOutSize1, lpOutBuf2, dwOutSize2);
+ dsw->dsw_FramesWritten += numFrames;
+ }
+
+error1:
+ if( stream->bufferProcessor.inputChannelCount > 0 )
+ {
+ /* Update our buffer offset and unlock sound buffer */
+ bytesProcessed = numFrames * dsw->dsw_BytesPerInputFrame;
+ dsw->dsw_ReadOffset = (dsw->dsw_ReadOffset + bytesProcessed) % dsw->dsw_InputSize;
+ IDirectSoundCaptureBuffer_Unlock( dsw->dsw_InputBuffer, lpInBuf1, dwInSize1, lpInBuf2, dwInSize2);
+ }
+error2:
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, numFrames );
+
+ }
+
+ return result;
+}
+/*******************************************************************/
+static void CALLBACK Pa_TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
+{
+ PaWinDsStream *stream;
+
+ stream = (PaWinDsStream *) dwUser;
+ if( stream == NULL ) return;
+
+ if( stream->isActive )
+ {
+ if( stream->abortProcessing )
+ {
+ stream->isActive = 0;
+ }
+ else if( stream->stopProcessing )
+ {
+ DSoundWrapper *dsw = &stream->directSoundWrapper;
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ DSW_ZeroEmptySpace( dsw );
+ /* clear isActive when all sound played */
+ if( dsw->dsw_FramesPlayed >= stream->framesWritten )
+ {
+ stream->isActive = 0;
+ }
+ }
+ else
+ {
+ stream->isActive = 0;
+ }
+ }
+ else
+ {
+ if( Pa_TimeSlice( stream ) != 0) /* Call time slice independant of timing method. */
+ {
+ /* FIXME implement handling of paComplete and paAbort if possible */
+ stream->stopProcessing = 1;
+ }
+ }
+
+ if( !stream->isActive ){
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+ }
+ }
+}
+
+/***********************************************************************************
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ DSW_Term( &stream->directSoundWrapper );
+
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+/***********************************************************************************/
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+ HRESULT hr;
+
+ if( stream->bufferProcessor.inputChannelCount > 0 )
+ {
+ hr = DSW_StartInput( &stream->directSoundWrapper );
+ DBUG(("StartStream: DSW_StartInput returned = 0x%X.\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ }
+
+ stream->framesWritten = 0;
+
+ stream->abortProcessing = 0;
+ stream->stopProcessing = 0;
+ stream->isActive = 1;
+
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ /* Give user callback a chance to pre-fill buffer. REVIEW - i thought we weren't pre-filling, rb. */
+ result = Pa_TimeSlice( stream );
+ if( result != paNoError ) return result; // FIXME - what if finished?
+
+ hr = DSW_StartOutput( &stream->directSoundWrapper );
+ DBUG(("PaHost_StartOutput: DSW_StartOutput returned = 0x%X.\n", hr));
+ if( hr != DS_OK )
+ {
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+ }
+
+
+ /* Create timer that will wake us up so we can fill the DSound buffer. */
+ {
+ int resolution;
+ int framesPerWakeup = stream->framesPerDSBuffer / 4;
+ int msecPerWakeup = MSEC_PER_SECOND * framesPerWakeup / (int) stream->streamRepresentation.streamInfo.sampleRate;
+ if( msecPerWakeup < 10 ) msecPerWakeup = 10;
+ else if( msecPerWakeup > 100 ) msecPerWakeup = 100;
+ resolution = msecPerWakeup/4;
+ stream->timerID = timeSetEvent( msecPerWakeup, resolution, (LPTIMECALLBACK) Pa_TimerCallback,
+ (DWORD) stream, TIME_PERIODIC );
+ }
+ if( stream->timerID == 0 )
+ {
+ stream->isActive = 0;
+ result = paUnanticipatedHostError;
+ PA_DS_SET_LAST_DIRECTSOUND_ERROR( hr );
+ goto error;
+ }
+
+ stream->isStarted = TRUE;
+
+error:
+ return result;
+}
+
+
+/***********************************************************************************/
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+ HRESULT hr;
+ int timeoutMsec;
+
+ stream->stopProcessing = 1;
+ /* Set timeout at 20% beyond maximum time we might wait. */
+ timeoutMsec = (int) (1200.0 * stream->framesPerDSBuffer / stream->streamRepresentation.streamInfo.sampleRate);
+ while( stream->isActive && (timeoutMsec > 0) )
+ {
+ Sleep(10);
+ timeoutMsec -= 10;
+ }
+ if( stream->timerID != 0 )
+ {
+ timeKillEvent(stream->timerID); /* Stop callback timer. */
+ stream->timerID = 0;
+ }
+
+
+ if( stream->bufferProcessor.outputChannelCount > 0 )
+ {
+ hr = DSW_StopOutput( &stream->directSoundWrapper );
+ }
+
+ if( stream->bufferProcessor.inputChannelCount > 0 )
+ {
+ hr = DSW_StopInput( &stream->directSoundWrapper );
+ }
+
+ stream->isStarted = FALSE;
+
+ return result;
+}
+
+
+/***********************************************************************************/
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ stream->abortProcessing = 1;
+ return StopStream( s );
+}
+
+
+/***********************************************************************************/
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ return !stream->isStarted;
+}
+
+
+/***********************************************************************************/
+static PaError IsStreamActive( PaStream *s )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ return stream->isActive;
+}
+
+/***********************************************************************************/
+static PaTime GetStreamTime( PaStream *s )
+{
+/*
+ new behavior for GetStreamTime is to return a stream based seconds clock
+ used for the outTime parameter to the callback.
+ FIXME: delete this comment when the other unnecessary related code has
+ been cleaned from this file.
+
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+ DSoundWrapper *dsw;
+ dsw = &stream->directSoundWrapper;
+ return dsw->dsw_FramesPlayed;
+*/
+ return PaUtil_GetTime();
+}
+
+
+/***********************************************************************************/
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
+
+/***********************************************************************************
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
+
+static PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return paNoError;
+}
+
+
+/***********************************************************************************/
+static PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return paNoError;
+}
+
+
+/***********************************************************************************/
+static signed long GetStreamReadAvailable( PaStream* s )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
+}
+
+
+/***********************************************************************************/
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+ PaWinDsStream *stream = (PaWinDsStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+
+ return 0;
+}
+
+
+
diff --git a/pd/portaudio/pa_win_ds/portaudio.def b/pd/portaudio/pa_win_ds/portaudio.def
new file mode 100644
index 00000000..8012b99e
--- /dev/null
+++ b/pd/portaudio/pa_win_ds/portaudio.def
@@ -0,0 +1,28 @@
+LIBRARY PortAudio
+DESCRIPTION 'PortAudio Portable interface to audio HW'
+
+EXPORTS
+ ; Explicit exports can go here
+ Pa_Initialize @1
+ Pa_Terminate @2
+ Pa_GetHostError @3
+ Pa_GetErrorText @4
+ Pa_CountDevices @5
+ Pa_GetDefaultInputDeviceID @6
+ Pa_GetDefaultOutputDeviceID @7
+ Pa_GetDeviceInfo @8
+ Pa_OpenStream @9
+ Pa_OpenDefaultStream @10
+ Pa_CloseStream @11
+ Pa_StartStream @12
+ Pa_StopStream @13
+ Pa_StreamActive @14
+ Pa_StreamTime @15
+ Pa_GetCPULoad @16
+ Pa_GetMinNumBuffers @17
+ Pa_Sleep @18
+
+ ;123456789012345678901234567890123456
+ ;000000000111111111122222222223333333
+
+
diff --git a/pd/portaudio/pa_win_wmme/Makefile.cygwin b/pd/portaudio/pa_win_wmme/Makefile.cygwin
new file mode 100644
index 00000000..5cb4acef
--- /dev/null
+++ b/pd/portaudio/pa_win_wmme/Makefile.cygwin
@@ -0,0 +1,34 @@
+
+# Makefile for PortAudio on cygwin
+# Contributed by Bill Eldridge on 6/13/2001
+
+ARCH= pa_win_wmme
+
+TESTS:= $(wildcard pa_tests/pa*.c pa_tests/debug*.c)
+
+.c.o:
+ -gcc -c -I./pa_common $< -o $*.o
+ -gcc $*.o -o $*.exe -L/usr/local/lib -L$(ARCH) -lportaudio.dll -lwinmm
+
+all: sharedlib tests
+
+sharedlib: ./pa_common/pa_lib.c
+ gcc -c -I./pa_common pa_common/pa_lib.c -o pa_common/pa_lib.o
+ gcc -c -I./pa_common pa_win_wmme/pa_win_wmme.c -o pa_win_wmme/pa_win_wmme.o
+ dlltool --export-all --output-def pa_win_wmme/pa_lib.def pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o
+ gcc -shared -Wl,--enable-auto-image-base -o pa_win_wmme/portaudio.dll -Wl,--out-implib=pa_win_wmme/libportaudio.dll.a pa_win_wmme/pa_lib.def pa_common/pa_lib.o pa_win_wmme/pa_win_wmme.o -L/usr/lib/w32api -lwinmm
+ cp pa_win_wmme/portaudio.dll /usr/local/bin
+
+tests: $(TESTS:.c=.o)
+
+sine:
+ gcc -c -I./pa_common pa_tests/patest_sine.c -o pa_tests/patest_sine.o
+ gcc pa_tests/patest_sine.o -o pa_tests/patest_sine.exe -L/usr/local/lib -lportaudio.dll -lwinmm
+
+clean:
+ -rm ./pa_tests/*.exe
+
+nothing:
+ gcc pa_tests/patest_sine.o -L/usr/lib/w32api -L./pa_win_wmme -lportaudio.dll -lwinmm
+
+
diff --git a/pd/portaudio/pa_win_wmme/pa_win_wmme.c b/pd/portaudio/pa_win_wmme/pa_win_wmme.c
new file mode 100644
index 00000000..2b1cc57d
--- /dev/null
+++ b/pd/portaudio/pa_win_wmme/pa_win_wmme.c
@@ -0,0 +1,2672 @@
+/*
+ * $Id: pa_win_wmme.c,v 1.6.2.44 2003/03/18 14:27:58 rossbencina Exp $
+ * pa_win_wmme.c
+ * Implementation of PortAudio for Windows MultiMedia Extensions (WMME)
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ *
+ * Authors: Ross Bencina and Phil Burk
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* Modification History:
+ PLB = Phil Burk
+ JM = Julien Maillard
+ RDB = Ross Bencina
+ PLB20010402 - sDevicePtrs now allocates based on sizeof(pointer)
+ PLB20010413 - check for excessive numbers of channels
+ PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
+ including conditional inclusion of memory.h,
+ and explicit typecasting on memory allocation
+ PLB20010802 - use GlobalAlloc for sDevicesPtr instead of PaHost_AllocFastMemory
+ PLB20010816 - pass process instead of thread to SetPriorityClass()
+ PLB20010927 - use number of frames instead of real-time for CPULoad calculation.
+ JM20020118 - prevent hung thread when buffers underflow.
+ PLB20020321 - detect Win XP versus NT, 9x; fix DBUG typo; removed init of CurrentCount
+ RDB20020411 - various renaming cleanups, factored streamData alloc and cpu usage init
+ RDB20020417 - stopped counting WAVE_MAPPER when there were no real devices
+ refactoring, renaming and fixed a few edge case bugs
+ RDB20020531 - converted to V19 framework
+ ** NOTE maintanance history is now stored in CVS **
+*/
+
+/** @file
+
+ @todo Handle case where user supplied full duplex buffer sizes are not compatible
+ (must be common multiples)
+
+ @todo Fix buffer catch up code, can sometimes get stuck
+
+ @todo Implement "close sample rate matching" if needed - is this really needed
+ in mme?
+
+ @todo Investigate supporting host buffer formats > 16 bits
+
+ @todo Implement buffer size and number of buffers code,
+ this code should generate defaults the way the old code did
+
+ @todo implement underflow/overflow streamCallback statusFlags, paNeverDropInput.
+
+ @todo Fix fixmes
+
+ @todo implement initialisation of PaDeviceInfo default*Latency fields (currently set to 0.)
+
+ @todo implement ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable
+
+ @todo implement IsFormatSupported
+
+ @todo implement PaDeviceInfo.defaultSampleRate;
+
+ @todo define UNICODE and _UNICODE in the project settings and see what breaks
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <windows.h>
+#include <mmsystem.h>
+#include <process.h>
+#include <assert.h>
+/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
+#ifndef __MWERKS__
+#include <malloc.h>
+#include <memory.h>
+#endif /* __MWERKS__ */
+
+#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 "pa_win_wmme.h"
+
+/************************************************* Constants ********/
+
+/* Switches for debugging. */
+#define PA_SIMULATE_UNDERFLOW_ (0) /* Set to one to force an underflow of the output buffer. */
+
+#define PA_USE_HIGH_LATENCY_ (0) /* For debugging glitches. */
+
+#if PA_USE_HIGH_LATENCY_
+ #define PA_MIN_MSEC_PER_HOST_BUFFER_ (100)
+ #define PA_MAX_MSEC_PER_HOST_BUFFER_ (300) /* Do not exceed unless user buffer exceeds */
+ #define PA_MIN_NUM_HOST_BUFFERS_ (4)
+ #define PA_MAX_NUM_HOST_BUFFERS_ (16) /* OK to exceed if necessary */
+ #define PA_WIN_9X_LATENCY_ (400)
+#else
+ #define PA_MIN_MSEC_PER_HOST_BUFFER_ (10)
+ #define PA_MAX_MSEC_PER_HOST_BUFFER_ (100) /* Do not exceed unless user buffer exceeds */
+ #define PA_MIN_NUM_HOST_BUFFERS_ (3)
+ #define PA_MAX_NUM_HOST_BUFFERS_ (16) /* OK to exceed if necessary */
+ #define PA_WIN_9X_LATENCY_ (200)
+#endif
+
+#define PA_MIN_TIMEOUT_MSEC_ (1000)
+
+/*
+** Use higher latency for NT because it is even worse at real-time
+** operation than Win9x.
+*/
+#define PA_WIN_NT_LATENCY_ (PA_WIN_9X_LATENCY_ * 2)
+#define PA_WIN_WDM_LATENCY_ (PA_WIN_9X_LATENCY_)
+
+
+static const char constInputMapperSuffix_[] = " - Input";
+static const char constOutputMapperSuffix_[] = " - Output";
+
+
+typedef struct PaWinMmeStream PaWinMmeStream; /* forward reference */
+
+/* prototypes for functions declared in this file */
+
+PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex );
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi );
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** stream,
+ 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 CloseStream( PaStream* stream );
+static PaError StartStream( PaStream *stream );
+static PaError StopStream( PaStream *stream );
+static PaError AbortStream( PaStream *stream );
+static PaError IsStreamStopped( PaStream *s );
+static PaError IsStreamActive( PaStream *stream );
+static PaTime GetStreamTime( PaStream *stream );
+static double GetStreamCpuLoad( PaStream* stream );
+static PaError ReadStream( PaStream* stream, void *buffer, unsigned long frames );
+static PaError WriteStream( PaStream* stream, void *buffer, unsigned long frames );
+static signed long GetStreamReadAvailable( PaStream* stream );
+static signed long GetStreamWriteAvailable( PaStream* stream );
+
+static PaError UpdateStreamTime( PaWinMmeStream *stream );
+
+/* macros for setting last host error information */
+
+#ifdef UNICODE
+
+#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \
+ { \
+ wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \
+ char mmeErrorText[ MAXERRORLENGTH ]; \
+ waveInGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \
+ WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\
+ mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \
+ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
+ }
+
+#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \
+ { \
+ wchar_t mmeErrorTextWide[ MAXERRORLENGTH ]; \
+ char mmeErrorText[ MAXERRORLENGTH ]; \
+ waveOutGetErrorText( mmresult, mmeErrorTextWide, MAXERRORLENGTH ); \
+ WideCharToMultiByte( CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR,\
+ mmeErrorTextWide, -1, mmeErrorText, MAXERRORLENGTH, NULL, NULL ); \
+ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
+ }
+
+#else /* !UNICODE */
+
+#define PA_MME_SET_LAST_WAVEIN_ERROR( mmresult ) \
+ { \
+ char mmeErrorText[ MAXERRORLENGTH ]; \
+ waveInGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \
+ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
+ }
+
+#define PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult ) \
+ { \
+ char mmeErrorText[ MAXERRORLENGTH ]; \
+ waveOutGetErrorText( mmresult, mmeErrorText, MAXERRORLENGTH ); \
+ PaUtil_SetLastHostErrorInfo( paMME, mmresult, mmeErrorText ); \
+ }
+
+#endif /* UNICODE */
+
+
+static void PaMme_SetLastSystemError( DWORD errorCode )
+{
+ LPVOID lpMsgBuf;
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ errorCode,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+ PaUtil_SetLastHostErrorInfo( paMME, errorCode, lpMsgBuf );
+ LocalFree( lpMsgBuf );
+}
+
+#define PA_MME_SET_LAST_SYSTEM_ERROR( errorCode ) \
+ PaMme_SetLastSystemError( errorCode )
+
+
+/* PaWinMmeHostApiRepresentation - host api datastructure specific to this implementation */
+
+typedef struct
+{
+ PaUtilHostApiRepresentation inheritedHostApiRep;
+ PaUtilStreamInterface callbackStreamInterface;
+ PaUtilStreamInterface blockingStreamInterface;
+
+ PaUtilAllocationGroup *allocations;
+
+ int numInputDevices, numOutputDevices;
+
+ /** winMmeDeviceIds is an array of WinMme device ids.
+ fields in the range [0, numInputDevices) are input device ids,
+ and [numInputDevices, numInputDevices + numOutputDevices) are output
+ device ids.
+ */
+ int *winMmeDeviceIds;
+}
+PaWinMmeHostApiRepresentation;
+
+
+/*************************************************************************
+ * Returns recommended device ID.
+ * On the PC, the recommended device can be specified by the user by
+ * setting an environment variable. For example, to use device #1.
+ *
+ * set PA_RECOMMENDED_OUTPUT_DEVICE=1
+ *
+ * The user should first determine the available device ID by using
+ * the supplied application "pa_devs".
+ */
+#define PA_ENV_BUF_SIZE_ (32)
+#define PA_REC_IN_DEV_ENV_NAME_ ("PA_RECOMMENDED_INPUT_DEVICE")
+#define PA_REC_OUT_DEV_ENV_NAME_ ("PA_RECOMMENDED_OUTPUT_DEVICE")
+static PaDeviceIndex GetEnvDefaultDeviceID( char *envName )
+{
+ PaDeviceIndex recommendedIndex = paNoDevice;
+ DWORD hresult;
+ char envbuf[PA_ENV_BUF_SIZE_];
+
+#ifndef WIN32_PLATFORM_PSPC /* no GetEnvironmentVariable on PocketPC */
+
+ /* Let user determine default device by setting environment variable. */
+ hresult = GetEnvironmentVariable( envName, envbuf, PA_ENV_BUF_SIZE_ );
+ if( (hresult > 0) && (hresult < PA_ENV_BUF_SIZE_) )
+ {
+ recommendedIndex = atoi( envbuf );
+ }
+#endif
+
+ return recommendedIndex;
+}
+
+static void InitializeDefaultDeviceIdsFromEnv( PaWinMmeHostApiRepresentation *hostApi )
+{
+ PaDeviceIndex device;
+
+ /* input */
+ device = GetEnvDefaultDeviceID( PA_REC_IN_DEV_ENV_NAME_ );
+ if( device != paNoDevice &&
+ ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
+ hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxInputChannels > 0 )
+ {
+ hostApi->inheritedHostApiRep.info.defaultInputDevice = device;
+ }
+
+ /* output */
+ device = GetEnvDefaultDeviceID( PA_REC_OUT_DEV_ENV_NAME_ );
+ if( device != paNoDevice &&
+ ( device >= 0 && device < hostApi->inheritedHostApiRep.info.deviceCount ) &&
+ hostApi->inheritedHostApiRep.deviceInfos[ device ]->maxOutputChannels > 0 )
+ {
+ hostApi->inheritedHostApiRep.info.defaultOutputDevice = device;
+ }
+}
+
+
+/** Convert external PA ID to a windows multimedia device ID
+*/
+static int LocalDeviceIndexToWinMmeDeviceId( PaWinMmeHostApiRepresentation *hostApi, PaDeviceIndex device )
+{
+ assert( device >= 0 && device < hostApi->numInputDevices + hostApi->numOutputDevices );
+
+ return hostApi->winMmeDeviceIds[ device ];
+}
+
+
+static PaError InitializeInputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
+ PaDeviceInfo *deviceInfo, int winMmeInputDeviceId, int *success )
+{
+ PaError result = paNoError;
+ char *deviceName; /* non-const ptr */
+ MMRESULT mmresult;
+ WAVEINCAPS wic;
+
+ *success = 0;
+
+ mmresult = waveInGetDevCaps( winMmeInputDeviceId, &wic, sizeof( WAVEINCAPS ) );
+ if( mmresult == MMSYSERR_NOMEM )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ else if( mmresult != MMSYSERR_NOERROR )
+ {
+ /* instead of returning paUnanticipatedHostError we return
+ paNoError, but leave success set as 0. This allows
+ Pa_Initialize to just ignore this device, without failing
+ the entire initialisation process.
+ */
+ return paNoError;
+ }
+
+ if( winMmeInputDeviceId == WAVE_MAPPER )
+ {
+ /* Append I/O suffix to WAVE_MAPPER device. */
+ deviceName = (char *)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, strlen( wic.szPname ) + 1 + sizeof(constInputMapperSuffix_) );
+ if( !deviceName )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ strcpy( deviceName, wic.szPname );
+ strcat( deviceName, constInputMapperSuffix_ );
+ }
+ else
+ {
+ deviceName = (char*)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, strlen( wic.szPname ) + 1 );
+ if( !deviceName )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ strcpy( deviceName, wic.szPname );
+ }
+ deviceInfo->name = deviceName;
+
+ deviceInfo->maxInputChannels = wic.wChannels;
+ /* Sometimes a device can return a rediculously large number of channels.
+ * This happened with an SBLive card on a Windows ME box.
+ * If that happens, then force it to 2 channels. PLB20010413
+ */
+ if( (deviceInfo->maxInputChannels < 1) || (deviceInfo->maxInputChannels > 256) )
+ {
+ PA_DEBUG(("Pa_GetDeviceInfo: Num input channels reported as %d! Changed to 2.\n", deviceInfo->maxInputChannels ));
+ deviceInfo->maxInputChannels = 2;
+ }
+
+ deviceInfo->defaultSampleRate = 0.; /* @todo IMPLEMENT ME */
+
+ *success = 1;
+
+error:
+ return result;
+}
+
+
+static PaError InitializeOutputDeviceInfo( PaWinMmeHostApiRepresentation *winMmeHostApi,
+ PaDeviceInfo *deviceInfo, int winMmeOutputDeviceId, int *success )
+{
+ PaError result = paNoError;
+ char *deviceName; /* non-const ptr */
+ MMRESULT mmresult;
+ WAVEOUTCAPS woc;
+
+ *success = 0;
+
+ mmresult = waveOutGetDevCaps( winMmeOutputDeviceId, &woc, sizeof( WAVEOUTCAPS ) );
+ if( mmresult == MMSYSERR_NOMEM )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ else if( mmresult != MMSYSERR_NOERROR )
+ {
+ /* instead of returning paUnanticipatedHostError we return
+ paNoError, but leave success set as 0. This allows
+ Pa_Initialize to just ignore this device, without failing
+ the entire initialisation process.
+ */
+ return paNoError;
+ }
+
+ if( winMmeOutputDeviceId == WAVE_MAPPER )
+ {
+ /* Append I/O suffix to WAVE_MAPPER device. */
+ deviceName = (char *)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, strlen( woc.szPname ) + 1 + sizeof(constOutputMapperSuffix_) );
+ if( !deviceName )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ strcpy( deviceName, woc.szPname );
+ strcat( deviceName, constOutputMapperSuffix_ );
+ }
+ else
+ {
+ deviceName = (char*)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, strlen( woc.szPname ) + 1 );
+ if( !deviceName )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ strcpy( deviceName, woc.szPname );
+ }
+ deviceInfo->name = deviceName;
+
+ deviceInfo->maxOutputChannels = woc.wChannels;
+ /* Sometimes a device can return a rediculously large number of channels.
+ * This happened with an SBLive card on a Windows ME box.
+ * It also happens on Win XP!
+ */
+ if( (deviceInfo->maxOutputChannels < 1) || (deviceInfo->maxOutputChannels > 256) )
+ {
+ PA_DEBUG(("Pa_GetDeviceInfo: Num output channels reported as %d! Changed to 2.\n", deviceInfo->maxOutputChannels ));
+ deviceInfo->maxOutputChannels = 2;
+ }
+
+ deviceInfo->defaultSampleRate = 0.; /* @todo IMPLEMENT ME */
+
+ *success = 1;
+
+error:
+ return result;
+}
+
+
+PaError PaWinMme_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+ PaError result = paNoError;
+ int i;
+ PaWinMmeHostApiRepresentation *winMmeHostApi;
+ int numInputDevices, numOutputDevices, maximumPossibleNumDevices;
+ PaDeviceInfo *deviceInfoArray;
+ int deviceInfoInitializationSucceeded;
+
+ winMmeHostApi = (PaWinMmeHostApiRepresentation*)PaUtil_AllocateMemory( sizeof(PaWinMmeHostApiRepresentation) );
+ if( !winMmeHostApi )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ winMmeHostApi->allocations = PaUtil_CreateAllocationGroup();
+ if( !winMmeHostApi->allocations )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ *hostApi = &winMmeHostApi->inheritedHostApiRep;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paMME;
+ (*hostApi)->info.name = "MME";
+
+
+ /* 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)->info.deviceCount = 0;
+ (*hostApi)->info.defaultInputDevice = paNoDevice;
+ (*hostApi)->info.defaultOutputDevice = paNoDevice;
+ winMmeHostApi->numInputDevices = 0;
+ winMmeHostApi->numOutputDevices = 0;
+
+
+ maximumPossibleNumDevices = 0;
+
+ numInputDevices = waveInGetNumDevs();
+ if( numInputDevices > 0 )
+ maximumPossibleNumDevices += numInputDevices + 1; /* assume there is a WAVE_MAPPER */
+
+ numOutputDevices = waveOutGetNumDevs();
+ if( numOutputDevices > 0 )
+ maximumPossibleNumDevices += numOutputDevices + 1; /* assume there is a WAVE_MAPPER */
+
+
+ if( maximumPossibleNumDevices > 0 ){
+
+ (*hostApi)->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, sizeof(PaDeviceInfo*) * maximumPossibleNumDevices );
+ if( !(*hostApi)->deviceInfos )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ /* allocate all device info structs in a contiguous block */
+ deviceInfoArray = (PaDeviceInfo*)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, sizeof(PaDeviceInfo) * maximumPossibleNumDevices );
+ if( !deviceInfoArray )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ winMmeHostApi->winMmeDeviceIds = (int*)PaUtil_GroupAllocateMemory(
+ winMmeHostApi->allocations, sizeof(int) * maximumPossibleNumDevices );
+ if( !winMmeHostApi->winMmeDeviceIds )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ if( numInputDevices > 0 ){
+ // -1 is the WAVE_MAPPER
+ for( i = -1; i < numInputDevices; ++i ){
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+
+ deviceInfo->maxInputChannels = 0;
+ deviceInfo->maxOutputChannels = 0;
+
+ deviceInfo->defaultLowInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultLowOutputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighOutputLatency = 0.; /* @todo IMPLEMENT ME */
+
+ result = InitializeInputDeviceInfo( winMmeHostApi, deviceInfo, i, &deviceInfoInitializationSucceeded );
+ if( result != paNoError )
+ goto error;
+
+ if( deviceInfoInitializationSucceeded ){
+ if( (*hostApi)->info.defaultInputDevice == paNoDevice )
+ (*hostApi)->info.defaultInputDevice = (*hostApi)->info.deviceCount;
+
+ winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = i;
+ (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
+
+ winMmeHostApi->numInputDevices++;
+ (*hostApi)->info.deviceCount++;
+ }
+ }
+ }
+
+ if( numOutputDevices > 0 ){
+ // -1 is the WAVE_MAPPER
+ for( i = -1; i < numOutputDevices; ++i ){
+ PaDeviceInfo *deviceInfo = &deviceInfoArray[ (*hostApi)->info.deviceCount ];
+ deviceInfo->structVersion = 2;
+ deviceInfo->hostApi = hostApiIndex;
+
+ deviceInfo->maxInputChannels = 0;
+ deviceInfo->maxOutputChannels = 0;
+
+ deviceInfo->defaultLowInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultLowOutputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighInputLatency = 0.; /* @todo IMPLEMENT ME */
+ deviceInfo->defaultHighOutputLatency = 0.; /* @todo IMPLEMENT ME */
+
+ result = InitializeOutputDeviceInfo( winMmeHostApi, deviceInfo, i, &deviceInfoInitializationSucceeded );
+ if( result != paNoError )
+ goto error;
+
+ if( deviceInfoInitializationSucceeded ){
+ if( (*hostApi)->info.defaultOutputDevice == paNoDevice )
+ (*hostApi)->info.defaultOutputDevice = (*hostApi)->info.deviceCount;
+
+ winMmeHostApi->winMmeDeviceIds[ (*hostApi)->info.deviceCount ] = i;
+ (*hostApi)->deviceInfos[ (*hostApi)->info.deviceCount ] = deviceInfo;
+
+ winMmeHostApi->numOutputDevices++;
+ (*hostApi)->info.deviceCount++;
+ }
+ }
+ }
+ }
+
+
+ InitializeDefaultDeviceIdsFromEnv( winMmeHostApi );
+
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface( &winMmeHostApi->callbackStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, GetStreamCpuLoad,
+ PaUtil_DummyReadWrite, PaUtil_DummyReadWrite, PaUtil_DummyGetAvailable, PaUtil_DummyGetAvailable );
+
+ PaUtil_InitializeStreamInterface( &winMmeHostApi->blockingStreamInterface, CloseStream, StartStream,
+ StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+ GetStreamTime, PaUtil_DummyGetCpuLoad,
+ ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+
+ return result;
+
+error:
+ if( winMmeHostApi )
+ {
+ if( winMmeHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( winMmeHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( winMmeHostApi );
+ }
+
+ return result;
+}
+
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+ PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
+
+ if( winMmeHostApi->allocations )
+ {
+ PaUtil_FreeAllAllocations( winMmeHostApi->allocations );
+ PaUtil_DestroyAllocationGroup( winMmeHostApi->allocations );
+ }
+
+ PaUtil_FreeMemory( winMmeHostApi );
+}
+
+
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate )
+{
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( inputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that input device can support inputChannelCount */
+ if( inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* validate inputStreamInfo */
+ if( inputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ inputChannelCount = 0;
+ }
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+
+ /* unless alternate device specification is supported, reject the use of
+ paUseHostApiSpecificDeviceSpecification */
+
+ if( outputParameters->device == paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ /* check that output device can support inputChannelCount */
+ if( outputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* validate outputStreamInfo */
+ if( outputParameters->hostApiSpecificStreamInfo )
+ return paIncompatibleHostApiSpecificStreamInfo; /* this implementation doesn't use custom stream info */
+ }
+ else
+ {
+ outputChannelCount = 0;
+ }
+
+ /*
+ IMPLEMENT ME:
+ - check that input device can support inputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - check that output device can support outputSampleFormat, or that
+ we have the capability to convert from outputSampleFormat to
+ a native format
+
+ - if a full duplex stream is requested, check that the combination
+ of input and output parameters is supported
+
+ - check that the device supports sampleRate
+ */
+
+ return paFormatIsSupported;
+}
+
+
+/* CalculateBufferSettings() fills the framesPerHostInputBuffer, numHostInputBuffers,
+ framesPerHostOutputBuffer and numHostOutputBuffers parameters based on the values
+ of the other parameters.
+
+*/
+
+static PaError CalculateBufferSettings(
+ unsigned long *framesPerHostInputBuffer, unsigned long *numHostInputBuffers,
+ unsigned long *framesPerHostOutputBuffer, unsigned long *numHostOutputBuffers,
+ int inputChannelCount, PaSampleFormat hostInputSampleFormat,
+ PaTime suggestedInputLatency, PaWinMmeStreamInfo *inputStreamInfo,
+ int outputChannelCount, PaSampleFormat hostOutputSampleFormat,
+ PaTime suggestedOutputLatency, PaWinMmeStreamInfo *outputStreamInfo,
+ double sampleRate, unsigned long framesPerBuffer )
+{
+ PaError result = paNoError;
+
+ if( inputChannelCount > 0 )
+ {
+ if( inputStreamInfo )
+ {
+ if( inputStreamInfo->flags & PaWinMmeUseLowLevelLatencyParameters )
+ {
+ if( inputStreamInfo->numBuffers <= 0
+ || inputStreamInfo->framesPerBuffer <= 0 )
+ {
+ result = paIncompatibleHostApiSpecificStreamInfo;
+ goto error;
+ }
+
+ *framesPerHostInputBuffer = inputStreamInfo->framesPerBuffer;
+ *numHostInputBuffers = inputStreamInfo->numBuffers;
+ }
+ }
+ else
+ {
+ /* hardwire for now, FIXME */
+ /* don't forget that there will be one more buffer than the number required to achieve the requested latency */
+ *framesPerHostInputBuffer = 4096;
+ *numHostInputBuffers = 4;
+
+ /*
+ Need to determine the right heuristic for mapping latency in
+ seconds to buffer sizes and number of buffers.
+
+ - for output don't allocate less than 1+1 buffers
+
+ - for input don't allocate less than 2+1 buffers
+ (less than 1+1 if input only)
+
+ - don't allocate buffers smaller than framesPerBuffer
+
+ - if the client doesn't care about the buffer size use a power
+ of two buffer size. otherwise use a multiple of the user
+ buffer size. if the user buffer size is a power of 2, it
+ might be wise to make the host buffer size a power of 2 too.
+
+ - there probably shouldn't be too many buffers ( 3 to 10 seems
+ reasonable).
+
+ - aside from a limit on what constitutes a "reasonable" number
+ of buffers, there should be as many buffers as possible,
+ because this will place a less bursty load on CPU resources
+
+ - the host buffers should be as big as practical (ie multiple
+ user buffers per host buffer).
+
+
+ . One way to achieve the above is to say: Try to have 8
+ host buffers, and host buffers cannot be larger than 32k
+ unless the user buffer size requires it"
+ I say 32k because buffers larger than this are known to
+ crash some drivers (Turtle Beach for example.)
+
+ just some idle rambling:
+
+ if( framesPerBuffer == 0 ){
+ // use a power of two buffer size
+
+ }else{
+ latencySamples = ceil(requestedLatency * sampleRate)
+
+ numBuffers = ceil(latencySamples / framesPerBuffer);
+
+ bufferSize = framesPerBuffer;
+
+ minBuffers = ( inputChannelCount > 0 && outputChannelCount > 0 ) ? 2 : 1;
+
+ if( numBuffers <= minBuffers ){
+ numBuffers = minBuffers;
+ }else{
+ make buffer size a multiple of framesPerBuffer until numBuffers is
+ greater than 4 and less than 10.
+ }
+ }
+ */
+ }
+ }
+ else
+ {
+ *framesPerHostInputBuffer = 0;
+ *numHostInputBuffers = 0;
+ }
+
+ if( outputChannelCount > 0 )
+ {
+ if( outputStreamInfo )
+ {
+ if( outputStreamInfo->flags & PaWinMmeUseLowLevelLatencyParameters )
+ {
+ if( outputStreamInfo->numBuffers <= 0
+ || outputStreamInfo->framesPerBuffer <= 0 )
+ {
+ result = paIncompatibleHostApiSpecificStreamInfo;
+ goto error;
+ }
+
+ *framesPerHostOutputBuffer = outputStreamInfo->framesPerBuffer;
+ *numHostOutputBuffers = outputStreamInfo->numBuffers;
+ }
+ }
+ else
+ {
+ /* hardwire for now, FIXME */
+ /* don't forget that there will be one more buffer than the number required to achieve the requested latency */
+ *framesPerHostOutputBuffer = 4096;
+ *numHostOutputBuffers = 4;
+ }
+ }
+ else
+ {
+ *framesPerHostOutputBuffer = 0;
+ *numHostOutputBuffers = 0;
+ }
+
+error:
+ return result;
+}
+
+
+
+typedef HWAVEIN MmeHandle;
+
+static PaError InitializeBufferSet( WAVEHDR **bufferSet, int numBuffers, int bufferBytes,
+ int isInput, /* if 0, then output */
+ MmeHandle mmeWaveHandle, int numDeviceChannels )
+{
+ PaError result = paNoError;
+ MMRESULT mmresult;
+ int i;
+
+ *bufferSet = 0;
+
+ /* Allocate an array to hold the buffer pointers. */
+ *bufferSet = (WAVEHDR *) PaUtil_AllocateMemory( sizeof(WAVEHDR)*numBuffers );
+ if( !*bufferSet )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i=0; i<numBuffers; ++i )
+ {
+ (*bufferSet)[i].lpData = 0;
+ }
+
+ /* Allocate each buffer. */
+ for( i=0; i<numBuffers; ++i )
+ {
+ (*bufferSet)[i].lpData = (char *)PaUtil_AllocateMemory( bufferBytes );
+ if( !(*bufferSet)[i].lpData )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ (*bufferSet)[i].dwBufferLength = bufferBytes;
+ (*bufferSet)[i].dwUser = 0xFFFFFFFF; /* indicates unprepared to error clean up code */
+
+ if( isInput )
+ {
+ mmresult = waveInPrepareHeader( mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ goto error;
+ }
+ }
+ else /* output */
+ {
+ mmresult = waveOutPrepareHeader( (HWAVEOUT)mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ goto error;
+ }
+ }
+
+ (*bufferSet)[i].dwUser = numDeviceChannels;
+ }
+
+ return result;
+
+error:
+ if( *bufferSet )
+ {
+ for( i=0; i<numBuffers; ++i )
+ {
+ if( (*bufferSet)[i].lpData )
+ {
+
+ if( (*bufferSet)[i].dwUser != 0xFFFFFFFF )
+ {
+ if( isInput )
+ waveInUnprepareHeader( mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+ else
+ waveOutUnprepareHeader( (HWAVEOUT)mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+ }
+ PaUtil_FreeMemory( (*bufferSet)[i].lpData );
+ }
+ }
+
+ PaUtil_FreeMemory( *bufferSet );
+ }
+
+ return result;
+}
+
+
+static void TerminateBufferSet( WAVEHDR * *bufferSet, unsigned int numBuffers, int isInput, MmeHandle mmeWaveHandle )
+{
+ unsigned int i;
+
+ for( i=0; i<numBuffers; ++i )
+ {
+ if( (*bufferSet)[i].lpData )
+ {
+ if( isInput )
+ waveInUnprepareHeader( mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+ else
+ waveOutUnprepareHeader( (HWAVEOUT)mmeWaveHandle, &(*bufferSet)[i], sizeof(WAVEHDR) );
+
+ PaUtil_FreeMemory( (*bufferSet)[i].lpData );
+ }
+ }
+
+ if( *bufferSet )
+ PaUtil_FreeMemory( *bufferSet );
+}
+
+
+/* PaWinMmeStream - a stream data structure specifically for this implementation */
+
+typedef struct PaWinMmeStream
+{
+ PaUtilStreamRepresentation streamRepresentation;
+ PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+ PaUtilBufferProcessor bufferProcessor;
+
+ CRITICAL_SECTION lock;
+
+ /* Input -------------- */
+ HWAVEIN *hWaveIns;
+ unsigned int numInputDevices;
+ /* unsigned int inputChannelCount; */
+ WAVEHDR **inputBuffers;
+ unsigned int numInputBuffers;
+ unsigned int currentInputBufferIndex;
+ unsigned int framesPerInputBuffer;
+ unsigned int framesUsedInCurrentInputBuffer;
+
+ /* Output -------------- */
+ HWAVEOUT *hWaveOuts;
+ unsigned int numOutputDevices;
+ /* unsigned int outputChannelCount; */
+ WAVEHDR **outputBuffers;
+ unsigned int numOutputBuffers;
+ unsigned int currentOutputBufferIndex;
+ unsigned int framesPerOutputBuffer;
+ unsigned int framesUsedInCurrentOutputBuffer;
+
+ /* Processing thread management -------------- */
+ HANDLE abortEvent;
+ HANDLE bufferEvent;
+ HANDLE processingThread;
+ DWORD processingThreadId;
+
+ char noHighPriorityProcessClass;
+ char useTimeCriticalProcessingThreadPriority;
+ char throttleProcessingThreadOnOverload; /* 0 -> don't throtte, non-0 -> throttle */
+ int processingThreadPriority;
+ int highThreadPriority;
+ int throttledThreadPriority;
+
+ 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 */
+
+ /* @todo FIXME: we no longer need the following for GetStreamTime support */
+ /* GetStreamTime() support ------------- */
+
+ PaTime streamPosition;
+ long previousStreamPosition; /* used to track frames played. */
+}
+PaWinMmeStream;
+
+
+/* the following macros are intended to improve the readability of the following code */
+#define PA_IS_INPUT_STREAM_( stream ) ( stream ->hWaveIns )
+#define PA_IS_OUTPUT_STREAM_( stream ) ( stream ->hWaveOuts )
+#define PA_IS_FULL_DUPLEX_STREAM_( stream ) ( stream ->hWaveIns && stream ->hWaveOuts )
+
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+ PaStream** s,
+ const PaStreamParameters *inputParameters,
+ const PaStreamParameters *outputParameters,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData )
+{
+ PaError result = paNoError;
+ PaWinMmeHostApiRepresentation *winMmeHostApi = (PaWinMmeHostApiRepresentation*)hostApi;
+ PaWinMmeStream *stream = 0;
+ PaSampleFormat hostInputSampleFormat, hostOutputSampleFormat;
+ int inputChannelCount, outputChannelCount;
+ PaSampleFormat inputSampleFormat, outputSampleFormat;
+ double suggestedInputLatency, suggestedOutputLatency;
+ PaWinMmeStreamInfo *inputStreamInfo, *outputStreamInfo;
+ unsigned long bytesPerInputFrame, bytesPerOutputFrame;
+ unsigned long framesPerHostInputBuffer;
+ unsigned long numHostInputBuffers;
+ unsigned long framesPerHostOutputBuffer;
+ unsigned long numHostOutputBuffers;
+ unsigned long framesPerBufferProcessorCall;
+ int lockInited = 0;
+ int bufferEventInited = 0;
+ int abortEventInited = 0;
+ WAVEFORMATEX wfx;
+ MMRESULT mmresult;
+ unsigned int i;
+ int channelCount;
+ PaWinMmeDeviceAndChannelCount *inputDevices = 0;
+ unsigned long numInputDevices = (inputParameters) ? 1 : 0;
+ PaWinMmeDeviceAndChannelCount *outputDevices = 0;
+ unsigned long numOutputDevices = (outputParameters) ? 1 : 0;
+ char noHighPriorityProcessClass = 0;
+ char useTimeCriticalProcessingThreadPriority = 0;
+ char throttleProcessingThreadOnOverload = 1;
+
+
+ if( inputParameters )
+ {
+ inputChannelCount = inputParameters->channelCount;
+ inputSampleFormat = inputParameters->sampleFormat;
+ suggestedInputLatency = inputParameters->suggestedLatency;
+
+ /* check that input device can support inputChannelCount */
+ if( (inputParameters->device != paUseHostApiSpecificDeviceSpecification) &&
+ (inputChannelCount > hostApi->deviceInfos[ inputParameters->device ]->maxInputChannels) )
+ return paInvalidChannelCount;
+
+
+ /* validate input hostApiSpecificStreamInfo */
+ inputStreamInfo = (PaWinMmeStreamInfo*)inputParameters->hostApiSpecificStreamInfo;
+ if( inputStreamInfo )
+ {
+ if( inputStreamInfo->size != sizeof( PaWinMmeStreamInfo )
+ || inputStreamInfo->version != 1 )
+ {
+ return paIncompatibleHostApiSpecificStreamInfo;
+ }
+
+ if( inputStreamInfo->flags & PaWinMmeNoHighPriorityProcessClass )
+ noHighPriorityProcessClass = 1;
+ if( inputStreamInfo->flags & PaWinMmeDontThrottleOverloadedProcessingThread )
+ throttleProcessingThreadOnOverload = 0;
+ if( inputStreamInfo->flags & PaWinMmeUseTimeCriticalThreadPriority )
+ useTimeCriticalProcessingThreadPriority = 1;
+
+ /* validate multidevice fields */
+
+ if( inputStreamInfo->flags & PaWinMmeUseMultipleDevices )
+ {
+ int totalChannels = 0;
+ for( i=0; i< inputStreamInfo->deviceCount; ++i )
+ {
+ /* validate that the device number is within range, and that
+ the number of channels is legal */
+ PaDeviceIndex hostApiDevice;
+
+ if( inputParameters->device != paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ channelCount = inputStreamInfo->devices[i].channelCount;
+
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
+ inputStreamInfo->devices[i].device, hostApi );
+ if( result != paNoError )
+ return result;
+
+ if( channelCount < 1 || channelCount > hostApi->deviceInfos[ hostApiDevice ]->maxInputChannels )
+ return paInvalidChannelCount;
+
+ /* FIXME this validation might be easier and better if there was a pautil
+ function which performed the validation in pa_front:ValidateOpenStreamParameters() */
+
+ totalChannels += channelCount;
+ }
+
+ if( totalChannels != inputChannelCount )
+ {
+ /* inputChannelCount must match total channels specified by multiple devices */
+ return paInvalidChannelCount; /* REVIEW use of this error code */
+ }
+
+ inputDevices = inputStreamInfo->devices;
+ numInputDevices = inputStreamInfo->deviceCount;
+ }
+ }
+
+ /* FIXME: establish which host formats are available */
+ hostInputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, inputSampleFormat );
+
+ }
+ else
+ {
+ inputChannelCount = 0;
+ inputSampleFormat = -1;
+ suggestedInputLatency = 0.;
+ inputStreamInfo = 0;
+ hostInputSampleFormat = -1;
+ }
+
+
+ if( outputParameters )
+ {
+ outputChannelCount = outputParameters->channelCount;
+ outputSampleFormat = outputParameters->sampleFormat;
+ suggestedOutputLatency = outputParameters->suggestedLatency;
+
+ /* check that input device can support inputChannelCount */
+ if( (outputParameters->device != paUseHostApiSpecificDeviceSpecification) &&
+ (inputChannelCount > hostApi->deviceInfos[ outputParameters->device ]->maxOutputChannels) )
+ return paInvalidChannelCount;
+
+
+ /* validate input hostApiSpecificStreamInfo */
+ outputStreamInfo = (PaWinMmeStreamInfo*)outputParameters->hostApiSpecificStreamInfo;
+ if( outputStreamInfo )
+ {
+ if( outputStreamInfo->size != sizeof( PaWinMmeStreamInfo )
+ || outputStreamInfo->version != 1 )
+ {
+ return paIncompatibleHostApiSpecificStreamInfo;
+ }
+
+ if( outputStreamInfo->flags & PaWinMmeNoHighPriorityProcessClass )
+ noHighPriorityProcessClass = 1;
+ if( outputStreamInfo->flags & PaWinMmeDontThrottleOverloadedProcessingThread )
+ throttleProcessingThreadOnOverload = 0;
+ if( outputStreamInfo->flags & PaWinMmeUseTimeCriticalThreadPriority )
+ useTimeCriticalProcessingThreadPriority = 1;
+
+ /* validate multidevice fields */
+
+ if( outputStreamInfo->flags & PaWinMmeUseMultipleDevices )
+ {
+ int totalChannels = 0;
+ for( i=0; i< outputStreamInfo->deviceCount; ++i )
+ {
+ /* validate that the device number is within range, and that
+ the number of channels is legal */
+ PaDeviceIndex hostApiDevice;
+
+ if( outputParameters->device != paUseHostApiSpecificDeviceSpecification )
+ return paInvalidDevice;
+
+ channelCount = outputStreamInfo->devices[i].channelCount;
+
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
+ outputStreamInfo->devices[i].device,
+ hostApi );
+ if( result != paNoError )
+ return result;
+
+ if( channelCount < 1 || channelCount > hostApi->deviceInfos[ hostApiDevice ]->maxOutputChannels )
+ return paInvalidChannelCount;
+
+ /* FIXME this validation might be easier and better if there was a pautil
+ function which performed the validation in pa_front:ValidateOpenStreamParameters() */
+
+ totalChannels += channelCount;
+ }
+
+ if( totalChannels != outputChannelCount )
+ {
+ /* outputChannelCount must match total channels specified by multiple devices */
+ return paInvalidChannelCount; /* REVIEW use of this error code */
+ }
+
+ outputDevices = outputStreamInfo->devices;
+ numOutputDevices = outputStreamInfo->deviceCount;
+ }
+ }
+
+ /* FIXME: establish which host formats are available */
+ hostOutputSampleFormat =
+ PaUtil_SelectClosestAvailableFormat( paInt16 /* native formats */, outputSampleFormat );
+ }
+ else
+ {
+ outputChannelCount = 0;
+ outputSampleFormat = -1;
+ outputStreamInfo = 0;
+ hostOutputSampleFormat = -1;
+ suggestedOutputLatency = 0.;
+ }
+
+
+ /*
+ IMPLEMENT ME:
+ - alter sampleRate to a close allowable rate if possible / necessary
+ */
+
+
+ /* validate platform specific flags */
+ if( (streamFlags & paPlatformSpecificFlags) != 0 )
+ return paInvalidFlag; /* unexpected platform specific flag */
+
+
+ result = CalculateBufferSettings( &framesPerHostInputBuffer, &numHostInputBuffers,
+ &framesPerHostOutputBuffer, &numHostOutputBuffers,
+ inputChannelCount, hostInputSampleFormat, suggestedInputLatency, inputStreamInfo,
+ outputChannelCount, hostOutputSampleFormat, suggestedOutputLatency, outputStreamInfo,
+ sampleRate, framesPerBuffer );
+ if( result != paNoError )
+ goto error;
+
+
+ stream = (PaWinMmeStream*)PaUtil_AllocateMemory( sizeof(PaWinMmeStream) );
+ if( !stream )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ stream->hWaveIns = 0;
+ stream->inputBuffers = 0;
+ stream->hWaveOuts = 0;
+ stream->outputBuffers = 0;
+ stream->processingThread = 0;
+
+ stream->noHighPriorityProcessClass = noHighPriorityProcessClass;
+ stream->useTimeCriticalProcessingThreadPriority = useTimeCriticalProcessingThreadPriority;
+ stream->throttleProcessingThreadOnOverload = throttleProcessingThreadOnOverload;
+
+ PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+ &winMmeHostApi->callbackStreamInterface, streamCallback, userData );
+
+ stream->streamRepresentation.streamInfo.inputLatency = (double)(framesPerHostInputBuffer * (numHostInputBuffers-1)) / sampleRate;
+ stream->streamRepresentation.streamInfo.outputLatency = (double)(framesPerHostOutputBuffer * (numHostOutputBuffers-1)) / sampleRate;
+ stream->streamRepresentation.streamInfo.sampleRate = sampleRate;
+
+ PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+
+
+ if( inputParameters && outputParameters ) /* full duplex */
+ {
+ /*
+ either host input and output buffers must be the same size, or the
+ larger one must be an integer multiple of the smaller one.
+ FIXME: should this return an error if the host specific latency
+ settings don't fulfill these constraints? rb: probably
+ */
+
+ if( framesPerHostInputBuffer < framesPerHostOutputBuffer )
+ {
+ assert( (framesPerHostOutputBuffer % framesPerHostInputBuffer) == 0 );
+
+ framesPerBufferProcessorCall = framesPerHostInputBuffer;
+ }
+ else
+ {
+ assert( (framesPerHostInputBuffer % framesPerHostOutputBuffer) == 0 );
+
+ framesPerBufferProcessorCall = framesPerHostOutputBuffer;
+ }
+ }
+ else if( inputParameters )
+ {
+ framesPerBufferProcessorCall = framesPerHostInputBuffer;
+ }
+ else if( outputParameters )
+ {
+ framesPerBufferProcessorCall = framesPerHostOutputBuffer;
+ }
+
+ stream->framesPerInputBuffer = framesPerHostInputBuffer;
+ stream->framesPerOutputBuffer = framesPerHostOutputBuffer;
+
+ result = PaUtil_InitializeBufferProcessor( &stream->bufferProcessor,
+ inputChannelCount, inputSampleFormat, hostInputSampleFormat,
+ outputChannelCount, outputSampleFormat, hostOutputSampleFormat,
+ sampleRate, streamFlags, framesPerBuffer,
+ framesPerBufferProcessorCall, paUtilFixedHostBufferSize,
+ streamCallback, userData );
+ if( result != paNoError )
+ goto error;
+
+ stream->isActive = 0;
+
+ stream->streamPosition = 0.;
+ stream->previousStreamPosition = 0;
+
+
+ stream->bufferEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if( stream->bufferEvent == NULL )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+ bufferEventInited = 1;
+
+ if( inputParameters )
+ {
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nSamplesPerSec = (DWORD) sampleRate;
+ wfx.cbSize = 0;
+
+ stream->numInputDevices = numInputDevices;
+ stream->hWaveIns = (HWAVEIN*)PaUtil_AllocateMemory( sizeof(HWAVEIN) * stream->numInputDevices );
+ if( !stream->hWaveIns )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i = 0; i < stream->numInputDevices; ++i )
+ stream->hWaveIns[i] = 0;
+
+ for( i = 0; i < stream->numInputDevices; ++i )
+ {
+ int inputWinMmeId;
+
+ if( inputDevices )
+ {
+ PaDeviceIndex hostApiDevice;
+
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
+ inputDevices[i].device, hostApi );
+ if( result != paNoError )
+ return result;
+
+ inputWinMmeId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, hostApiDevice );
+ wfx.nChannels = (WORD) inputDevices[i].channelCount;
+ }
+ else
+ {
+ inputWinMmeId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, inputParameters->device );
+ wfx.nChannels = (WORD) inputChannelCount;
+ }
+
+ bytesPerInputFrame = wfx.nChannels * stream->bufferProcessor.bytesPerHostInputSample;
+
+ wfx.nAvgBytesPerSec = (DWORD)(bytesPerInputFrame * sampleRate);
+ wfx.nBlockAlign = (WORD)bytesPerInputFrame;
+ wfx.wBitsPerSample = (WORD)((bytesPerInputFrame/wfx.nChannels) * 8);
+
+ /* REVIEW: consider not firing an event for input when a full duplex stream is being used */
+
+ mmresult = waveInOpen( &stream->hWaveIns[i], inputWinMmeId, &wfx,
+ (DWORD)stream->bufferEvent, (DWORD) stream, CALLBACK_EVENT );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ switch( mmresult )
+ {
+ case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
+ result = paDeviceUnavailable;
+ break;
+ case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
+ result = paInternalError; /* portaudio should ensure that only good device ids are used */
+ break;
+ case MMSYSERR_NODRIVER: /* No device driver is present. */
+ result = paDeviceUnavailable;
+ break;
+ case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
+ result = paInsufficientMemory;
+ break;
+ case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
+ result = paInternalError; /* REVIEW: port audio shouldn't get this far without using compatible format info */
+ break;
+ default:
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ }
+ goto error;
+ }
+ }
+ }
+
+ if( outputParameters )
+ {
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nSamplesPerSec = (DWORD) sampleRate;
+ wfx.cbSize = 0;
+
+ stream->numOutputDevices = numOutputDevices;
+ stream->hWaveOuts = (HWAVEOUT*)PaUtil_AllocateMemory( sizeof(HWAVEOUT) * stream->numOutputDevices );
+ if( !stream->hWaveOuts )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i = 0; i < stream->numOutputDevices; ++i )
+ stream->hWaveOuts[i] = 0;
+
+ for( i = 0; i < stream->numOutputDevices; ++i )
+ {
+ int outputWinMmeId;
+
+ if( outputDevices )
+ {
+ PaDeviceIndex hostApiDevice;
+
+ result = PaUtil_DeviceIndexToHostApiDeviceIndex( &hostApiDevice,
+ outputDevices[i].device, hostApi );
+ if( result != paNoError )
+ return result;
+
+ outputWinMmeId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, hostApiDevice );
+ wfx.nChannels = (WORD) outputDevices[i].channelCount;
+ }
+ else
+ {
+ outputWinMmeId = LocalDeviceIndexToWinMmeDeviceId( winMmeHostApi, outputParameters->device );
+ wfx.nChannels = (WORD) outputChannelCount;
+ }
+
+ bytesPerOutputFrame = wfx.nChannels * stream->bufferProcessor.bytesPerHostOutputSample;
+
+ wfx.nAvgBytesPerSec = (DWORD)(bytesPerOutputFrame * sampleRate);
+ wfx.nBlockAlign = (WORD)bytesPerOutputFrame;
+ wfx.wBitsPerSample = (WORD)((bytesPerOutputFrame/wfx.nChannels) * 8);
+
+ mmresult = waveOutOpen( &stream->hWaveOuts[i], outputWinMmeId, &wfx,
+ (DWORD)stream->bufferEvent, (DWORD) stream, CALLBACK_EVENT );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ switch( mmresult )
+ {
+ case MMSYSERR_ALLOCATED: /* Specified resource is already allocated. */
+ result = paDeviceUnavailable;
+ break;
+ case MMSYSERR_BADDEVICEID: /* Specified device identifier is out of range. */
+ result = paInternalError; /* portaudio should ensure that only good device ids are used */
+ break;
+ case MMSYSERR_NODRIVER: /* No device driver is present. */
+ result = paDeviceUnavailable;
+ break;
+ case MMSYSERR_NOMEM: /* Unable to allocate or lock memory. */
+ result = paInsufficientMemory;
+ break;
+ case WAVERR_BADFORMAT: /* Attempted to open with an unsupported waveform-audio format. */
+ result = paInternalError; /* REVIEW: port audio shouldn't get this far without using compatible format info */
+ break;
+ default:
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ }
+ goto error;
+ }
+ }
+ }
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ stream->inputBuffers = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * stream->numInputDevices );
+ if( stream->inputBuffers == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i =0; i < stream->numInputDevices; ++i )
+ stream->inputBuffers[i] = 0;
+
+ stream->numInputBuffers = numHostInputBuffers;
+
+ for( i =0; i < stream->numInputDevices; ++i )
+ {
+ int hostInputBufferBytes = Pa_GetSampleSize( hostInputSampleFormat ) *
+ framesPerHostInputBuffer *
+ ((inputDevices) ? inputDevices[i].channelCount : inputChannelCount);
+ if( hostInputBufferBytes < 0 )
+ {
+ result = paInternalError;
+ goto error;
+ }
+
+ result = InitializeBufferSet( &stream->inputBuffers[i], numHostInputBuffers, hostInputBufferBytes,
+ 1 /* isInput */,
+ (MmeHandle)stream->hWaveIns[i],
+ ((inputDevices) ? inputDevices[i].channelCount : inputChannelCount) );
+
+ if( result != paNoError )
+ goto error;
+ }
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ stream->outputBuffers = (WAVEHDR**)PaUtil_AllocateMemory( sizeof(WAVEHDR*) * stream->numOutputDevices );
+ if( stream->outputBuffers == 0 )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+
+ for( i =0; i < stream->numOutputDevices; ++i )
+ stream->outputBuffers[i] = 0;
+
+ stream->numOutputBuffers = numHostOutputBuffers;
+
+ for( i=0; i < stream->numOutputDevices; ++i )
+ {
+ int hostOutputBufferBytes = Pa_GetSampleSize( hostOutputSampleFormat ) *
+ framesPerHostOutputBuffer *
+ ((outputDevices) ? outputDevices[i].channelCount : outputChannelCount);
+ if( hostOutputBufferBytes < 0 )
+ {
+ result = paInternalError;
+ goto error;
+ }
+
+ result = InitializeBufferSet( &stream->outputBuffers[i], numHostOutputBuffers, hostOutputBufferBytes,
+ 0 /* not isInput */,
+ (MmeHandle)stream->hWaveOuts[i],
+ ((outputDevices) ? outputDevices[i].channelCount : outputChannelCount) );
+
+ if( result != paNoError )
+ goto error;
+ }
+ }
+
+ stream->abortEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ if( stream->abortEvent == NULL )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+ abortEventInited = 1;
+
+ InitializeCriticalSection( &stream->lock );
+ lockInited = 1;
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostOutputBuffer * stream->numOutputBuffers) / sampleRate);
+ else
+ stream->allBuffersDurationMs = (DWORD) (1000.0 * (framesPerHostInputBuffer * stream->numInputBuffers) / sampleRate);
+
+
+ *s = (PaStream*)stream;
+
+ return result;
+
+error:
+ if( lockInited )
+ DeleteCriticalSection( &stream->lock );
+
+ if( abortEventInited )
+ CloseHandle( stream->abortEvent );
+
+
+ if( stream->inputBuffers )
+ {
+ for( i =0 ; i< stream->numInputDevices; ++i )
+ {
+ if( stream->inputBuffers[i] )
+ {
+ TerminateBufferSet( &stream->inputBuffers[i], stream->numInputBuffers,
+ 1 /* isInput */, (MmeHandle)stream->hWaveIns[i] );
+ }
+ }
+
+ PaUtil_FreeMemory( stream->inputBuffers );
+ }
+
+ if( stream->outputBuffers )
+ {
+ for( i =0 ; i< stream->numOutputDevices; ++i )
+ {
+ if( stream->outputBuffers[i] )
+ {
+ TerminateBufferSet( &stream->outputBuffers[i], stream->numOutputBuffers,
+ 0 /* not isInput */, (MmeHandle)stream->hWaveOuts[i] );
+ }
+ }
+
+ PaUtil_FreeMemory( stream->outputBuffers );
+ }
+
+ if( stream->hWaveIns )
+ {
+ for( i =0 ; i< stream->numInputDevices; ++i )
+ {
+ if( stream->hWaveIns[i] )
+ waveInClose( stream->hWaveIns[i] );
+ }
+
+ PaUtil_FreeMemory( stream->hWaveIns );
+ }
+
+ if( stream->hWaveOuts )
+ {
+ for( i =0 ; i< stream->numOutputDevices; ++i )
+ {
+ if( stream->hWaveOuts[i] )
+ waveOutClose( stream->hWaveOuts[i] );
+ }
+
+ PaUtil_FreeMemory( stream->hWaveOuts );
+ }
+
+ if( bufferEventInited )
+ CloseHandle( stream->bufferEvent );
+
+ if( stream )
+ PaUtil_FreeMemory( stream );
+
+ return result;
+}
+
+
+/* return non-zero if any output buffers are queued */
+static int OutputBuffersAreQueued( PaWinMmeStream *stream )
+{
+ int result = 0;
+ unsigned int i, j;
+
+ if( PA_IS_OUTPUT_STREAM_( stream ) )
+ {
+ for( i=0; i<stream->numOutputBuffers; ++i )
+ {
+ for( j=0; j < stream->numOutputDevices; ++j )
+ {
+ if( !( stream->outputBuffers[ j ][ i ].dwFlags & WHDR_DONE) )
+ {
+ result++;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+
+static PaError AdvanceToNextInputBuffer( PaWinMmeStream *stream )
+{
+ PaError result = paNoError;
+ MMRESULT mmresult;
+ unsigned int i;
+
+ for( i=0; i< stream->numInputDevices; ++i )
+ {
+ mmresult = waveInAddBuffer( stream->hWaveIns[i],
+ &stream->inputBuffers[i][ stream->currentInputBufferIndex ],
+ sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ }
+ }
+ stream->currentInputBufferIndex = (stream->currentInputBufferIndex+1 >= stream->numInputBuffers) ?
+ 0 : stream->currentInputBufferIndex+1;
+
+ stream->framesUsedInCurrentInputBuffer = 0;
+
+ return result;
+}
+
+
+static PaError AdvanceToNextOutputBuffer( PaWinMmeStream *stream )
+{
+ PaError result = paNoError;
+ MMRESULT mmresult;
+ unsigned int i;
+
+ for( i=0; i< stream->numOutputDevices; ++i )
+ {
+ mmresult = waveOutWrite( stream->hWaveOuts[i],
+ &stream->outputBuffers[i][ stream->currentOutputBufferIndex ],
+ sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ }
+ }
+
+ stream->currentOutputBufferIndex = (stream->currentOutputBufferIndex+1 >= stream->numOutputBuffers) ?
+ 0 : stream->currentOutputBufferIndex+1;
+
+ stream->framesUsedInCurrentOutputBuffer = 0;
+
+ return result;
+}
+
+
+static DWORD WINAPI ProcessingThreadProc( void *pArg )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream *)pArg;
+ HANDLE events[2];
+ int numEvents = 0;
+ DWORD result = paNoError;
+ DWORD waitResult;
+/** @todo:
+Gordon Gidluck:
+> function: ProcessingThreadProc()
+> line #1665 DWORD timeout = stream->allBuffersDurationMs * 0.5;
+> conversion from 'double ' to 'unsigned long ', possible loss of data
+*/
+ DWORD timeout = stream->allBuffersDurationMs * 0.5;
+ DWORD numTimeouts = 0;
+ int hostBuffersAvailable;
+ signed int hostInputBufferIndex, hostOutputBufferIndex;
+ int callbackResult;
+ int done = 0;
+ unsigned int channel, i, j;
+ unsigned long framesProcessed;
+
+ /* prepare event array for call to WaitForMultipleObjects() */
+ events[numEvents++] = stream->bufferEvent;
+ events[numEvents++] = stream->abortEvent;
+
+ /* loop until something causes us to stop */
+ while( !done )
+ {
+ /* wait for MME to signal that a buffer is available, or for
+ the PA abort event to be signaled */
+ waitResult = WaitForMultipleObjects( numEvents, events, FALSE, timeout );
+ if( waitResult == WAIT_FAILED )
+ {
+ result = paUnanticipatedHostError;
+ /* FIXME/REVIEW: can't return host error info from an asyncronous thread */
+ done = 1;
+ }
+ else if( waitResult == WAIT_TIMEOUT )
+ {
+ /* if a timeout is encountered, continue */
+ numTimeouts += 1;
+ }
+
+ if( stream->abortProcessing )
+ {
+ /* Pa_AbortStream() has been called, stop processing immediately */
+ done = 1;
+ }
+ else if( stream->stopProcessing )
+ {
+ /* Pa_StopStream() has been called or the user callback returned
+ non-zero, processing will continue until all output buffers
+ are marked as done. The stream will stop immediately if it
+ is input-only.
+ */
+
+ if( !OutputBuffersAreQueued( stream ) )
+ {
+ done = 1; /* Will cause thread to return. */
+ }
+ }
+ else
+ {
+ hostBuffersAvailable = 1;
+
+ /* process all available host buffers */
+ do
+ {
+ hostInputBufferIndex = -1;
+ hostOutputBufferIndex = -1;
+
+ if( PA_IS_INPUT_STREAM_(stream))
+ {
+ hostInputBufferIndex = stream->currentInputBufferIndex;
+ for( i=0; i<stream->numInputDevices; ++i )
+ {
+ if( !(stream->inputBuffers[i][ stream->currentInputBufferIndex ].dwFlags & WHDR_DONE) )
+ {
+ hostInputBufferIndex = -1;
+ break;
+ }
+ }
+
+ if( hostInputBufferIndex != -1 )
+ {
+ /* if all of the other buffers are also ready then we dicard all but the
+ most recent. */
+ int inputCatchUp = 1;
+
+ for( i=0; i < stream->numInputBuffers && inputCatchUp == 1; ++i )
+ {
+ for( j=0; j<stream->numInputDevices; ++j )
+ {
+ if( !(stream->inputBuffers[ j ][ i ].dwFlags & WHDR_DONE) )
+ {
+ inputCatchUp = 0;
+ break;
+ }
+ }
+ }
+
+ if( inputCatchUp )
+ {
+ for( i=0; i < stream->numInputBuffers - 1; ++i )
+ {
+ result = AdvanceToNextInputBuffer( stream );
+ if( result != paNoError )
+ done = 1;
+ }
+ }
+ }
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ hostOutputBufferIndex = stream->currentOutputBufferIndex;
+ for( i=0; i<stream->numOutputDevices; ++i )
+ {
+ if( !(stream->outputBuffers[i][ stream->currentOutputBufferIndex ].dwFlags & WHDR_DONE) )
+ {
+ hostOutputBufferIndex = -1;
+ break;
+ }
+ }
+
+ if( hostOutputBufferIndex != - 1 )
+ {
+ /* if all of the other buffers are also ready, catch up by copying
+ the most recently generated buffer into all but one of the output
+ buffers */
+ int outputCatchUp = 1;
+
+ for( i=0; i < stream->numOutputBuffers && outputCatchUp == 1; ++i )
+ {
+ for( j=0; j<stream->numOutputDevices; ++j )
+ {
+ if( !(stream->outputBuffers[ j ][ i ].dwFlags & WHDR_DONE) )
+ {
+ outputCatchUp = 0;
+ break;
+ }
+ }
+ }
+
+ if( outputCatchUp )
+ {
+ /* FIXME: this is an output underflow buffer slip and should be flagged as such */
+ unsigned int previousBufferIndex = (stream->currentOutputBufferIndex==0)
+ ? stream->numOutputBuffers - 1
+ : stream->currentOutputBufferIndex - 1;
+
+ for( i=0; i < stream->numOutputBuffers - 1; ++i )
+ {
+ for( j=0; j<stream->numOutputDevices; ++j )
+ {
+ if( stream->outputBuffers[j][ stream->currentOutputBufferIndex ].lpData
+ != stream->outputBuffers[j][ previousBufferIndex ].lpData )
+ {
+ CopyMemory( stream->outputBuffers[j][ stream->currentOutputBufferIndex ].lpData,
+ stream->outputBuffers[j][ previousBufferIndex ].lpData,
+ stream->outputBuffers[j][ stream->currentOutputBufferIndex ].dwBufferLength );
+ }
+ }
+
+ result = AdvanceToNextOutputBuffer( stream );
+ if( result != paNoError )
+ done = 1;
+ }
+ }
+ }
+ }
+
+
+ if( (PA_IS_FULL_DUPLEX_STREAM_(stream) && hostInputBufferIndex != -1 && hostOutputBufferIndex != -1) ||
+ (!PA_IS_FULL_DUPLEX_STREAM_(stream) && ( hostInputBufferIndex != -1 || hostOutputBufferIndex != -1 ) ) )
+ {
+ PaStreamCallbackTimeInfo timeInfo = {0,0,0}; /* @todo implement inputBufferAdcTime and currentTime */
+
+
+ if( hostOutputBufferIndex != -1 ){
+ MMTIME time;
+ double now;
+ long totalRingFrames;
+ long ringPosition;
+ long playbackPosition;
+
+ time.wType = TIME_SAMPLES;
+ waveOutGetPosition( stream->hWaveOuts[0], &time, sizeof(MMTIME) );
+ now = PaUtil_GetTime();
+
+ totalRingFrames = stream->numOutputBuffers * stream->bufferProcessor.framesPerHostBuffer;
+
+ ringPosition = stream->currentOutputBufferIndex * stream->bufferProcessor.framesPerHostBuffer;
+
+ playbackPosition = time.u.sample % totalRingFrames;
+
+ if( playbackPosition >= ringPosition ){
+ timeInfo.outputBufferDacTime =
+ now + ((double)( ringPosition + (totalRingFrames - playbackPosition) ) * stream->bufferProcessor.samplePeriod );
+ }else{
+ timeInfo.outputBufferDacTime =
+ now + ((double)( ringPosition - playbackPosition ) * stream->bufferProcessor.samplePeriod );
+ }
+ }
+
+
+ PaUtil_BeginCpuLoadMeasurement( &stream->cpuLoadMeasurer );
+
+ PaUtil_BeginBufferProcessing( &stream->bufferProcessor, &timeInfo );
+
+ if( hostInputBufferIndex != -1 )
+ {
+ PaUtil_SetInputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
+
+ channel = 0;
+ for( i=0; i<stream->numInputDevices; ++i )
+ {
+ /* we have stored the number of channels in the buffer in dwUser */
+ int channelCount = stream->inputBuffers[i][ hostInputBufferIndex ].dwUser;
+
+ PaUtil_SetInterleavedInputChannels( &stream->bufferProcessor, channel,
+ stream->inputBuffers[i][ hostInputBufferIndex ].lpData +
+ stream->framesUsedInCurrentInputBuffer * channelCount *
+ stream->bufferProcessor.bytesPerHostInputSample,
+ channelCount );
+
+
+ channel += channelCount;
+ }
+ }
+
+ if( hostOutputBufferIndex != -1 )
+ {
+ PaUtil_SetOutputFrameCount( &stream->bufferProcessor, 0 /* default to host buffer size */ );
+
+ channel = 0;
+ for( i=0; i<stream->numOutputDevices; ++i )
+ {
+ /* we have stored the number of channels in the buffer in dwUser */
+ int channelCount = stream->outputBuffers[i][ hostOutputBufferIndex ].dwUser;
+
+ PaUtil_SetInterleavedOutputChannels( &stream->bufferProcessor, channel,
+ stream->outputBuffers[i][ hostOutputBufferIndex ].lpData +
+ stream->framesUsedInCurrentOutputBuffer * channelCount *
+ stream->bufferProcessor.bytesPerHostOutputSample,
+ channelCount );
+
+ /* we have stored the number of channels in the buffer in dwUser */
+ channel += channelCount;
+ }
+ }
+
+ framesProcessed = PaUtil_EndBufferProcessing( &stream->bufferProcessor, &callbackResult );
+
+ stream->framesUsedInCurrentInputBuffer += framesProcessed;
+ stream->framesUsedInCurrentOutputBuffer += framesProcessed;
+
+ PaUtil_EndCpuLoadMeasurement( &stream->cpuLoadMeasurer, framesProcessed );
+
+ if( callbackResult == paContinue )
+ {
+ /* nothing special to do */
+ }
+ else if( callbackResult == paAbort )
+ {
+ stream->abortProcessing = 1;
+ done = 1;
+ /* FIXME: should probably do a reset here */
+ result = paNoError;
+ }
+ else
+ {
+ /* User cllback has asked us to stop with paComplete or other non-zero value */
+ stream->stopProcessing = 1; /* stop once currently queued audio has finished */
+ result = paNoError;
+ }
+
+ /*
+ FIXME: the following code is incorrect, because stopProcessing should
+ still queue the current buffer.
+ */
+ if( stream->stopProcessing == 0 && stream->abortProcessing == 0 )
+ {
+ if( stream->throttleProcessingThreadOnOverload != 0 )
+ {
+ if( PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer ) > 1. )
+ {
+ if( stream->processingThreadPriority != stream->throttledThreadPriority )
+ {
+ SetThreadPriority( stream->processingThread, stream->throttledThreadPriority );
+ stream->processingThreadPriority = stream->throttledThreadPriority;
+ }
+
+/** @todo:
+Gordon Gidluck:
+> function: ProcessingThreadProc()
+> line #1947/1948 Sleep( stream->bufferProcessor.framesPerHostBuffer *
+> stream->bufferProcessor.samplePeriod * .25 );
+> conversion from 'double ' to 'unsigned long ', possible loss of data
+> integral size mismatch in argument; conversion supplied
+*/
+ /* sleep for a quater of a buffer's duration to give other processes a go */
+ Sleep( stream->bufferProcessor.framesPerHostBuffer *
+ stream->bufferProcessor.samplePeriod * .25 );
+ }
+ else
+ {
+ if( stream->processingThreadPriority != stream->highThreadPriority )
+ {
+ SetThreadPriority( stream->processingThread, stream->highThreadPriority );
+ stream->processingThreadPriority = stream->highThreadPriority;
+ }
+ }
+ }
+
+ if( PA_IS_INPUT_STREAM_(stream) &&
+ stream->framesUsedInCurrentInputBuffer == stream->framesPerInputBuffer )
+ {
+ result = AdvanceToNextInputBuffer( stream );
+ if( result != paNoError )
+ done = 1;
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) &&
+ stream->framesUsedInCurrentOutputBuffer == stream->framesPerOutputBuffer )
+ {
+ result = AdvanceToNextOutputBuffer( stream );
+ if( result != paNoError )
+ done = 1;
+ }
+ }
+ }
+ else
+ {
+ hostBuffersAvailable = 0;
+ }
+ }
+ while( hostBuffersAvailable &&
+ stream->stopProcessing == 0 &&
+ stream->abortProcessing == 0 &&
+ !done );
+ }
+
+ result = UpdateStreamTime( stream );
+ if( result != paNoError )
+ done = 1;
+ }
+
+ stream->isActive = 0;
+
+ if( stream->streamRepresentation.streamFinishedCallback != 0 )
+ stream->streamRepresentation.streamFinishedCallback( stream->streamRepresentation.userData );
+
+ return result;
+}
+
+
+/*
+ When CloseStream() is called, the multi-api layer ensures that
+ the stream has already been stopped or aborted.
+*/
+static PaError CloseStream( PaStream* s )
+{
+ PaError result = paNoError;
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+ MMRESULT mmresult;
+ unsigned int i;
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numInputDevices; ++i )
+ {
+ TerminateBufferSet( &stream->inputBuffers[i], stream->numInputBuffers,
+ 1 /* isInput */, (MmeHandle)stream->hWaveIns[i] );
+ }
+
+ PaUtil_FreeMemory( stream->inputBuffers );
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numOutputDevices; ++i )
+ {
+ TerminateBufferSet( &stream->outputBuffers[i], stream->numOutputBuffers,
+ 0 /* not isInput */, (MmeHandle)stream->hWaveOuts[i] );
+ }
+
+ PaUtil_FreeMemory( stream->outputBuffers );
+ }
+
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numInputDevices; ++i )
+ {
+ mmresult = waveInClose( stream->hWaveIns[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ goto error;
+ }
+ }
+
+ PaUtil_FreeMemory( stream->hWaveIns );
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numOutputDevices; ++i )
+ {
+ mmresult = waveOutClose( stream->hWaveOuts[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ goto error;
+ }
+ }
+
+ PaUtil_FreeMemory( stream->hWaveOuts );
+ }
+
+ if( CloseHandle( stream->bufferEvent ) == 0 )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+
+ if( CloseHandle( stream->abortEvent ) == 0 )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+
+ DeleteCriticalSection( &stream->lock );
+
+ PaUtil_TerminateBufferProcessor( &stream->bufferProcessor );
+ PaUtil_TerminateStreamRepresentation( &stream->streamRepresentation );
+ PaUtil_FreeMemory( stream );
+
+error:
+ /* FIXME: consider how to best clean up on failure */
+ return result;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+ MMRESULT mmresult;
+ unsigned int i, j;
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numInputBuffers; ++i )
+ {
+ for( j=0; j<stream->numInputDevices; ++j )
+ {
+ mmresult = waveInAddBuffer( stream->hWaveIns[j], &stream->inputBuffers[j][i], sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ goto error;
+ }
+ }
+ }
+ stream->currentInputBufferIndex = 0;
+ stream->framesUsedInCurrentInputBuffer = 0;
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i=0; i<stream->numOutputDevices; ++i )
+ {
+ if( (mmresult = waveOutPause( stream->hWaveOuts[i] )) != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ goto error;
+ }
+ }
+
+ for( i=0; i<stream->numOutputBuffers; ++i )
+ {
+ for( j=0; j<stream->numOutputDevices; ++j )
+ {
+ ZeroMemory( stream->outputBuffers[j][i].lpData, stream->outputBuffers[j][i].dwBufferLength );
+ mmresult = waveOutWrite( stream->hWaveOuts[j], &stream->outputBuffers[j][i], sizeof(WAVEHDR) );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ goto error;
+ }
+ }
+ }
+ stream->currentOutputBufferIndex = 0;
+ stream->framesUsedInCurrentOutputBuffer = 0;
+ }
+
+ stream->streamPosition = 0.;
+ stream->previousStreamPosition = 0;
+
+ stream->isActive = 1;
+ stream->stopProcessing = 0;
+ stream->abortProcessing = 0;
+
+ if( ResetEvent( stream->bufferEvent ) == 0 )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+
+ if( ResetEvent( stream->abortEvent ) == 0 )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+
+ /* Create thread that waits for audio buffers to be ready for processing. */
+ stream->processingThread = CreateThread( 0, 0, ProcessingThreadProc, stream, 0, &stream->processingThreadId );
+ if( !stream->processingThread )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+
+ /* I used to pass the thread which was failing. I now pass GetCurrentProcess().
+ * This fix could improve latency for some applications. It could also result in CPU
+ * starvation if the callback did too much processing.
+ * I also added result checks, so we might see more failures at initialization.
+ * Thanks to Alberto di Bene for spotting this.
+ */
+ /* REVIEW: should we reset the priority class when the stream has stopped?
+ - would be best to refcount priority boosts incase more than one
+ stream is open
+ */
+
+ if( !stream->noHighPriorityProcessClass )
+ {
+#ifndef WIN32_PLATFORM_PSPC /* no SetPriorityClass or HIGH_PRIORITY_CLASS on PocketPC */
+
+ if( !SetPriorityClass( GetCurrentProcess(), HIGH_PRIORITY_CLASS ) ) /* PLB20010816 */
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+#endif
+ }
+
+ if( stream->useTimeCriticalProcessingThreadPriority )
+ stream->highThreadPriority = THREAD_PRIORITY_TIME_CRITICAL;
+ else
+ stream->highThreadPriority = THREAD_PRIORITY_HIGHEST;
+
+ stream->throttledThreadPriority = THREAD_PRIORITY_NORMAL;
+
+ if( !SetThreadPriority( stream->processingThread, stream->highThreadPriority ) )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_SYSTEM_ERROR( GetLastError() );
+ goto error;
+ }
+ stream->processingThreadPriority = stream->highThreadPriority;
+
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i < stream->numInputDevices; ++i )
+ {
+ mmresult = waveInStart( stream->hWaveIns[i] );
+ PA_DEBUG(("Pa_StartStream: waveInStart returned = 0x%X.\n", mmresult));
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ goto error;
+ }
+ }
+ }
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i=0; i < stream->numOutputDevices; ++i )
+ {
+ if( (mmresult = waveOutRestart( stream->hWaveOuts[i] )) != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ goto error;
+ }
+ }
+ }
+
+ return result;
+
+error:
+ /* FIXME: implement recovery as best we can
+ This should involve rolling back to a state as-if this function had never been called
+ */
+ return result;
+}
+
+
+static PaError StopStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+ int timeout;
+ DWORD waitResult;
+ MMRESULT mmresult;
+ unsigned int i;
+
+ /*
+ FIXME: the error checking in this function needs review. the basic
+ idea is to return from this function in a known state - for example
+ there is no point avoiding calling waveInReset just because
+ the thread times out.
+ */
+
+
+ /* Tell processing thread to stop generating more data and to let current data play out. */
+ stream->stopProcessing = 1;
+
+ /* Calculate timeOut longer than longest time it could take to return all buffers. */
+ timeout = stream->allBuffersDurationMs * 1.5;
+ if( timeout < PA_MIN_TIMEOUT_MSEC_ )
+ timeout = PA_MIN_TIMEOUT_MSEC_;
+
+ PA_DEBUG(("WinMME StopStream: waiting for background thread.\n"));
+
+ waitResult = WaitForSingleObject( stream->processingThread, timeout );
+ if( waitResult == WAIT_TIMEOUT )
+ {
+ /* try to abort */
+ stream->abortProcessing = 1;
+ SetEvent( stream->abortEvent );
+ waitResult = WaitForSingleObject( stream->processingThread, timeout );
+ if( waitResult == WAIT_TIMEOUT )
+ {
+ PA_DEBUG(("WinMME StopStream: timed out while waiting for background thread to finish.\n"));
+ result = paTimedOut;
+ }
+ }
+
+ CloseHandle( stream->processingThread );
+ stream->processingThread = NULL;
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i =0; i < stream->numOutputDevices; ++i )
+ {
+ mmresult = waveOutReset( stream->hWaveOuts[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ }
+ }
+ }
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i < stream->numInputDevices; ++i )
+ {
+ mmresult = waveInReset( stream->hWaveIns[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ result = paUnanticipatedHostError;
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ }
+ }
+ }
+
+ stream->isActive = 0;
+
+ return result;
+}
+
+
+static PaError AbortStream( PaStream *s )
+{
+ PaError result = paNoError;
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+ int timeout;
+ DWORD waitResult;
+ MMRESULT mmresult;
+ unsigned int i;
+
+ /*
+ FIXME: the error checking in this function needs review. the basic
+ idea is to return from this function in a known state - for example
+ there is no point avoiding calling waveInReset just because
+ the thread times out.
+ */
+
+ /* Tell processing thread to abort immediately */
+ stream->abortProcessing = 1;
+ SetEvent( stream->abortEvent );
+
+ /* Calculate timeOut longer than longest time it could take to return all buffers. */
+ timeout = stream->allBuffersDurationMs * 1.5;
+ if( timeout < PA_MIN_TIMEOUT_MSEC_ )
+ timeout = PA_MIN_TIMEOUT_MSEC_;
+
+ if( PA_IS_OUTPUT_STREAM_(stream) )
+ {
+ for( i =0; i < stream->numOutputDevices; ++i )
+ {
+ mmresult = waveOutReset( stream->hWaveOuts[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ return paUnanticipatedHostError;
+ }
+ }
+ }
+
+ if( PA_IS_INPUT_STREAM_(stream) )
+ {
+ for( i=0; i < stream->numInputDevices; ++i )
+ {
+ mmresult = waveInReset( stream->hWaveIns[i] );
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ return paUnanticipatedHostError;
+ }
+ }
+ }
+
+
+ PA_DEBUG(("WinMME AbortStream: waiting for background thread.\n"));
+
+ waitResult = WaitForSingleObject( stream->processingThread, timeout );
+ if( waitResult == WAIT_TIMEOUT )
+ {
+ PA_DEBUG(("WinMME AbortStream: timed out while waiting for background thread to finish.\n"));
+ return paTimedOut;
+ }
+
+ CloseHandle( stream->processingThread );
+ stream->processingThread = NULL;
+
+ stream->isActive = 0;
+
+ return result;
+}
+
+
+static PaError IsStreamStopped( PaStream *s )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ return ( stream->processingThread == NULL );
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ return stream->isActive;
+}
+
+
+/* UpdateStreamTime() must be called periodically because mmtime.u.sample
+ is a DWORD and can wrap and lose sync after a few hours.
+ */
+static PaError UpdateStreamTime( PaWinMmeStream *stream )
+{
+ MMRESULT mmresult;
+ MMTIME mmtime;
+ mmtime.wType = TIME_SAMPLES;
+
+ if( stream->hWaveOuts )
+ {
+ /* assume that all devices have the same position */
+ mmresult = waveOutGetPosition( stream->hWaveOuts[0], &mmtime, sizeof(mmtime) );
+
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ PA_MME_SET_LAST_WAVEOUT_ERROR( mmresult );
+ return paUnanticipatedHostError;
+ }
+ }
+ else
+ {
+ /* assume that all devices have the same position */
+ mmresult = waveInGetPosition( stream->hWaveIns[0], &mmtime, sizeof(mmtime) );
+
+ if( mmresult != MMSYSERR_NOERROR )
+ {
+ PA_MME_SET_LAST_WAVEIN_ERROR( mmresult );
+ return paUnanticipatedHostError;
+ }
+ }
+
+
+ /* This data has two variables and is shared by foreground and background.
+ * So we need to make it thread safe. */
+ EnterCriticalSection( &stream->lock );
+ stream->streamPosition += ((long)mmtime.u.sample) - stream->previousStreamPosition;
+ stream->previousStreamPosition = (long)mmtime.u.sample;
+ LeaveCriticalSection( &stream->lock );
+
+ return paNoError;
+}
+
+
+static PaTime GetStreamTime( PaStream *s )
+{
+/*
+ new behavior for GetStreamTime is to return a stream based seconds clock
+ used for the outTime parameter to the callback.
+ FIXME: delete this comment when the other unnecessary related code has
+ been cleaned from this file.
+
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+ PaError error = UpdateStreamTime( stream );
+
+ if( error == paNoError )
+ return stream->streamPosition;
+ else
+ return 0;
+*/
+ (void) s; /* unused parameter */
+ return PaUtil_GetTime();
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
+/*
+ As separate stream interfaces are used for blocking and callback
+ streams, the following functions can be guaranteed to only be called
+ for blocking streams.
+*/
+
+static PaError ReadStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameters */
+ (void) buffer;
+ (void) frames;
+
+ return paNoError;
+}
+
+
+static PaError WriteStream( PaStream* s,
+ void *buffer,
+ unsigned long frames )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameters */
+ (void) buffer;
+ (void) frames;
+
+ return paNoError;
+}
+
+
+static signed long GetStreamReadAvailable( PaStream* s )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameter */
+
+ return 0;
+}
+
+
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+ PaWinMmeStream *stream = (PaWinMmeStream*)s;
+
+ /* IMPLEMENT ME, see portaudio.h for required behavior*/
+ (void) stream; /* unused parameter */
+
+ return 0;
+}
+
+
+
+
diff --git a/pd/portaudio/pa_win_wmme/pa_win_wmme.h b/pd/portaudio/pa_win_wmme/pa_win_wmme.h
new file mode 100644
index 00000000..d5c18a28
--- /dev/null
+++ b/pd/portaudio/pa_win_wmme/pa_win_wmme.h
@@ -0,0 +1,105 @@
+#ifndef PA_WIN_WMME_H
+#define PA_WIN_WMME_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * MME specific extensions
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+#include "portaudio.h"
+
+#define PaWinMmeUseLowLevelLatencyParameters (0x01)
+#define PaWinMmeUseMultipleDevices (0x02) /* use mme specific multiple device feature */
+
+/* by default, the mme implementation boosts the process priority class to
+ HIGH_PRIORITY_CLASS. This flag disables that priority boost */
+#define PaWinMmeNoHighPriorityProcessClass (0x03)
+
+/* by default, the mme implementation drops the processing thread's priority
+ to THREAD_PRIORITY_NORMAL and sleeps the thread if the CPU load exceeds 100% */
+#define PaWinMmeDontThrottleOverloadedProcessingThread (0x04)
+
+/* by default, the mme implementation sets the processing thread's priority to
+ THREAD_PRIORITY_HIGHEST. This flag sets the priority to
+ THREAD_PRIORITY_TIME_CRITICAL instead. Note that this has the potential
+ to freeze the machine, especially when used in combination with
+ PaWinMmeDontThrottleOverloadedProcessingThread */
+#define PaWinMmeUseTimeCriticalThreadPriority (0x05)
+
+typedef struct PaWinMmeDeviceAndChannelCount{
+ PaDeviceIndex device;
+ int channelCount;
+}PaWinMmeDeviceAndChannelCount;
+
+
+typedef struct PaWinMmeStreamInfo{
+ unsigned long size; /* sizeof(PaWinMmeStreamInfo) */
+ PaHostApiTypeId hostApiType; /* paMME */
+ unsigned long version; /* 1 */
+
+ unsigned long flags;
+
+ /* low-level latency setting support
+ These settings control the number and size of host buffers in order
+ to set latency. They will be used instead of the generic parameters
+ to Pa_OpenStream() if flags contains the PaWinMmeUseLowLevelLatencyParameters
+ flag.
+ */
+ unsigned long framesPerBuffer;
+ unsigned long numBuffers;
+
+ /* multiple devices per direction support
+ If flags contains the PaWinMmeUseMultipleDevices flag,
+ this functionality will be used, otherwise the device parameter to
+ Pa_OpenStream() will be used instead.
+ If devices are specified here, the corresponding device parameter
+ to Pa_OpenStream() should be set to paUseHostApiSpecificDeviceSpecification,
+ otherwise an paInvalidDevice error will result.
+ The total number of channels accross all specified devices
+ must agree with the corresponding channelCount parameter to
+ Pa_OpenStream() otherwise a paInvalidChannelCount error will result.
+ */
+ PaWinMmeDeviceAndChannelCount *devices;
+ unsigned long deviceCount;
+
+}PaWinMmeStreamInfo;
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PA_WIN_WMME_H */
diff --git a/pd/portaudio/pablio/pablio.h b/pd/portaudio/pablio/pablio.h
index 9060c560..85843ae9 100644
--- a/pd/portaudio/pablio/pablio.h
+++ b/pd/portaudio/pablio/pablio.h
@@ -7,7 +7,7 @@ extern "C"
#endif /* __cplusplus */
/*
- * $Id: pablio.h,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * $Id: pablio.h,v 1.1.1.2 2003-05-09 16:03:59 ggeiger Exp $
* PABLIO.h
* Portable Audio Blocking read/write utility.
*
@@ -96,8 +96,9 @@ long GetAudioStreamReadable( PABLIO_Stream *aStream );
*
* flags parameter can be an ORed combination of:
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
+ * and either PABLIO_MONO or PABLIO_STEREO
*/
-PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,
PaSampleFormat format, long flags );
PaError CloseAudioStream( PABLIO_Stream *aStream );
diff --git a/pd/portaudio/pablio/pablio_pd.c b/pd/portaudio/pablio/pablio_pd.c
index e7105e9b..49323ef1 100644
--- a/pd/portaudio/pablio/pablio_pd.c
+++ b/pd/portaudio/pablio/pablio_pd.c
@@ -1,5 +1,5 @@
/*
- * $Id: pablio_pd.c,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * $Id: pablio_pd.c,v 1.1.1.2 2003-05-09 16:03:59 ggeiger Exp $
* pablio.c
* Portable Audio Blocking Input/Output utility.
*
@@ -54,7 +54,9 @@
static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
- PaTimestamp outTime, void *userData );
+ const PaStreamCallbackTimeInfo *outTime,
+ PaStreamCallbackFlags myflags,
+ void *userData );
static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );
static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
@@ -67,7 +69,9 @@ static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
*/
static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
- PaTimestamp outTime, void *userData )
+ const PaStreamCallbackTimeInfo *outTime,
+ PaStreamCallbackFlags myflags,
+ void *userData )
{
PABLIO_Stream *data = (PABLIO_Stream*)userData;
long numBytes = data->bytesPerFrame * framesPerBuffer;
@@ -198,6 +202,7 @@ PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
long doWrite = 0;
PaError err;
PABLIO_Stream *aStream;
+ PaStreamParameters instreamparams, outstreamparams; /* MSP */
long minNumBuffers;
long numFrames;
@@ -208,16 +213,16 @@ PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
if (indeviceno < 0) /* MSP... */
{
- indeviceno = Pa_GetDefaultInputDeviceID();
+ indeviceno = Pa_GetDefaultInputDevice();
fprintf(stderr, "using default input device number: %d\n", indeviceno);
}
if (outdeviceno < 0)
{
- outdeviceno = Pa_GetDefaultOutputDeviceID();
+ outdeviceno = Pa_GetDefaultOutputDevice();
fprintf(stderr, "using default output device number: %d\n", outdeviceno);
}
nbuffers = RoundUpToNextPowerOf2(nbuffers);
- fprintf(stderr, "nchan %d, flags %d, bufs %d, framesperbuf %d\n",
+ fprintf(stderr, "nchan %d, flags %ld, bufs %d, framesperbuf %d\n",
nchannels, flags, nbuffers, framesperbuf);
/* ...MSP */
@@ -236,19 +241,22 @@ PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
aStream->samplesPerFrame = nchannels; /* MSP */
aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
- /* Initialize PortAudio */
- err = Pa_Initialize();
- if( err != paNoError ) goto error;
-/* Warning: numFrames must be larger than amount of data processed per
- interrupt inside PA to prevent glitches. */ /* MSP */
- minNumBuffers = Pa_GetMinNumBuffers(framesperbuf, sampleRate);
- if (minNumBuffers > nbuffers)
- fprintf(stderr,
- "warning: number of buffers %d less than recommended minimum %d\n",
- (int)nbuffers, (int)minNumBuffers);
numFrames = nbuffers * framesperbuf;
+ instreamparams.device = indeviceno; /* MSP */
+ instreamparams.channelCount = nchannels;
+ instreamparams.sampleFormat = format;
+ instreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
+ instreamparams.hostApiSpecificStreamInfo = 0;
+
+ outstreamparams.device = outdeviceno;
+ outstreamparams.channelCount = nchannels;
+ outstreamparams.sampleFormat = format;
+ outstreamparams.suggestedLatency = nbuffers*framesperbuf/sampleRate;
+ outstreamparams.hostApiSpecificStreamInfo = 0;
+
+
/* Initialize Ring Buffers */
doRead = ((flags & PABLIO_READ) != 0);
doWrite = ((flags & PABLIO_WRITE) != 0);
@@ -271,17 +279,10 @@ PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
* audio drivers. */
err = Pa_OpenStream(
&aStream->stream,
- (doRead ? indeviceno : paNoDevice), /* MSP */
- (doRead ? aStream->samplesPerFrame : 0 ),
- format,
- NULL,
- (doWrite ? outdeviceno : paNoDevice), /* MSP */
- (doWrite ? aStream->samplesPerFrame : 0 ),
- format,
- NULL,
+ (doRead ? &instreamparams : 0), /* MSP */
+ (doWrite ? &outstreamparams : 0), /* MSP */
sampleRate,
framesperbuf, /* MSP */
- nbuffers, /* MSP */
paNoFlag, /* MSP -- portaudio will clip for us */
blockingIOCallback,
aStream );
diff --git a/pd/portaudio/pablio/pablio_pd.h b/pd/portaudio/pablio/pablio_pd.h
index b87b9f5a..8f8a688a 100644
--- a/pd/portaudio/pablio/pablio_pd.h
+++ b/pd/portaudio/pablio/pablio_pd.h
@@ -7,7 +7,7 @@ extern "C"
#endif /* __cplusplus */
/*
- * $Id: pablio_pd.h,v 1.1.1.1 2002-07-29 17:06:17 ggeiger Exp $
+ * $Id: pablio_pd.h,v 1.1.1.2 2003-05-09 16:03:59 ggeiger Exp $
* PABLIO.h
* Portable Audio Blocking read/write utility.
*
@@ -53,7 +53,7 @@ typedef struct
{
RingBuffer inFIFO;
RingBuffer outFIFO;
- PortAudioStream *stream;
+ PaStream *stream; /* MSP -- was PortAudioStream; probably an error */
int bytesPerFrame;
int samplesPerFrame;
}
diff --git a/pd/portaudio/pablio/pablio_pd.o b/pd/portaudio/pablio/pablio_pd.o
new file mode 100644
index 00000000..359a8c49
--- /dev/null
+++ b/pd/portaudio/pablio/pablio_pd.o
Binary files differ
diff --git a/pd/portaudio/pablio/ringbuffer_pd.o b/pd/portaudio/pablio/ringbuffer_pd.o
new file mode 100644
index 00000000..a348b1ed
--- /dev/null
+++ b/pd/portaudio/pablio/ringbuffer_pd.o
Binary files differ
diff --git a/pd/portaudio/testcvs/changeme.txt b/pd/portaudio/testcvs/changeme.txt
new file mode 100644
index 00000000..2866c3b7
--- /dev/null
+++ b/pd/portaudio/testcvs/changeme.txt
@@ -0,0 +1,8 @@
+This is just a dopy little file used to test the CVS repository.
+Feel free to trash this file.
+Minor change.
+Another tweak.
+philburk tweak
+stephane test
+Phil changed this again on 2/21/02. Yawn...
+
diff --git a/pd/portaudio_v18/LICENSE.txt b/pd/portaudio_v18/LICENSE.txt
new file mode 100644
index 00000000..105da3f7
--- /dev/null
+++ b/pd/portaudio_v18/LICENSE.txt
@@ -0,0 +1,65 @@
+Portable header file to contain:
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio API Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+Implementation files to contain:
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * Latest version at: http://www.audiomulch.com/portaudio/
+ * <platform> Implementation
+ * Copyright (c) 1999-2000 <author(s)>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */ \ No newline at end of file
diff --git a/pd/portaudio_v18/MSP-README.txt b/pd/portaudio_v18/MSP-README.txt
new file mode 100644
index 00000000..c134e3a9
--- /dev/null
+++ b/pd/portaudio_v18/MSP-README.txt
@@ -0,0 +1,6 @@
+These files are from the V18 "patch" branch, snapshot of 030324. We just use
+this for Mac now, and using v19 instead for linux and MSW.
+
+I changed some code in pablio.c as marked.
+
+-MSP
diff --git a/pd/portaudio_v18/README.txt b/pd/portaudio_v18/README.txt
new file mode 100644
index 00000000..d1e5d7d6
--- /dev/null
+++ b/pd/portaudio_v18/README.txt
@@ -0,0 +1,81 @@
+README for PortAudio
+Implementations for PC DirectSound and Mac SoundManager
+
+/*
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com//
+ *
+ * Copyright (c) 1999-2000 Phil Burk and Ross Bencina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+PortAudio is a portable audio I/O library designed for cross-platform
+support of audio. It uses a callback mechanism to request audio processing.
+Audio can be generated in various formats, including 32 bit floating point,
+and will be converted to the native format internally.
+
+Documentation:
+ See "pa_common/portaudio.h" for API spec.
+ See docs folder for a tutorial.
+ Also see http://www.portaudio.com/docs/
+ And see "pa_tests/patest_saw.c" for an example.
+
+For information on compiling programs with PortAudio, please see the
+tutorial at:
+
+ http://www.portaudio.com/docs/pa_tutorial.html
+
+Important Files and Folders:
+ pa_common/ = platform independant code
+ pa_common/portaudio.h = header file for PortAudio API. Specifies API.
+ pa_common/pa_lib.c = host independant code for all implementations.
+
+ pablio = simple blocking read/write interface
+
+Platform Implementations
+ pa_asio = ASIO for Windows and Macintosh
+ pa_beos = BeOS
+ pa_mac = Macintosh Sound Manager for OS 8,9 and Carbon
+ pa_mac_core = Macintosh Core Audio for OS X
+ pa_sgi = Silicon Graphics AL
+ pa_unix_oss = OSS implementation for various Unixes
+ pa_win_ds = Windows Direct Sound
+ pa_win_wmme = Windows MME (most widely supported)
+
+Test Programs
+ pa_tests/pa_fuzz.c = guitar fuzz box
+ pa_tests/pa_devs.c = print a list of available devices
+ pa_tests/pa_minlat.c = determine minimum latency for your machine
+ pa_tests/paqa_devs.c = self test that opens all devices
+ pa_tests/paqa_errs.c = test error detection and reporting
+ pa_tests/patest_clip.c = hear a sine wave clipped and unclipped
+ pa_tests/patest_dither.c = hear effects of dithering (extremely subtle)
+ pa_tests/patest_pink.c = fun with pink noise
+ pa_tests/patest_record.c = record and playback some audio
+ pa_tests/patest_maxsines.c = how many sine waves can we play? Tests Pa_GetCPULoad().
+ pa_tests/patest_sine.c = output a sine wave in a simple PA app
+ pa_tests/patest_sync.c = test syncronization of audio and video
+ pa_tests/patest_wire.c = pass input to output, wire simulator
diff --git a/pd/portaudio_v18/pa_common/pa_convert.c b/pd/portaudio_v18/pa_common/pa_convert.c
new file mode 100644
index 00000000..72e021eb
--- /dev/null
+++ b/pd/portaudio_v18/pa_common/pa_convert.c
@@ -0,0 +1,470 @@
+/*
+ * pa_conversions.c
+ * portaudio
+ *
+ * Created by Phil Burk on Mon Mar 18 2002.
+ *
+ */
+#include <stdio.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+
+#define CLIP( val, min, max ) { val = ((val) < (min)) ? min : (((val) < (max)) ? (max) : (val)); }
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ short samp = (short) (*sourceBuffer * (32767.0f));
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16_Clip(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ long samp = (long) (*sourceBuffer * (32767.0f));
+ CLIP( samp, -0x8000, 0x7FFF );
+ *targetBuffer = (short) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16_ClipDither(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
+ float dithered = (*sourceBuffer * (32766.0f)) + dither;
+ long samp = (long) dithered;
+ CLIP( samp, -0x8000, 0x7FFF );
+ *targetBuffer = (short) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int16_Dither(
+ float *sourceBuffer, int sourceStride,
+ short *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
+ float dithered = (*sourceBuffer * (32766.0f)) + dither;
+ *targetBuffer = (short) dithered;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+
+/*************************************************************************/
+static void PaConvert_Int16_Float32(
+ short *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = *sourceBuffer * (1.0f / 32768.0f);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ char samp = (char) (*sourceBuffer * (127.0));
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8_Clip(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ long samp = (long) (*sourceBuffer * 127.0f);
+ CLIP( samp, -0x80, 0x7F );
+ *targetBuffer = (char) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8_ClipDither(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE;
+ float dithered = (*sourceBuffer * (126.0f)) + dither;
+ long samp = (long) dithered;
+ CLIP( samp, -0x80, 0x7F );
+ *targetBuffer = (char) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int8_Dither(
+ float *sourceBuffer, int sourceStride,
+ char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ // use smaller scaler to prevent overflow when we add the dither
+ float dither = PaConvert_TriangularDither() * PA_DITHER_SCALE; //FIXME
+ float dithered = (*sourceBuffer * (126.0f)) + dither;
+ long samp = (long) dithered;
+ *targetBuffer = (char) samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Int8_Float32(
+ char *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = *sourceBuffer * (1.0f / 128.0f);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_UInt8(
+ float *sourceBuffer, int sourceStride,
+ unsigned char *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ unsigned char samp = (unsigned char)(128 + (*sourceBuffer * (127.0)));
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_UInt8_Float32(
+ unsigned char *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = (*sourceBuffer - 128) * (1.0f / 128.0f);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int32(
+ float *sourceBuffer, int sourceStride,
+ long *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ int samp = (int) (*sourceBuffer * 0x7FFFFFFF);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Float32_Int32_Clip(
+ float *sourceBuffer, int sourceStride,
+ long *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ int samp;
+ float fs = *sourceBuffer;
+ CLIP( fs, -1.0f, 0.999999f );
+ samp = (int) (*sourceBuffer * 0x7FFFFFFF);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static void PaConvert_Int32_Float32(
+ long *sourceBuffer, int sourceStride,
+ float *targetBuffer, int targetStride,
+ int numSamples )
+{
+ int i;
+ for( i=0; i<numSamples; i++ )
+ {
+ float samp = *sourceBuffer * (1.0f / 0x7FFFFFFF);
+ *targetBuffer = samp;
+ sourceBuffer += sourceStride;
+ targetBuffer += targetStride;
+ }
+}
+
+/*************************************************************************/
+static PortAudioConverter *PaConvert_SelectProc( PaSampleFormat sourceFormat,
+ PaSampleFormat targetFormat, int ifClip, int ifDither )
+{
+ PortAudioConverter *proc = NULL;
+ switch( sourceFormat )
+ {
+ case paUInt8:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_UInt8_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+ case paInt8:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_Int8_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+ case paInt16:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_Int16_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case paInt32:
+ switch( targetFormat )
+ {
+ case paFloat32:
+ proc = (PortAudioConverter *) PaConvert_Int32_Float32;
+ break;
+ default:
+ break;
+ }
+ break;
+
+ case paFloat32:
+ switch( targetFormat )
+ {
+ case paUInt8:
+ proc = (PortAudioConverter *) PaConvert_Float32_UInt8;
+ break;
+ case paInt8:
+ if( ifClip && ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_ClipDither;
+ else if( ifClip ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_Clip;
+ else if( ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int8_Dither;
+ else proc = (PortAudioConverter *) PaConvert_Float32_Int8;
+ break;
+ case paInt16:
+ if( ifClip && ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_ClipDither;
+ else if( ifClip ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_Clip;
+ else if( ifDither ) proc = (PortAudioConverter *) PaConvert_Float32_Int16_Dither;
+ else proc = (PortAudioConverter *) PaConvert_Float32_Int16;
+ break;
+ case paInt32:
+ /* Don't bother dithering a 32 bit integer! */
+ if( ifClip ) proc = (PortAudioConverter *) PaConvert_Float32_Int32_Clip;
+ else proc = (PortAudioConverter *) PaConvert_Float32_Int32;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ return proc;
+
+}
+
+/*************************************************************************/
+PaError PaConvert_SetupInput( internalPortAudioStream *past,
+ PaSampleFormat nativeInputSampleFormat )
+{
+ past->past_NativeInputSampleFormat = nativeInputSampleFormat;
+ past->past_InputConversionSourceStride = 1;
+ past->past_InputConversionTargetStride = 1;
+
+ if( nativeInputSampleFormat != past->past_InputSampleFormat )
+ {
+ int ifDither = (past->past_Flags & paDitherOff) == 0;
+ past->past_InputConversionProc = PaConvert_SelectProc( nativeInputSampleFormat,
+ past->past_InputSampleFormat, 0, ifDither );
+ if( past->past_InputConversionProc == NULL ) return paSampleFormatNotSupported;
+ }
+ else
+ {
+ past->past_InputConversionProc = NULL; /* no conversion necessary */
+ }
+
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaConvert_SetupOutput( internalPortAudioStream *past,
+ PaSampleFormat nativeOutputSampleFormat )
+{
+
+ past->past_NativeOutputSampleFormat = nativeOutputSampleFormat;
+ past->past_OutputConversionSourceStride = 1;
+ past->past_OutputConversionTargetStride = 1;
+
+ if( nativeOutputSampleFormat != past->past_OutputSampleFormat )
+ {
+ int ifDither = (past->past_Flags & paDitherOff) == 0;
+ int ifClip = (past->past_Flags & paClipOff) == 0;
+
+ past->past_OutputConversionProc = PaConvert_SelectProc( past->past_OutputSampleFormat,
+ nativeOutputSampleFormat, ifClip, ifDither );
+ if( past->past_OutputConversionProc == NULL ) return paSampleFormatNotSupported;
+ }
+ else
+ {
+ past->past_OutputConversionProc = NULL; /* no conversion necessary */
+ }
+
+ return paNoError;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from native format to user format,
+** call user code,
+** then convert output to native format.
+** Returns result from user callback.
+*/
+long PaConvert_Process( internalPortAudioStream *past,
+ void *nativeInputBuffer,
+ void *nativeOutputBuffer )
+{
+ int userResult;
+ void *inputBuffer = NULL;
+ void *outputBuffer = NULL;
+
+ /* Get native input data. */
+ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+ {
+ if( past->past_InputSampleFormat == past->past_NativeInputSampleFormat )
+ {
+ /* Already in native format so just read directly from native buffer. */
+ inputBuffer = nativeInputBuffer;
+ }
+ else
+ {
+ inputBuffer = past->past_InputBuffer;
+ /* Convert input data to user format. */
+ (*past->past_InputConversionProc)(nativeInputBuffer, past->past_InputConversionSourceStride,
+ inputBuffer, past->past_InputConversionTargetStride,
+ past->past_FramesPerUserBuffer * past->past_NumInputChannels );
+ }
+ }
+
+ /* Are we doing output? */
+ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+ {
+ outputBuffer = (past->past_OutputConversionProc == NULL) ?
+ nativeOutputBuffer : past->past_OutputBuffer;
+ }
+ /*
+ AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+ AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+ */
+ /* Call user callback routine. */
+ userResult = past->past_Callback(
+ inputBuffer,
+ outputBuffer,
+ past->past_FramesPerUserBuffer,
+ past->past_FrameCount,
+ past->past_UserData );
+
+ /* Advance frame counter for timestamp. */
+ past->past_FrameCount += past->past_FramesPerUserBuffer; // FIXME - should this be in here?
+
+ /* Convert to native format if necessary. */
+ if( (past->past_OutputConversionProc != NULL ) && (outputBuffer != NULL) )
+ {
+ (*past->past_OutputConversionProc)( outputBuffer, past->past_OutputConversionSourceStride,
+ nativeOutputBuffer, past->past_OutputConversionTargetStride,
+ past->past_FramesPerUserBuffer * past->past_NumOutputChannels );
+ }
+
+ return userResult;
+}
diff --git a/pd/portaudio_v18/pa_common/pa_host.h b/pd/portaudio_v18/pa_common/pa_host.h
new file mode 100644
index 00000000..db898fe0
--- /dev/null
+++ b/pd/portaudio_v18/pa_common/pa_host.h
@@ -0,0 +1,189 @@
+#ifndef PA_HOST_H
+#define PA_HOST_H
+
+/*
+ * $Id: pa_host.h,v 1.3.4.1 2003/02/11 21:33:58 philburk Exp $
+ * Host dependant internal API for PortAudio
+ *
+ * Author: Phil Burk <philburk@softsynth.com>
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.softsynth.com/portaudio/
+ * DirectSound and Macintosh Implementation
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "portaudio.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#ifndef SUPPORT_AUDIO_CAPTURE
+#define SUPPORT_AUDIO_CAPTURE (1)
+#endif
+
+#ifndef int32
+ typedef long int32;
+#endif
+#ifndef uint32
+ typedef unsigned long uint32;
+#endif
+#ifndef int16
+ typedef short int16;
+#endif
+#ifndef uint16
+ typedef unsigned short uint16;
+#endif
+
+/* Used to convert between various sample formats. */
+typedef void (PortAudioConverter)(
+ void *inputBuffer, int inputStride,
+ void *outputBuffer, int outputStride,
+ int numSamples );
+
+#define PA_MAGIC (0x18273645)
+
+/************************************************************************************/
+/****************** Structures ******************************************************/
+/************************************************************************************/
+
+typedef struct internalPortAudioStream
+{
+ uint32 past_Magic; /* ID for struct to catch bugs. */
+
+ /* Begin user specified information. */
+ uint32 past_FramesPerUserBuffer;
+ uint32 past_NumUserBuffers;
+ double past_SampleRate; /* Closest supported sample rate. */
+ int past_NumInputChannels;
+ int past_NumOutputChannels;
+ PaDeviceID past_InputDeviceID;
+ PaDeviceID past_OutputDeviceID;
+ PaSampleFormat past_InputSampleFormat;
+ PaSampleFormat past_OutputSampleFormat;
+ PortAudioCallback *past_Callback;
+ void *past_UserData;
+ uint32 past_Flags;
+ /* End user specified information. */
+
+ void *past_DeviceData;
+ PaSampleFormat past_NativeOutputSampleFormat;
+ PaSampleFormat past_NativeInputSampleFormat;
+
+ /* Flags for communicating between foreground and background. */
+ volatile int past_IsActive; /* Background is still playing. */
+ volatile int past_StopSoon; /* Background should keep playing when buffers empty. */
+ volatile int past_StopNow; /* Background should stop playing now. */
+ /* These buffers are used when the native format does not match the user format. */
+ void *past_InputBuffer;
+ uint32 past_InputBufferSize; /* Size in bytes of the input buffer. */
+ void *past_OutputBuffer;
+ uint32 past_OutputBufferSize;
+ /* Measurements */
+ uint32 past_NumCallbacks;
+ PaTimestamp past_FrameCount; /* Frames output to buffer. */
+ /* For measuring CPU utilization. */
+ double past_AverageInsideCount;
+ double past_AverageTotalCount;
+ double past_Usage;
+ int past_IfLastExitValid;
+ /* Format Conversion */
+ /* These are setup by PaConversion_Setup() */
+ PortAudioConverter *past_InputConversionProc;
+ int past_InputConversionSourceStride;
+ int past_InputConversionTargetStride;
+ PortAudioConverter *past_OutputConversionProc;
+ int past_OutputConversionSourceStride;
+ int past_OutputConversionTargetStride;
+}
+internalPortAudioStream;
+
+/************************************************************************************/
+/******** These functions must be provided by a platform implementation. ************/
+/************************************************************************************/
+
+PaError PaHost_Init( void );
+PaError PaHost_Term( void );
+
+PaError PaHost_OpenStream( internalPortAudioStream *past );
+PaError PaHost_CloseStream( internalPortAudioStream *past );
+
+PaError PaHost_StartOutput( internalPortAudioStream *past );
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort );
+PaError PaHost_StartInput( internalPortAudioStream *past );
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort );
+PaError PaHost_StartEngine( internalPortAudioStream *past );
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort );
+PaError PaHost_StreamActive( internalPortAudioStream *past );
+
+void *PaHost_AllocateFastMemory( long numBytes );
+void PaHost_FreeFastMemory( void *addr, long numBytes );
+
+/* This only called if PA_VALIDATE_RATE IS CALLED. */
+PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
+ double *closestFrameRatePtr );
+
+/**********************************************************************/
+/************ Common Utility Routines provided by PA ******************/
+/**********************************************************************/
+
+/* PaHost_IsInitialized() returns non-zero if PA is initialized, 0 otherwise */
+int PaHost_IsInitialized( void );
+
+internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream );
+
+int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable,
+ int numRates, double frameRate );
+
+long Pa_CallConvertInt16( internalPortAudioStream *past,
+ short *nativeInputBuffer,
+ short *nativeOutputBuffer );
+
+/* Calculate 2 LSB dither signal with a triangular distribution.
+** Ranged properly for adding to a 32 bit 1.31 fixed point value prior to >>15.
+** Range of output is +/- 65535
+** Multiply by PA_DITHER_SCALE to get a float between -2.0 and 2.0. */
+#define PA_DITHER_BITS (15)
+#define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
+long PaConvert_TriangularDither( void );
+
+PaError PaConvert_SetupInput( internalPortAudioStream *past,
+ PaSampleFormat nativeInputSampleFormat );
+
+PaError PaConvert_SetupOutput( internalPortAudioStream *past,
+ PaSampleFormat nativeOutputSampleFormat );
+
+long PaConvert_Process( internalPortAudioStream *past,
+ void *nativeInputBuffer,
+ void *nativeOutputBuffer );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PA_HOST_H */
diff --git a/pd/portaudio_v18/pa_common/pa_lib.c b/pd/portaudio_v18/pa_common/pa_lib.c
new file mode 100644
index 00000000..bf97de22
--- /dev/null
+++ b/pd/portaudio_v18/pa_common/pa_lib.c
@@ -0,0 +1,806 @@
+/*
+ * $Id: pa_lib.c,v 1.3.4.2 2003/03/15 02:50:14 pieter Exp $
+ * Portable Audio I/O Library
+ * Host Independant Layer
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* Modification History:
+ PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
+ PLB20010820 - fix dither and shift for recording PaUInt8 format
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
+#ifdef _WIN32
+#ifndef __MWERKS__
+#include <memory.h>
+#endif /* __MWERKS__ */
+#else /* !_WIN32 */
+#include <memory.h>
+#endif /* _WIN32 */
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+/* The reason we might NOT want to validate the rate before opening the stream
+ * is because many DirectSound drivers lie about the rates they actually support.
+ */
+#define PA_VALIDATE_RATE (0) /* If true validate sample rate against driver info. */
+
+/*
+O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for conversion
+*/
+
+#ifndef FALSE
+ #define FALSE (0)
+ #define TRUE (!FALSE)
+#endif
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x) /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */
+
+static PaError Pa_KillStream( PortAudioStream *stream, int abort );
+
+/***********************************************************************/
+int PaHost_FindClosestTableEntry( double allowableError, const double *rateTable, int numRates, double frameRate )
+{
+ double err, minErr = allowableError;
+ int i, bestFit = -1;
+
+ for( i=0; i<numRates; i++ )
+ {
+ err = fabs( frameRate - rateTable[i] );
+ if( err < minErr )
+ {
+ minErr = err;
+ bestFit = i;
+ }
+ }
+ return bestFit;
+}
+
+/**************************************************************************
+** Make sure sample rate is legal and also convert to enumeration for driver.
+*/
+PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
+ double *closestFrameRatePtr )
+{
+ long bestRateIndex;
+ const PaDeviceInfo *pdi;
+ pdi = Pa_GetDeviceInfo( id );
+ if( pdi == NULL )
+ {
+ return paInvalidDeviceId;
+ }
+
+ if( pdi->numSampleRates == -1 )
+ {
+ /* Is it out of range? */
+ if( (requestedFrameRate < pdi->sampleRates[0]) ||
+ (requestedFrameRate > pdi->sampleRates[1]) )
+ {
+ return paInvalidSampleRate;
+ }
+
+ *closestFrameRatePtr = requestedFrameRate;
+ }
+ else
+ {
+ bestRateIndex = PaHost_FindClosestTableEntry( 1.0, pdi->sampleRates, pdi->numSampleRates, requestedFrameRate );
+ if( bestRateIndex < 0 ) return paInvalidSampleRate;
+ *closestFrameRatePtr = pdi->sampleRates[bestRateIndex];
+ }
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError Pa_OpenStream(
+ PortAudioStream** streamPtrPtr,
+ PaDeviceID inputDeviceID,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDeviceID,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ unsigned long streamFlags,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ internalPortAudioStream *past = NULL;
+ PaError result = paNoError;
+ int bitsPerInputSample;
+ int bitsPerOutputSample;
+ /* Print passed parameters. */
+ DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n",
+ streamPtrPtr, inputDeviceID, numInputChannels,
+ inputSampleFormat, inputDriverInfo ));
+ DBUG((" %d, %d, %d, %p, /* output */\n",
+ outputDeviceID, numOutputChannels,
+ outputSampleFormat, outputDriverInfo ));
+ DBUG((" %g, %d, %d, 0x%x, , %p )\n",
+ sampleRate, framesPerBuffer, numberOfBuffers,
+ streamFlags, userData ));
+
+ /* Check for parameter errors. */
+ if( (streamFlags & ~(paClipOff | paDitherOff)) != 0 ) return paInvalidFlag;
+ if( streamPtrPtr == NULL ) return paBadStreamPtr;
+ if( inputDriverInfo != NULL ) return paHostError; /* REVIEW */
+ if( outputDriverInfo != NULL ) return paHostError; /* REVIEW */
+ if( (inputDeviceID < 0) && ( outputDeviceID < 0) ) return paInvalidDeviceId;
+ if( (outputDeviceID >= Pa_CountDevices()) || (inputDeviceID >= Pa_CountDevices()) )
+ {
+ return paInvalidDeviceId;
+ }
+ if( (numInputChannels <= 0) && ( numOutputChannels <= 0) ) return paInvalidChannelCount;
+
+#if SUPPORT_AUDIO_CAPTURE
+ if( inputDeviceID >= 0 )
+ {
+ PaError size = Pa_GetSampleSize( inputSampleFormat );
+ if( size < 0 ) return size;
+ bitsPerInputSample = 8 * size;
+ if( (numInputChannels <= 0) ) return paInvalidChannelCount;
+ }
+#else
+ if( inputDeviceID >= 0 )
+ {
+ return paInvalidChannelCount;
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+ else
+ {
+ if( numInputChannels > 0 ) return paInvalidChannelCount;
+ bitsPerInputSample = 0;
+ }
+
+ if( outputDeviceID >= 0 )
+ {
+ PaError size = Pa_GetSampleSize( outputSampleFormat );
+ if( size < 0 ) return size;
+ bitsPerOutputSample = 8 * size;
+ if( (numOutputChannels <= 0) ) return paInvalidChannelCount;
+ }
+ else
+ {
+ if( numOutputChannels > 0 ) return paInvalidChannelCount;
+ bitsPerOutputSample = 0;
+ }
+
+ if( callback == NULL ) return paNullCallback;
+
+ /* Allocate and clear stream structure. */
+ past = (internalPortAudioStream *) PaHost_AllocateFastMemory( sizeof(internalPortAudioStream) );
+ if( past == NULL ) return paInsufficientMemory;
+ memset( past, 0, sizeof(internalPortAudioStream) );
+ AddTraceMessage("Pa_OpenStream: past", (long) past );
+
+ past->past_Magic = PA_MAGIC; /* Set ID to catch bugs. */
+ past->past_FramesPerUserBuffer = framesPerBuffer;
+ past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() MUST CHECK FOR ZERO! */
+ past->past_Callback = callback;
+ past->past_UserData = userData;
+ past->past_OutputSampleFormat = outputSampleFormat;
+ past->past_InputSampleFormat = inputSampleFormat;
+ past->past_OutputDeviceID = outputDeviceID;
+ past->past_InputDeviceID = inputDeviceID;
+ past->past_NumInputChannels = numInputChannels;
+ past->past_NumOutputChannels = numOutputChannels;
+ past->past_Flags = streamFlags;
+
+ /* Check for absurd sample rates. */
+ if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
+ {
+ result = paInvalidSampleRate;
+ goto cleanup;
+ }
+
+ /* Allocate buffers that may be used for format conversion from user to native buffers. */
+ if( numInputChannels > 0 )
+ {
+
+#if PA_VALIDATE_RATE
+ result = PaHost_ValidateSampleRate( inputDeviceID, sampleRate, &past->past_SampleRate );
+ if( result < 0 )
+ {
+ goto cleanup;
+ }
+#else
+ past->past_SampleRate = sampleRate;
+#endif
+ /* Allocate single Input buffer for passing formatted samples to user callback. */
+ past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8);
+ past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize);
+ if( past->past_InputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ past->past_InputBuffer = NULL;
+ }
+
+ /* Allocate single Output buffer. */
+ if( numOutputChannels > 0 )
+ {
+#if PA_VALIDATE_RATE
+ result = PaHost_ValidateSampleRate( outputDeviceID, sampleRate, &past->past_SampleRate );
+ if( result < 0 )
+ {
+ goto cleanup;
+ }
+#else
+ past->past_SampleRate = sampleRate;
+#endif
+ past->past_OutputBufferSize = framesPerBuffer * numOutputChannels * ((bitsPerOutputSample+7) / 8);
+ past->past_OutputBuffer = PaHost_AllocateFastMemory(past->past_OutputBufferSize);
+ if( past->past_OutputBuffer == NULL )
+ {
+ result = paInsufficientMemory;
+ goto cleanup;
+ }
+ }
+ else
+ {
+ past->past_OutputBuffer = NULL;
+ }
+
+ result = PaHost_OpenStream( past );
+ if( result < 0 ) goto cleanup;
+
+ *streamPtrPtr = (void *) past;
+
+ return result;
+
+cleanup:
+ if( past != NULL ) Pa_CloseStream( past );
+ *streamPtrPtr = NULL;
+ return result;
+}
+
+
+/*************************************************************************/
+PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData )
+{
+ return Pa_OpenStream(
+ stream,
+ ((numInputChannels > 0) ? Pa_GetDefaultInputDeviceID() : paNoDevice),
+ numInputChannels, sampleFormat, NULL,
+ ((numOutputChannels > 0) ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
+ numOutputChannels, sampleFormat, NULL,
+ sampleRate, framesPerBuffer, numberOfBuffers, paNoFlag, callback, userData );
+}
+
+/*************************************************************************/
+PaError Pa_CloseStream( PortAudioStream* stream)
+{
+ PaError result;
+ internalPortAudioStream *past;
+
+ DBUG(("Pa_CloseStream()\n"));
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ Pa_AbortStream( past );
+ result = PaHost_CloseStream( past );
+
+ if( past->past_InputBuffer ) PaHost_FreeFastMemory( past->past_InputBuffer, past->past_InputBufferSize );
+ if( past->past_OutputBuffer ) PaHost_FreeFastMemory( past->past_OutputBuffer, past->past_OutputBufferSize );
+ PaHost_FreeFastMemory( past, sizeof(internalPortAudioStream) );
+
+ return result;
+}
+
+/*************************************************************************/
+PaError Pa_StartStream( PortAudioStream *stream )
+{
+ PaError result = paHostError;
+ internalPortAudioStream *past;
+
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ past->past_FrameCount = 0.0;
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ result = PaHost_StartInput( past );
+ DBUG(("Pa_StartStream: PaHost_StartInput returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ result = PaHost_StartOutput( past );
+ DBUG(("Pa_StartStream: PaHost_StartOutput returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ result = PaHost_StartEngine( past );
+ DBUG(("Pa_StartStream: PaHost_StartEngine returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+
+ return paNoError;
+
+error:
+ return result;
+}
+
+/*************************************************************************/
+PaError Pa_StopStream( PortAudioStream *stream )
+{
+ return Pa_KillStream( stream, 0 );
+}
+
+/*************************************************************************/
+PaError Pa_AbortStream( PortAudioStream *stream )
+{
+ return Pa_KillStream( stream, 1 );
+}
+
+/*************************************************************************/
+static PaError Pa_KillStream( PortAudioStream *stream, int abort )
+{
+ PaError result = paNoError;
+ internalPortAudioStream *past;
+
+ DBUG(("Pa_StopStream().\n"));
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+
+ if( (past->past_NumInputChannels > 0) || (past->past_NumOutputChannels > 0) )
+ {
+ result = PaHost_StopEngine( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopEngine returned = 0x%X.\n", result));
+ if( result < 0 ) goto error;
+ }
+
+ if( past->past_NumInputChannels > 0 )
+ {
+ result = PaHost_StopInput( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopInput returned = 0x%X.\n", result));
+ if( result != paNoError ) goto error;
+ }
+
+ if( past->past_NumOutputChannels > 0 )
+ {
+ result = PaHost_StopOutput( past, abort );
+ DBUG(("Pa_StopStream: PaHost_StopOutput returned = 0x%X.\n", result));
+ if( result != paNoError ) goto error;
+ }
+
+error:
+ past->past_Usage = 0;
+ past->past_IfLastExitValid = 0;
+
+ return result;
+}
+
+/*************************************************************************/
+PaError Pa_StreamActive( PortAudioStream *stream )
+{
+ internalPortAudioStream *past;
+ if( stream == NULL ) return paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+ return PaHost_StreamActive( past );
+}
+
+/*************************************************************************/
+const char *Pa_GetErrorText( PaError errnum )
+{
+ const char *msg;
+
+ switch(errnum)
+ {
+ case paNoError: msg = "Success"; break;
+ case paHostError: msg = "Host error."; break;
+ case paInvalidChannelCount: msg = "Invalid number of channels."; break;
+ case paInvalidSampleRate: msg = "Invalid sample rate."; break;
+ case paInvalidDeviceId: msg = "Invalid device ID."; break;
+ case paInvalidFlag: msg = "Invalid flag."; break;
+ case paSampleFormatNotSupported: msg = "Sample format not supported"; break;
+ case paBadIODeviceCombination: msg = "Illegal combination of I/O devices."; break;
+ case paInsufficientMemory: msg = "Insufficient memory."; break;
+ case paBufferTooBig: msg = "Buffer too big."; break;
+ case paBufferTooSmall: msg = "Buffer too small."; break;
+ case paNullCallback: msg = "No callback routine specified."; break;
+ case paBadStreamPtr: msg = "Invalid stream pointer."; break;
+ case paTimedOut : msg = "Wait Timed Out."; break;
+ case paInternalError: msg = "Internal PortAudio Error."; break;
+ case paDeviceUnavailable: msg = "Device Unavailable."; break;
+ default: msg = "Illegal error number."; break;
+ }
+ return msg;
+}
+
+/*
+ Get CPU Load as a fraction of total CPU time.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ The amount may vary depending on CPU load.
+ This function may be called from the callback function.
+*/
+double Pa_GetCPULoad( PortAudioStream* stream)
+{
+ internalPortAudioStream *past;
+ if( stream == NULL ) return (double) paBadStreamPtr;
+ past = (internalPortAudioStream *) stream;
+ return past->past_Usage;
+}
+
+/*************************************************************************/
+internalPortAudioStream* PaHost_GetStreamRepresentation( PortAudioStream *stream )
+{
+ internalPortAudioStream* result = (internalPortAudioStream*) stream;
+
+ if( result == NULL || result->past_Magic != PA_MAGIC )
+ return NULL;
+ else
+ return result;
+}
+
+/*************************************************************
+** Calculate 2 LSB dither signal with a triangular distribution.
+** Ranged properly for adding to a 32 bit integer prior to >>15.
+** Range of output is +/- 32767
+*/
+#define PA_DITHER_BITS (15)
+#define PA_DITHER_SCALE (1.0f / ((1<<PA_DITHER_BITS)-1))
+long PaConvert_TriangularDither( void )
+{
+ static unsigned long previous = 0;
+ static unsigned long randSeed1 = 22222;
+ static unsigned long randSeed2 = 5555555;
+ long current, highPass;
+ /* Generate two random numbers. */
+ randSeed1 = (randSeed1 * 196314165) + 907633515;
+ randSeed2 = (randSeed2 * 196314165) + 907633515;
+ /* Generate triangular distribution about 0.
+ * Shift before adding to prevent overflow which would skew the distribution.
+ * Also shift an extra bit for the high pass filter.
+ */
+#define DITHER_SHIFT ((32 - PA_DITHER_BITS) + 1)
+ current = (((long)randSeed1)>>DITHER_SHIFT) + (((long)randSeed2)>>DITHER_SHIFT);
+ /* High pass filter to reduce audibility. */
+ highPass = current - previous;
+ previous = current;
+ return highPass;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from Int16, call user code, then convert output
+** to Int16 format for native use.
+** Assumes host native format is paInt16.
+** Returns result from user callback.
+*/
+long Pa_CallConvertInt16( internalPortAudioStream *past,
+ short *nativeInputBuffer,
+ short *nativeOutputBuffer )
+{
+ long temp;
+ int userResult;
+ unsigned int i;
+ void *inputBuffer = NULL;
+ void *outputBuffer = NULL;
+
+#if SUPPORT_AUDIO_CAPTURE
+ /* Get native data from DirectSound. */
+ if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+ {
+ /* Convert from native format to PA format. */
+ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels;
+ switch(past->past_InputSampleFormat)
+ {
+
+ case paFloat32:
+ {
+ float *inBufPtr = (float *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = nativeInputBuffer[i] * (1.0f / 32767.0f);
+ }
+ break;
+ }
+
+ case paInt32:
+ {
+ /* Convert 16 bit data to 32 bit integers */
+ int *inBufPtr = (int *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = nativeInputBuffer[i] << 16;
+ }
+ break;
+ }
+
+ case paInt16:
+ {
+ /* Already in correct format so don't copy. */
+ inputBuffer = nativeInputBuffer;
+ break;
+ }
+
+ case paInt8:
+ {
+ /* Convert 16 bit data to 8 bit chars */
+ char *inBufPtr = (char *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = (char)(nativeInputBuffer[i] >> 8);
+ }
+ }
+ else
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = nativeInputBuffer[i];
+ temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
+ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ inBufPtr[i] = (char)(temp >> 8);
+ }
+ }
+ break;
+ }
+
+ case paUInt8:
+ {
+ /* Convert 16 bit data to 8 bit unsigned chars */
+ unsigned char *inBufPtr = (unsigned char *) past->past_InputBuffer;
+ inputBuffer = past->past_InputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ inBufPtr[i] = (unsigned char)((nativeInputBuffer[i] >> 8) + 0x80);
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = nativeInputBuffer[i];
+ temp += PaConvert_TriangularDither() >> 8; /* PLB20010820 */
+ temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ inBufPtr[i] = (unsigned char)((temp>>8) + 0x80); /* PLB20010820 */
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+
+ /* Are we doing output time? */
+ if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+ {
+ /* May already be in native format so just write directly to native buffer. */
+ outputBuffer = (past->past_OutputSampleFormat == paInt16) ?
+ (void*)nativeOutputBuffer : past->past_OutputBuffer;
+ }
+ /*
+ AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+ AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+ */
+ /* Call user callback routine. */
+ userResult = past->past_Callback(
+ inputBuffer,
+ outputBuffer,
+ past->past_FramesPerUserBuffer,
+ past->past_FrameCount,
+ past->past_UserData );
+
+ past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
+
+ /* Convert to native format if necessary. */
+ if( outputBuffer != NULL )
+ {
+ unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
+ switch(past->past_OutputSampleFormat)
+ {
+ case paFloat32:
+ {
+ float *outBufPtr = (float *) past->past_OutputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ if( past->past_Flags & paClipOff ) /* NOTHING */
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (outBufPtr[i] * (32767.0f));
+ }
+ }
+ else /* CLIP */
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ temp = (long)(outBufPtr[i] * 32767.0f);
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ }
+ else
+ {
+ /* If you dither then you have to clip because dithering could push the signal out of range! */
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ float dither = PaConvert_TriangularDither()*PA_DITHER_SCALE;
+ float dithered = (outBufPtr[i] * (32767.0f)) + dither;
+ temp = (long) (dithered);
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ break;
+ }
+
+ case paInt32:
+ {
+ int *outBufPtr = (int *) past->past_OutputBuffer;
+ if( past->past_Flags & paDitherOff )
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (outBufPtr[i] >> 16 );
+ }
+ }
+ else
+ {
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ /* Shift one bit down before dithering so that we have room for overflow from add. */
+ temp = (outBufPtr[i] >> 1) + PaConvert_TriangularDither();
+ temp = temp >> 15;
+ *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+ }
+ }
+ break;
+ }
+
+ case paInt8:
+ {
+ char *outBufPtr = (char *) past->past_OutputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (((int)outBufPtr[i]) << 8);
+ }
+ break;
+ }
+
+ case paUInt8:
+ {
+ unsigned char *outBufPtr = (unsigned char *) past->past_OutputBuffer;
+ for( i=0; i<samplesPerBuffer; i++ )
+ {
+ *nativeOutputBuffer++ = (short) (((int)(outBufPtr[i] - 0x80)) << 8);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ }
+
+ return userResult;
+}
+
+/*************************************************************************/
+PaError Pa_Initialize( void )
+{
+ if( gInitCount++ > 0 ) return paNoError;
+ ResetTraceMessages();
+ return PaHost_Init();
+}
+
+PaError Pa_Terminate( void )
+{
+ PaError result = paNoError;
+
+ if( gInitCount == 0 ) return paNoError;
+ else if( --gInitCount == 0 )
+ {
+ result = PaHost_Term();
+ DumpTraceMessages();
+ }
+ return result;
+}
+
+int PaHost_IsInitialized()
+{
+ return gInitCount;
+}
+
+/*************************************************************************/
+PaError Pa_GetSampleSize( PaSampleFormat format )
+{
+ int size;
+ switch(format )
+ {
+
+ case paUInt8:
+ case paInt8:
+ size = 1;
+ break;
+
+ case paInt16:
+ size = 2;
+ break;
+
+ case paPackedInt24:
+ size = 3;
+ break;
+
+ case paFloat32:
+ case paInt32:
+ case paInt24:
+ size = 4;
+ break;
+
+ default:
+ size = paSampleFormatNotSupported;
+ break;
+ }
+ return (PaError) size;
+}
+
+
diff --git a/pd/portaudio_v18/pa_common/pa_trace.c b/pd/portaudio_v18/pa_common/pa_trace.c
new file mode 100644
index 00000000..d55a6d37
--- /dev/null
+++ b/pd/portaudio_v18/pa_common/pa_trace.c
@@ -0,0 +1,83 @@
+/*
+ * $Id: pa_trace.c,v 1.1.1.1 2002/01/22 00:52:11 phil Exp $
+ * Portable Audio I/O Library Trace Facility
+ * Store trace information in real-time for later printing.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pa_trace.h"
+
+#if TRACE_REALTIME_EVENTS
+
+static char *traceTextArray[MAX_TRACE_RECORDS];
+static int traceIntArray[MAX_TRACE_RECORDS];
+static int traceIndex = 0;
+static int traceBlock = 0;
+
+/*********************************************************************/
+void ResetTraceMessages()
+{
+ traceIndex = 0;
+}
+
+/*********************************************************************/
+void DumpTraceMessages()
+{
+ int i;
+ int numDump = (traceIndex < MAX_TRACE_RECORDS) ? traceIndex : MAX_TRACE_RECORDS;
+
+ printf("DumpTraceMessages: traceIndex = %d\n", traceIndex );
+ for( i=0; i<numDump; i++ )
+ {
+ printf("%3d: %s = 0x%08X\n",
+ i, traceTextArray[i], traceIntArray[i] );
+ }
+ ResetTraceMessages();
+ fflush(stdout);
+}
+
+/*********************************************************************/
+void AddTraceMessage( char *msg, int data )
+{
+ if( (traceIndex == MAX_TRACE_RECORDS) && (traceBlock == 0) )
+ {
+ traceBlock = 1;
+ /* DumpTraceMessages(); */
+ }
+ else if( traceIndex < MAX_TRACE_RECORDS )
+ {
+ traceTextArray[traceIndex] = msg;
+ traceIntArray[traceIndex] = data;
+ traceIndex++;
+ }
+}
+
+#endif
diff --git a/pd/portaudio_v18/pa_common/pa_trace.h b/pd/portaudio_v18/pa_common/pa_trace.h
new file mode 100644
index 00000000..d0fc904c
--- /dev/null
+++ b/pd/portaudio_v18/pa_common/pa_trace.h
@@ -0,0 +1,67 @@
+#ifndef PA_TRACE_H
+#define PA_TRACE_H
+/*
+ * $Id: pa_trace.h,v 1.1.1.1 2002/01/22 00:52:11 phil Exp $
+ * Portable Audio I/O Library Trace Facility
+ * Store trace information in real-time for later printing.
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#define TRACE_REALTIME_EVENTS (0) /* Keep log of various real-time events. */
+#define MAX_TRACE_RECORDS (2048)
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+
+ /************************************************************************************/
+ /****************** Prototypes ******************************************************/
+ /************************************************************************************/
+
+#if TRACE_REALTIME_EVENTS
+
+ void DumpTraceMessages();
+ void ResetTraceMessages();
+ void AddTraceMessage( char *msg, int data );
+
+#else
+
+#define AddTraceMessage(msg,data) /* noop */
+#define ResetTraceMessages() /* noop */
+#define DumpTraceMessages() /* noop */
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PA_TRACE_H */
diff --git a/pd/portaudio_v18/pa_common/portaudio.h b/pd/portaudio_v18/pa_common/portaudio.h
new file mode 100644
index 00000000..06f7079b
--- /dev/null
+++ b/pd/portaudio_v18/pa_common/portaudio.h
@@ -0,0 +1,463 @@
+#ifndef PORT_AUDIO_H
+#define PORT_AUDIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: portaudio.h,v 1.5 2002/03/26 18:04:22 philburk Exp $
+ * PortAudio Portable Real-Time Audio Library
+ * PortAudio API Header File
+ * Latest version available at: http://www.audiomulch.com/portaudio/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+typedef int PaError;
+typedef enum {
+ paNoError = 0,
+
+ paHostError = -10000,
+ paInvalidChannelCount,
+ paInvalidSampleRate,
+ paInvalidDeviceId,
+ paInvalidFlag,
+ paSampleFormatNotSupported,
+ paBadIODeviceCombination,
+ paInsufficientMemory,
+ paBufferTooBig,
+ paBufferTooSmall,
+ paNullCallback,
+ paBadStreamPtr,
+ paTimedOut,
+ paInternalError,
+ paDeviceUnavailable
+} PaErrorNum;
+
+/*
+ Pa_Initialize() is the library initialisation function - call this before
+ using the library.
+
+*/
+
+PaError Pa_Initialize( void );
+
+/*
+ Pa_Terminate() is the library termination function - call this after
+ using the library.
+
+*/
+
+PaError Pa_Terminate( void );
+
+/*
+ Pa_GetHostError() returns a host specific error code.
+ This can be called after receiving a PortAudio error code of paHostError.
+
+*/
+
+long Pa_GetHostError( void );
+
+/*
+ Pa_GetErrorText() translates the supplied PortAudio error number
+ into a human readable message.
+
+*/
+
+const char *Pa_GetErrorText( PaError errnum );
+
+/*
+ Sample formats
+
+ These are formats used to pass sound data between the callback and the
+ stream. Each device has a "native" format which may be used when optimum
+ efficiency or control over conversion is required.
+
+ Formats marked "always available" are supported (emulated) by all
+ PortAudio implementations.
+
+ The floating point representation (paFloat32) uses +1.0 and -1.0 as the
+ maximum and minimum respectively.
+
+ paUInt8 is an unsigned 8 bit format where 128 is considered "ground"
+
+*/
+
+typedef unsigned long PaSampleFormat;
+#define paFloat32 ((PaSampleFormat) (1<<0)) /*always available*/
+#define paInt16 ((PaSampleFormat) (1<<1)) /*always available*/
+#define paInt32 ((PaSampleFormat) (1<<2)) /*always available*/
+#define paInt24 ((PaSampleFormat) (1<<3))
+#define paPackedInt24 ((PaSampleFormat) (1<<4))
+#define paInt8 ((PaSampleFormat) (1<<5))
+#define paUInt8 ((PaSampleFormat) (1<<6))
+#define paCustomFormat ((PaSampleFormat) (1<<16))
+
+/*
+ Device enumeration mechanism.
+
+ Device ids range from 0 to Pa_CountDevices()-1.
+
+ Devices may support input, output or both.
+
+*/
+
+typedef int PaDeviceID;
+#define paNoDevice -1
+
+int Pa_CountDevices( void );
+
+typedef struct
+{
+ int structVersion;
+ const char *name;
+ int maxInputChannels;
+ int maxOutputChannels;
+ /* Number of discrete rates, or -1 if range supported. */
+ int numSampleRates;
+ /* Array of supported sample rates, or {min,max} if range supported. */
+ const double *sampleRates;
+ PaSampleFormat nativeSampleFormats;
+}
+PaDeviceInfo;
+
+/*
+ Pa_GetDefaultInputDeviceID(), Pa_GetDefaultOutputDeviceID() return the
+ default device ids for input and output respectively, or paNoDevice if
+ no device is available.
+ The result can be passed to Pa_OpenStream().
+
+ On the PC, the user can specify a default device by
+ setting an environment variable. For example, to use device #1.
+
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ids by using
+ the supplied application "pa_devs".
+
+*/
+
+PaDeviceID Pa_GetDefaultInputDeviceID( void );
+PaDeviceID Pa_GetDefaultOutputDeviceID( void );
+
+
+
+/*
+ Pa_GetDeviceInfo() returns a pointer to an immutable PaDeviceInfo structure
+ for the device specified.
+ If the device parameter is out of range the function returns NULL.
+
+ PortAudio manages the memory referenced by the returned pointer, the client
+ must not manipulate or free the memory. The pointer is only guaranteed to be
+ valid between calls to Pa_Initialize() and Pa_Terminate().
+
+*/
+
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID device );
+
+/*
+ PaTimestamp is used to represent a continuous sample clock with arbitrary
+ start time that can be used for syncronization. The type is used for the
+ outTime argument to the PortAudioCallback and as the result of Pa_StreamTime()
+
+*/
+
+typedef double PaTimestamp;
+
+/*
+ PortAudioCallback is implemented by PortAudio clients.
+
+ inputBuffer and outputBuffer are arrays of interleaved samples,
+ the format, packing and number of channels used by the buffers are
+ determined by parameters to Pa_OpenStream() (see below).
+
+ framesPerBuffer is the number of sample frames to be processed by the callback.
+
+ outTime is the time in samples when the buffer(s) processed by
+ this callback will begin being played at the audio output.
+ See also Pa_StreamTime()
+
+ userData is the value of a user supplied pointer passed to Pa_OpenStream()
+ intended for storing synthesis data etc.
+
+ return value:
+ The callback can return a non-zero value to stop the stream. This may be
+ useful in applications such as soundfile players where a specific duration
+ of output is required. However, it is not necessary to utilise this mechanism
+ as StopStream() will also terminate the stream. A callback returning a
+ non-zero value must fill the entire outputBuffer.
+
+ NOTE: None of the other stream functions may be called from within the
+ callback function except for Pa_GetCPULoad().
+
+*/
+
+typedef int (PortAudioCallback)(
+ void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+
+
+/*
+ Stream flags
+
+ These flags may be supplied (ored together) in the streamFlags argument to
+ the Pa_OpenStream() function.
+
+*/
+
+#define paNoFlag (0)
+#define paClipOff (1<<0) /* disable default clipping of out of range samples */
+#define paDitherOff (1<<1) /* disable default dithering */
+#define paPlatformSpecificFlags (0x00010000)
+typedef unsigned long PaStreamFlags;
+
+/*
+ A single PortAudioStream provides multiple channels of real-time
+ input and output audio streaming to a client application.
+ Pointers to PortAudioStream objects are passed between PortAudio functions.
+*/
+
+typedef void PortAudioStream;
+#define PaStream PortAudioStream
+
+/*
+ Pa_OpenStream() opens a stream for either input, output or both.
+
+ stream is the address of a PortAudioStream pointer which will receive
+ a pointer to the newly opened stream.
+
+ inputDevice is the id of the device used for input (see PaDeviceID above.)
+ inputDevice may be paNoDevice to indicate that an input device is not required.
+
+ numInputChannels is the number of channels of sound to be delivered to the
+ callback. It can range from 1 to the value of maxInputChannels in the
+ PaDeviceInfo record for the device specified by the inputDevice parameter.
+ If inputDevice is paNoDevice numInputChannels is ignored.
+
+ inputSampleFormat is the sample format of inputBuffer provided to the callback
+ function. inputSampleFormat may be any of the formats described by the
+ PaSampleFormat enumeration (see above). PortAudio guarantees support for
+ the device's native formats (nativeSampleFormats in the device info record)
+ and additionally 16 and 32 bit integer and 32 bit floating point formats.
+ Support for other formats is implementation defined.
+
+ inputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ inputDriverInfo is never required for correct operation. If not used
+ inputDriverInfo should be NULL.
+
+ outputDevice is the id of the device used for output (see PaDeviceID above.)
+ outputDevice may be paNoDevice to indicate that an output device is not required.
+
+ numOutputChannels is the number of channels of sound to be supplied by the
+ callback. See the definition of numInputChannels above for more details.
+
+ outputSampleFormat is the sample format of the outputBuffer filled by the
+ callback function. See the definition of inputSampleFormat above for more
+ details.
+
+ outputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or stream processing.
+ outputDriverInfo is never required for correct operation. If not used
+ outputDriverInfo should be NULL.
+
+ sampleRate is the desired sampleRate. For full-duplex streams it is the
+ sample rate for both input and output
+
+ framesPerBuffer is the length in sample frames of all internal sample buffers
+ used for communication with platform specific audio routines. Wherever
+ possible this corresponds to the framesPerBuffer parameter passed to the
+ callback function.
+
+ numberOfBuffers is the number of buffers used for multibuffered communication
+ with the platform specific audio routines. If you pass zero, then an optimum
+ value will be chosen for you internally. This parameter is provided only
+ as a guide - and does not imply that an implementation must use multibuffered
+ i/o when reliable double buffering is available (such as SndPlayDoubleBuffer()
+ on the Macintosh.)
+
+ streamFlags may contain a combination of flags ORed together.
+ These flags modify the behaviour of the streaming process. Some flags may only
+ be relevant to certain buffer formats.
+
+ callback is a pointer to a client supplied function that is responsible
+ for processing and filling input and output buffers (see above for details.)
+
+ userData is a client supplied pointer which is passed to the callback
+ function. It could for example, contain a pointer to instance data necessary
+ for processing the audio buffers.
+
+ return value:
+ Upon success Pa_OpenStream() returns PaNoError and places a pointer to a
+ valid PortAudioStream in the stream argument. The stream is inactive (stopped).
+ If a call to Pa_OpenStream() fails a non-zero error code is returned (see
+ PaError above) and the value of stream is invalid.
+
+*/
+
+PaError Pa_OpenStream( PortAudioStream** stream,
+ PaDeviceID inputDevice,
+ int numInputChannels,
+ PaSampleFormat inputSampleFormat,
+ void *inputDriverInfo,
+ PaDeviceID outputDevice,
+ int numOutputChannels,
+ PaSampleFormat outputSampleFormat,
+ void *outputDriverInfo,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PaStreamFlags streamFlags,
+ PortAudioCallback *callback,
+ void *userData );
+
+
+/*
+ Pa_OpenDefaultStream() is a simplified version of Pa_OpenStream() that opens
+ the default input and/or output devices. Most parameters have identical meaning
+ to their Pa_OpenStream() counterparts, with the following exceptions:
+
+ If either numInputChannels or numOutputChannels is 0 the respective device
+ is not opened. This has the same effect as passing paNoDevice in the device
+ arguments to Pa_OpenStream().
+
+ sampleFormat applies to both the input and output buffers.
+
+*/
+
+PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+ int numInputChannels,
+ int numOutputChannels,
+ PaSampleFormat sampleFormat,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ unsigned long numberOfBuffers,
+ PortAudioCallback *callback,
+ void *userData );
+
+/*
+ Pa_CloseStream() closes an audio stream, flushing any pending buffers.
+
+*/
+
+PaError Pa_CloseStream( PortAudioStream* );
+
+/*
+ Pa_StartStream() and Pa_StopStream() begin and terminate audio processing.
+ Pa_StopStream() waits until all pending audio buffers have been played.
+ Pa_AbortStream() stops playing immediately without waiting for pending
+ buffers to complete.
+
+*/
+
+PaError Pa_StartStream( PortAudioStream *stream );
+
+PaError Pa_StopStream( PortAudioStream *stream );
+
+PaError Pa_AbortStream( PortAudioStream *stream );
+
+/*
+ Pa_StreamActive() returns one (1) when the stream is active (ie playing
+ or recording audio), zero (0) when not playing, or a negative error number
+ if the stream is invalid.
+ The stream is active between calls to Pa_StartStream() and Pa_StopStream(),
+ but may also become inactive if the callback returns a non-zero value.
+ In the latter case, the stream is considered inactive after the last
+ buffer has finished playing.
+
+*/
+
+PaError Pa_StreamActive( PortAudioStream *stream );
+
+/*
+ Pa_StreamTime() returns the current output time in samples for the stream.
+ This time may be used as a time reference (for example synchronizing audio to
+ MIDI).
+
+*/
+
+PaTimestamp Pa_StreamTime( PortAudioStream *stream );
+
+/*
+ Pa_GetCPULoad() returns the CPU Load for the stream.
+ The "CPU Load" is a fraction of total CPU time consumed by the stream's
+ audio processing routines including, but not limited to the client supplied
+ callback.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ This function may be called from the callback function or the application.
+
+*/
+
+double Pa_GetCPULoad( PortAudioStream* stream );
+
+/*
+ Pa_GetMinNumBuffers() returns the minimum number of buffers required by
+ the current host based on minimum latency.
+ On the PC, for the DirectSound implementation, latency can be optionally set
+ by user by setting an environment variable.
+ For example, to set latency to 200 msec, put:
+
+ set PA_MIN_LATENCY_MSEC=200
+
+ in the AUTOEXEC.BAT file and reboot.
+ If the environment variable is not set, then the latency will be determined
+ based on the OS. Windows NT has higher latency than Win95.
+
+*/
+
+int Pa_GetMinNumBuffers( int framesPerBuffer, double sampleRate );
+
+/*
+ Pa_Sleep() puts the caller to sleep for at least 'msec' milliseconds.
+ You may sleep longer than the requested time so don't rely on this for
+ accurate musical timing.
+
+ Pa_Sleep() is provided as a convenience for authors of portable code (such as
+ the tests and examples in the PortAudio distribution.)
+
+*/
+
+void Pa_Sleep( long msec );
+
+/*
+ Pa_GetSampleSize() returns the size in bytes of a single sample in the
+ supplied PaSampleFormat, or paSampleFormatNotSupported if the format is
+ no supported.
+
+*/
+
+PaError Pa_GetSampleSize( PaSampleFormat format );
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PORT_AUDIO_H */
diff --git a/pd/portaudio_v18/pa_mac_core/notes.txt b/pd/portaudio_v18/pa_mac_core/notes.txt
new file mode 100644
index 00000000..3b557d9a
--- /dev/null
+++ b/pd/portaudio_v18/pa_mac_core/notes.txt
@@ -0,0 +1,34 @@
+Notes on Core Audio Implementation of PortAudio
+
+by Phil Burk and Darren Gibbs
+
+Document last updated October 18, 2002
+
+WHAT WORKS
+
+Output with very low latency, <10 msec.
+Half duplex input or output.
+Full duplex
+The paFLoat32, paInt16, paInt8, paUInt8 sample formats.
+Pa_GetCPULoad()
+Pa_StreamTime()
+
+KNOWN BUGS OR LIMITATIONS
+
+The iMic supports multiple sample rates.
+But there is a bug when changing sample rates:
+ Run patest_record.c at rate A - it works.
+ Then run patest_record.c at rate B - it FAIL!
+ Then run patest_record.c again at rate B - it works!
+
+
+DEVICE MAPPING
+
+CoreAudio devices can support both input and output. But the sample
+rates supported may be different. So we have map one or two PortAudio
+device to each CoreAudio device depending on whether it supports
+input, output or both.
+
+When we query devices, we first get a list of CoreAudio devices. Then
+we scan the list and add a PortAudio device for each CoreAudio device
+that supports input. Then we make a scan for output devices.
diff --git a/pd/portaudio_v18/pa_mac_core/pa_mac_core.c b/pd/portaudio_v18/pa_mac_core/pa_mac_core.c
new file mode 100644
index 00000000..5bf24cb6
--- /dev/null
+++ b/pd/portaudio_v18/pa_mac_core/pa_mac_core.c
@@ -0,0 +1,2116 @@
+/*
+ * $Id: pa_mac_core.c,v 1.8.4.8 2003/03/07 01:34:18 philburk Exp $
+ * pa_mac_core.c
+ * Implementation of PortAudio for Mac OS X Core Audio
+ *
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ *
+ * Authors: Ross Bencina and Phil Burk
+ * Copyright (c) 1999-2002 Ross Bencina and Phil Burk
+ *
+ * Theory of Operation
+ *
+ * This code uses the HAL (Hardware Access Layer) of the Apple CoreAudio library.
+ * This is the layer closes to the hardware.
+ * The HAL layer only supports the native HW supported sample rates.
+ * So if the chip only supports 44100 Hz, then the HAL only supports 44100.
+ * To provide other rates we use the handy Apple AudioConverter which provides
+ * sample rate conversion, mono-to-stereo conversion, and buffer size adaptation.
+ *
+ * There are four modes of operation:
+ * PA_MODE_OUTPUT_ONLY,
+ * PA_MODE_INPUT_ONLY,
+ * PA_MODE_IO_ONE_DEVICE,
+ * PA_MODE_IO_TWO_DEVICES
+ *
+ * The processing pipeline for PA_MODE_IO_ONE_DEVICE is in one thread:
+ *
+ * PaOSX_CoreAudioIOCallback() input buffers -> RingBuffer -> input.AudioConverter ->
+ * PortAudio callback -> output.AudioConverter -> PaOSX_CoreAudioIOCallback() output buffers
+ *
+ * For two separate devices, we have to use two separate callbacks.
+ * We pass data between them using a RingBuffer FIFO.
+ * The processing pipeline for PA_MODE_IO_TWO_DEVICES is split into two threads:
+ *
+ * PaOSX_CoreAudioInputCallback() input buffers -> RingBuffer
+ *
+ * RingBuffer -> input.AudioConverter ->
+ * PortAudio callback -> output.AudioConverter -> PaOSX_CoreAudioIOCallback() output buffers
+ *
+ * License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * CHANGE HISTORY:
+
+ 3.29.2001 - Phil Burk - First pass... converted from Window MME code with help from Darren.
+ 3.30.2001 - Darren Gibbs - Added more support for dynamically querying device info.
+ 12.7.2001 - Gord Peters - Tweaks to compile on PA V17 and OS X 10.1
+ 2.7.2002 - Darren and Phil - fixed isInput so GetProperty works better,
+ fixed device queries for numChannels and sampleRates,
+ one CoreAudio device now maps to separate input and output PaDevices,
+ audio input works if using same CoreAudio device (some HW devices make separate CoreAudio devices).
+ 2.22.2002 - Stephane Letz - Explicit cast needed for compilation with Code Warrior 7
+ 3.19.2002 - Phil Burk - Added paInt16, paInt8, format using new "pa_common/pa_convert.c" file.
+ Return error if opened in mono mode cuz not supported. [Supported 10.12.2002]
+ Add support for Pa_GetCPULoad();
+ Fixed timestamp in callback and Pa_StreamTime() (Thanks n++k for the advice!)
+ Check for invalid sample rates and return an error.
+ Check for getenv("PA_MIN_LATENCY_MSEC") to set latency externally.
+ Better error checking for invalid channel counts and invalid devices.
+ 3.29.2002 - Phil Burk - Fixed Pa_GetCPULoad() for small buffers.
+ 3.31.2002 - Phil Burk - Use getrusage() instead of gettimeofday() for CPU Load calculation.
+ 10.12.2002 - Phil Burk - Use AudioConverter to allow wide range of sample rates, and mono.
+ Use FIFO (from pablio/rinbuffer.h) so that we can pull data through converter.
+ Added PaOSX_FixVolumeScalar() to make iMic audible.
+ 10.17.2002 - Phil Burk - Support full duplex between two different devices.
+ Name internal functions PaOSX_*
+ Dumped useless PA_MIN_LATENCY_MSEC environment variable.
+ Use kAudioDevicePropertyStreamFormatMatch to determine max channels.
+ 02.03.2003 - Phil Burk - always use AudioConverters so that we can adapt when format changes.
+ Synchronize with device when format changes.
+ 02.13.2003 - Phil Burk - scan for maxChannels because FormatMatch won't tell us.
+ 03.05.2003 - Phil Burk and Dominic Mazzoni - interleave and deinterleave multiple
+ CoreAudio buffers. Needed for MOTU828 and some other N>2 channel devices.
+ See code related to "streamInterleavingBuffer".
+ 03.06.2003 - Phil Burk and Ryan Francesconi - fixed numChannels query for MOTU828.
+ Handle fact that MOTU828 gives you 8 channels even when you ask for 2!
+*/
+
+#include <CoreServices/CoreServices.h>
+#include <CoreAudio/CoreAudio.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/DefaultAudioOutput.h>
+#include <AudioToolbox/AudioConverter.h>
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+#include "ringbuffer.h"
+
+/************************************************* Constants ********/
+#define SET_DEVICE_BUFFER_SIZE (1)
+
+/* To trace program, enable TRACE_REALTIME_EVENTS in pa_trace.h */
+#define PA_TRACE_RUN (0)
+#define PA_TRACE_START_STOP (0)
+
+#define PA_MIN_LATENCY_MSEC (20) /* FIXME */
+#define MIN_TIMEOUT_MSEC (3000)
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define PRINT_ERR( msg, err ) PRINT(( msg ": error = 0x%0lX = '%s'\n", (err), ErrorToString(err)) )
+#define DBUG(x) /* PRINT(x) */
+#define DBUGBACK(x) /* if( sMaxBackgroundErrorMessages-- > 0 ) PRINT(x) */
+#define DBUGX(x)
+
+// define value of isInput passed to CoreAudio routines
+#define IS_INPUT (true)
+#define IS_OUTPUT (false)
+
+typedef enum PaDeviceMode
+{
+ PA_MODE_OUTPUT_ONLY,
+ PA_MODE_INPUT_ONLY,
+ PA_MODE_IO_ONE_DEVICE,
+ PA_MODE_IO_TWO_DEVICES
+} PaDeviceMode;
+
+#define PA_USING_OUTPUT (pahsc->mode != PA_MODE_INPUT_ONLY)
+#define PA_USING_INPUT (pahsc->mode != PA_MODE_OUTPUT_ONLY)
+
+/**************************************************************
+ * Information needed by PortAudio specific to a CoreAudio device.
+ */
+typedef struct PaHostInOut_s
+{
+ AudioDeviceID audioDeviceID; /* CoreAudio specific ID */
+ int bytesPerUserNativeBuffer; /* User buffer size in native host format. Depends on numChannels. */
+ AudioConverterRef converter;
+ void *converterBuffer;
+ int numChannels;
+ /** Used for interleaving or de-interleaving multiple streams for devices like MOTU828. */
+ int streamInterleavingBufferLen; /**< size in bytes */
+ Float32 *streamInterleavingBuffer;
+} PaHostInOut;
+
+/**************************************************************
+ * Structure for internal host specific stream data.
+ * This is allocated on a per stream basis.
+ */
+typedef struct PaHostSoundControl
+{
+ PaHostInOut input;
+ PaHostInOut output;
+ AudioDeviceID primaryDeviceID;
+ PaDeviceMode mode;
+ RingBuffer ringBuffer;
+ char *ringBufferData;
+ Boolean formatListenerCalled;
+ /* For measuring CPU utilization. */
+ struct rusage entryRusage;
+ double inverseMicrosPerHostBuffer; /* 1/Microseconds of real-time audio per user buffer. */
+} PaHostSoundControl;
+
+/**************************************************************
+ * Structure for internal extended device info query.
+ * There will be one or two PortAudio devices for each Core Audio device:
+ * one input and or one output.
+ */
+typedef struct PaHostDeviceInfo
+{
+ PaDeviceInfo paInfo;
+ AudioDeviceID audioDeviceID;
+}
+PaHostDeviceInfo;
+
+/************************************************* Shared Data ********/
+/* FIXME - put Mutex around this shared data. */
+static int sNumPaDevices = 0; /* Total number of PaDeviceInfos */
+static int sNumInputDevices = 0; /* Total number of input PaDeviceInfos */
+static int sNumOutputDevices = 0;
+static int sNumCoreDevices = 0;
+static AudioDeviceID *sCoreDeviceIDs; // Array of Core AudioDeviceIDs
+static PaHostDeviceInfo *sDeviceInfos = NULL;
+static int sDefaultInputDeviceID = paNoDevice;
+static int sDefaultOutputDeviceID = paNoDevice;
+static int sSavedHostError = 0;
+
+static const double supportedSampleRateRange[] = { 8000.0, 96000.0 }; /* FIXME - go to double HW rate. */
+static const char sMapperSuffixInput[] = " - Input";
+static const char sMapperSuffixOutput[] = " - Output";
+
+/* Debug support. */
+//static int sMaxBackgroundErrorMessages = 100;
+//static int sCoverageCounter = 1; // used to check code coverage during validation
+
+/* We index the input devices first, then the output devices. */
+#define LOWEST_INPUT_DEVID (0)
+#define HIGHEST_INPUT_DEVID (sNumInputDevices - 1)
+#define LOWEST_OUTPUT_DEVID (sNumInputDevices)
+#define HIGHEST_OUTPUT_DEVID (sNumPaDevices - 1)
+
+/************************************************* Macros ********/
+
+/************************************************* Prototypes **********/
+
+static PaError PaOSX_QueryDevices( void );
+static int PaOSX_ScanDevices( Boolean isInput );
+static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput );
+static PaDeviceID PaOSX_QueryDefaultInputDevice( void );
+static PaDeviceID PaOSX_QueryDefaultOutputDevice( void );
+static void PaOSX_CalcHostBufferSize( internalPortAudioStream *past );
+
+static OSStatus PAOSX_DevicePropertyListener (AudioDeviceID inDevice,
+ UInt32 inChannel,
+ Boolean isInput,
+ AudioDevicePropertyID inPropertyID,
+ void* inClientData);
+
+/**********************************************************************/
+/* OS X errors are 4 character ID that can be printed.
+ * Note that uses a static pad so result must be printed immediately.
+ */
+static OSStatus statusText[2] = { 0, 0 };
+static const char *ErrorToString( OSStatus err )
+{
+ const char *str;
+
+ switch (err)
+ {
+ case kAudioHardwareUnspecifiedError:
+ str = "kAudioHardwareUnspecifiedError";
+ break;
+ case kAudioHardwareNotRunningError:
+ str = "kAudioHardwareNotRunningError";
+ break;
+ case kAudioHardwareUnknownPropertyError:
+ str = "kAudioHardwareUnknownPropertyError";
+ break;
+ case kAudioDeviceUnsupportedFormatError:
+ str = "kAudioDeviceUnsupportedFormatError";
+ break;
+ case kAudioHardwareBadPropertySizeError:
+ str = "kAudioHardwareBadPropertySizeError";
+ break;
+ case kAudioHardwareIllegalOperationError:
+ str = "kAudioHardwareIllegalOperationError";
+ break;
+ default:
+ statusText[0] = err;
+ str = (const char *)statusText;
+ break;
+ }
+
+ return str;
+}
+
+/**********************************************************************/
+static unsigned long RoundUpToNextPowerOf2( unsigned long n )
+{
+ long numBits = 0;
+ if( ((n-1) & n) == 0) return n; /* Already Power of two. */
+ while( n > 0 )
+ {
+ n= n>>1;
+ numBits++;
+ }
+ return (1<<numBits);
+}
+
+/********************************* BEGIN CPU UTILIZATION MEASUREMENT ****/
+static void Pa_StartUsageCalculation( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+ /* Query user CPU timer for usage analysis and to prevent overuse of CPU. */
+ getrusage( RUSAGE_SELF, &pahsc->entryRusage );
+}
+
+static long SubtractTime_AminusB( struct timeval *timeA, struct timeval *timeB )
+{
+ long secs = timeA->tv_sec - timeB->tv_sec;
+ long usecs = secs * 1000000;
+ usecs += (timeA->tv_usec - timeB->tv_usec);
+ return usecs;
+}
+
+/******************************************************************************
+** Measure fractional CPU load based on real-time it took to calculate
+** buffers worth of output.
+*/
+static void Pa_EndUsageCalculation( internalPortAudioStream *past )
+{
+ struct rusage currentRusage;
+ long usecsElapsed;
+ double newUsage;
+
+#define LOWPASS_COEFFICIENT_0 (0.95)
+#define LOWPASS_COEFFICIENT_1 (0.99999 - LOWPASS_COEFFICIENT_0)
+
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return;
+
+ if( getrusage( RUSAGE_SELF, &currentRusage ) == 0 )
+ {
+ usecsElapsed = SubtractTime_AminusB( &currentRusage.ru_utime, &pahsc->entryRusage.ru_utime );
+
+ /* Use inverse because it is faster than the divide. */
+ newUsage = usecsElapsed * pahsc->inverseMicrosPerHostBuffer;
+
+ past->past_Usage = (LOWPASS_COEFFICIENT_0 * past->past_Usage) +
+ (LOWPASS_COEFFICIENT_1 * newUsage);
+ }
+}
+/****************************************** END CPU UTILIZATION *******/
+
+/************************************************************************/
+static PaDeviceID PaOSX_QueryDefaultInputDevice( void )
+{
+ OSStatus err = noErr;
+ UInt32 count;
+ int i;
+ AudioDeviceID tempDeviceID = kAudioDeviceUnknown;
+ PaDeviceID defaultDeviceID = paNoDevice;
+
+ // get the default output device for the HAL
+ // it is required to pass the size of the data to be returned
+ count = sizeof(tempDeviceID);
+ err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultInputDevice, &count, (void *) &tempDeviceID);
+ if (err != noErr) goto error;
+
+ // scan input devices to see which one matches this device
+ defaultDeviceID = paNoDevice;
+ for( i=LOWEST_INPUT_DEVID; i<=HIGHEST_INPUT_DEVID; i++ )
+ {
+ DBUG(("PaOSX_QueryDefaultInputDevice: i = %d, aDevId = %ld\n", i, sDeviceInfos[i].audioDeviceID ));
+ if( sDeviceInfos[i].audioDeviceID == tempDeviceID )
+ {
+ defaultDeviceID = i;
+ break;
+ }
+ }
+error:
+ return defaultDeviceID;
+}
+
+/************************************************************************/
+static PaDeviceID PaOSX_QueryDefaultOutputDevice( void )
+{
+ OSStatus err = noErr;
+ UInt32 count;
+ int i;
+ AudioDeviceID tempDeviceID = kAudioDeviceUnknown;
+ PaDeviceID defaultDeviceID = paNoDevice;
+
+ // get the default output device for the HAL
+ // it is required to pass the size of the data to be returned
+ count = sizeof(tempDeviceID);
+ err = AudioHardwareGetProperty( kAudioHardwarePropertyDefaultOutputDevice, &count, (void *) &tempDeviceID);
+ if (err != noErr) goto error;
+
+ // scan output devices to see which one matches this device
+ defaultDeviceID = paNoDevice;
+ for( i=LOWEST_OUTPUT_DEVID; i<=HIGHEST_OUTPUT_DEVID; i++ )
+ {
+ DBUG(("PaOSX_QueryDefaultOutputDevice: i = %d, aDevId = %ld\n", i, sDeviceInfos[i].audioDeviceID ));
+ if( sDeviceInfos[i].audioDeviceID == tempDeviceID )
+ {
+ defaultDeviceID = i;
+ break;
+ }
+ }
+error:
+ return defaultDeviceID;
+}
+
+/******************************************************************/
+static PaError PaOSX_QueryDevices( void )
+{
+ OSStatus err = noErr;
+ UInt32 outSize;
+ Boolean outWritable;
+ int numBytes;
+
+ // find out how many Core Audio devices there are, if any
+ outSize = sizeof(outWritable);
+ err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &outSize, &outWritable);
+ if (err != noErr)
+ {
+ PRINT_ERR("Couldn't get info about list of audio devices", err);
+ sSavedHostError = err;
+ return paHostError;
+ }
+
+ // calculate the number of device available
+ sNumCoreDevices = outSize / sizeof(AudioDeviceID);
+
+ // Bail if there aren't any devices
+ if (sNumCoreDevices < 1)
+ {
+ PRINT(("No Devices Available"));
+ return paHostError;
+ }
+
+ // make space for the devices we are about to get
+ sCoreDeviceIDs = (AudioDeviceID *)malloc(outSize);
+
+ // get an array of AudioDeviceIDs
+ err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &outSize, (void *)sCoreDeviceIDs);
+ if (err != noErr)
+ {
+ PRINT_ERR("Couldn't get list of audio device IDs", err);
+ sSavedHostError = err;
+ return paHostError;
+ }
+
+ // Allocate structures to hold device info pointers.
+ // There will be a maximum of two Pa devices per Core Audio device, input and/or output.
+ numBytes = sNumCoreDevices * 2 * sizeof(PaHostDeviceInfo);
+ sDeviceInfos = (PaHostDeviceInfo *) PaHost_AllocateFastMemory( numBytes );
+ if( sDeviceInfos == NULL ) return paInsufficientMemory;
+
+ // Scan all the Core Audio devices to see which support input and allocate a
+ // PaHostDeviceInfo structure for each one.
+ DBUG(("PaOSX_QueryDevices: scan for input ======================\n"));
+ PaOSX_ScanDevices( IS_INPUT );
+ sNumInputDevices = sNumPaDevices;
+ // Now scan all the output devices.
+ DBUG(("PaOSX_QueryDevices: scan for output ======================\n"));
+ PaOSX_ScanDevices( IS_OUTPUT );
+ sNumOutputDevices = sNumPaDevices - sNumInputDevices;
+
+ // Figure out which of the devices that we scanned is the default device.
+ sDefaultInputDeviceID = PaOSX_QueryDefaultInputDevice();
+ sDefaultOutputDeviceID = PaOSX_QueryDefaultOutputDevice();
+
+ return paNoError;
+}
+
+
+/*************************************************************************/
+/* Query a device for its sample rate.
+ * @return positive rate or 0.0 on error.
+ */
+static Float64 PaOSX_GetDeviceSampleRate( AudioDeviceID deviceID, Boolean isInput )
+{
+ OSStatus err = noErr;
+ AudioStreamBasicDescription formatDesc;
+ UInt32 dataSize;
+ dataSize = sizeof(formatDesc);
+ err = AudioDeviceGetProperty( deviceID, 0, isInput,
+ kAudioDevicePropertyStreamFormat, &dataSize, &formatDesc);
+ if( err != noErr ) return 0.0;
+ else return formatDesc.mSampleRate;
+}
+
+/*************************************************************************/
+/* Allocate a string containing the device name. */
+static char *PaOSX_DeviceNameFromID(AudioDeviceID deviceID, Boolean isInput )
+{
+ OSStatus err = noErr;
+ UInt32 outSize;
+ Boolean outWritable;
+ char *deviceName = nil;
+
+ // query size of name
+ err = AudioDeviceGetPropertyInfo(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, &outWritable);
+ if (err == noErr)
+ {
+ deviceName = (char*)malloc( outSize + 1);
+ if( deviceName )
+ {
+ err = AudioDeviceGetProperty(deviceID, 0, isInput, kAudioDevicePropertyDeviceName, &outSize, deviceName);
+ if (err != noErr)
+ PRINT_ERR("Couldn't get audio device name", err);
+ }
+ }
+
+ return deviceName;
+}
+
+/*************************************************************************
+** Scan all of the Core Audio devices to see which support selected
+** input or output mode.
+** Changes sNumDevices, and fills in sDeviceInfos.
+*/
+static int PaOSX_ScanDevices( Boolean isInput )
+{
+ int coreDeviceIndex;
+ int result;
+ PaHostDeviceInfo *hostDeviceInfo;
+ int numAdded = 0;
+
+ for( coreDeviceIndex=0; coreDeviceIndex<sNumCoreDevices; coreDeviceIndex++ )
+ {
+ // try to fill in next PaHostDeviceInfo
+ hostDeviceInfo = &sDeviceInfos[sNumPaDevices];
+ result = PaOSX_QueryDeviceInfo( hostDeviceInfo, coreDeviceIndex, isInput );
+ DBUG(("PaOSX_ScanDevices: paDevId = %d, coreDevId = %d, result = %d\n", sNumPaDevices, coreDeviceIndex, result ));
+ if( result > 0 )
+ {
+ sNumPaDevices += 1; // bump global counter if we got one
+ numAdded += 1;
+ }
+ else if( result < 0 ) return result;
+ }
+ return numAdded;
+}
+
+/*************************************************************************
+** Determine the maximum number of channels a device will support.
+** @return maxChannels or negative error.
+*/
+static int PaOSX_GetMaxChannels( AudioDeviceID devID, Boolean isInput )
+{
+ OSStatus err;
+ UInt32 outSize;
+ AudioStreamBasicDescription formatDesc;
+ int maxChannels;
+ int numChannels;
+ Boolean gotMax;
+
+ // Scan to find highest matching format.
+ // Unfortunately some devices won't just return maxChannels for the match.
+ // For example, some 8 channel devices return 2 when given 256 as input.
+ gotMax = false;
+ maxChannels = 0;
+ while( !gotMax )
+ {
+
+ memset( &formatDesc, 0, sizeof(formatDesc));
+ numChannels = maxChannels + 2;
+ DBUG(("PaOSX_GetMaxChannels: try numChannels = %d = %d + 2\n",
+ numChannels, maxChannels ));
+ formatDesc.mChannelsPerFrame = numChannels;
+ outSize = sizeof(formatDesc);
+
+ err = AudioDeviceGetProperty( devID, 0,
+ isInput, kAudioDevicePropertyStreamFormatMatch, &outSize, &formatDesc);
+
+ DBUG(("PaOSX_GetMaxChannels: err 0x%0x, formatDesc.mChannelsPerFrame= %d\n",
+ err, formatDesc.mChannelsPerFrame ));
+ if( err != noErr )
+ {
+ gotMax = true;
+ }
+ else
+ {
+ // This value worked so we have a new candidate for maxChannels.
+ if (formatDesc.mChannelsPerFrame > numChannels)
+ {
+ maxChannels = formatDesc.mChannelsPerFrame;
+ }
+ else if(formatDesc.mChannelsPerFrame < numChannels)
+ {
+ gotMax = true;
+ }
+ else
+ {
+ maxChannels = numChannels;
+ }
+ }
+ }
+ return maxChannels;
+}
+
+/*************************************************************************
+** Try to fill in the device info for this device.
+** Return 1 if a good device that PA can use.
+** Return 0 if not appropriate
+** or return negative error.
+**
+*/
+static int PaOSX_QueryDeviceInfo( PaHostDeviceInfo *hostDeviceInfo, int coreDeviceIndex, Boolean isInput )
+{
+ OSStatus err;
+ UInt32 outSize;
+ AudioStreamBasicDescription formatDesc;
+ AudioDeviceID devID;
+ PaDeviceInfo *deviceInfo = &hostDeviceInfo->paInfo;
+ int maxChannels;
+
+ deviceInfo->structVersion = 1;
+ deviceInfo->maxInputChannels = 0;
+ deviceInfo->maxOutputChannels = 0;
+
+ deviceInfo->sampleRates = supportedSampleRateRange; // because we use sample rate converter to get continuous rates
+ deviceInfo->numSampleRates = -1;
+
+ devID = sCoreDeviceIDs[ coreDeviceIndex ];
+ hostDeviceInfo->audioDeviceID = devID;
+ DBUG(("PaOSX_QueryDeviceInfo: coreDeviceIndex = %d, devID = %d, isInput = %d\n",
+ coreDeviceIndex, (int) devID, isInput ));
+
+ // Get data format info from the device.
+ outSize = sizeof(formatDesc);
+ err = AudioDeviceGetProperty(devID, 0, isInput, kAudioDevicePropertyStreamFormat, &outSize, &formatDesc);
+ // This just may not be an appropriate device for input or output so leave quietly.
+ if( (err != noErr) || (formatDesc.mChannelsPerFrame == 0) ) goto error;
+
+ DBUG(("PaOSX_QueryDeviceInfo: mFormatID = 0x%x\n", (unsigned int) formatDesc.mFormatID));
+ DBUG(("PaOSX_QueryDeviceInfo: mFormatFlags = 0x%x\n",(unsigned int) formatDesc.mFormatFlags));
+
+ // Right now the Core Audio headers only define one formatID: LinearPCM
+ // Apparently LinearPCM must be Float32 for now.
+ if( (formatDesc.mFormatID == kAudioFormatLinearPCM) &&
+ ((formatDesc.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0) )
+ {
+ deviceInfo->nativeSampleFormats = paFloat32;
+ }
+ else
+ {
+ PRINT(("PaOSX_QueryDeviceInfo: ERROR - not LinearPCM & Float32!!!\n"));
+ return paSampleFormatNotSupported;
+ }
+
+ maxChannels = PaOSX_GetMaxChannels( devID, isInput );
+ if( maxChannels <= 0 ) goto error;
+ if( isInput )
+ {
+ deviceInfo->maxInputChannels = maxChannels;
+ }
+ else
+ {
+ deviceInfo->maxOutputChannels = maxChannels;
+ }
+
+ // Get the device name
+ deviceInfo->name = PaOSX_DeviceNameFromID( devID, isInput );
+ DBUG(("PaOSX_QueryDeviceInfo: name = %s\n", deviceInfo->name ));
+ return 1;
+
+error:
+ return 0;
+}
+
+/**********************************************************************/
+static PaError PaOSX_MaybeQueryDevices( void )
+{
+ if( sNumPaDevices == 0 )
+ {
+ return PaOSX_QueryDevices();
+ }
+ return 0;
+}
+
+static char zeroPad[256] = { 0 };
+
+/**********************************************************************
+** This is the proc that supplies the data to the AudioConverterFillBuffer call.
+** We can pass back arbitrarily sized blocks so if the FIFO region is split
+** just pass back the first half.
+*/
+static OSStatus PaOSX_InputConverterCallbackProc (AudioConverterRef inAudioConverter,
+ UInt32* outDataSize,
+ void** outData,
+ void* inUserData)
+{
+ internalPortAudioStream *past = (internalPortAudioStream *) inUserData;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ void *dataPtr1;
+ long size1;
+ void *dataPtr2;
+ long size2;
+
+ /* Pass contiguous region from FIFO directly to converter. */
+ RingBuffer_GetReadRegions( &pahsc->ringBuffer, *outDataSize,
+ &dataPtr1, &size1, &dataPtr2, &size2 );
+
+ if( size1 > 0 )
+ {
+ *outData = dataPtr1;
+ *outDataSize = size1;
+ RingBuffer_AdvanceReadIndex( &pahsc->ringBuffer, size1 );
+ DBUGX(("PaOSX_InputConverterCallbackProc: read %ld bytes from FIFO.\n", size1 ));
+ }
+ else
+ {
+ DBUGBACK(("PaOSX_InputConverterCallbackProc: got no data!\n"));
+ *outData = zeroPad; /* Give it zero data to keep it happy. */
+ *outDataSize = sizeof(zeroPad);
+ }
+ return noErr;
+}
+
+/*****************************************************************************
+** Get audio input, if any, from passed in buffer, or from converter or from FIFO,
+** then run PA callback and output data.
+*/
+static OSStatus PaOSX_LoadAndProcess( internalPortAudioStream *past,
+ void *inputBuffer, void *outputBuffer )
+{
+ OSStatus err = noErr;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ if( past->past_StopSoon )
+ {
+ if( outputBuffer )
+ {
+ /* Clear remainder of audio buffer if we are waiting for stop. */
+ AddTraceMessage("PaOSX_LoadAndProcess: zero rest of wave buffer ", i );
+ memset( outputBuffer, 0, pahsc->output.bytesPerUserNativeBuffer );
+ }
+ }
+ else
+ {
+ /* Do we need data from the converted input? */
+ if( PA_USING_INPUT )
+ {
+ UInt32 size = pahsc->input.bytesPerUserNativeBuffer;
+ err = AudioConverterFillBuffer(
+ pahsc->input.converter,
+ PaOSX_InputConverterCallbackProc,
+ past,
+ &size,
+ pahsc->input.converterBuffer);
+ if( err != noErr ) return err;
+ inputBuffer = pahsc->input.converterBuffer;
+ }
+
+ /* Fill part of audio converter buffer by converting input to user format,
+ * calling user callback, then converting output to native format. */
+ if( PaConvert_Process( past, inputBuffer, outputBuffer ))
+ {
+ past->past_StopSoon = 1;
+ }
+ }
+ return err;
+}
+
+/*****************************************************************************
+** This is the proc that supplies the data to the AudioConverterFillBuffer call
+*/
+static OSStatus PaOSX_OutputConverterCallbackProc (AudioConverterRef inAudioConverter,
+ UInt32* outDataSize,
+ void** outData,
+ void* inUserData)
+{
+ internalPortAudioStream *past = (internalPortAudioStream *) inUserData;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ *outData = pahsc->output.converterBuffer;
+ *outDataSize = pahsc->output.bytesPerUserNativeBuffer;
+
+ return PaOSX_LoadAndProcess ( past, pahsc->input.converterBuffer, pahsc->output.converterBuffer );
+}
+
+/**********************************************************************
+** If data available, write it to the Ring Buffer so we can
+** pull it from the other side.
+*/
+static OSStatus PaOSX_WriteInputRingBuffer( internalPortAudioStream *past,
+ const AudioBufferList* inInputData )
+{
+ int numBytes = 0;
+ int currentInterleavedChannelIndex;
+ int numFramesInInputBuffer;
+ int numInterleavedChannels;
+ int numChannelsRemaining;
+ int i;
+ long writeRoom;
+ char *inputNativeBufferfPtr = NULL;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ /* Do we need to interleave the buffers first? */
+ if( past->past_NumInputChannels != inInputData->mBuffers[0].mNumberChannels )
+ {
+
+ numFramesInInputBuffer = inInputData->mBuffers[0].mDataByteSize / (sizeof(float) * inInputData->mBuffers[0].mNumberChannels);
+
+ numBytes = numFramesInInputBuffer * sizeof(float) * past->past_NumInputChannels;
+
+ /* Allocate temporary buffer if needed. */
+ if ( (pahsc->input.streamInterleavingBuffer != NULL) &&
+ (pahsc->input.streamInterleavingBufferLen < numBytes) )
+ {
+ PaHost_FreeFastMemory( pahsc->input.streamInterleavingBuffer, pahsc->input.streamInterleavingBufferLen );
+ pahsc->input.streamInterleavingBuffer = NULL;
+ }
+ if ( pahsc->input.streamInterleavingBuffer == NULL )
+ {
+ pahsc->input.streamInterleavingBufferLen = numBytes;
+ pahsc->input.streamInterleavingBuffer = (float *)PaHost_AllocateFastMemory( pahsc->input.streamInterleavingBufferLen );
+ }
+
+ /* Perform interleaving by writing to temp buffer. */
+ currentInterleavedChannelIndex = 0;
+ numInterleavedChannels = past->past_NumInputChannels;
+ numChannelsRemaining = numInterleavedChannels;
+
+ for( i=0; i<inInputData->mNumberBuffers; i++ )
+ {
+ int j;
+ int numBufChannels = inInputData->mBuffers[i].mNumberChannels;
+ /* Don't use more than we need or more than we have. */
+ int numChannelsUsedInThisBuffer = (numChannelsRemaining < numBufChannels ) ?
+ numChannelsRemaining : numBufChannels;
+ for( j=0; j<numChannelsUsedInThisBuffer; j++ )
+ {
+ int k;
+ /* Move one channel from CoreAudio buffer to interleaved buffer. */
+ for( k=0; k<numFramesInInputBuffer; k++ )
+ {
+ pahsc->input.streamInterleavingBuffer[ k*numInterleavedChannels + currentInterleavedChannelIndex ] =
+ ((float *)inInputData->mBuffers[i].mData)[ k*numBufChannels + j ];
+ }
+ currentInterleavedChannelIndex++;
+ }
+ numChannelsRemaining -= numChannelsUsedInThisBuffer;
+ if( numChannelsRemaining <= 0 ) break;
+ }
+
+ inputNativeBufferfPtr = (char *)pahsc->input.streamInterleavingBuffer;
+ }
+ else
+ {
+ inputNativeBufferfPtr = (char*)inInputData->mBuffers[0].mData;
+ numBytes += inInputData->mBuffers[0].mDataByteSize;
+ }
+
+ writeRoom = RingBuffer_GetWriteAvailable( &pahsc->ringBuffer );
+
+ if( numBytes <= writeRoom )
+ {
+ RingBuffer_Write( &pahsc->ringBuffer, inputNativeBufferfPtr, numBytes );
+ DBUGBACK(("PaOSX_WriteInputRingBuffer: wrote %ld bytes to FIFO.\n", inInputData->mBuffers[0].mDataByteSize));
+ } // FIXME else drop samples on floor, remember overflow???
+
+ return noErr;
+}
+
+/**********************************************************************
+** Use any available input buffers by writing to RingBuffer.
+** Process input if PA_MODE_INPUT_ONLY.
+*/
+static OSStatus PaOSX_HandleInput( internalPortAudioStream *past,
+ const AudioBufferList* inInputData )
+{
+ OSStatus err = noErr;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ if( inInputData->mNumberBuffers > 0 )
+ {
+ /* Write to FIFO here if we are only using this callback. */
+ if( (pahsc->mode == PA_MODE_INPUT_ONLY) || (pahsc->mode == PA_MODE_IO_ONE_DEVICE) )
+ {
+ err = PaOSX_WriteInputRingBuffer( past, inInputData );
+ if( err != noErr ) goto error;
+ }
+ }
+
+ if( pahsc->mode == PA_MODE_INPUT_ONLY )
+ {
+ /* Generate user buffers as long as we have a half full input FIFO. */
+ long halfSize = pahsc->ringBuffer.bufferSize / 2;
+ while( (RingBuffer_GetReadAvailable( &pahsc->ringBuffer ) >= halfSize) &&
+ (past->past_StopSoon == 0) )
+ {
+ err = PaOSX_LoadAndProcess ( past, NULL, NULL );
+ if( err != noErr ) goto error;
+ }
+ }
+
+error:
+ return err;
+}
+
+/**********************************************************************
+** Fill any available output buffers.
+*/
+static OSStatus PaOSX_HandleOutput( internalPortAudioStream *past,
+ AudioBufferList* outOutputData )
+{
+ OSStatus err = noErr;
+ void *outputNativeBufferfPtr = NULL;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ UInt32 numBytes = 0;
+ int numChannelsRemaining;
+ Boolean deinterleavingNeeded;
+ int numFramesInOutputBuffer;
+
+ deinterleavingNeeded = past->past_NumOutputChannels != outOutputData->mBuffers[0].mNumberChannels;
+
+ numFramesInOutputBuffer = outOutputData->mBuffers[0].mDataByteSize / (sizeof(float) * outOutputData->mBuffers[0].mNumberChannels);
+
+ if( pahsc->mode != PA_MODE_INPUT_ONLY )
+ {
+ /* If we are using output, then we need an empty output buffer. */
+ if( outOutputData->mNumberBuffers > 0 )
+ {
+
+ /* If we have multiple CoreAudio buffers, then we will need to deinterleave after conversion. */
+ if( deinterleavingNeeded )
+ {
+ numBytes = numFramesInOutputBuffer * sizeof(float) * past->past_NumOutputChannels;
+
+ /* Free old buffer if we are allocating new one. */
+ if ( (pahsc->output.streamInterleavingBuffer != NULL) &&
+ (pahsc->output.streamInterleavingBufferLen < numBytes) )
+ {
+ PaHost_FreeFastMemory( pahsc->output.streamInterleavingBuffer, pahsc->output.streamInterleavingBufferLen );
+ pahsc->output.streamInterleavingBuffer = NULL;
+ }
+ /* Allocate interleaving buffer if needed. */
+ if ( pahsc->output.streamInterleavingBuffer == NULL )
+ {
+ pahsc->output.streamInterleavingBufferLen = numBytes;
+ pahsc->output.streamInterleavingBuffer = (float *)PaHost_AllocateFastMemory( pahsc->output.streamInterleavingBufferLen );
+ }
+
+ outputNativeBufferfPtr = (void*)pahsc->output.streamInterleavingBuffer;
+ }
+ else
+ {
+ numBytes = outOutputData->mBuffers[0].mDataByteSize;
+ outputNativeBufferfPtr = (void*)outOutputData->mBuffers[0].mData;
+ }
+
+ /* Pull code from PA user through converter. */
+ err = AudioConverterFillBuffer(
+ pahsc->output.converter,
+ PaOSX_OutputConverterCallbackProc,
+ past,
+ &numBytes,
+ outputNativeBufferfPtr);
+ if( err != noErr )
+ {
+ PRINT_ERR("PaOSX_HandleOutput: AudioConverterFillBuffer failed", err);
+ goto error;
+ }
+
+ /* Deinterleave data from PortAudio and write to multiple CoreAudio buffers. */
+ if( deinterleavingNeeded )
+ {
+ int numInterleavedChannels = past->past_NumOutputChannels;
+ int i, currentInterleavedChannelIndex = 0;
+ numChannelsRemaining = numInterleavedChannels;
+
+ for( i=0; i<outOutputData->mNumberBuffers; i++ )
+ {
+ int numBufChannels = outOutputData->mBuffers[i].mNumberChannels;
+ int j;
+ /* Don't use more than we need or more than we have. */
+ int numChannelsUsedInThisBuffer = (numChannelsRemaining < numBufChannels ) ?
+ numChannelsRemaining : numBufChannels;
+
+ for( j=0; j<numChannelsUsedInThisBuffer; j++ )
+ {
+ int k;
+ /* Move one channel from interleaved buffer to CoreAudio buffer. */
+ for( k=0; k<numFramesInOutputBuffer; k++ )
+ {
+ ((float *)outOutputData->mBuffers[i].mData)[ k*numBufChannels + j ] =
+ pahsc->output.streamInterleavingBuffer[ k*numInterleavedChannels + currentInterleavedChannelIndex ];
+ }
+ currentInterleavedChannelIndex++;
+ }
+
+ numChannelsRemaining -= numChannelsUsedInThisBuffer;
+ if( numChannelsRemaining <= 0 ) break;
+ }
+ }
+ }
+ }
+
+error:
+ return err;
+}
+
+/******************************************************************
+ * This callback is used when two separate devices are used for input and output.
+ * This often happens when using USB devices which present as two devices: input and output.
+ * It just writes its data to a FIFO so that it can be read by the main callback
+ * proc PaOSX_CoreAudioIOCallback().
+ */
+static OSStatus PaOSX_CoreAudioInputCallback (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
+ const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime,
+ AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime,
+ void* contextPtr)
+{
+ OSStatus err = noErr;
+ internalPortAudioStream *past = (internalPortAudioStream *) contextPtr;
+ PaHostSoundControl *pahsc;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ /* If there is a FIFO for input then write to it. */
+ if( pahsc->ringBufferData != NULL )
+ {
+ err = PaOSX_WriteInputRingBuffer( past, inInputData );
+ if( err != noErr ) goto error;
+ }
+error:
+ return err;
+}
+
+/******************************************************************
+ * This is the primary callback for CoreAudio.
+ * It can handle input and/or output for a single device.
+ * It takes input from CoreAudio, converts it and passes it to the
+ * PortAudio user callback. Then takes the PA results and passes it
+ * back to CoreAudio.
+ */
+static OSStatus PaOSX_CoreAudioIOCallback (AudioDeviceID inDevice, const AudioTimeStamp* inNow,
+ const AudioBufferList* inInputData, const AudioTimeStamp* inInputTime,
+ AudioBufferList* outOutputData, const AudioTimeStamp* inOutputTime,
+ void* contextPtr)
+{
+ OSStatus err = noErr;
+ internalPortAudioStream *past;
+ PaHostSoundControl *pahsc;
+ past = (internalPortAudioStream *) contextPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ /* Has someone asked us to abort by calling Pa_AbortStream()? */
+ if( past->past_StopNow )
+ {
+ past->past_IsActive = 0; /* Will cause thread to return. */
+ }
+ /* Has someone asked us to stop by calling Pa_StopStream()
+ * OR has a user callback returned '1' to indicate finished.
+ */
+ else if( past->past_StopSoon )
+ {
+ // FIXME - Pretend all done. Should wait for audio to play out but CoreAudio latency very low.
+ past->past_IsActive = 0; /* Will cause thread to return. */
+ }
+ else
+ {
+ /* use time stamp from CoreAudio if valid */
+ if( inOutputTime->mFlags & kAudioTimeStampSampleTimeValid)
+ {
+ past->past_FrameCount = inOutputTime->mSampleTime;
+ }
+ else if( inInputTime->mFlags & kAudioTimeStampSampleTimeValid)
+ {
+ past->past_FrameCount = inInputTime->mSampleTime;
+ }
+
+ /* Measure CPU load. */
+ Pa_StartUsageCalculation( past );
+ past->past_NumCallbacks += 1;
+
+ /* Process full input buffer. */
+ err = PaOSX_HandleInput( past, inInputData );
+ if( err != 0 ) goto error;
+
+ /* Fill up empty output buffers. */
+ err = PaOSX_HandleOutput( past, outOutputData );
+ if( err != 0 ) goto error;
+
+ Pa_EndUsageCalculation( past );
+ }
+
+ if( err != 0 ) DBUG(("PaOSX_CoreAudioIOCallback: returns %ld.\n", err ));
+
+error:
+ return err;
+}
+
+/*******************************************************************/
+/** Attempt to set device sample rate.
+ * This is not critical because we use an AudioConverter but we may
+ * get better fidelity if we can avoid resampling.
+ *
+ * Only set format once because some devices take time to settle.
+ * Return flag indicating whether format changed so we know whether to wait
+ * for DevicePropertyListener to get called.
+ *
+ * @return negative error, zero if no change, or one if changed successfully.
+ */
+static PaError PaOSX_SetFormat( AudioDeviceID devID, Boolean isInput,
+ double desiredRate, int desiredNumChannels )
+{
+ AudioStreamBasicDescription formatDesc;
+ PaError result = 0;
+ OSStatus err;
+ UInt32 dataSize;
+ Float64 originalRate;
+ int originalChannels;
+
+ /* Get current device format. This is critical because if we pass
+ * zeros for unspecified fields then the iMic device gets switched to a 16 bit
+ * integer format!!! I don't know if this is a Mac bug or not. But it only
+ * started happening when I upgraded from OS X V10.1 to V10.2 (Jaguar).
+ */
+ dataSize = sizeof(formatDesc);
+ err = AudioDeviceGetProperty( devID, 0, isInput,
+ kAudioDevicePropertyStreamFormat, &dataSize, &formatDesc);
+ if( err != noErr )
+ {
+ PRINT_ERR("PaOSX_SetFormat: Could not get format.", err);
+ sSavedHostError = err;
+ return paHostError;
+ }
+
+ originalRate = formatDesc.mSampleRate;
+ originalChannels = formatDesc.mChannelsPerFrame;
+
+ // Is it already set to the correct format?
+ if( (originalRate != desiredRate) || (originalChannels != desiredNumChannels) )
+ {
+ DBUG(("PaOSX_SetFormat: try to change sample rate to %f.\n", desiredRate ));
+ DBUG(("PaOSX_SetFormat: try to set number of channels to %d\n", desiredNumChannels));
+
+ formatDesc.mSampleRate = desiredRate;
+ formatDesc.mChannelsPerFrame = desiredNumChannels;
+ formatDesc.mBytesPerFrame = formatDesc.mChannelsPerFrame * sizeof(float);
+ formatDesc.mBytesPerPacket = formatDesc.mBytesPerFrame * formatDesc.mFramesPerPacket;
+
+ err = AudioDeviceSetProperty( devID, 0, 0,
+ isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
+ if (err != noErr)
+ {
+ /* Could not set to desired rate so query for closest match. */
+ dataSize = sizeof(formatDesc);
+ err = AudioDeviceGetProperty( devID, 0,
+ isInput, kAudioDevicePropertyStreamFormatMatch, &dataSize, &formatDesc);
+
+ DBUG(("PaOSX_SetFormat: closest rate is %f.\n", formatDesc.mSampleRate ));
+ DBUG(("PaOSX_SetFormat: closest numChannels is %d.\n", (int)formatDesc.mChannelsPerFrame ));
+ // Set to closest if different from original.
+ if( (err == noErr) &&
+ ((originalRate != formatDesc.mSampleRate) ||
+ (originalChannels != formatDesc.mChannelsPerFrame)) )
+ {
+ err = AudioDeviceSetProperty( devID, 0, 0,
+ isInput, kAudioDevicePropertyStreamFormat, sizeof(formatDesc), &formatDesc);
+ if( err == noErr ) result = 1;
+ }
+ }
+ else result = 1;
+ }
+
+ return result;
+}
+
+/*******************************************************************
+ * Check volume level of device. If below threshold, then set to newLevel.
+ * Using volume instead of decibels because decibel range varies by device.
+ */
+static void PaOSX_FixVolumeScalars( AudioDeviceID devID, Boolean isInput,
+ int numChannels, double threshold, double newLevel )
+{
+ OSStatus err = noErr;
+ UInt32 dataSize;
+ int iChannel;
+
+/* The master channel is 0. Left and right are channels 1 and 2. */
+/* Fix volume. */
+ for( iChannel = 0; iChannel<=numChannels; iChannel++ )
+ {
+ Float32 fdata32;
+ dataSize = sizeof( fdata32 );
+ err = AudioDeviceGetProperty( devID, iChannel, isInput,
+ kAudioDevicePropertyVolumeScalar, &dataSize, &fdata32 );
+ if( err == noErr )
+ {
+ DBUG(("kAudioDevicePropertyVolumeScalar for channel %d = %f\n", iChannel, fdata32));
+ if( fdata32 <= (Float32) threshold )
+ {
+ dataSize = sizeof( fdata32 );
+ fdata32 = (Float32) newLevel;
+ err = AudioDeviceSetProperty( devID, 0, iChannel, isInput,
+ kAudioDevicePropertyVolumeScalar, dataSize, &fdata32 );
+ if( err != noErr )
+ {
+ PRINT(("Warning: audio volume is very low and could not be turned up.\n"));
+ }
+ else
+ {
+ PRINT(("Volume for audio channel %d was <= %4.2f so set to %4.2f by PortAudio!\n",
+ iChannel, threshold, newLevel ));
+ }
+ }
+ }
+ }
+/* Unmute if muted. */
+ for( iChannel = 0; iChannel<=numChannels; iChannel++ )
+ {
+ UInt32 uidata32;
+ dataSize = sizeof( uidata32 );
+ err = AudioDeviceGetProperty( devID, iChannel, isInput,
+ kAudioDevicePropertyMute, &dataSize, &uidata32 );
+ if( err == noErr )
+ {
+ DBUG(("uidata32 for channel %d = %ld\n", iChannel, uidata32));
+ if( uidata32 == 1 ) // muted?
+ {
+ dataSize = sizeof( uidata32 );
+ uidata32 = 0; // unmute
+ err = AudioDeviceSetProperty( devID, 0, iChannel, isInput,
+ kAudioDevicePropertyMute, dataSize, &uidata32 );
+ if( err != noErr )
+ {
+ PRINT(("Warning: audio is muted and could not be unmuted!\n"));
+ }
+ else
+ {
+ PRINT(("Audio channel %d was unmuted by PortAudio!\n", iChannel ));
+ }
+ }
+ }
+ }
+
+}
+
+#if 0
+static void PaOSX_DumpDeviceInfo( AudioDeviceID devID, Boolean isInput )
+{
+ OSStatus err = noErr;
+ UInt32 dataSize;
+ UInt32 uidata32;
+ Float32 fdata32;
+ AudioValueRange audioRange;
+
+ dataSize = sizeof( uidata32 );
+ err = AudioDeviceGetProperty( devID, 0, isInput,
+ kAudioDevicePropertyLatency, &dataSize, &uidata32 );
+ if( err != noErr )
+ {
+ PRINT_ERR("Error reading kAudioDevicePropertyLatency", err);
+ return;
+ }
+ PRINT(("kAudioDevicePropertyLatency = %d\n", (int)uidata32 ));
+
+ dataSize = sizeof( fdata32 );
+ err = AudioDeviceGetProperty( devID, 1, isInput,
+ kAudioDevicePropertyVolumeScalar, &dataSize, &fdata32 );
+ if( err != noErr )
+ {
+ PRINT_ERR("Error reading kAudioDevicePropertyVolumeScalar", err);
+ return;
+ }
+ PRINT(("kAudioDevicePropertyVolumeScalar = %f\n", fdata32 ));
+
+ dataSize = sizeof( uidata32 );
+ err = AudioDeviceGetProperty( devID, 0, isInput,
+ kAudioDevicePropertyBufferSize, &dataSize, &uidata32 );
+ if( err != noErr )
+ {
+ PRINT_ERR("Error reading buffer size", err);
+ return;
+ }
+ PRINT(("kAudioDevicePropertyBufferSize = %d bytes\n", (int)uidata32 ));
+
+ dataSize = sizeof( audioRange );
+ err = AudioDeviceGetProperty( devID, 0, isInput,
+ kAudioDevicePropertyBufferSizeRange, &dataSize, &audioRange );
+ if( err != noErr )
+ {
+ PRINT_ERR("Error reading buffer size range", err);
+ return;
+ }
+ PRINT(("kAudioDevicePropertyBufferSizeRange = %g to %g bytes\n", audioRange.mMinimum, audioRange.mMaximum ));
+
+ dataSize = sizeof( uidata32 );
+ err = AudioDeviceGetProperty( devID, 0, isInput,
+ kAudioDevicePropertyBufferFrameSize, &dataSize, &uidata32 );
+ if( err != noErr )
+ {
+ PRINT_ERR("Error reading buffer size", err);
+ return;
+ }
+ PRINT(("kAudioDevicePropertyBufferFrameSize = %d frames\n", (int)uidata32 ));
+
+ dataSize = sizeof( audioRange );
+ err = AudioDeviceGetProperty( devID, 0, isInput,
+ kAudioDevicePropertyBufferFrameSizeRange, &dataSize, &audioRange );
+ if( err != noErr )
+ {
+ PRINT_ERR("Error reading buffer size range", err);
+ return;
+ }
+ PRINT(("kAudioDevicePropertyBufferFrameSizeRange = %g to %g frames\n", audioRange.mMinimum, audioRange.mMaximum ));
+
+ return;
+}
+#endif
+
+/*******************************************************************/
+static OSStatus PAOSX_DevicePropertyListener (AudioDeviceID inDevice,
+ UInt32 inChannel,
+ Boolean isInput,
+ AudioDevicePropertyID inPropertyID,
+ void* inClientData)
+{
+ PaHostSoundControl *pahsc;
+ internalPortAudioStream *past;
+ UInt32 dataSize;
+ OSStatus err = noErr;
+ AudioStreamBasicDescription userStreamFormat, hardwareStreamFormat;
+ Boolean updateInverseMicros;
+ Boolean updateConverter;
+
+ past = (internalPortAudioStream *) inClientData;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ DBUG(("PAOSX_DevicePropertyListener: called with propertyID = 0x%0X\n", (unsigned int) inPropertyID ));
+
+ updateInverseMicros = (inDevice == pahsc->primaryDeviceID) &&
+ ((inPropertyID == kAudioDevicePropertyStreamFormat) ||
+ (inPropertyID == kAudioDevicePropertyBufferFrameSize));
+
+ updateConverter = (inPropertyID == kAudioDevicePropertyStreamFormat);
+
+ // Sample rate needed for both.
+ if( updateConverter || updateInverseMicros )
+ {
+
+ /* Get target device format */
+ dataSize = sizeof(hardwareStreamFormat);
+ err = AudioDeviceGetProperty(inDevice, 0, isInput,
+ kAudioDevicePropertyStreamFormat, &dataSize, &hardwareStreamFormat);
+ if( err != noErr )
+ {
+ PRINT_ERR("PAOSX_DevicePropertyListener: Could not get device format", err);
+ sSavedHostError = err;
+ goto error;
+ }
+ }
+
+ if( updateConverter )
+ {
+ DBUG(("PAOSX_DevicePropertyListener: HW rate = %f\n", hardwareStreamFormat.mSampleRate ));
+ DBUG(("PAOSX_DevicePropertyListener: user rate = %f\n", past->past_SampleRate ));
+ DBUG(("PAOSX_DevicePropertyListener: HW mChannelsPerFrame = %d\n", (int)hardwareStreamFormat.mChannelsPerFrame ));
+
+ /* Set source user format. */
+ userStreamFormat = hardwareStreamFormat;
+ userStreamFormat.mSampleRate = past->past_SampleRate; // sample rate of the user synthesis code
+ userStreamFormat.mChannelsPerFrame = (isInput) ? past->past_NumInputChannels : past->past_NumOutputChannels; // the number of channels in each frame
+ DBUG(("PAOSX_DevicePropertyListener: User mChannelsPerFrame = %d\n", (int)userStreamFormat.mChannelsPerFrame ));
+
+ userStreamFormat.mBytesPerFrame = userStreamFormat.mChannelsPerFrame * sizeof(float);
+ userStreamFormat.mBytesPerPacket = userStreamFormat.mBytesPerFrame * userStreamFormat.mFramesPerPacket;
+
+ /* Don't use AudioConverter for merging channels. */
+ if( hardwareStreamFormat.mChannelsPerFrame > userStreamFormat.mChannelsPerFrame )
+ {
+ hardwareStreamFormat.mChannelsPerFrame = userStreamFormat.mChannelsPerFrame;
+ hardwareStreamFormat.mBytesPerFrame = userStreamFormat.mBytesPerFrame;
+ hardwareStreamFormat.mBytesPerPacket = userStreamFormat.mBytesPerPacket;
+ }
+
+ if( isInput )
+ {
+ if( pahsc->input.converter != NULL )
+ {
+ verify_noerr(AudioConverterDispose (pahsc->input.converter));
+ }
+
+ // Convert from hardware format to user format.
+ err = AudioConverterNew (
+ &hardwareStreamFormat,
+ &userStreamFormat,
+ &pahsc->input.converter );
+ if( err != noErr )
+ {
+ PRINT_ERR("Could not create input format converter", err);
+ sSavedHostError = err;
+ goto error;
+ }
+ }
+ else
+ {
+ if( pahsc->output.converter != NULL )
+ {
+ verify_noerr(AudioConverterDispose (pahsc->output.converter));
+ }
+
+ // Convert from user format to hardware format.
+ err = AudioConverterNew (
+ &userStreamFormat,
+ &hardwareStreamFormat,
+ &pahsc->output.converter );
+ if( err != noErr )
+ {
+ PRINT_ERR("Could not create output format converter", err);
+ sSavedHostError = err;
+ goto error;
+ }
+ }
+ }
+
+ if( updateInverseMicros )
+ {
+ // Update coefficient used to calculate CPU Load based on sampleRate and bufferSize.
+ UInt32 ioBufferSize;
+ dataSize = sizeof(ioBufferSize);
+ err = AudioDeviceGetProperty( inDevice, 0, isInput,
+ kAudioDevicePropertyBufferFrameSize, &dataSize,
+ &ioBufferSize);
+ if( err == noErr )
+ {
+ pahsc->inverseMicrosPerHostBuffer = hardwareStreamFormat.mSampleRate /
+ (1000000.0 * ioBufferSize);
+ }
+ }
+
+error:
+ pahsc->formatListenerCalled = true;
+ return err;
+}
+
+/* Allocate FIFO between Device callback and Converter callback so that device can push data
+* and converter can pull data.
+*/
+static PaError PaOSX_CreateInputRingBuffer( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ OSStatus err = noErr;
+ UInt32 dataSize;
+ double sampleRateRatio;
+ long numBytes;
+ UInt32 framesPerHostBuffer;
+ UInt32 bytesForDevice;
+ UInt32 bytesForUser;
+ AudioStreamBasicDescription formatDesc;
+
+ dataSize = sizeof(formatDesc);
+ err = AudioDeviceGetProperty( pahsc->input.audioDeviceID, 0, IS_INPUT,
+ kAudioDevicePropertyStreamFormat, &dataSize, &formatDesc);
+ if( err != noErr )
+ {
+ PRINT_ERR("PaOSX_CreateInputRingBuffer: Could not get I/O buffer size.\n", err);
+ sSavedHostError = err;
+ return paHostError;
+ }
+
+ // If device is delivering audio faster than being consumed then buffer must be bigger.
+ sampleRateRatio = formatDesc.mSampleRate / past->past_SampleRate;
+
+ // Get size of CoreAudio IO buffers.
+ dataSize = sizeof(framesPerHostBuffer);
+ err = AudioDeviceGetProperty( pahsc->input.audioDeviceID, 0, IS_INPUT,
+ kAudioDevicePropertyBufferFrameSize, &dataSize,
+ &framesPerHostBuffer);
+ if( err != noErr )
+ {
+ PRINT_ERR("PaOSX_CreateInputRingBuffer: Could not get I/O buffer size.\n", err);
+ sSavedHostError = err;
+ return paHostError;
+ }
+
+ bytesForDevice = framesPerHostBuffer * formatDesc.mChannelsPerFrame * sizeof(Float32) * 2;
+
+ bytesForUser = past->past_FramesPerUserBuffer * past->past_NumInputChannels *
+ sizeof(Float32) * 3 * sampleRateRatio;
+
+ // Ring buffer should be large enough to consume audio input from device,
+ // and to deliver a complete user buffer.
+ numBytes = (bytesForDevice > bytesForUser) ? bytesForDevice : bytesForUser;
+
+ numBytes = RoundUpToNextPowerOf2( numBytes );
+
+ DBUG(("PaOSX_CreateInputRingBuffer: FIFO numBytes = %ld\n", numBytes));
+ pahsc->ringBufferData = PaHost_AllocateFastMemory( numBytes );
+ if( pahsc->ringBufferData == NULL )
+ {
+ return paInsufficientMemory;
+ }
+ RingBuffer_Init( &pahsc->ringBuffer, numBytes, pahsc->ringBufferData );
+ // make it look full at beginning
+ RingBuffer_AdvanceWriteIndex( &pahsc->ringBuffer, numBytes );
+
+ return paNoError;
+}
+
+/******************************************************************
+ * Try to set the I/O bufferSize of the device.
+ * Scale the size by the ratio of the sample rates so that the converter will have
+ * enough data to operate on.
+ */
+static OSStatus PaOSX_SetDeviceBufferSize( AudioDeviceID devID, Boolean isInput, int framesPerUserBuffer, Float64 sampleRateRatio )
+{
+ UInt32 dataSize;
+ UInt32 ioBufferSize;
+ int scaler;
+
+ scaler = (int) sampleRateRatio;
+ if( sampleRateRatio > (Float64) scaler ) scaler += 1;
+ DBUG(("PaOSX_SetDeviceBufferSize: buffer size scaler = %d\n", scaler ));
+ ioBufferSize = framesPerUserBuffer * scaler;
+
+ // Limit buffer size to reasonable value.
+ if( ioBufferSize < 128 ) ioBufferSize = 128;
+
+ dataSize = sizeof(ioBufferSize);
+ return AudioDeviceSetProperty( devID, 0, 0, isInput,
+ kAudioDevicePropertyBufferFrameSize, dataSize,
+ &ioBufferSize);
+}
+
+
+/*******************************************************************/
+static PaError PaOSX_OpenCommonDevice( internalPortAudioStream *past,
+ PaHostInOut *inOut, Boolean isInput )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ PaError result = paNoError;
+ OSStatus err = noErr;
+ Float64 deviceRate;
+
+ PaOSX_FixVolumeScalars( inOut->audioDeviceID, isInput,
+ inOut->numChannels, 0.1, 0.9 );
+
+ // The HW device format changes are asynchronous.
+ // So we don't know when or if the PAOSX_DevicePropertyListener() will
+ // get called. To be safe, call the listener now to forcibly create the converter.
+ if( inOut->converter == NULL )
+ {
+ err = PAOSX_DevicePropertyListener (inOut->audioDeviceID,
+ 0, isInput, kAudioDevicePropertyStreamFormat, past);
+ if (err != kAudioHardwareNoError)
+ {
+ PRINT_ERR("PaOSX_OpenCommonDevice: PAOSX_DevicePropertyListener failed.\n", err);
+ sSavedHostError = err;
+ return paHostError;
+ }
+ }
+
+ // Add listener for when format changed by other apps.
+ DBUG(("PaOSX_OpenCommonDevice: call AudioDeviceAddPropertyListener()\n" ));
+ err = AudioDeviceAddPropertyListener( inOut->audioDeviceID, 0, isInput,
+ kAudioDevicePropertyStreamFormat,
+ (AudioDevicePropertyListenerProc) PAOSX_DevicePropertyListener, past );
+ if (err != noErr)
+ {
+ return -1; // FIXME
+ }
+
+ // Only change format if current HW format is different.
+ // Don't bother to check result because we are going to use an AudioConverter anyway.
+ pahsc->formatListenerCalled = false;
+ result = PaOSX_SetFormat( inOut->audioDeviceID, isInput, past->past_SampleRate, inOut->numChannels );
+ // Synchronize with device because format changes put some devices into unusable mode.
+ if( result > 0 )
+ {
+ const int sleepDurMsec = 50;
+ int spinCount = MIN_TIMEOUT_MSEC / sleepDurMsec;
+ while( !pahsc->formatListenerCalled && (spinCount > 0) )
+ {
+ Pa_Sleep( sleepDurMsec ); // FIXME - use a semaphore or signal
+ spinCount--;
+ }
+ if( !pahsc->formatListenerCalled )
+ {
+ PRINT(("PaOSX_OpenCommonDevice: timed out waiting for device format to settle.\n"));
+ }
+ result = 0;
+ }
+
+#if SET_DEVICE_BUFFER_SIZE
+ // Try to set the I/O bufferSize of the device.
+ {
+ Float64 ratio;
+ deviceRate = PaOSX_GetDeviceSampleRate( inOut->audioDeviceID, isInput );
+ if( deviceRate <= 0.0 ) deviceRate = past->past_SampleRate;
+ ratio = deviceRate / past->past_SampleRate ;
+ err = PaOSX_SetDeviceBufferSize( inOut->audioDeviceID, isInput,
+ past->past_FramesPerUserBuffer, ratio );
+ if( err != noErr )
+ {
+ DBUG(("PaOSX_OpenCommonDevice: Could not set I/O buffer size.\n"));
+ }
+ }
+#endif
+
+ /* Allocate an input buffer because we need it between the user callback and the converter. */
+ inOut->converterBuffer = PaHost_AllocateFastMemory( inOut->bytesPerUserNativeBuffer );
+ if( inOut->converterBuffer == NULL )
+ {
+ return paInsufficientMemory;
+ }
+
+ return result;
+}
+
+/*******************************************************************/
+static PaError PaOSX_OpenInputDevice( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ const PaHostDeviceInfo *hostDeviceInfo;
+ PaError result = paNoError;
+
+ DBUG(("PaOSX_OpenInputDevice: -------------\n"));
+
+ if( (past->past_InputDeviceID < LOWEST_INPUT_DEVID) ||
+ (past->past_InputDeviceID > HIGHEST_INPUT_DEVID) )
+ {
+ return paInvalidDeviceId;
+ }
+ hostDeviceInfo = &sDeviceInfos[past->past_InputDeviceID];
+
+ if( past->past_NumInputChannels > hostDeviceInfo->paInfo.maxInputChannels )
+ {
+ return paInvalidChannelCount; /* Too many channels! */
+ }
+ pahsc->input.numChannels = past->past_NumInputChannels;
+
+ // setup PA conversion procedure
+ result = PaConvert_SetupInput( past, paFloat32 );
+
+ result = PaOSX_OpenCommonDevice( past, &pahsc->input, IS_INPUT );
+ if( result != paNoError ) goto error;
+
+ // Allocate a ring buffer so we can push in data from device, and pull through AudioConverter.
+ result = PaOSX_CreateInputRingBuffer( past );
+ if( result != paNoError ) goto error;
+
+error:
+ return result;
+}
+
+/*******************************************************************/
+static PaError PaOSX_OpenOutputDevice( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ const PaHostDeviceInfo *hostDeviceInfo;
+ PaError result = paNoError;
+
+ DBUG(("PaOSX_OpenOutputDevice: -------------\n"));
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ // Validate DeviceID
+ DBUG(("PaOSX_OpenOutputDevice: deviceID = 0x%x\n", past->past_OutputDeviceID));
+ if( (past->past_OutputDeviceID < LOWEST_OUTPUT_DEVID) ||
+ (past->past_OutputDeviceID > HIGHEST_OUTPUT_DEVID) )
+ {
+ return paInvalidDeviceId;
+ }
+ hostDeviceInfo = &sDeviceInfos[past->past_OutputDeviceID];
+
+ // Validate number of channels.
+ if( past->past_NumOutputChannels > hostDeviceInfo->paInfo.maxOutputChannels )
+ {
+ return paInvalidChannelCount; /* Too many channels! */
+ }
+ pahsc->output.numChannels = past->past_NumOutputChannels;
+
+ // setup conversion procedure
+ result = PaConvert_SetupOutput( past, paFloat32 );
+ if( result != paNoError ) goto error;
+
+ result = PaOSX_OpenCommonDevice( past, &pahsc->output, IS_OUTPUT );
+ if( result != paNoError ) goto error;
+
+error:
+ return result;
+}
+
+/*******************************************************************
+* Determine how many User Buffers we can put into our CoreAudio stream buffer.
+* Uses:
+* past->past_FramesPerUserBuffer, etc.
+* Sets:
+* past->past_NumUserBuffers
+* pahsc->input.bytesPerUserNativeBuffer
+* pahsc->output.bytesPerUserNativeBuffer
+*/
+static void PaOSX_CalcHostBufferSize( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc = ( PaHostSoundControl *)past->past_DeviceData;
+
+ // Determine number of user buffers based strictly on minimum reasonable buffer size.
+ // We ignore the Pa_OpenStream numBuffer parameter because CoreAudio has a big
+ // mix buffer and handles latency automatically.
+ past->past_NumUserBuffers = Pa_GetMinNumBuffers( past->past_FramesPerUserBuffer, past->past_SampleRate );
+
+ // calculate buffer sizes in bytes
+ pahsc->input.bytesPerUserNativeBuffer = past->past_FramesPerUserBuffer *
+ Pa_GetSampleSize(paFloat32) * past->past_NumInputChannels;
+ pahsc->output.bytesPerUserNativeBuffer = past->past_FramesPerUserBuffer *
+ Pa_GetSampleSize(paFloat32) * past->past_NumOutputChannels;
+
+ DBUG(("PaOSX_CalcNumHostBuffers: past_NumUserBuffers = %ld\n", past->past_NumUserBuffers ));
+ DBUG(("PaOSX_CalcNumHostBuffers: input.bytesPerUserNativeBuffer = %d\n", pahsc->input.bytesPerUserNativeBuffer ));
+ DBUG(("PaOSX_CalcNumHostBuffers: output.bytesPerUserNativeBuffer = %d\n", pahsc->output.bytesPerUserNativeBuffer ));
+}
+
+/*****************************************************************************/
+/************** Internal Host API ********************************************/
+/*****************************************************************************/
+PaError PaHost_OpenStream( internalPortAudioStream *past )
+{
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc;
+ Boolean useInput;
+ Boolean useOutput;
+
+ assert( past->past_Magic == PA_MAGIC );
+
+ /* Allocate and initialize host data. */
+ pahsc = (PaHostSoundControl *) malloc(sizeof(PaHostSoundControl));
+ if( pahsc == NULL )
+ {
+ result = paInsufficientMemory;
+ goto error;
+ }
+ memset( pahsc, 0, sizeof(PaHostSoundControl) );
+ past->past_DeviceData = (void *) pahsc;
+ pahsc->primaryDeviceID = kAudioDeviceUnknown;
+ pahsc->input.audioDeviceID = kAudioDeviceUnknown;
+ pahsc->output.audioDeviceID = kAudioDeviceUnknown;
+
+ PaOSX_CalcHostBufferSize( past );
+
+ useOutput = (past->past_OutputDeviceID != paNoDevice) && (past->past_NumOutputChannels > 0);
+ useInput = (past->past_InputDeviceID != paNoDevice) && (past->past_NumInputChannels > 0);
+
+ // Set device IDs and determine IO Device mode.
+ if( useOutput )
+ {
+ pahsc->output.audioDeviceID = sDeviceInfos[past->past_OutputDeviceID].audioDeviceID;
+ pahsc->primaryDeviceID = pahsc->output.audioDeviceID;
+ if( useInput )
+ {
+ pahsc->input.audioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
+ pahsc->mode = ( pahsc->input.audioDeviceID != pahsc->primaryDeviceID ) ?
+ PA_MODE_IO_TWO_DEVICES : PA_MODE_IO_ONE_DEVICE;
+ }
+ else
+ {
+ pahsc->mode = PA_MODE_OUTPUT_ONLY;
+ }
+ }
+ else
+ {
+ /* Just input, not output. */
+ pahsc->input.audioDeviceID = sDeviceInfos[past->past_InputDeviceID].audioDeviceID;
+ pahsc->primaryDeviceID = pahsc->input.audioDeviceID;
+ pahsc->mode = PA_MODE_INPUT_ONLY;
+ }
+
+ DBUG(("outputDeviceID = %ld\n", pahsc->output.audioDeviceID ));
+ DBUG(("inputDeviceID = %ld\n", pahsc->input.audioDeviceID ));
+ DBUG(("primaryDeviceID = %ld\n", pahsc->primaryDeviceID ));
+
+ /* ------------------ OUTPUT */
+ if( useOutput )
+ {
+ result = PaOSX_OpenOutputDevice( past );
+ if( result < 0 ) goto error;
+ }
+
+ /* ------------------ INPUT */
+ if( useInput )
+ {
+ result = PaOSX_OpenInputDevice( past );
+ if( result < 0 ) goto error;
+ }
+
+ return result;
+
+error:
+ PaHost_CloseStream( past );
+ return result;
+}
+
+/*************************************************************************/
+PaError PaHost_StartOutput( internalPortAudioStream *past )
+{
+ return 0;
+}
+
+/*************************************************************************/
+PaError PaHost_StartInput( internalPortAudioStream *past )
+{
+ return 0;
+}
+
+/*************************************************************************/
+PaError PaHost_StartEngine( internalPortAudioStream *past )
+{
+ OSStatus err = noErr;
+ PaError result = paNoError;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ past->past_StopSoon = 0;
+ past->past_StopNow = 0;
+ past->past_IsActive = 1;
+
+/* If full duplex and using two separate devices then start input device. */
+ if( pahsc->mode == PA_MODE_IO_TWO_DEVICES )
+ {
+ // Associate an IO proc with the device and pass a pointer to the audio data context
+ err = AudioDeviceAddIOProc(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback, past);
+ if (err != noErr)
+ {
+ PRINT_ERR("PaHost_StartEngine: AudioDeviceAddIOProc secondary failed", err );
+ goto error;
+ }
+
+ // start playing sound through the device
+ err = AudioDeviceStart(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback);
+ if (err != noErr)
+ {
+ PRINT_ERR("PaHost_StartEngine: AudioDeviceStart secondary failed", err );
+ PRINT(("The program may succeed if you run it again!\n"));
+ goto error;
+ }
+ }
+
+ // Associate an IO proc with the device and pass a pointer to the audio data context
+ err = AudioDeviceAddIOProc(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback, past);
+ if (err != noErr)
+ {
+ PRINT_ERR("PaHost_StartEngine: AudioDeviceAddIOProc primary failed", err );
+ goto error;
+ }
+
+ // start playing sound through the device
+ err = AudioDeviceStart(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback);
+ if (err != noErr)
+ {
+ PRINT_ERR("PaHost_StartEngine: AudioDeviceStart primary failed", err );
+ PRINT(("The program may succeed if you run it again!\n"));
+ goto error;
+ }
+
+ return result;
+
+error:
+ sSavedHostError = err;
+ return paHostError;
+}
+
+/*************************************************************************/
+PaError PaHost_StopEngine( internalPortAudioStream *past, int abort )
+{
+ OSStatus err = noErr;
+ PaHostSoundControl *pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+ (void) abort;
+
+ /* Tell background thread to stop generating more data and to let current data play out. */
+ past->past_StopSoon = 1;
+ /* If aborting, tell background thread to stop NOW! */
+ if( abort ) past->past_StopNow = 1;
+ past->past_IsActive = 0;
+
+#if PA_TRACE_START_STOP
+ AddTraceMessage( "PaHost_StopOutput: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
+#endif
+
+ // FIXME - we should ask proc to stop instead of stopping abruptly
+ err = AudioDeviceStop(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback);
+ if (err != noErr)
+ {
+ goto error;
+ }
+
+ err = AudioDeviceRemoveIOProc(pahsc->primaryDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioIOCallback);
+ if (err != noErr) goto error;
+
+/* If full duplex and using two separate devices then stop second input device. */
+ if( pahsc->mode == PA_MODE_IO_TWO_DEVICES )
+ {
+ err = AudioDeviceStop(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback);
+ if (err != noErr) goto error;
+ err = AudioDeviceRemoveIOProc(pahsc->input.audioDeviceID, (AudioDeviceIOProc)PaOSX_CoreAudioInputCallback);
+ if (err != noErr) goto error;
+ }
+
+ return paNoError;
+
+error:
+ sSavedHostError = err;
+ return paHostError;
+}
+
+/*************************************************************************/
+PaError PaHost_StopInput( internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+/*************************************************************************/
+PaError PaHost_StopOutput( internalPortAudioStream *past, int abort )
+{
+ return paNoError;
+}
+
+/*******************************************************************/
+PaError PaHost_CloseStream( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paNoError;
+
+ //PaOSX_DumpDeviceInfo( sDeviceInfos[past->past_OutputDeviceID].audioDeviceID, IS_OUTPUT );
+
+#if PA_TRACE_START_STOP
+ AddTraceMessage( "PaHost_CloseStream: pahsc_HWaveOut ", (int) pahsc->pahsc_HWaveOut );
+#endif
+ // Stop Listener callbacks ASAP before dismantling stream.
+ if( PA_USING_INPUT )
+ {
+ AudioDeviceRemovePropertyListener( pahsc->input.audioDeviceID, 0, IS_INPUT,
+ kAudioDevicePropertyStreamFormat,
+ (AudioDevicePropertyListenerProc) PAOSX_DevicePropertyListener );
+ }
+
+ if( PA_USING_OUTPUT )
+ {
+ AudioDeviceRemovePropertyListener( pahsc->output.audioDeviceID, 0, IS_OUTPUT,
+ kAudioDevicePropertyStreamFormat,
+ (AudioDevicePropertyListenerProc) PAOSX_DevicePropertyListener );
+ }
+
+ if( pahsc->output.converterBuffer != NULL )
+ {
+ PaHost_FreeFastMemory( pahsc->output.converterBuffer, pahsc->output.bytesPerUserNativeBuffer );
+ }
+ if( pahsc->input.converterBuffer != NULL )
+ {
+ PaHost_FreeFastMemory( pahsc->input.converterBuffer, pahsc->input.bytesPerUserNativeBuffer );
+ }
+ if( pahsc->ringBufferData != NULL )
+ {
+ PaHost_FreeFastMemory( pahsc->ringBufferData, pahsc->ringBuffer.bufferSize );
+ }
+ if( pahsc->output.converter != NULL )
+ {
+ verify_noerr(AudioConverterDispose (pahsc->output.converter));
+ }
+ if( pahsc->input.converter != NULL )
+ {
+ verify_noerr(AudioConverterDispose (pahsc->input.converter));
+ }
+ if ( pahsc->input.streamInterleavingBuffer != NULL )
+ {
+ PaHost_FreeFastMemory( pahsc->input.streamInterleavingBuffer, pahsc->input.streamInterleavingBufferLen );
+ }
+ if ( pahsc->output.streamInterleavingBuffer != NULL )
+ {
+ PaHost_FreeFastMemory( pahsc->output.streamInterleavingBuffer, pahsc->output.streamInterleavingBufferLen );
+ }
+
+ free( pahsc );
+ past->past_DeviceData = NULL;
+
+ return paNoError;
+}
+
+/**********************************************************************
+** Initialize Host dependant part of API.
+*/
+PaError PaHost_Init( void )
+{
+ return PaOSX_MaybeQueryDevices();
+}
+
+/*************************************************************************
+** Cleanup device info.
+*/
+PaError PaHost_Term( void )
+{
+ int i;
+
+ if( sDeviceInfos != NULL )
+ {
+ for( i=0; i<sNumPaDevices; i++ )
+ {
+ if( sDeviceInfos[i].paInfo.name != NULL )
+ {
+ free( (char*)sDeviceInfos[i].paInfo.name );
+ }
+ }
+ free( sDeviceInfos );
+ sDeviceInfos = NULL;
+ }
+
+ sNumPaDevices = 0;
+ return paNoError;
+}
+
+/*************************************************************************
+ * Allocate memory that can be accessed in real-time.
+ * This may need to be held in physical memory so that it is not
+ * paged to virtual memory.
+ * This call MUST be balanced with a call to PaHost_FreeFastMemory().
+ */
+void *PaHost_AllocateFastMemory( long numBytes )
+{
+ void *addr = malloc( numBytes ); /* FIXME - do we need physical memory, not virtual memory? */
+ if( addr != NULL ) memset( addr, 0, numBytes );
+ return addr;
+}
+
+/*************************************************************************
+ * Free memory that could be accessed in real-time.
+ * This call MUST be balanced with a call to PaHost_AllocateFastMemory().
+ */
+void PaHost_FreeFastMemory( void *addr, long numBytes )
+{
+ if( addr != NULL ) free( addr );
+}
+
+
+/***********************************************************************/
+PaError PaHost_StreamActive( internalPortAudioStream *past )
+{
+ PaHostSoundControl *pahsc;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+ if( pahsc == NULL ) return paInternalError;
+ return (PaError) past->past_IsActive;
+}
+
+/*****************************************************************************/
+/************** External User API ********************************************/
+/*****************************************************************************/
+
+/**********************************************************************
+** Query devices and use result.
+*/
+PaDeviceID Pa_GetDefaultInputDeviceID( void )
+{
+ PaError result = PaOSX_MaybeQueryDevices();
+ if( result < 0 ) return result;
+ return sDefaultInputDeviceID;
+}
+
+PaDeviceID Pa_GetDefaultOutputDeviceID( void )
+{
+ PaError result = PaOSX_MaybeQueryDevices();
+ if( result < 0 ) return result;
+ return sDefaultOutputDeviceID;
+}
+
+
+/*************************************************************************
+** Determine minimum number of buffers required for this host based
+** on minimum latency. Because CoreAudio manages latency, this just selects
+** a reasonably small number of buffers.
+*/
+int Pa_GetMinNumBuffers( int framesPerBuffer, double framesPerSecond )
+{
+ int minBuffers;
+ double denominator;
+ int minLatencyMsec = PA_MIN_LATENCY_MSEC;
+ denominator = 1000.0 * framesPerBuffer;
+ minBuffers = (int) (((minLatencyMsec * framesPerSecond) + denominator - 1) / denominator );
+ if( minBuffers < 1 ) minBuffers = 1;
+ return minBuffers;
+}
+
+/*************************************************************************/
+void Pa_Sleep( long msec )
+{
+ usleep( msec * 1000 );
+}
+
+/*************************************************************************/
+PaTimestamp Pa_StreamTime( PortAudioStream *stream )
+{
+ AudioTimeStamp timeStamp;
+ PaTimestamp streamTime;
+ PaHostSoundControl *pahsc;
+ internalPortAudioStream *past = (internalPortAudioStream *) stream;
+ if( past == NULL ) return paBadStreamPtr;
+ pahsc = (PaHostSoundControl *) past->past_DeviceData;
+
+ AudioDeviceGetCurrentTime(pahsc->primaryDeviceID, &timeStamp);
+
+ streamTime = ( timeStamp.mFlags & kAudioTimeStampSampleTimeValid) ?
+ timeStamp.mSampleTime : past->past_FrameCount;
+
+ return streamTime;
+}
+
+/************************************************************************************/
+long Pa_GetHostError()
+{
+ return sSavedHostError;
+}
+
+/*************************************************************************/
+int Pa_CountDevices()
+{
+ if( sNumPaDevices <= 0 ) Pa_Initialize();
+ return sNumPaDevices;
+}
+
+/*************************************************************************
+** PaDeviceInfo structures have already been created
+** so just return the pointer.
+**
+*/
+const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceID id )
+{
+ if( id < 0 || id >= sNumPaDevices )
+ return NULL;
+
+ return &sDeviceInfos[id].paInfo;
+}
+
+
diff --git a/pd/portaudio_v18/pablio/README.txt b/pd/portaudio_v18/pablio/README.txt
new file mode 100644
index 00000000..99c7d146
--- /dev/null
+++ b/pd/portaudio_v18/pablio/README.txt
@@ -0,0 +1,39 @@
+README for PABLIO
+Portable Audio Blocking I/O Library
+Author: Phil Burk
+
+PABLIO is a simplified interface to PortAudio that provide
+read/write style blocking I/O.
+
+Please see the .DOC file for documentation.
+
+/*
+ * More information on PortAudio at: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
diff --git a/pd/portaudio_v18/pablio/pablio.c b/pd/portaudio_v18/pablio/pablio.c
new file mode 100644
index 00000000..d3a1bcf2
--- /dev/null
+++ b/pd/portaudio_v18/pablio/pablio.c
@@ -0,0 +1,327 @@
+/*
+ * $Id: pablio.c,v 1.1.1.1.4.4 2003/03/13 17:28:33 philburk Exp $
+ * pablio.c
+ * Portable Audio Blocking Input/Output utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* History:
+ * PLB021214 - check for valid stream in CloseAudioStream() to prevent hang.
+ * add timeOutMSec to CloseAudioStream() to prevent hang.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "ringbuffer.h"
+#include "pablio.h"
+#include <string.h>
+
+/************************************************************************/
+/******** Constants *****************************************************/
+/************************************************************************/
+
+#define FRAMES_PER_BUFFER (256)
+
+/************************************************************************/
+/******** Prototypes ****************************************************/
+/************************************************************************/
+
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
+
+/************************************************************************/
+/******** Functions *****************************************************/
+/************************************************************************/
+
+/* Called from PortAudio.
+ * Read and write data only if there is room in FIFOs.
+ */
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ PABLIO_Stream *data = (PABLIO_Stream*)userData;
+ long numBytes = data->bytesPerFrame * framesPerBuffer;
+ (void) outTime;
+
+ /* This may get called with NULL inputBuffer during initial setup. */
+ if( inputBuffer != NULL )
+ {
+ RingBuffer_Write( &data->inFIFO, inputBuffer, numBytes );
+ }
+ if( outputBuffer != NULL )
+ {
+ int i;
+ int numRead = RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes );
+ /* Zero out remainder of buffer if we run out of data. */
+ for( i=numRead; i<numBytes; i++ )
+ {
+ ((char *)outputBuffer)[i] = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Allocate buffer. */
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )
+{
+ long numBytes = numFrames * bytesPerFrame;
+ char *buffer = (char *) malloc( numBytes );
+ if( buffer == NULL ) return paInsufficientMemory;
+ memset( buffer, 0, numBytes );
+ return (PaError) RingBuffer_Init( rbuf, numBytes, buffer );
+}
+
+/* Free buffer. */
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf )
+{
+ if( rbuf->buffer ) free( rbuf->buffer );
+ rbuf->buffer = NULL;
+ return paNoError;
+}
+
+/************************************************************
+ * Write data to ring buffer.
+ * Will not return until all the data has been written.
+ */
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
+{
+ long bytesWritten;
+ char *p = (char *) data;
+ long numBytes = aStream->bytesPerFrame * numFrames;
+ while( numBytes > 0)
+ {
+ bytesWritten = RingBuffer_Write( &aStream->outFIFO, p, numBytes );
+ numBytes -= bytesWritten;
+ p += bytesWritten;
+ if( numBytes > 0) Pa_Sleep(10);
+ }
+ return numFrames;
+}
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
+{
+ long bytesRead;
+ char *p = (char *) data;
+ long numBytes = aStream->bytesPerFrame * numFrames;
+ while( numBytes > 0)
+ {
+ bytesRead = RingBuffer_Read( &aStream->inFIFO, p, numBytes );
+ numBytes -= bytesRead;
+ p += bytesRead;
+ if( numBytes > 0) Pa_Sleep(10);
+ }
+ return numFrames;
+}
+
+/************************************************************
+ * Return the number of frames that could be written to the stream without
+ * having to wait.
+ */
+long GetAudioStreamWriteable( PABLIO_Stream *aStream )
+{
+ int bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ return bytesEmpty / aStream->bytesPerFrame;
+}
+
+/************************************************************
+ * Return the number of frames that are available to be read from the
+ * stream without having to wait.
+ */
+long GetAudioStreamReadable( PABLIO_Stream *aStream )
+{
+ int bytesFull = RingBuffer_GetReadAvailable( &aStream->inFIFO );
+ return bytesFull / aStream->bytesPerFrame;
+}
+
+/************************************************************/
+static unsigned long RoundUpToNextPowerOf2( unsigned long n )
+{
+ long numBits = 0;
+ if( ((n-1) & n) == 0) return n; /* Already Power of two. */
+ while( n > 0 )
+ {
+ n= n>>1;
+ numBits++;
+ }
+ return (1<<numBits);
+}
+
+/************************************************************
+ * Opens a PortAudio stream with default characteristics.
+ * Allocates PABLIO_Stream structure.
+ *
+ * flags parameter can be an ORed combination of:
+ * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
+ * and either PABLIO_MONO or PABLIO_STEREO
+ */
+PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+ PaSampleFormat format, long flags )
+{
+ long bytesPerSample;
+ long doRead = 0;
+ long doWrite = 0;
+ PaError err;
+ PABLIO_Stream *aStream;
+ long minNumBuffers;
+ long numFrames;
+
+ /* Allocate PABLIO_Stream structure for caller. */
+ aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );
+ if( aStream == NULL ) return paInsufficientMemory;
+ memset( aStream, 0, sizeof(PABLIO_Stream) );
+
+ /* Determine size of a sample. */
+ bytesPerSample = Pa_GetSampleSize( format );
+ if( bytesPerSample < 0 )
+ {
+ err = (PaError) bytesPerSample;
+ goto error;
+ }
+ aStream->samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2;
+ aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
+
+ /* Initialize PortAudio */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+ /* Warning: numFrames must be larger than amount of data processed per interrupt
+ * inside PA to prevent glitches. Just to be safe, adjust size upwards.
+ */
+ minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );
+ numFrames = minNumBuffers * FRAMES_PER_BUFFER;
+ /* The PortAudio callback runs in a high priority thread. But PABLIO
+ * runs in a normal foreground thread. So we may have much worse
+ * latency in PABLIO. So adjust latency to a safe level.
+ */
+ {
+ const int safeLatencyMSec = 200;
+ int minLatencyMSec = (int) ((1000 * numFrames) / sampleRate);
+ if( minLatencyMSec < safeLatencyMSec )
+ {
+ numFrames = (int) ((safeLatencyMSec * sampleRate) / 1000);
+ }
+ }
+ numFrames = RoundUpToNextPowerOf2( numFrames );
+
+ /* Initialize Ring Buffers */
+ doRead = ((flags & PABLIO_READ) != 0);
+ doWrite = ((flags & PABLIO_WRITE) != 0);
+ if(doRead)
+ {
+ err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame );
+ if( err != paNoError ) goto error;
+ }
+ if(doWrite)
+ {
+ long numBytes;
+ err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame );
+ if( err != paNoError ) goto error;
+ /* Make Write FIFO appear full initially. */
+ numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes );
+ }
+
+ /* Open a PortAudio stream that we will use to communicate with the underlying
+ * audio drivers. */
+ err = Pa_OpenStream(
+ &aStream->stream,
+ (doRead ? Pa_GetDefaultInputDeviceID() : paNoDevice),
+ (doRead ? aStream->samplesPerFrame : 0 ),
+ format,
+ NULL,
+ (doWrite ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
+ (doWrite ? aStream->samplesPerFrame : 0 ),
+ format,
+ NULL,
+ sampleRate,
+ FRAMES_PER_BUFFER,
+ minNumBuffers,
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */
+ blockingIOCallback,
+ aStream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( aStream->stream );
+ if( err != paNoError ) goto error;
+
+ *rwblPtr = aStream;
+ return paNoError;
+
+error:
+ CloseAudioStream( aStream );
+ *rwblPtr = NULL;
+ return err;
+}
+
+/************************************************************/
+PaError CloseAudioStream( PABLIO_Stream *aStream )
+{
+ PaError err = paNoError;
+ int bytesEmpty;
+ int byteSize = aStream->outFIFO.bufferSize;
+
+ if( aStream->stream != NULL ) /* Make sure stream was opened. PLB021214 */
+ {
+ /* If we are writing data, make sure we play everything written. */
+ if( byteSize > 0 )
+ {
+ int timeOutMSec = 2000;
+ bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ while( (bytesEmpty < byteSize) && (timeOutMSec > 0) )
+ {
+ Pa_Sleep( 20 );
+ timeOutMSec -= 20;
+ bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ }
+ }
+ err = Pa_StopStream( aStream->stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( aStream->stream );
+ }
+
+error:
+ Pa_Terminate();
+ PABLIO_TermFIFO( &aStream->inFIFO );
+ PABLIO_TermFIFO( &aStream->outFIFO );
+ free( aStream );
+ return err;
+}
diff --git a/pd/portaudio_v18/pablio/pablio.def b/pd/portaudio_v18/pablio/pablio.def
new file mode 100644
index 00000000..9e2c4e3c
--- /dev/null
+++ b/pd/portaudio_v18/pablio/pablio.def
@@ -0,0 +1,35 @@
+LIBRARY PABLIOV18
+DESCRIPTION 'PABLIO Portable Audio Blocking I/O'
+
+EXPORTS
+ ; Explicit exports can go here
+ Pa_Initialize @1
+ Pa_Terminate @2
+ Pa_GetHostError @3
+ Pa_GetErrorText @4
+ Pa_CountDevices @5
+ Pa_GetDefaultInputDeviceID @6
+ Pa_GetDefaultOutputDeviceID @7
+ Pa_GetDeviceInfo @8
+ Pa_OpenStream @9
+ Pa_OpenDefaultStream @10
+ Pa_CloseStream @11
+ Pa_StartStream @12
+ Pa_StopStream @13
+ Pa_StreamActive @14
+ Pa_StreamTime @15
+ Pa_GetCPULoad @16
+ Pa_GetMinNumBuffers @17
+ Pa_Sleep @18
+
+ OpenAudioStream @19
+ CloseAudioStream @20
+ WriteAudioStream @21
+ ReadAudioStream @22
+
+ Pa_GetSampleSize @23
+
+ ;123456789012345678901234567890123456
+ ;000000000111111111122222222223333333
+
+
diff --git a/pd/portaudio_v18/pablio/pablio.h b/pd/portaudio_v18/pablio/pablio.h
new file mode 100644
index 00000000..a4871f38
--- /dev/null
+++ b/pd/portaudio_v18/pablio/pablio.h
@@ -0,0 +1,109 @@
+#ifndef _PABLIO_H
+#define _PABLIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: pablio.h,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $
+ * PABLIO.h
+ * Portable Audio Blocking read/write utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com/portaudio/
+ *
+ * Include file for PABLIO, the Portable Audio Blocking I/O Library.
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "ringbuffer.h"
+#include <string.h>
+
+typedef struct
+{
+ RingBuffer inFIFO;
+ RingBuffer outFIFO;
+ PortAudioStream *stream;
+ int bytesPerFrame;
+ int samplesPerFrame;
+}
+PABLIO_Stream;
+
+/* Values for flags for OpenAudioStream(). */
+#define PABLIO_READ (1<<0)
+#define PABLIO_WRITE (1<<1)
+#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE)
+#define PABLIO_MONO (1<<2)
+#define PABLIO_STEREO (1<<3)
+
+/************************************************************
+ * Write data to ring buffer.
+ * Will not return until all the data has been written.
+ */
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
+
+/************************************************************
+ * Return the number of frames that could be written to the stream without
+ * having to wait.
+ */
+long GetAudioStreamWriteable( PABLIO_Stream *aStream );
+
+/************************************************************
+ * Return the number of frames that are available to be read from the
+ * stream without having to wait.
+ */
+long GetAudioStreamReadable( PABLIO_Stream *aStream );
+
+/************************************************************
+ * Opens a PortAudio stream with default characteristics.
+ * Allocates PABLIO_Stream structure.
+ *
+ * flags parameter can be an ORed combination of:
+ * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
+ * and either PABLIO_MONO or PABLIO_STEREO
+ */
+PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,
+ PaSampleFormat format, long flags );
+
+PaError CloseAudioStream( PABLIO_Stream *aStream );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _PABLIO_H */
diff --git a/pd/portaudio_v18/pablio/pablio_pd.c b/pd/portaudio_v18/pablio/pablio_pd.c
new file mode 100644
index 00000000..2596b73c
--- /dev/null
+++ b/pd/portaudio_v18/pablio/pablio_pd.c
@@ -0,0 +1,341 @@
+/*
+ * $Id: pablio_pd.c,v 1.1.1.1 2003-05-09 16:04:00 ggeiger Exp $
+ * pablio.c
+ * Portable Audio Blocking Input/Output utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* History:
+ * PLB021214 - check for valid stream in CloseAudioStream() to prevent hang.
+ * add timeOutMSec to CloseAudioStream() to prevent hang.
+ */
+
+ /* changes by Miller Puckette (MSP) to support Pd: device selection,
+ settable audio buffer size, and settable number of channels.
+ LATER also fix it to poll for input and output fifo fill points. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "ringbuffer.h"
+#include "pablio_pd.h" /* MSP */
+#include <string.h>
+
+ /* MSP -- FRAMES_PER_BUFFER constant removed */
+
+/************************************************************************/
+/******** Prototypes ****************************************************/
+/************************************************************************/
+
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData );
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
+
+/************************************************************************/
+/******** Functions *****************************************************/
+/************************************************************************/
+
+/* Called from PortAudio.
+ * Read and write data only if there is room in FIFOs.
+ */
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
+ unsigned long framesPerBuffer,
+ PaTimestamp outTime, void *userData )
+{
+ PABLIO_Stream *data = (PABLIO_Stream*)userData;
+ long numBytes = data->bytesPerFrame * framesPerBuffer;
+ (void) outTime;
+
+ /* This may get called with NULL inputBuffer during initial setup. */
+ if( inputBuffer != NULL )
+ {
+ RingBuffer_Write( &data->inFIFO, inputBuffer, numBytes );
+ }
+ if( outputBuffer != NULL )
+ {
+ int i;
+ int numRead = RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes );
+ /* Zero out remainder of buffer if we run out of data. */
+ for( i=numRead; i<numBytes; i++ )
+ {
+ ((char *)outputBuffer)[i] = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Allocate buffer. */
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )
+{
+ long numBytes = numFrames * bytesPerFrame;
+ char *buffer = (char *) malloc( numBytes );
+ if( buffer == NULL ) return paInsufficientMemory;
+ memset( buffer, 0, numBytes );
+ return (PaError) RingBuffer_Init( rbuf, numBytes, buffer );
+}
+
+/* Free buffer. */
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf )
+{
+ if( rbuf->buffer ) free( rbuf->buffer );
+ rbuf->buffer = NULL;
+ return paNoError;
+}
+
+/************************************************************
+ * Write data to ring buffer.
+ * Will not return until all the data has been written.
+ */
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
+{
+ long bytesWritten;
+ char *p = (char *) data;
+ long numBytes = aStream->bytesPerFrame * numFrames;
+ while( numBytes > 0)
+ {
+ bytesWritten = RingBuffer_Write( &aStream->outFIFO, p, numBytes );
+ numBytes -= bytesWritten;
+ p += bytesWritten;
+ if( numBytes > 0) Pa_Sleep(10);
+ }
+ return numFrames;
+}
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
+{
+ long bytesRead;
+ char *p = (char *) data;
+ long numBytes = aStream->bytesPerFrame * numFrames;
+ while( numBytes > 0)
+ {
+ bytesRead = RingBuffer_Read( &aStream->inFIFO, p, numBytes );
+ numBytes -= bytesRead;
+ p += bytesRead;
+ if( numBytes > 0) Pa_Sleep(10);
+ }
+ return numFrames;
+}
+
+/************************************************************
+ * Return the number of frames that could be written to the stream without
+ * having to wait.
+ */
+long GetAudioStreamWriteable( PABLIO_Stream *aStream )
+{
+ int bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ return bytesEmpty / aStream->bytesPerFrame;
+}
+
+/************************************************************
+ * Return the number of frames that are available to be read from the
+ * stream without having to wait.
+ */
+long GetAudioStreamReadable( PABLIO_Stream *aStream )
+{
+ int bytesFull = RingBuffer_GetReadAvailable( &aStream->inFIFO );
+ return bytesFull / aStream->bytesPerFrame;
+}
+
+/************************************************************/
+static unsigned long RoundUpToNextPowerOf2( unsigned long n )
+{
+ long numBits = 0;
+ if( ((n-1) & n) == 0) return n; /* Already Power of two. */
+ while( n > 0 )
+ {
+ n= n>>1;
+ numBits++;
+ }
+ return (1<<numBits);
+}
+
+/************************************************************
+ * Opens a PortAudio stream with default characteristics.
+ * Allocates PABLIO_Stream structure.
+ *
+ * flags parameter can be an ORed combination of:
+ * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
+ * and either PABLIO_MONO or PABLIO_STEREO
+ */
+PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+ PaSampleFormat format, long flags, int nchannels,
+ int framesperbuf, int nbuffers,
+ int indeviceno, int outdeviceno) /* MSP */
+{
+ long bytesPerSample;
+ long doRead = 0;
+ long doWrite = 0;
+ PaError err;
+ PABLIO_Stream *aStream;
+ long minNumBuffers;
+ long numFrames;
+
+ if (indeviceno < 0) /* MSP... */
+ {
+ indeviceno = Pa_GetDefaultInputDeviceID();
+ fprintf(stderr, "using default input device number: %d\n", indeviceno);
+ }
+ if (outdeviceno < 0)
+ {
+ outdeviceno = Pa_GetDefaultOutputDeviceID();
+ fprintf(stderr, "using default output device number: %d\n", outdeviceno);
+ }
+ nbuffers = RoundUpToNextPowerOf2(nbuffers);
+ fprintf(stderr, "nchan %d, flags %d, bufs %d, framesperbuf %d\n",
+ nchannels, flags, nbuffers, framesperbuf);
+ /* ...MSP */
+
+ /* Allocate PABLIO_Stream structure for caller. */
+ aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );
+ if( aStream == NULL ) return paInsufficientMemory;
+ memset( aStream, 0, sizeof(PABLIO_Stream) );
+
+ /* Determine size of a sample. */
+ bytesPerSample = Pa_GetSampleSize( format );
+ if( bytesPerSample < 0 )
+ {
+ err = (PaError) bytesPerSample;
+ goto error;
+ }
+ aStream->samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2;
+ aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
+
+ /* Initialize PortAudio */
+ err = Pa_Initialize();
+ if( err != paNoError ) goto error;
+
+/* Warning: numFrames must be larger than amount of data processed per
+ interrupt inside PA to prevent glitches. */ /* MSP... */
+ minNumBuffers = Pa_GetMinNumBuffers(framesperbuf, sampleRate);
+ if (minNumBuffers > nbuffers)
+ fprintf(stderr,
+ "warning: number of buffers %d less than recommended minimum %d\n",
+ (int)nbuffers, (int)minNumBuffers);
+ numFrames = nbuffers * framesperbuf; /* ...MSP */
+
+
+ /* Initialize Ring Buffers */
+ doRead = ((flags & PABLIO_READ) != 0);
+ doWrite = ((flags & PABLIO_WRITE) != 0);
+ if(doRead)
+ {
+ err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame );
+ if( err != paNoError ) goto error;
+ }
+ if(doWrite)
+ {
+ long numBytes;
+ err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame );
+ if( err != paNoError ) goto error;
+ /* Make Write FIFO appear full initially. */
+ numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes );
+ }
+
+ /* Open a PortAudio stream that we will use to communicate with the underlying
+ * audio drivers. */
+ err = Pa_OpenStream(
+ &aStream->stream,
+ (doRead ? indeviceno : paNoDevice), /* MSP */
+ (doRead ? aStream->samplesPerFrame : 0 ),
+ format,
+ NULL,
+ (doWrite ? outdeviceno : paNoDevice), /* MSP */
+ (doWrite ? aStream->samplesPerFrame : 0 ),
+ format,
+ NULL,
+ sampleRate,
+ framesperbuf, /* MSP */
+ nbuffers, /* MSP */
+ paNoFlag, /* MSP -- portaudio will clip for us */
+ blockingIOCallback,
+ aStream );
+ if( err != paNoError ) goto error;
+
+ err = Pa_StartStream( aStream->stream );
+ if( err != paNoError ) /* MSP... */
+ {
+ fprintf(stderr, "Pa_StartStream failed; closing audio stream...\n");
+ CloseAudioStream( aStream );
+ goto error;
+ } /* ...MSP */
+
+ *rwblPtr = aStream;
+ return paNoError;
+
+error:
+ CloseAudioStream( aStream );
+ *rwblPtr = NULL;
+ return err;
+}
+
+/************************************************************/
+PaError CloseAudioStream( PABLIO_Stream *aStream )
+{
+ PaError err = paNoError;
+ int bytesEmpty;
+ int byteSize = aStream->outFIFO.bufferSize;
+
+ if( aStream->stream != NULL ) /* Make sure stream was opened. PLB021214 */
+ {
+ /* If we are writing data, make sure we play everything written. */
+ if( byteSize > 0 )
+ {
+ int timeOutMSec = 2000;
+ bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ while( (bytesEmpty < byteSize) && (timeOutMSec > 0) )
+ {
+ Pa_Sleep( 20 );
+ timeOutMSec -= 20;
+ bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+ }
+ }
+ err = Pa_StopStream( aStream->stream );
+ if( err != paNoError ) goto error;
+ err = Pa_CloseStream( aStream->stream );
+ }
+
+error:
+ Pa_Terminate();
+ PABLIO_TermFIFO( &aStream->inFIFO );
+ PABLIO_TermFIFO( &aStream->outFIFO );
+ free( aStream );
+ return err;
+}
diff --git a/pd/portaudio_v18/pablio/pablio_pd.h b/pd/portaudio_v18/pablio/pablio_pd.h
new file mode 100644
index 00000000..a99e74b6
--- /dev/null
+++ b/pd/portaudio_v18/pablio/pablio_pd.h
@@ -0,0 +1,110 @@
+#ifndef _PABLIO_H
+#define _PABLIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: pablio_pd.h,v 1.1.1.1 2003-05-09 16:04:00 ggeiger Exp $
+ * PABLIO.h
+ * Portable Audio Blocking read/write utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com/portaudio/
+ *
+ * Include file for PABLIO, the Portable Audio Blocking I/O Library.
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "ringbuffer.h"
+#include <string.h>
+
+typedef struct
+{
+ RingBuffer inFIFO;
+ RingBuffer outFIFO;
+ PaStream *stream; /* MSP -- was PortAudioStream; probably an error */
+ int bytesPerFrame;
+ int samplesPerFrame;
+}
+PABLIO_Stream;
+
+/* Values for flags for OpenAudioStream(). */
+#define PABLIO_READ (1<<0)
+#define PABLIO_WRITE (1<<1)
+#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE)
+#define PABLIO_MONO (1<<2)
+#define PABLIO_STEREO (1<<3)
+
+/************************************************************
+ * Write data to ring buffer.
+ * Will not return until all the data has been written.
+ */
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
+
+/************************************************************
+ * Return the number of frames that could be written to the stream without
+ * having to wait.
+ */
+long GetAudioStreamWriteable( PABLIO_Stream *aStream );
+
+/************************************************************
+ * Return the number of frames that are available to be read from the
+ * stream without having to wait.
+ */
+long GetAudioStreamReadable( PABLIO_Stream *aStream );
+
+/************************************************************
+ * Opens a PortAudio stream with default characteristics.
+ * Allocates PABLIO_Stream structure.
+ *
+ * flags parameter can be an ORed combination of:
+ * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
+ */
+PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+ PaSampleFormat format, long flags, int nchannels,
+ int framesperbuf, int nbuffers,
+ int indeviceno, int outdeviceno); /* MSP */
+
+PaError CloseAudioStream( PABLIO_Stream *aStream );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _PABLIO_H */
diff --git a/pd/portaudio_v18/pablio/ringbuffer.c b/pd/portaudio_v18/pablio/ringbuffer.c
new file mode 100644
index 00000000..e0c02890
--- /dev/null
+++ b/pd/portaudio_v18/pablio/ringbuffer.c
@@ -0,0 +1,199 @@
+/*
+ * $Id: ringbuffer.c,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $
+ * ringbuffer.c
+ * Ring Buffer utility..
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+/***************************************************************************
+ * Initialize FIFO.
+ * numBytes must be power of 2, returns -1 if not.
+ */
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )
+{
+ if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */
+ rbuf->bufferSize = numBytes;
+ rbuf->buffer = (char *)dataPtr;
+ RingBuffer_Flush( rbuf );
+ rbuf->bigMask = (numBytes*2)-1;
+ rbuf->smallMask = (numBytes)-1;
+ return 0;
+}
+/***************************************************************************
+** Return number of bytes available for reading. */
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf )
+{
+ return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );
+}
+/***************************************************************************
+** Return number of bytes available for writing. */
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf )
+{
+ return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));
+}
+
+/***************************************************************************
+** Clear buffer. Should only be called when buffer is NOT being read. */
+void RingBuffer_Flush( RingBuffer *rbuf )
+{
+ rbuf->writeIndex = rbuf->readIndex = 0;
+}
+
+/***************************************************************************
+** Get address of region(s) to which we can write data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
+ void **dataPtr1, long *sizePtr1,
+ void **dataPtr2, long *sizePtr2 )
+{
+ long index;
+ long available = RingBuffer_GetWriteAvailable( rbuf );
+ if( numBytes > available ) numBytes = available;
+ /* Check to see if write is not contiguous. */
+ index = rbuf->writeIndex & rbuf->smallMask;
+ if( (index + numBytes) > rbuf->bufferSize )
+ {
+ /* Write data in two blocks that wrap the buffer. */
+ long firstHalf = rbuf->bufferSize - index;
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = firstHalf;
+ *dataPtr2 = &rbuf->buffer[0];
+ *sizePtr2 = numBytes - firstHalf;
+ }
+ else
+ {
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = numBytes;
+ *dataPtr2 = NULL;
+ *sizePtr2 = 0;
+ }
+ return numBytes;
+}
+
+
+/***************************************************************************
+*/
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )
+{
+ return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
+}
+
+/***************************************************************************
+** Get address of region(s) from which we can read data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+ void **dataPtr1, long *sizePtr1,
+ void **dataPtr2, long *sizePtr2 )
+{
+ long index;
+ long available = RingBuffer_GetReadAvailable( rbuf );
+ if( numBytes > available ) numBytes = available;
+ /* Check to see if read is not contiguous. */
+ index = rbuf->readIndex & rbuf->smallMask;
+ if( (index + numBytes) > rbuf->bufferSize )
+ {
+ /* Write data in two blocks that wrap the buffer. */
+ long firstHalf = rbuf->bufferSize - index;
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = firstHalf;
+ *dataPtr2 = &rbuf->buffer[0];
+ *sizePtr2 = numBytes - firstHalf;
+ }
+ else
+ {
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = numBytes;
+ *dataPtr2 = NULL;
+ *sizePtr2 = 0;
+ }
+ return numBytes;
+}
+/***************************************************************************
+*/
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )
+{
+ return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
+}
+
+/***************************************************************************
+** Return bytes written. */
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes )
+{
+ long size1, size2, numWritten;
+ void *data1, *data2;
+ numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+ if( size2 > 0 )
+ {
+
+ memcpy( data1, data, size1 );
+ data = ((char *)data) + size1;
+ memcpy( data2, data, size2 );
+ }
+ else
+ {
+ memcpy( data1, data, size1 );
+ }
+ RingBuffer_AdvanceWriteIndex( rbuf, numWritten );
+ return numWritten;
+}
+
+/***************************************************************************
+** Return bytes read. */
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )
+{
+ long size1, size2, numRead;
+ void *data1, *data2;
+ numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+ if( size2 > 0 )
+ {
+ memcpy( data, data1, size1 );
+ data = ((char *)data) + size1;
+ memcpy( data, data2, size2 );
+ }
+ else
+ {
+ memcpy( data, data1, size1 );
+ }
+ RingBuffer_AdvanceReadIndex( rbuf, numRead );
+ return numRead;
+}
diff --git a/pd/portaudio_v18/pablio/ringbuffer.h b/pd/portaudio_v18/pablio/ringbuffer.h
new file mode 100644
index 00000000..4be71d18
--- /dev/null
+++ b/pd/portaudio_v18/pablio/ringbuffer.h
@@ -0,0 +1,102 @@
+#ifndef _RINGBUFFER_H
+#define _RINGBUFFER_H
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: ringbuffer.h,v 1.1.1.1.4.1 2003/03/13 17:28:14 philburk Exp $
+ * ringbuffer.h
+ * Ring Buffer utility..
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program is distributed with the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+typedef struct
+{
+ long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_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. */
+ long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */
+ long smallMask; /* Used for fitting indices to buffer. */
+ char *buffer;
+}
+RingBuffer;
+/*
+ * Initialize Ring Buffer.
+ * numBytes must be power of 2, returns -1 if not.
+ */
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
+
+/* Clear buffer. Should only be called when buffer is NOT being read. */
+void RingBuffer_Flush( RingBuffer *rbuf );
+
+/* Return number of bytes available for writing. */
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
+/* Return number of bytes available for read. */
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf );
+/* Return bytes written. */
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes );
+/* Return bytes read. */
+long RingBuffer_Read( RingBuffer *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,
+ void **dataPtr1, long *sizePtr1,
+ void **dataPtr2, long *sizePtr2 );
+long RingBuffer_AdvanceWriteIndex( RingBuffer *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 written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+ void **dataPtr1, long *sizePtr1,
+ void **dataPtr2, long *sizePtr2 );
+
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _RINGBUFFER_H */
diff --git a/pd/portaudio_v18/pablio/ringbuffer_pd.c b/pd/portaudio_v18/pablio/ringbuffer_pd.c
new file mode 100644
index 00000000..97e060c1
--- /dev/null
+++ b/pd/portaudio_v18/pablio/ringbuffer_pd.c
@@ -0,0 +1,214 @@
+/*
+ * $Id: ringbuffer_pd.c,v 1.1.1.1 2003-05-09 16:04:00 ggeiger Exp $
+ * ringbuffer.c
+ * Ring Buffer utility..
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+/*
+ * modified 2002/07/13 by olaf.matthes@gmx.de to allow any number if channels
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+/***************************************************************************
+ * Initialize FIFO.
+ */
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )
+{
+ rbuf->bufferSize = numBytes;
+ rbuf->buffer = (char *)dataPtr;
+ RingBuffer_Flush( rbuf );
+ return 0;
+}
+/***************************************************************************
+** Return number of bytes available for reading. */
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf )
+{
+ long ret = (rbuf->writeIndex - rbuf->readIndex) + rbuf->bufferSize;
+ if (ret >= 2 * rbuf->bufferSize)
+ ret -= 2 * rbuf->bufferSize;
+ return ( ret );
+}
+/***************************************************************************
+** Return number of bytes available for writing. */
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf )
+{
+ return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));
+}
+
+/***************************************************************************
+** Clear buffer. Should only be called when buffer is NOT being read. */
+void RingBuffer_Flush( RingBuffer *rbuf )
+{
+ rbuf->writeIndex = rbuf->readIndex = 0;
+}
+
+/***************************************************************************
+** Get address of region(s) to which we can write data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
+ void **dataPtr1, long *sizePtr1,
+ void **dataPtr2, long *sizePtr2 )
+{
+ long index;
+ long available = RingBuffer_GetWriteAvailable( rbuf );
+ if( numBytes > available ) numBytes = available;
+ /* Check to see if write is not contiguous. */
+ index = rbuf->writeIndex;
+ while (index >= rbuf->bufferSize)
+ index -= rbuf->bufferSize;
+ if( (index + numBytes) > rbuf->bufferSize )
+ {
+ /* Write data in two blocks that wrap the buffer. */
+ long firstHalf = rbuf->bufferSize - index;
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = firstHalf;
+ *dataPtr2 = &rbuf->buffer[0];
+ *sizePtr2 = numBytes - firstHalf;
+ }
+ else
+ {
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = numBytes;
+ *dataPtr2 = NULL;
+ *sizePtr2 = 0;
+ }
+ return numBytes;
+}
+
+
+/***************************************************************************
+*/
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )
+{
+ long ret = (rbuf->writeIndex + numBytes);
+ if ( ret > 2 * rbuf->bufferSize)
+ ret -= 2 * rbuf->bufferSize; /* check for end of buffer */
+ return rbuf->writeIndex = ret;
+}
+
+/***************************************************************************
+** Get address of region(s) from which we can read data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+ void **dataPtr1, long *sizePtr1,
+ void **dataPtr2, long *sizePtr2 )
+{
+ long index;
+ long available = RingBuffer_GetReadAvailable( rbuf );
+ if( numBytes > available ) numBytes = available;
+ /* Check to see if read is not contiguous. */
+ index = rbuf->readIndex;
+ while (index > rbuf->bufferSize)
+ index -= rbuf->bufferSize;
+
+ if( (index + numBytes) > rbuf->bufferSize )
+ {
+ /* Write data in two blocks that wrap the buffer. */
+ long firstHalf = rbuf->bufferSize - index;
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = firstHalf;
+ *dataPtr2 = &rbuf->buffer[0];
+ *sizePtr2 = numBytes - firstHalf;
+ }
+ else
+ {
+ *dataPtr1 = &rbuf->buffer[index];
+ *sizePtr1 = numBytes;
+ *dataPtr2 = NULL;
+ *sizePtr2 = 0;
+ }
+ return numBytes;
+}
+/***************************************************************************
+*/
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )
+{
+ long ret = (rbuf->readIndex + numBytes);
+ if( ret > 2 * rbuf->bufferSize)
+ ret -= 2 * rbuf->bufferSize;
+ return rbuf->readIndex = ret;
+}
+
+/***************************************************************************
+** Return bytes written. */
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes )
+{
+ long size1, size2, numWritten;
+ void *data1, *data2;
+ numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+ if( size2 > 0 )
+ {
+
+ memcpy( data1, data, size1 );
+ data = ((char *)data) + size1;
+ memcpy( data2, data, size2 );
+ }
+ else
+ {
+ memcpy( data1, data, size1 );
+ }
+ RingBuffer_AdvanceWriteIndex( rbuf, numWritten );
+ return numWritten;
+}
+
+/***************************************************************************
+** Return bytes read. */
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )
+{
+ long size1, size2, numRead;
+ void *data1, *data2;
+ numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+ if( size2 > 0 )
+ {
+ memcpy( data, data1, size1 );
+ data = ((char *)data) + size1;
+ memcpy( data, data2, size2 );
+ }
+ else
+ {
+ memcpy( data, data1, size1 );
+ }
+ RingBuffer_AdvanceReadIndex( rbuf, numRead );
+ return numRead;
+}
diff --git a/pd/portaudio_v18/pablio/test_rw.c b/pd/portaudio_v18/pablio/test_rw.c
new file mode 100644
index 00000000..27a94b43
--- /dev/null
+++ b/pd/portaudio_v18/pablio/test_rw.c
@@ -0,0 +1,99 @@
+/*
+ * $Id: test_rw.c,v 1.2 2002/02/22 22:06:23 philburk Exp $
+ * test_rw.c
+ * Read input from one stream and write it to another.
+ *
+ * Author: Phil Burk, http://www.softsynth.com/portaudio/
+ *
+ * This program uses PABLIO, the Portable Audio Blocking I/O Library.
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "pablio.h"
+
+/*
+** Note that many of the older ISA sound cards on PCs do NOT support
+** full duplex audio (simultaneous record and playback).
+** And some only support full duplex at lower sample rates.
+*/
+#define SAMPLE_RATE (44100)
+#define NUM_SECONDS (5)
+#define SAMPLES_PER_FRAME (2)
+#define FRAMES_PER_BLOCK (64)
+
+/* Select whether we will use floats or shorts. */
+#if 1
+#define SAMPLE_TYPE paFloat32
+typedef float SAMPLE;
+#else
+#define SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+#endif
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i;
+ SAMPLE samples[SAMPLES_PER_FRAME * FRAMES_PER_BLOCK];
+ PaError err;
+ PABLIO_Stream *aStream;
+
+ printf("Full duplex sound test using PortAudio and RingBuffers\n");
+ fflush(stdout);
+
+ /* Open simplified blocking I/O layer on top of PortAudio. */
+ err = OpenAudioStream( &aStream, SAMPLE_RATE, SAMPLE_TYPE,
+ (PABLIO_READ_WRITE | PABLIO_STEREO) );
+ if( err != paNoError ) goto error;
+
+ /* Process samples in the foreground. */
+ for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK )
+ {
+ /* Read one block of data into sample array from audio input. */
+ ReadAudioStream( aStream, samples, FRAMES_PER_BLOCK );
+ /* Write that same block of data to output. */
+ WriteAudioStream( aStream, samples, FRAMES_PER_BLOCK );
+ }
+
+ CloseAudioStream( aStream );
+
+ printf("Full duplex sound test complete.\n" );
+ fflush(stdout);
+ return 0;
+
+error:
+ Pa_Terminate();
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
diff --git a/pd/portaudio_v18/pablio/test_rw_echo.c b/pd/portaudio_v18/pablio/test_rw_echo.c
new file mode 100644
index 00000000..7bc4e9b4
--- /dev/null
+++ b/pd/portaudio_v18/pablio/test_rw_echo.c
@@ -0,0 +1,123 @@
+/*
+ * $Id: test_rw_echo.c,v 1.1.1.1 2002/01/22 00:52:54 phil Exp $
+ * test_rw_echo.c
+ * Echo delayed input to output.
+ *
+ * Author: Phil Burk, http://www.softsynth.com/portaudio/
+ *
+ * This program uses PABLIO, the Portable Audio Blocking I/O Library.
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.
+ *
+ * Note that if you need low latency, you should not use PABLIO.
+ * Use the PA_OpenStream callback technique which is lower level
+ * than PABLIO.
+ *
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pablio.h"
+#include <string.h>
+
+/*
+** Note that many of the older ISA sound cards on PCs do NOT support
+** full duplex audio (simultaneous record and playback).
+** And some only support full duplex at lower sample rates.
+*/
+#define SAMPLE_RATE (22050)
+#define NUM_SECONDS (20)
+#define SAMPLES_PER_FRAME (2)
+
+/* Select whether we will use floats or shorts. */
+#if 1
+#define SAMPLE_TYPE paFloat32
+typedef float SAMPLE;
+#else
+#define SAMPLE_TYPE paInt16
+typedef short SAMPLE;
+#endif
+
+#define NUM_ECHO_FRAMES (2*SAMPLE_RATE)
+SAMPLE samples[NUM_ECHO_FRAMES][SAMPLES_PER_FRAME] = {0.0};
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i;
+ PaError err;
+ PABLIO_Stream *aInStream;
+ PABLIO_Stream *aOutStream;
+ int index;
+
+ printf("Full duplex sound test using PABLIO\n");
+ fflush(stdout);
+
+ /* Open simplified blocking I/O layer on top of PortAudio. */
+ /* Open input first so it can start to fill buffers. */
+ err = OpenAudioStream( &aInStream, SAMPLE_RATE, SAMPLE_TYPE,
+ (PABLIO_READ | PABLIO_STEREO) );
+ if( err != paNoError ) goto error;
+ /* printf("opened input\n"); fflush(stdout); /**/
+
+ err = OpenAudioStream( &aOutStream, SAMPLE_RATE, SAMPLE_TYPE,
+ (PABLIO_WRITE | PABLIO_STEREO) );
+ if( err != paNoError ) goto error;
+ /* printf("opened output\n"); fflush(stdout); /**/
+
+ /* Process samples in the foreground. */
+ index = 0;
+ for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i++ )
+ {
+ /* Write old frame of data to output. */
+ /* samples[index][1] = (i&256) * (1.0f/256.0f); /* sawtooth */
+ WriteAudioStream( aOutStream, &samples[index][0], 1 );
+
+ /* Read one frame of data into sample array for later output. */
+ ReadAudioStream( aInStream, &samples[index][0], 1 );
+ index += 1;
+ if( index >= NUM_ECHO_FRAMES ) index = 0;
+
+ if( (i & 0xFFFF) == 0 ) printf("i = %d\n", i ); fflush(stdout); /**/
+ }
+
+ CloseAudioStream( aOutStream );
+ CloseAudioStream( aInStream );
+
+ printf("R/W echo sound test complete.\n" );
+ fflush(stdout);
+ return 0;
+
+error:
+ fprintf( stderr, "An error occured while using PortAudio\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
diff --git a/pd/portaudio_v18/pablio/test_w_saw.c b/pd/portaudio_v18/pablio/test_w_saw.c
new file mode 100644
index 00000000..ca727aa2
--- /dev/null
+++ b/pd/portaudio_v18/pablio/test_w_saw.c
@@ -0,0 +1,108 @@
+/*
+ * $Id: test_w_saw.c,v 1.1.1.1.4.1 2003/02/12 02:22:21 philburk Exp $
+ * test_w_saw.c
+ * Generate stereo sawtooth waveforms.
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses PABLIO, the Portable Audio Blocking I/O Library.
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.
+ *
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pablio.h"
+#include <string.h>
+
+#define SAMPLE_RATE (44100)
+#define NUM_SECONDS (15)
+#define SAMPLES_PER_FRAME (2)
+
+#define FREQUENCY (220.0f)
+#define PHASE_INCREMENT (2.0f * FREQUENCY / SAMPLE_RATE)
+#define FRAMES_PER_BLOCK (100)
+
+float samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME];
+float phases[SAMPLES_PER_FRAME];
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i,j;
+ PaError err;
+ PABLIO_Stream *aOutStream;
+
+ printf("Generate sawtooth waves using PABLIO.\n");
+ fflush(stdout);
+
+ /* Open simplified blocking I/O layer on top of PortAudio. */
+ err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paFloat32,
+ (PABLIO_WRITE | PABLIO_STEREO) );
+ if( err != paNoError ) goto error;
+
+ /* Initialize oscillator phases. */
+ phases[0] = 0.0;
+ phases[1] = 0.0;
+
+ for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK )
+ {
+ /* Generate sawtooth waveforms in a block for efficiency. */
+ for( j=0; j<FRAMES_PER_BLOCK; j++ )
+ {
+ /* Generate a sawtooth wave by incrementing a variable. */
+ phases[0] += PHASE_INCREMENT;
+ /* The signal range is -1.0 to +1.0 so wrap around if we go over. */
+ if( phases[0] > 1.0f ) phases[0] -= 2.0f;
+ samples[j][0] = phases[0];
+
+ /* On the second channel, generate a sawtooth wave a fifth higher. */
+ phases[1] += PHASE_INCREMENT * (3.0f / 2.0f);
+ if( phases[1] > 1.0f ) phases[1] -= 2.0f;
+ samples[j][1] = phases[1];
+ }
+
+ /* Write samples to output. */
+ WriteAudioStream( aOutStream, samples, FRAMES_PER_BLOCK );
+ }
+
+ CloseAudioStream( aOutStream );
+
+ printf("Sawtooth sound test complete.\n" );
+ fflush(stdout);
+ return 0;
+
+error:
+ fprintf( stderr, "An error occured while using PABLIO\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
diff --git a/pd/portaudio_v18/pablio/test_w_saw8.c b/pd/portaudio_v18/pablio/test_w_saw8.c
new file mode 100644
index 00000000..0f7e02e3
--- /dev/null
+++ b/pd/portaudio_v18/pablio/test_w_saw8.c
@@ -0,0 +1,106 @@
+/*
+ * $Id: test_w_saw8.c,v 1.1.1.1 2002/01/22 00:52:55 phil Exp $
+ * test_w_saw8.c
+ * Generate stereo 8 bit sawtooth waveforms.
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses PABLIO, the Portable Audio Blocking I/O Library.
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.
+ *
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pablio.h"
+#include <string.h>
+
+#define SAMPLE_RATE (22050)
+#define NUM_SECONDS (6)
+#define SAMPLES_PER_FRAME (2)
+
+
+#define FRAMES_PER_BLOCK (100)
+
+unsigned char samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME];
+unsigned char phases[SAMPLES_PER_FRAME];
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i,j;
+ PaError err;
+ PABLIO_Stream *aOutStream;
+
+ printf("Generate unsigned 8 bit sawtooth waves using PABLIO.\n");
+ fflush(stdout);
+
+ /* Open simplified blocking I/O layer on top of PortAudio. */
+ err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paUInt8,
+ (PABLIO_WRITE | PABLIO_STEREO) );
+ if( err != paNoError ) goto error;
+
+ /* Initialize oscillator phases to "ground" level for paUInt8. */
+ phases[0] = 128;
+ phases[1] = 128;
+
+ for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK )
+ {
+ /* Generate sawtooth waveforms in a block for efficiency. */
+ for( j=0; j<FRAMES_PER_BLOCK; j++ )
+ {
+ /* Generate a sawtooth wave by incrementing a variable. */
+ phases[0] += 1;
+ /* We don't have to do anything special to wrap when using paUint8 because
+ * 8 bit arithmetic automatically wraps. */
+ samples[j][0] = phases[0];
+
+ /* On the second channel, generate a higher sawtooth wave. */
+ phases[1] += 3;
+ samples[j][1] = phases[1];
+ }
+
+ /* Write samples to output. */
+ WriteAudioStream( aOutStream, samples, FRAMES_PER_BLOCK );
+ }
+
+ CloseAudioStream( aOutStream );
+
+ printf("Sawtooth sound test complete.\n" );
+ fflush(stdout);
+ return 0;
+
+error:
+ fprintf( stderr, "An error occured while using PABLIO\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
diff --git a/pd/portaudio_v18/pablio/test_w_saw_pd.c b/pd/portaudio_v18/pablio/test_w_saw_pd.c
new file mode 100644
index 00000000..d5e8f1c9
--- /dev/null
+++ b/pd/portaudio_v18/pablio/test_w_saw_pd.c
@@ -0,0 +1,108 @@
+/*
+ * $Id: test_w_saw_pd.c,v 1.1.1.1 2003-05-09 16:04:00 ggeiger Exp $
+ * test_w_saw.c
+ * Generate stereo sawtooth waveforms.
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses PABLIO, the Portable Audio Blocking I/O Library.
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.
+ *
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pablio_pd.h"
+#include <string.h>
+
+#define SAMPLE_RATE (44100)
+#define NUM_SECONDS (6)
+#define SAMPLES_PER_FRAME (2)
+
+#define FREQUENCY (220.0f)
+#define PHASE_INCREMENT (2.0f * FREQUENCY / SAMPLE_RATE)
+#define FRAMES_PER_BLOCK (100)
+
+float samples[FRAMES_PER_BLOCK][SAMPLES_PER_FRAME];
+float phases[SAMPLES_PER_FRAME];
+
+/*******************************************************************/
+int main(void);
+int main(void)
+{
+ int i,j;
+ PaError err;
+ PABLIO_Stream *aOutStream;
+
+ printf("Generate sawtooth waves using PABLIO.\n");
+ fflush(stdout);
+
+ /* Open simplified blocking I/O layer on top of PortAudio. */
+ err = OpenAudioStream( &aOutStream, SAMPLE_RATE, paFloat32,
+ PABLIO_WRITE, 2, 512, 8, -1, -1 );
+ if( err != paNoError ) goto error;
+
+ /* Initialize oscillator phases. */
+ phases[0] = 0.0;
+ phases[1] = 0.0;
+
+ for( i=0; i<(NUM_SECONDS * SAMPLE_RATE); i += FRAMES_PER_BLOCK )
+ {
+ /* Generate sawtooth waveforms in a block for efficiency. */
+ for( j=0; j<FRAMES_PER_BLOCK; j++ )
+ {
+ /* Generate a sawtooth wave by incrementing a variable. */
+ phases[0] += PHASE_INCREMENT;
+ /* The signal range is -1.0 to +1.0 so wrap around if we go over. */
+ if( phases[0] > 1.0f ) phases[0] -= 2.0f;
+ samples[j][0] = phases[0];
+
+ /* On the second channel, generate a sawtooth wave a fifth higher. */
+ phases[1] += PHASE_INCREMENT * (3.0f / 2.0f);
+ if( phases[1] > 1.0f ) phases[1] -= 2.0f;
+ samples[j][1] = phases[1];
+ }
+
+ /* Write samples to output. */
+ WriteAudioStream( aOutStream, samples, FRAMES_PER_BLOCK );
+ }
+
+ CloseAudioStream( aOutStream );
+
+ printf("Sawtooth sound test complete.\n" );
+ fflush(stdout);
+ return 0;
+
+error:
+ fprintf( stderr, "An error occured while using PABLIO\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return -1;
+}
diff --git a/pd/portmidi_osx/MSP-README.txt b/pd/portmidi_osx/MSP-README.txt
new file mode 100644
index 00000000..c48e8c8e
--- /dev/null
+++ b/pd/portmidi_osx/MSP-README.txt
@@ -0,0 +1,3 @@
+This is from a PortMidi pre-release for OSX.
+
+-MSP
diff --git a/pd/portmidi_osx/Makefile b/pd/portmidi_osx/Makefile
new file mode 100644
index 00000000..d8667355
--- /dev/null
+++ b/pd/portmidi_osx/Makefile
@@ -0,0 +1,24 @@
+CC = cc
+CFLAGS = -Wmost
+LDFLAGS = -framework Carbon -framework CoreMIDI
+OBJS = ptdarwin.o pmutil.o pmmacosx.o pmdarwin.o portmidi.o
+LIBS =
+
+all: libportmidi.a pmtest
+
+libportmidi.a: portmidi.h porttime.h pminternal.h $(OBJS)
+ rm -f libportmidi.a
+ ar rv libportmidi.a $(OBJS)
+ ranlib libportmidi.a
+
+pmtest: pmtest.c libportmidi.a
+ $(CC) $(CFLAGS) pmtest.c $(OBJS) -o pmtest $(LDFLAGS) $(LIBS)
+
+pmmacosx.o: pmmacosx.c portmidi.h pminternal.h pmmacosx.h porttime.h
+pmdarwin.o: pmdarwin.c portmidi.h pmmacosx.h
+pmutil.o: pmutil.c portmidi.h pmutil.h pminternal.h
+portmidi.o: portmidi.c portmidi.h pminternal.h
+ptdarwin.o: ptdarwin.c porttime.h portmidi.h
+
+clean:
+ rm -f pmtest *.o
diff --git a/pd/portmidi_osx/README b/pd/portmidi_osx/README
new file mode 100644
index 00000000..6a72c56f
--- /dev/null
+++ b/pd/portmidi_osx/README
@@ -0,0 +1,12 @@
+PortMidi for MacOS X / Darwin
+Jon Parise <jparise@cmu.edu>
+$Date: 2003-05-09 16:04:00 $
+
+This is the MacOS X / Darwin port of the PortMidi library from the Carnegie
+Mellon Computer Music Group. It is based on the Apple CoreAudio MIDI
+interface.
+
+This port was finished in early 2002. At this point, I consider the code
+base complete.
+
+- Jon
diff --git a/pd/portmidi_osx/pmdarwin.c b/pd/portmidi_osx/pmdarwin.c
new file mode 100644
index 00000000..3ca2c87a
--- /dev/null
+++ b/pd/portmidi_osx/pmdarwin.c
@@ -0,0 +1,36 @@
+/*
+ * PortMidi OS-dependent interface for Darwin (MacOS X)
+ * Jon Parise <jparise@cmu.edu>
+ *
+ * $Id: pmdarwin.c,v 1.1.1.1 2003-05-09 16:04:00 ggeiger Exp $
+ */
+
+/*
+ * This file only needs to implement pm_init(), which calls various
+ * routines to register the available midi devices. This file must
+ * be separate from the main portmidi.c file because it is system
+ * dependent, and it is separate from, say, pmwinmm.c, because it
+ * might need to register devices for winmm, directx, and others.
+ */
+
+#include <stdlib.h>
+#include "portmidi.h"
+#include "pmmacosx.h"
+
+PmError pm_init()
+{
+ return pm_macosx_init();
+}
+
+PmError pm_term()
+{
+ return pm_macosx_term();
+}
+
+PmDeviceID Pm_GetDefaultInputDeviceID() { return 0; };
+PmDeviceID Pm_GetDefaultOutputDeviceID() { return 0; };
+
+void *pm_alloc(size_t s) { return malloc(s); }
+
+void pm_free(void *ptr) { free(ptr); }
+
diff --git a/pd/portmidi_osx/pminternal.h b/pd/portmidi_osx/pminternal.h
new file mode 100644
index 00000000..2a92e16d
--- /dev/null
+++ b/pd/portmidi_osx/pminternal.h
@@ -0,0 +1,100 @@
+/* pminternal.h -- header for interface implementations */
+
+/* this file is included by files that implement library internals */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+/* these are defined in system-specific file */
+void *pm_alloc(size_t s);
+void pm_free(void *ptr);
+
+struct pm_internal_struct;
+
+/* these do not use PmInternal because it is not defined yet... */
+typedef PmError (*pm_write_fn)(struct pm_internal_struct *midi,
+ PmEvent *buffer, long length);
+typedef PmError (*pm_open_fn)(struct pm_internal_struct *midi,
+ void *driverInfo);
+typedef PmError (*pm_abort_fn)(struct pm_internal_struct *midi);
+typedef PmError (*pm_close_fn)(struct pm_internal_struct *midi);
+
+typedef struct {
+ pm_write_fn write;
+ pm_open_fn open;
+ pm_abort_fn abort;
+ pm_close_fn close;
+} pm_fns_node, *pm_fns_type;
+
+/* when open fails, the dictionary gets this set of functions: */
+extern pm_fns_node pm_none_dictionary;
+
+typedef struct {
+ PmDeviceInfo pub;
+ void *descriptor; /* system-specific data to open device */
+ pm_fns_type dictionary;
+} descriptor_node, *descriptor_type;
+
+
+#define pm_descriptor_max 32
+extern descriptor_node descriptors[pm_descriptor_max];
+extern int descriptor_index;
+
+
+typedef unsigned long (*time_get_proc_type)(void *time_info);
+
+typedef struct pm_internal_struct {
+ short write_flag; /* MIDI_IN, or MIDI_OUT */
+ int device_id; /* which device is open (index to descriptors) */
+ PmTimeProcPtr time_proc; /* where to get the time */
+ void *time_info; /* pass this to get_time() */
+ PmEvent *buffer; /* input or output buffer */
+ long buffer_len; /* how big is the buffer */
+ long latency; /* time delay in ms between timestamps and actual output */
+ /* set to zero to get immediate, simple blocking output */
+ /* if latency is zero, timestamps will be ignored */
+ int overflow; /* set to non-zero if input is dropped */
+ int flush; /* flag to drop incoming sysex data because of overflow */
+ int sysex_in_progress; /* use for overflow management */
+ struct pm_internal_struct *thru;
+ PmTimestamp last_msg_time; /* timestamp of last message */
+ long head;
+ long tail;
+ pm_fns_type dictionary; /* implementation functions */
+ void *descriptor; /* system-dependent state */
+} PmInternal;
+
+
+typedef struct {
+ long head;
+ long tail;
+ long len;
+ long msg_size;
+ long overflow;
+ char *buffer;
+} PmQueueRep;
+
+
+PmError pm_init(void); /* defined in a system-specific file */
+PmError pm_term(void); /* defined in a system-specific file */
+int pm_in_device(int n, char *interf, char *device);
+int pm_out_device(int n, char *interf, char *device);
+PmError none_write(PmInternal *midi, PmEvent *buffer, long length);
+PmError pm_success_fn(PmInternal *midi);
+PmError pm_fail_fn(PmInternal *midi);
+long pm_in_poll(PmInternal *midi);
+long pm_out_poll(PmInternal *midi);
+
+PmError pm_add_device(char *interf, char *name, int input, void *descriptor,
+ pm_fns_type dictionary);
+
+void pm_enqueue(PmInternal *midi, PmEvent *event);
+
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/pd/portmidi_osx/pmmacosx.c b/pd/portmidi_osx/pmmacosx.c
new file mode 100644
index 00000000..7fe8adc4
--- /dev/null
+++ b/pd/portmidi_osx/pmmacosx.c
@@ -0,0 +1,336 @@
+/*
+ * Platform interface to the MacOS X CoreMIDI framework
+ *
+ * Jon Parise <jparise@cmu.edu>
+ *
+ * $Id: pmmacosx.c,v 1.1.1.1 2003-05-09 16:04:00 ggeiger Exp $
+ */
+
+#include "portmidi.h"
+#include "pminternal.h"
+#include "porttime.h"
+#include "pmmacosx.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <CoreServices/CoreServices.h>
+#include <CoreMIDI/MIDIServices.h>
+
+#define PACKET_BUFFER_SIZE 1024
+
+static MIDIClientRef client = NULL; /* Client handle to the MIDI server */
+static MIDIPortRef portIn = NULL; /* Input port handle */
+static MIDIPortRef portOut = NULL; /* Output port handle */
+
+extern pm_fns_node pm_macosx_in_dictionary;
+extern pm_fns_node pm_macosx_out_dictionary;
+
+static int
+midi_length(long msg)
+{
+ int status, high, low;
+ static int high_lengths[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00 through 0x70 */
+ 3, 3, 3, 3, 2, 2, 3, 1 /* 0x80 through 0xf0 */
+ };
+ static int low_lengths[] = {
+ 1, 1, 3, 2, 1, 1, 1, 1, /* 0xf0 through 0xf8 */
+ 1, 1, 1, 1, 1, 1, 1, 1 /* 0xf9 through 0xff */
+ };
+
+ status = msg & 0xFF;
+ high = status >> 4;
+ low = status & 15;
+
+ return (high != 0xF0) ? high_lengths[high] : low_lengths[low];
+}
+
+static PmTimestamp
+get_timestamp(PmInternal *midi)
+{
+ PmTimeProcPtr time_proc;
+
+ /* Set the time procedure accordingly */
+ time_proc = midi->time_proc;
+ if (time_proc == NULL) {
+ time_proc = Pt_Time;
+ }
+
+ return (*time_proc)(midi->time_info);
+}
+
+/* called when MIDI packets are received */
+static void
+readProc(const MIDIPacketList *newPackets, void *refCon, void *connRefCon)
+{
+ PmInternal *midi;
+ PmEvent event;
+ MIDIPacket *packet;
+ unsigned int packetIndex;
+
+ /* Retrieve the context for this connection */
+ midi = (PmInternal *) connRefCon;
+
+ packet = (MIDIPacket *) &newPackets->packet[0];
+ for (packetIndex = 0; packetIndex < newPackets->numPackets; packetIndex++) {
+
+ /* Build the PmMessage for the PmEvent structure */
+ switch (packet->length) {
+ case 1:
+ event.message = Pm_Message(packet->data[0], 0, 0);
+ break;
+ case 2:
+ event.message = Pm_Message(packet->data[0], packet->data[1], 0);
+ break;
+ case 3:
+ event.message = Pm_Message(packet->data[0], packet->data[1],
+ packet->data[2]);
+ break;
+ default:
+ /* Skip packets that are too large to fit in a PmMessage */
+ continue;
+ }
+
+ /* Set the timestamp and dispatch this message */
+ event.timestamp = get_timestamp(midi);
+ pm_enqueue(midi, &event);
+
+ /* Advance to the next packet in the packet list */
+ packet = MIDIPacketNext(packet);
+ }
+}
+
+static PmError
+midi_in_open(PmInternal *midi, void *driverInfo)
+{
+ MIDIEndpointRef endpoint;
+
+ endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
+ if (endpoint == NULL) {
+ return pmInvalidDeviceId;
+ }
+
+ if (MIDIPortConnectSource(portIn, endpoint, midi) != noErr) {
+ return pmHostError;
+ }
+
+ return pmNoError;
+}
+
+static PmError
+midi_in_close(PmInternal *midi)
+{
+ MIDIEndpointRef endpoint;
+
+ endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
+ if (endpoint == NULL) {
+ return pmInvalidDeviceId;
+ }
+
+ if (MIDIPortDisconnectSource(portIn, endpoint) != noErr) {
+ return pmHostError;
+ }
+
+ return pmNoError;
+}
+
+static PmError
+midi_out_open(PmInternal *midi, void *driverInfo)
+{
+ /*
+ * MIDISent() only requires an output port (portOut) and a valid MIDI
+ * endpoint (which we've already created and stored in the PmInternal
+ * structure). Therefore, no additional work needs to be done here to
+ * open the device for output.
+ */
+
+ return pmNoError;
+}
+
+static PmError
+midi_out_close(PmInternal *midi)
+{
+ return pmNoError;
+}
+
+static PmError
+midi_abort(PmInternal *midi)
+{
+ return pmNoError;
+}
+
+static PmError
+midi_write(PmInternal *midi, PmEvent *events, long length)
+{
+ Byte packetBuffer[PACKET_BUFFER_SIZE];
+ MIDIEndpointRef endpoint;
+ MIDIPacketList *packetList;
+ MIDIPacket *packet;
+ MIDITimeStamp timestamp;
+ PmTimeProcPtr time_proc;
+ PmEvent event;
+ unsigned int pm_time;
+ unsigned int eventIndex;
+ unsigned int messageLength;
+ Byte message[3];
+
+ endpoint = (MIDIEndpointRef) descriptors[midi->device_id].descriptor;
+ if (endpoint == NULL) {
+ return pmInvalidDeviceId;
+ }
+
+ /* Make sure the packetBuffer is large enough */
+ if (length > PACKET_BUFFER_SIZE) {
+ return pmHostError;
+ }
+
+ /*
+ * Initialize the packet list. Each packet contains bytes that are to
+ * be played at the same time.
+ */
+ packetList = (MIDIPacketList *) packetBuffer;
+ if ((packet = MIDIPacketListInit(packetList)) == NULL) {
+ return pmHostError;
+ }
+
+ /* Set the time procedure accordingly */
+ time_proc = midi->time_proc;
+ if (time_proc == NULL) {
+ time_proc = Pt_Time;
+ }
+
+ /* Extract the event data and pack it into the message buffer */
+ for (eventIndex = 0; eventIndex < length; eventIndex++) {
+ event = events[eventIndex];
+
+ /* Compute the timestamp */
+ pm_time = (*time_proc)(midi->time_info);
+ timestamp = pm_time + midi->latency;
+
+ messageLength = midi_length(event.message);
+ message[0] = Pm_MessageStatus(event.message);
+ message[1] = Pm_MessageData1(event.message);
+ message[2] = Pm_MessageData2(event.message);
+
+ /* Add this message to the packet list */
+ packet = MIDIPacketListAdd(packetList, sizeof(packetBuffer), packet,
+ timestamp, messageLength, message);
+ if (packet == NULL) {
+ return pmHostError;
+ }
+ }
+
+ if (MIDISend(portOut, endpoint, packetList) != noErr) {
+ return pmHostError;
+ }
+
+ return pmNoError;
+}
+
+pm_fns_node pm_macosx_in_dictionary = {
+ none_write,
+ midi_in_open,
+ midi_abort,
+ midi_in_close
+};
+
+pm_fns_node pm_macosx_out_dictionary = {
+ midi_write,
+ midi_out_open,
+ midi_abort,
+ midi_out_close
+};
+
+PmError
+pm_macosx_init(void)
+{
+ OSStatus status;
+ ItemCount numDevices, numInputs, numOutputs;
+ MIDIEndpointRef endpoint;
+ CFStringEncoding defaultEncoding;
+ CFStringRef deviceName;
+ char nameBuf[256];
+ int i;
+
+ /* Determine the number of MIDI devices on the system */
+ numDevices = MIDIGetNumberOfDevices();
+ numInputs = MIDIGetNumberOfSources();
+ numOutputs = MIDIGetNumberOfDestinations();
+
+ /* Return prematurely if no devices exist on the system */
+ if (numDevices <= 0) {
+ return pmHostError;
+ }
+
+ /* Determine the default system character encording */
+ defaultEncoding = CFStringGetSystemEncoding();
+
+ /* Iterate over the MIDI input devices */
+ for (i = 0; i < numInputs; i++) {
+ endpoint = MIDIGetSource(i);
+ if (endpoint == NULL) {
+ continue;
+ }
+
+ /* Get the name of this device */
+ MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &deviceName);
+ CFStringGetCString(deviceName, nameBuf, 256, defaultEncoding);
+ CFRelease(deviceName);
+
+ /* Register this device with PortMidi */
+ pm_add_device("CoreMIDI", nameBuf, TRUE, (void *)endpoint,
+ &pm_macosx_in_dictionary);
+ }
+
+ /* Iterate over the MIDI output devices */
+ for (i = 0; i < numOutputs; i++) {
+ endpoint = MIDIGetDestination(i);
+ if (endpoint == NULL) {
+ continue;
+ }
+
+ /* Get the name of this device */
+ MIDIObjectGetStringProperty(endpoint, kMIDIPropertyName, &deviceName);
+ CFStringGetCString(deviceName, nameBuf, 256, defaultEncoding);
+ CFRelease(deviceName);
+
+ /* Register this device with PortMidi */
+ pm_add_device("CoreMIDI", nameBuf, FALSE, (void *)endpoint,
+ &pm_macosx_out_dictionary);
+ }
+
+ /* Initialize the client handle */
+ status = MIDIClientCreate(CFSTR("PortMidi"), NULL, NULL, &client);
+ if (status != noErr) {
+ fprintf(stderr, "Could not initialize client: %d\n", (int)status);
+ return pmHostError;
+ }
+
+ /* Create the input port */
+ status = MIDIInputPortCreate(client, CFSTR("Input port"), readProc, NULL,
+ &portIn);
+ if (status != noErr) {
+ fprintf(stderr, "Could not create input port: %d\n", (int)status);
+ return pmHostError;
+ }
+
+ /* Create the output port */
+ status = MIDIOutputPortCreate(client, CFSTR("Output port"), &portOut);
+ if (status != noErr) {
+ fprintf(stderr, "Could not create output port: %d\n", (int)status);
+ return pmHostError;
+ }
+
+ return pmNoError;
+}
+
+PmError
+pm_macosx_term(void)
+{
+ if (client != NULL) MIDIClientDispose(client);
+ if (portIn != NULL) MIDIPortDispose(portIn);
+ if (portOut != NULL) MIDIPortDispose(portOut);
+
+ return pmNoError;
+}
diff --git a/pd/portmidi_osx/pmmacosx.h b/pd/portmidi_osx/pmmacosx.h
new file mode 100644
index 00000000..15e9551d
--- /dev/null
+++ b/pd/portmidi_osx/pmmacosx.h
@@ -0,0 +1,4 @@
+/* system-specific definitions */
+
+PmError pm_macosx_init(void);
+PmError pm_macosx_term(void);
diff --git a/pd/portmidi_osx/pmtest b/pd/portmidi_osx/pmtest
new file mode 100644
index 00000000..8adc5334
--- /dev/null
+++ b/pd/portmidi_osx/pmtest
Binary files differ
diff --git a/pd/portmidi_osx/pmtest.c b/pd/portmidi_osx/pmtest.c
new file mode 100644
index 00000000..5628d25e
--- /dev/null
+++ b/pd/portmidi_osx/pmtest.c
@@ -0,0 +1,136 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "portmidi.h"
+#include "porttime.h"
+#include "pminternal.h"
+
+#define LATENCY 0
+#define NUM_ECHOES 10
+
+int
+main()
+{
+ int i = 0;
+ int n = 0;
+ PmStream *midi_in;
+ PmStream *midi_out;
+ PmError err;
+ char line[80];
+ PmEvent buffer[NUM_ECHOES];
+ int transpose;
+ int delay;
+ int status, data1, data2;
+ int statusprefix;
+
+
+
+ /* always start the timer before you start midi */
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+
+
+ for (i = 0; i < Pm_CountDevices(); i++) {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ printf("%d: %s, %s", i, info->interf, info->name);
+ if (info->input) printf(" (input)");
+ if (info->output) printf(" (output)");
+ printf("\n");
+ }
+
+ /* OPEN INPUT DEVICE */
+
+ printf("Type input number: ");
+ while (n != 1) {
+ n = scanf("%d", &i);
+ gets(line);
+ }
+
+ err = Pm_OpenInput(&midi_in, i, NULL, 100, NULL, NULL, NULL);
+ if (err) {
+ printf("could not open midi device: %s\n", Pm_GetErrorText(err));
+ exit(1);
+ }
+ printf("Midi Input opened.\n");
+
+ /* OPEN OUTPUT DEVICE */
+
+ printf("Type output number: ");
+ n = 0;
+ while (n != 1) {
+ n = scanf("%d", &i);
+ gets(line);
+ }
+
+ err = Pm_OpenOutput(&midi_out, i, NULL, 0, NULL, NULL, LATENCY);
+ if (err) {
+ printf("could not open midi device: %s\n", Pm_GetErrorText(err));
+ exit(1);
+ }
+ printf("Midi Output opened with %d ms latency.\n", LATENCY);
+
+
+
+ /* Get input from user for parameters */
+ printf("Type number of milliseconds for echoes: ");
+ n = 0;
+ while (n != 1) {
+ n = scanf("%d", &delay);
+ gets(line);
+ }
+
+ printf("Type number of semitones to transpose up: ");
+ n = 0;
+ while (n != 1) {
+ n = scanf("%d", &transpose);
+ gets(line);
+ }
+
+
+
+ /* loop, echoing input back transposed with multiple taps */
+
+ printf("Press C2 on the keyboard (2 octaves below middle C) to quit.\nWaiting for MIDI input...\n");
+
+ do {
+ err = Pm_Read(midi_in, buffer, 1);
+ if (err == 0) continue; /* no bytes read. */
+
+ /* print a hash mark for each event read. */
+ printf("#");
+ fflush(stdout);
+
+ status = Pm_MessageStatus(buffer[0].message);
+ data1 = Pm_MessageData1(buffer[0].message);
+ data2 = Pm_MessageData2(buffer[0].message);
+ statusprefix = status >> 4;
+
+ /* ignore messages other than key-down and key-up */
+ if ((statusprefix != 0x9) && (statusprefix != 0x8)) continue;
+
+ printf("\nReceived key message = %X %X %X, at time %ld\n", status, data1, data2, buffer[0].timestamp);
+ fflush(stdout);
+
+ /* immediately send the echoes to PortMIDI */
+ for (i = 1; i < NUM_ECHOES; i++) {
+ buffer[i].message = Pm_Message(status, data1 + transpose, data2 >> i);
+ buffer[i].timestamp = buffer[0].timestamp + (i * delay);
+ }
+ Pm_Write(midi_out, buffer, NUM_ECHOES);
+ } while (data1 != 36); /* quit when C2 is pressed */
+
+ printf("Key C2 pressed. Exiting...\n");
+ fflush(stdout);
+
+ /* Give the echoes time to finish before quitting. */
+ sleep(((NUM_ECHOES * delay) / 1000) + 1);
+
+ Pm_Close(midi_in);
+ Pm_Close(midi_out);
+
+ printf("Done.\n");
+ return 0;
+}
+
+
+
diff --git a/pd/portmidi_osx/pmutil.c b/pd/portmidi_osx/pmutil.c
new file mode 100644
index 00000000..f3582a42
--- /dev/null
+++ b/pd/portmidi_osx/pmutil.c
@@ -0,0 +1,86 @@
+/* pmutil.c -- some helpful utilities for building midi
+ applications that use PortMidi
+ */
+#include "stdlib.h"
+#include "memory.h"
+#include "portmidi.h"
+#include "pmutil.h"
+#include "pminternal.h"
+
+
+PmQueue *Pm_QueueCreate(long num_msgs, long bytes_per_msg)
+{
+ PmQueueRep *queue = (PmQueueRep *) malloc(sizeof(PmQueueRep));
+ if (!queue) return NULL;
+ queue->len = num_msgs * bytes_per_msg;
+ queue->buffer = malloc(queue->len);
+ if (!queue->buffer) {
+ free(queue);
+ return NULL;
+ }
+ queue->head = 0;
+ queue->tail = 0;
+ queue->msg_size = bytes_per_msg;
+ queue->overflow = FALSE;
+ return queue;
+}
+
+
+PmError Pm_QueueDestroy(PmQueue *q)
+{
+ PmQueueRep *queue = (PmQueueRep *) q;
+ if (!queue || !queue->buffer) return pmBadPtr;
+ free(queue->buffer);
+ free(queue);
+ return pmNoError;
+}
+
+
+PmError Pm_Dequeue(PmQueue *q, void *msg)
+{
+ long head;
+ PmQueueRep *queue = (PmQueueRep *) q;
+ if (queue->overflow) {
+ queue->overflow = FALSE;
+ return pmBufferOverflow;
+ }
+ head = queue->head; /* make sure this is written after access */
+ if (head == queue->tail) return 0;
+ memcpy(msg, queue->buffer + head, queue->msg_size);
+ head += queue->msg_size;
+ if (head == queue->len) head = 0;
+ queue->head = head;
+ return 1; /* success */
+}
+
+
+/* source should not enqueue data if overflow is set */
+/**/
+PmError Pm_Enqueue(PmQueue *q, void *msg)
+{
+ PmQueueRep *queue = (PmQueueRep *) q;
+ long tail = queue->tail;
+ memcpy(queue->buffer + tail, msg, queue->msg_size);
+ tail += queue->msg_size;
+ if (tail == queue->len) tail = 0;
+ if (tail == queue->head) {
+ queue->overflow = TRUE;
+ /* do not update tail, so message is lost */
+ return pmBufferOverflow;
+ }
+ queue->tail = tail;
+ return pmNoError;
+}
+
+
+int Pm_QueueFull(PmQueue *q)
+{
+ PmQueueRep *queue = (PmQueueRep *) q;
+ long tail = queue->tail;
+ tail += queue->msg_size;
+ if (tail == queue->len) {
+ tail = 0;
+ }
+ return (tail == queue->head);
+}
+
diff --git a/pd/portmidi_osx/pmutil.h b/pd/portmidi_osx/pmutil.h
new file mode 100644
index 00000000..b6268ed3
--- /dev/null
+++ b/pd/portmidi_osx/pmutil.h
@@ -0,0 +1,44 @@
+/* pmutil.h -- some helpful utilities for building midi
+ applications that use PortMidi
+ */
+
+typedef void PmQueue;
+
+/*
+ A single-reader, single-writer queue is created by
+ Pm_QueueCreate(), which takes the number of messages and
+ the message size as parameters. The queue only accepts
+ fixed sized messages. Returns NULL if memory cannot be allocated.
+
+ Pm_QueueDestroy() destroys the queue and frees its storage.
+ */
+
+PmQueue *Pm_QueueCreate(long num_msgs, long bytes_per_msg);
+PmError Pm_QueueDestroy(PmQueue *queue);
+
+/*
+ Pm_Dequeue() removes one item from the queue, copying it into msg.
+ Returns 1 if successful, and 0 if the queue is empty.
+ Returns pmBufferOverflow and clears the overflow flag if
+ the flag is set.
+ */
+PmError Pm_Dequeue(PmQueue *queue, void *msg);
+
+
+/*
+ Pm_Enqueue() inserts one item into the queue, copying it from msg.
+ Returns pmNoError if successful and pmBufferOverflow if the queue was
+ already full. If pmBufferOverflow is returned, the overflow flag is set.
+ */
+PmError Pm_Enqueue(PmQueue *queue, void *msg);
+
+
+/*
+ Pm_QueueFull() returns non-zero if the queue is full
+ Pm_QueueEmpty() returns non-zero if the queue is empty
+
+ Either condition may change immediately because a parallel
+ enqueue or dequeue operation could be in progress.
+ */
+int Pm_QueueFull(PmQueue *queue);
+#define Pm_QueueEmpty(m) (m->head == m->tail)
diff --git a/pd/portmidi_osx/portmidi.c b/pd/portmidi_osx/portmidi.c
new file mode 100644
index 00000000..c2a32ae7
--- /dev/null
+++ b/pd/portmidi_osx/portmidi.c
@@ -0,0 +1,358 @@
+#include "stdlib.h"
+#include "portmidi.h"
+#include "pminternal.h"
+
+#define is_empty(midi) ((midi)->tail == (midi)->head)
+
+static int pm_initialized = FALSE;
+
+int descriptor_index = 0;
+descriptor_node descriptors[pm_descriptor_max];
+
+
+/* pm_add_device -- describe interface/device pair to library
+ *
+ * This is called at intialization time, once for each
+ * interface (e.g. DirectSound) and device (e.g. SoundBlaster 1)
+ * The strings are retained but NOT COPIED, so do not destroy them!
+ *
+ * returns pmInvalidDeviceId if device memory is exceeded
+ * otherwise returns pmNoError
+ */
+PmError pm_add_device(char *interf, char *name, int input,
+ void *descriptor, pm_fns_type dictionary)
+{
+ if (descriptor_index >= pm_descriptor_max) {
+ return pmInvalidDeviceId;
+ }
+ descriptors[descriptor_index].pub.interf = interf;
+ descriptors[descriptor_index].pub.name = name;
+ descriptors[descriptor_index].pub.input = input;
+ descriptors[descriptor_index].pub.output = !input;
+ descriptors[descriptor_index].descriptor = descriptor;
+ descriptors[descriptor_index].dictionary = dictionary;
+ descriptor_index++;
+ return pmNoError;
+}
+
+
+PmError Pm_Initialize( void )
+{
+ if (!pm_initialized) {
+ PmError err = pm_init(); /* defined by implementation specific file */
+ if (err) return err;
+ pm_initialized = TRUE;
+ }
+ return pmNoError;
+}
+
+
+PmError Pm_Terminate( void )
+{
+ PmError err = pmNoError;
+ if (pm_initialized) {
+ err = pm_term(); /* defined by implementation specific file */
+ /* note that even when pm_term() fails, we mark portmidi as
+ not initialized */
+ pm_initialized = FALSE;
+ }
+ return err;
+}
+
+
+int Pm_CountDevices( void )
+{
+ PmError err = Pm_Initialize();
+ if (err) return err;
+
+ return descriptor_index;
+}
+
+
+const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id )
+{
+ PmError err = Pm_Initialize();
+ if (err) return NULL;
+
+ if (id >= 0 && id < descriptor_index) {
+ return &descriptors[id].pub;
+ }
+ return NULL;
+}
+
+
+/* failure_fn -- "noop" function pointer */
+/**/
+PmError failure_fn(PmInternal *midi)
+{
+ return pmBadPtr;
+}
+
+
+/* pm_success_fn -- "noop" function pointer */
+/**/
+PmError pm_success_fn(PmInternal *midi)
+{
+ return pmNoError;
+}
+
+
+PmError none_write(PmInternal *midi, PmEvent *buffer, long length)
+{
+ return length; /* if we return 0, caller might get into a loop */
+}
+
+PmError pm_fail_fn(PmInternal *midi)
+{
+ return pmBadPtr;
+}
+
+static PmError none_open(PmInternal *midi, void *driverInfo)
+{
+ return pmBadPtr;
+}
+
+#define none_abort pm_fail_fn
+
+#define none_close pm_fail_fn
+
+
+pm_fns_node pm_none_dictionary = {
+ none_write, none_open,
+ none_abort, none_close };
+
+
+/* Pm_Read -- read up to length longs from source into buffer */
+/*
+ * returns number of longs actually read, or error code
+ When the reader wants data:
+ if overflow_flag:
+ do not get anything
+ empty the buffer (read_ptr = write_ptr)
+ clear overflow_flag
+ return pmBufferOverflow
+ get data
+ return number of messages
+
+
+ */
+PmError Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length)
+{
+ PmInternal *midi = (PmInternal *) stream;
+ int n = 0;
+ long head = midi->head;
+ while (head != midi->tail && n < length) {
+ *buffer++ = midi->buffer[head++];
+ if (head == midi->buffer_len) head = 0;
+ n++;
+ }
+ midi->head = head;
+ if (midi->overflow) {
+ midi->head = midi->tail;
+ midi->overflow = FALSE;
+ return pmBufferOverflow;
+ }
+ return n;
+}
+
+
+PmError Pm_Poll( PortMidiStream *stream )
+{
+ PmInternal *midi = (PmInternal *) stream;
+ return midi->head != midi->tail;
+}
+
+
+PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length)
+{
+ PmInternal *midi = (PmInternal *) stream;
+ return (*midi->dictionary->write)(midi, buffer, length);
+}
+
+
+PmError Pm_WriteShort( PortMidiStream *stream, long when, long msg)
+{
+ PmEvent event;
+ event.timestamp = when;
+ event.message = msg;
+ return Pm_Write(stream, &event, 1);
+}
+
+
+PmError Pm_OpenInput( PortMidiStream** stream,
+ PmDeviceID inputDevice,
+ void *inputDriverInfo,
+ long bufferSize,
+ PmTimeProcPtr time_proc,
+ void *time_info,
+ PmStream *thru)
+{
+ PmInternal *midi;
+
+ PmError err = Pm_Initialize();
+ if (err) return err;
+
+ if (inputDevice < 0 || inputDevice >= descriptor_index) {
+ return pmInvalidDeviceId;
+ }
+
+ if (!descriptors[inputDevice].pub.input) {
+ return pmInvalidDeviceId;
+ }
+
+ midi = (PmInternal *) malloc(sizeof(PmInternal));
+ *stream = midi;
+ if (!midi) return pmInsufficientMemory;
+
+ midi->head = 0;
+ midi->tail = 0;
+ midi->dictionary = &pm_none_dictionary;
+ midi->overflow = FALSE;
+ midi->flush = FALSE;
+ midi->sysex_in_progress = FALSE;
+ midi->buffer_len = bufferSize;
+ midi->buffer = (PmEvent *) pm_alloc(sizeof(PmEvent) * midi->buffer_len);
+ if (!midi->buffer) return pmInsufficientMemory;
+ midi->latency = 0;
+ midi->thru = thru;
+ midi->time_proc = time_proc;
+ midi->time_info = time_info;
+ midi->device_id = inputDevice;
+ midi->dictionary = descriptors[inputDevice].dictionary;
+ midi->write_flag = FALSE;
+ err = (*midi->dictionary->open)(midi, inputDriverInfo);
+ if (err) {
+ pm_free(midi->buffer);
+ *stream = NULL;
+ }
+ return err;
+}
+
+
+PmError Pm_OpenOutput( PortMidiStream** stream,
+ PmDeviceID outputDevice,
+ void *outputDriverInfo,
+ long bufferSize,
+ PmTimeProcPtr time_proc,
+ void *time_info,
+ long latency )
+{
+ PmInternal *midi;
+
+ PmError err = Pm_Initialize();
+ if (err) return err;
+
+ if (outputDevice < 0 || outputDevice >= descriptor_index) {
+ return pmInvalidDeviceId;
+ }
+
+ if (!descriptors[outputDevice].pub.output) {
+ return pmInvalidDeviceId;
+ }
+
+ midi = (PmInternal *) pm_alloc(sizeof(PmInternal));
+ *stream = midi;
+ if (!midi) return pmInsufficientMemory;
+
+ midi->head = 0;
+ midi->tail = 0;
+ midi->buffer_len = bufferSize;
+ midi->buffer = NULL;
+ midi->device_id = outputDevice;
+ midi->dictionary = descriptors[outputDevice].dictionary;
+ midi->time_proc = time_proc;
+ midi->time_info = time_info;
+ midi->latency = latency;
+ midi->write_flag = TRUE;
+ err = (*midi->dictionary->open)(midi, outputDriverInfo);
+ if (err) {
+ *stream = NULL;
+ pm_free(midi); // Fixed by Ning Hu, Sep.2001
+ }
+ return err;
+}
+
+
+PmError Pm_Abort( PortMidiStream* stream )
+{
+ PmInternal *midi = (PmInternal *) stream;
+ return (*midi->dictionary->abort)(midi);
+}
+
+
+PmError Pm_Close( PortMidiStream *stream )
+{
+ PmInternal *midi = (PmInternal *) stream;
+ return (*midi->dictionary->close)(midi);
+}
+
+
+const char *Pm_GetErrorText( PmError errnum )
+{
+ const char *msg;
+
+ switch(errnum)
+ {
+ case pmNoError: msg = "Success"; break;
+ case pmHostError: msg = "Host error."; break;
+ case pmInvalidDeviceId: msg = "Invalid device ID."; break;
+ case pmInsufficientMemory: msg = "Insufficient memory."; break;
+ case pmBufferTooSmall: msg = "Buffer too small."; break;
+ case pmBadPtr: msg = "Bad pointer."; break;
+ case pmInternalError: msg = "Internal PortMidi Error."; break;
+ default: msg = "Illegal error number."; break;
+ }
+ return msg;
+}
+
+
+long pm_next_time(PmInternal *midi)
+{
+ return midi->buffer[midi->head].timestamp;
+}
+
+
+/* source should not enqueue data if overflow is set */
+/*
+ When producer has data to enqueue:
+ if buffer is full:
+ set overflow_flag and flush_flag
+ return
+ else if overflow_flag:
+ return
+ else if flush_flag:
+ if sysex message is in progress:
+ return
+ else:
+ clear flush_flag
+ // fall through to enqueue data
+ enqueue the data
+
+ */
+void pm_enqueue(PmInternal *midi, PmEvent *event)
+{
+ long tail = midi->tail;
+ midi->buffer[tail++] = *event;
+ if (tail == midi->buffer_len) tail = 0;
+ if (tail == midi->head || midi->overflow) {
+ midi->overflow = TRUE;
+ midi->flush = TRUE;
+ return;
+ }
+ if (midi->flush) {
+ if (midi->sysex_in_progress) return;
+ else midi->flush = FALSE;
+ }
+ midi->tail = tail;
+}
+
+
+int pm_queue_full(PmInternal *midi)
+{
+ long tail = midi->tail + 1;
+ if (tail == midi->buffer_len) tail = 0;
+ return tail == midi->head;
+}
+
+
+
diff --git a/pd/portmidi_osx/portmidi.h b/pd/portmidi_osx/portmidi.h
new file mode 100644
index 00000000..3e648c90
--- /dev/null
+++ b/pd/portmidi_osx/portmidi.h
@@ -0,0 +1,338 @@
+#ifndef PORT_MIDI_H
+#define PORT_MIDI_H
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * PortMidi Portable Real-Time Audio Library
+ * PortMidi API Header File
+ * Latest version available at: http://www.cs.cmu.edu/~music/portmidi/
+ *
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ * Copyright (c) 2001 Roger B. Dannenberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* CHANGELOG FOR PORTMIDI -- THIS VERSION IS 1.0
+ *
+ * 21Jan02 RBD Added tests in Pm_OpenInput() and Pm_OpenOutput() to
+ * prevent opening an input as output and vice versa.
+ * Added comments and documentation.
+ * Implemented Pm_Terminate().
+ */
+
+#ifndef FALSE
+ #define FALSE 0
+#endif
+#ifndef TRUE
+ #define TRUE 1
+#endif
+
+
+typedef enum {
+ pmNoError = 0,
+
+ pmHostError = -10000,
+ pmInvalidDeviceId, /* out of range or
+ output device when input is requested or
+ input device when output is requested */
+ //pmInvalidFlag,
+ pmInsufficientMemory,
+ pmBufferTooSmall,
+ pmBufferOverflow,
+ pmBadPtr,
+ pmInternalError
+} PmError;
+
+/*
+ Pm_Initialize() is the library initialisation function - call this before
+ using the library.
+*/
+
+PmError Pm_Initialize( void );
+
+/*
+ Pm_Terminate() is the library termination function - call this after
+ using the library.
+*/
+
+PmError Pm_Terminate( void );
+
+/*
+ Return host specific error number. All host-specific errors are translated
+ to the single error class pmHostError. To find out the original error
+ number, call Pm_GetHostError().
+ This can be called after a function returns a PmError equal to pmHostError.
+*/
+int Pm_GetHostError();
+
+/*
+ Translate the error number into a human readable message.
+*/
+const char *Pm_GetErrorText( PmError errnum );
+
+
+/*
+ Device enumeration mechanism.
+
+ Device ids range from 0 to Pm_CountDevices()-1.
+
+ Devices may support input, output or both. Device 0 is always the "default"
+ device. Other platform specific devices are specified by positive device
+ ids.
+*/
+
+typedef int PmDeviceID;
+#define pmNoDevice -1
+
+typedef struct {
+ int structVersion;
+ const char *interf;
+ const char *name;
+ int input; /* true iff input is available */
+ int output; /* true iff output is available */
+} PmDeviceInfo;
+
+
+int Pm_CountDevices( void );
+/*
+ Pm_GetDefaultInputDeviceID(), Pm_GetDefaultOutputDeviceID()
+
+ Return the default device ID or pmNoDevice if there is no devices.
+ The result can be passed to Pm_OpenMidi().
+
+ On the PC, the user can specify a default device by
+ setting an environment variable. For example, to use device #1.
+
+ set PM_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ID by using
+ the supplied application "pm_devs".
+*/
+PmDeviceID Pm_GetDefaultInputDeviceID( void );
+PmDeviceID Pm_GetDefaultOutputDeviceID( void );
+
+/*
+ PmTimestamp is used to represent a millisecond clock with arbitrary
+ start time. The type is used for all MIDI timestampes and clocks.
+*/
+
+typedef long PmTimestamp;
+
+/* TRUE if t1 before t2? */
+#define PmBefore(t1,t2) ((t1-t2) < 0)
+
+
+/*
+ Pm_GetDeviceInfo() returns a pointer to a PmDeviceInfo structure
+ referring to the device specified by id.
+ If id is out of range the function returns NULL.
+
+ The returned structure is owned by the PortMidi implementation and must
+ not be manipulated or freed. The pointer is guaranteed to be valid
+ between calls to Pm_Initialize() and Pm_Terminate().
+*/
+
+const PmDeviceInfo* Pm_GetDeviceInfo( PmDeviceID id );
+
+
+/*
+ A single PortMidiStream is a descriptor for an open MIDI device.
+*/
+
+typedef void PortMidiStream;
+#define PmStream PortMidiStream
+
+typedef PmTimestamp (*PmTimeProcPtr)(void *time_info);
+
+
+/*
+ Pm_Open() opens a device; for either input or output.
+
+ Port is the address of a PortMidiStream pointer which will receive
+ a pointer to the newly opened stream.
+
+ inputDevice is the id of the device used for input (see PmDeviceID above.)
+
+ inputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or handle processing.
+ inputDriverInfo is never required for correct operation. If not used
+ inputDriverInfo should be NULL.
+
+ outputDevice is the id of the device used for output (see PmDeviceID above.)
+
+ outputDriverInfo is a pointer to an optional driver specific data structure
+ containing additional information for device setup or handle processing.
+ outputDriverInfo is never required for correct operation. If not used
+ outputDriverInfo should be NULL.
+
+ latency is the delay in milliseconds applied to timestamps to determine
+ when the output should actually occur.
+
+ time_proc is a pointer to a procedure that returns time in milliseconds. It
+ may be NULL, in which case a default millisecond timebase is used.
+
+ time_info is a pointer passed to time_proc.
+
+ thru points to a PmMidi descriptor opened for output; Midi input will be
+ copied to this output. To disable Midi thru, use NULL.
+
+ return value:
+ Upon success Pm_Open() returns PmNoError and places a pointer to a
+ valid PortMidiStream in the stream argument.
+ If a call to Pm_Open() fails a nonzero error code is returned (see
+ PMError above) and the value of port is invalid.
+
+*/
+
+PmError Pm_OpenInput( PortMidiStream** stream,
+ PmDeviceID inputDevice,
+ void *inputDriverInfo,
+ long bufferSize,
+ PmTimeProcPtr time_proc,
+ void *time_info,
+ PmStream* thru );
+
+
+PmError Pm_OpenOutput( PortMidiStream** stream,
+ PmDeviceID outputDevice,
+ void *outputDriverInfo,
+ long bufferSize,
+ PmTimeProcPtr time_proc,
+ void *time_info,
+ long latency );
+
+
+/*
+ Pm_Abort() terminates outgoing messages immediately
+ */
+PmError Pm_Abort( PortMidiStream* stream );
+
+/*
+ Pm_Close() closes a midi stream, flushing any pending buffers.
+*/
+
+PmError Pm_Close( PortMidiStream* stream );
+
+
+/*
+ Pm_Message() encodes a short Midi message into a long word. If data1
+ and/or data2 are not present, use zero. The port parameter is the
+ index of the Midi port if the device supports more than one.
+
+ Pm_MessagePort(), Pm_MessageStatus(), Pm_MessageData1(), and
+ Pm_MessageData2() extract fields from a long-encoded midi message.
+*/
+
+#define Pm_Message(status, data1, data2) \
+ ((((data2) << 16) & 0xFF0000) | \
+ (((data1) << 8) & 0xFF00) | \
+ ((status) & 0xFF))
+
+#define Pm_MessageStatus(msg) ((msg) & 0xFF)
+#define Pm_MessageData1(msg) (((msg) >> 8) & 0xFF)
+#define Pm_MessageData2(msg) (((msg) >> 16) & 0xFF)
+
+/* All midi data comes in the form of PmEvent structures. A sysex
+ message is encoded as a sequence of PmEvent structures, with each
+ structure carrying 4 bytes of the message, i.e. only the first
+ PmEvent carries the status byte.
+
+ When receiving sysex messages, the sysex message is terminated
+ by either an EOX status byte (anywhere in the 4 byte message) or
+ by a non-real-time status byte in the low order byte of message.
+ If you get a non-real-time status byte, it means the sysex message
+ was somehow truncated. It is permissible to interleave real-time
+ messages within sysex messages.
+ */
+
+typedef long PmMessage;
+
+typedef struct {
+ PmMessage message;
+ PmTimestamp timestamp;
+} PmEvent;
+
+
+/*
+ Pm_Read() retrieves midi data into a buffer, and returns the number
+ of events read. Result is a non-negative number unless an error occurs,
+ in which case a PmError value will be returned.
+
+ Buffer Overflow
+
+ The problem: if an input overflow occurs, data will be lost, ultimately
+ because there is no flow control all the way back to the data source.
+ When data is lost, the receiver should be notified and some sort of
+ graceful recovery should take place, e.g. you shouldn't resume receiving
+ in the middle of a long sysex message.
+
+ With a lock-free fifo, which is pretty much what we're stuck with to
+ enable portability to the Mac, it's tricky for the producer and consumer
+ to synchronously reset the buffer and resume normal operation.
+
+ Solution: the buffer managed by PortMidi will be flushed when an overflow
+ occurs. The consumer (Pm_Read()) gets an error message (pmBufferOverflow)
+ and ordinary processing resumes as soon as a new message arrives. The
+ remainder of a partial sysex message is not considered to be a "new
+ message" and will be flushed as well.
+
+*/
+
+PmError Pm_Read( PortMidiStream *stream, PmEvent *buffer, long length );
+
+/*
+ Pm_Poll() tests whether input is available, returning TRUE, FALSE, or
+ an error value.
+*/
+
+PmError Pm_Poll( PortMidiStream *stream);
+
+/*
+ Pm_Write() writes midi data from a buffer. This may contain short
+ messages or sysex messages that are converted into a sequence of PmEvent
+ structures. Use Pm_WriteSysEx() to write a sysex message stored as a
+ contiguous array of bytes.
+*/
+
+PmError Pm_Write( PortMidiStream *stream, PmEvent *buffer, long length );
+
+/*
+ Pm_WriteShort() writes a timestamped non-system-exclusive midi message.
+*/
+
+PmError Pm_WriteShort( PortMidiStream *stream, PmTimestamp when, long msg);
+
+/*
+ Pm_WriteSysEx() writes a timestamped system-exclusive midi message.
+*/
+PmError Pm_WriteSysEx( PortMidiStream *stream, PmTimestamp when, char *msg);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* PORT_MIDI_H */
diff --git a/pd/portmidi_osx/porttime.h b/pd/portmidi_osx/porttime.h
new file mode 100644
index 00000000..8592106d
--- /dev/null
+++ b/pd/portmidi_osx/porttime.h
@@ -0,0 +1,30 @@
+/* porttime.h -- portable interface to millisecond timer */
+
+/* Should there be a way to choose the source of time here? */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef enum {
+ ptNoError = 0,
+ ptHostError = -10000,
+ ptAlreadyStarted,
+ ptAlreadyStopped
+} PtError;
+
+
+typedef long PtTimestamp;
+
+typedef int (PtCallback)( PtTimestamp timestamp, void *userData );
+
+
+PtError Pt_Start(int resolution, PtCallback *callback, void *userData);
+PtError Pt_Stop();
+int Pt_Started();
+PtTimestamp Pt_Time();
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/pd/portmidi_osx/ptdarwin.c b/pd/portmidi_osx/ptdarwin.c
new file mode 100644
index 00000000..7df41b1c
--- /dev/null
+++ b/pd/portmidi_osx/ptdarwin.c
@@ -0,0 +1,58 @@
+/*
+ * Portable timer implementation for Darwin / MacOS X
+ *
+ * Jon Parise <jparise@cmu.edu>
+ *
+ * $Id: ptdarwin.c,v 1.1.1.1 2003-05-09 16:04:00 ggeiger Exp $
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include "porttime.h"
+
+#define TRUE 1
+#define FALSE 0
+
+static int time_started_flag = FALSE;
+static struct timeval time_offset;
+
+PtError Pt_Start(int resolution, PtCallback *callback, void *userData)
+{
+ struct timezone tz;
+
+ if (callback) printf("error in porttime: callbacks not implemented\n");
+ time_started_flag = TRUE;
+ gettimeofday(&time_offset, &tz);
+
+ return ptNoError;
+}
+
+
+PtError Pt_Stop()
+{
+ time_started_flag = FALSE;
+ return ptNoError;
+}
+
+
+int Pt_Started()
+{
+ return time_started_flag;
+}
+
+
+PtTimestamp Pt_Time()
+{
+ long seconds, milliseconds;
+ struct timeval now;
+ struct timezone tz;
+
+ gettimeofday(&now, &tz);
+ seconds = now.tv_sec - time_offset.tv_sec;
+ milliseconds = (now.tv_usec - time_offset.tv_usec) / 1000;
+
+ return (seconds * 1000 + milliseconds);
+}
+
+
+
diff --git a/pd/src/configure b/pd/src/configure
index aa179b0c..30c377dd 100755
--- a/pd/src/configure
+++ b/pd/src/configure
@@ -1,36 +1,310 @@
#! /bin/sh
-
# Guess values for system-dependent variables and create Makefiles.
-# Generated automatically using autoconf version 2.13
-# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+# Generated by GNU Autoconf 2.53.
#
+# Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
# This configure script is free software; the Free Software Foundation
# gives unlimited permission to copy, distribute and modify it.
-# Defaults:
-ac_help=
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# NLS nuisances.
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+(set +x; test -n "`(LANG=C; export LANG) 2>&1`") &&
+ { $as_unset LANG || test "${LANG+set}" != set; } ||
+ { LANG=C; export LANG; }
+(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") &&
+ { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } ||
+ { LC_ALL=C; export LC_ALL; }
+(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") &&
+ { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } ||
+ { LC_TIME=C; export LC_TIME; }
+(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") &&
+ { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } ||
+ { LC_CTYPE=C; export LC_CTYPE; }
+(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") &&
+ { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } ||
+ { LANGUAGE=C; export LANGUAGE; }
+(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") &&
+ { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } ||
+ { LC_COLLATE=C; export LC_COLLATE; }
+(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") &&
+ { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } ||
+ { LC_NUMERIC=C; export LC_NUMERIC; }
+(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") &&
+ { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } ||
+ { LC_MESSAGES=C; export LC_MESSAGES; }
+
+
+# Name of the executable.
+as_me=`(basename "$0") 2>/dev/null ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conftest.sh
+ echo "exit 0" >>conftest.sh
+ chmod +x conftest.sh
+ if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conftest.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
+ esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
+done
+;;
+ esac
+
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
+
+
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
+
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
+ else
+ as_ln_s='ln -s'
+ fi
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
+fi
+rm -f conf$$ conf$$.exe conf$$.file
+
+as_executable_p="test -f"
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; }
+
+
+# Name of the host.
+# hostname on some systems (SVR3.2, Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+exec 6>&1
+
+#
+# Initializations.
+#
ac_default_prefix=/usr/local
-# Any additions from configure.in:
-ac_help="$ac_help
- --enable-alsa compile ALSA support"
-ac_help="$ac_help
- --enable-old-alsa ALSA 0.5x support"
-ac_help="$ac_help
- --enable-rme compile RME support"
-ac_help="$ac_help
- --enable-debug debugging support"
-ac_help="$ac_help
- --with-x use the X Window System"
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+# Maximum number of lines to put in a shell here document.
+# This variable seems obsolete. It should probably be removed, and
+# only ac_max_sed_lines should be used.
+: ${ac_max_here_lines=38}
+
+# Identity of this package.
+PACKAGE_NAME=
+PACKAGE_TARNAME=
+PACKAGE_VERSION=
+PACKAGE_STRING=
+PACKAGE_BUGREPORT=
+
+ac_unique_file="d_arithmetic.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#if HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#if STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# if HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#if HAVE_STRING_H
+# if !STDC_HEADERS && HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#if HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#if HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+# if HAVE_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
# The variables have the same names as the options, with
# dashes changed to underlines.
-build=NONE
-cache_file=./config.cache
+cache_file=/dev/null
exec_prefix=NONE
-host=NONE
no_create=
-nonopt=NONE
no_recursion=
prefix=NONE
program_prefix=NONE
@@ -39,10 +313,15 @@ program_transform_name=s,x,x,
silent=
site=
srcdir=
-target=NONE
verbose=
x_includes=NONE
x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
bindir='${exec_prefix}/bin'
sbindir='${exec_prefix}/sbin'
libexecdir='${exec_prefix}/libexec'
@@ -56,17 +335,9 @@ oldincludedir='/usr/include'
infodir='${prefix}/info'
mandir='${prefix}/man'
-# Initialize some other variables.
-subdirs=
-MFLAGS= MAKEFLAGS=
-SHELL=${CONFIG_SHELL-/bin/sh}
-# Maximum number of lines to put in a shell here document.
-ac_max_here_lines=12
-
ac_prev=
for ac_option
do
-
# If the previous option needs an argument, assign it.
if test -n "$ac_prev"; then
eval "$ac_prev=\$ac_option"
@@ -74,59 +345,59 @@ do
continue
fi
- case "$ac_option" in
- -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
- *) ac_optarg= ;;
- esac
+ ac_optarg=`expr "x$ac_option" : 'x[^=]*=\(.*\)'`
# Accept the important Cygnus configure options, so we can diagnose typos.
- case "$ac_option" in
+ case $ac_option in
-bindir | --bindir | --bindi | --bind | --bin | --bi)
ac_prev=bindir ;;
-bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
- bindir="$ac_optarg" ;;
+ bindir=$ac_optarg ;;
-build | --build | --buil | --bui | --bu)
- ac_prev=build ;;
+ ac_prev=build_alias ;;
-build=* | --build=* | --buil=* | --bui=* | --bu=*)
- build="$ac_optarg" ;;
+ build_alias=$ac_optarg ;;
-cache-file | --cache-file | --cache-fil | --cache-fi \
| --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
ac_prev=cache_file ;;
-cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
| --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
- cache_file="$ac_optarg" ;;
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
-datadir | --datadir | --datadi | --datad | --data | --dat | --da)
ac_prev=datadir ;;
-datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
| --da=*)
- datadir="$ac_optarg" ;;
+ datadir=$ac_optarg ;;
-disable-* | --disable-*)
- ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
# Reject names that are not valid shell variable names.
- if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
- { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
- fi
- ac_feature=`echo $ac_feature| sed 's/-/_/g'`
- eval "enable_${ac_feature}=no" ;;
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ eval "enable_$ac_feature=no" ;;
-enable-* | --enable-*)
- ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
# Reject names that are not valid shell variable names.
- if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
- { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
- fi
- ac_feature=`echo $ac_feature| sed 's/-/_/g'`
- case "$ac_option" in
- *=*) ;;
+ expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid feature name: $ac_feature" >&2
+ { (exit 1); exit 1; }; }
+ ac_feature=`echo $ac_feature | sed 's/-/_/g'`
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
*) ac_optarg=yes ;;
esac
- eval "enable_${ac_feature}='$ac_optarg'" ;;
+ eval "enable_$ac_feature='$ac_optarg'" ;;
-exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
| --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
@@ -135,95 +406,47 @@ do
-exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
| --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
| --exec=* | --exe=* | --ex=*)
- exec_prefix="$ac_optarg" ;;
+ exec_prefix=$ac_optarg ;;
-gas | --gas | --ga | --g)
# Obsolete; use --with-gas.
with_gas=yes ;;
- -help | --help | --hel | --he)
- # Omit some internal or obsolete options to make the list less imposing.
- # This message is too long to be a string in the A/UX 3.1 sh.
- cat << EOF
-Usage: configure [options] [host]
-Options: [defaults in brackets after descriptions]
-Configuration:
- --cache-file=FILE cache test results in FILE
- --help print this message
- --no-create do not create output files
- --quiet, --silent do not print \`checking...' messages
- --version print the version of autoconf that created configure
-Directory and file names:
- --prefix=PREFIX install architecture-independent files in PREFIX
- [$ac_default_prefix]
- --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
- [same as prefix]
- --bindir=DIR user executables in DIR [EPREFIX/bin]
- --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
- --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
- --datadir=DIR read-only architecture-independent data in DIR
- [PREFIX/share]
- --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
- --sharedstatedir=DIR modifiable architecture-independent data in DIR
- [PREFIX/com]
- --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
- --libdir=DIR object code libraries in DIR [EPREFIX/lib]
- --includedir=DIR C header files in DIR [PREFIX/include]
- --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
- --infodir=DIR info documentation in DIR [PREFIX/info]
- --mandir=DIR man documentation in DIR [PREFIX/man]
- --srcdir=DIR find the sources in DIR [configure dir or ..]
- --program-prefix=PREFIX prepend PREFIX to installed program names
- --program-suffix=SUFFIX append SUFFIX to installed program names
- --program-transform-name=PROGRAM
- run sed PROGRAM on installed program names
-EOF
- cat << EOF
-Host type:
- --build=BUILD configure for building on BUILD [BUILD=HOST]
- --host=HOST configure for HOST [guessed]
- --target=TARGET configure for TARGET [TARGET=HOST]
-Features and packages:
- --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
- --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
- --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
- --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
- --x-includes=DIR X include files are in DIR
- --x-libraries=DIR X library files are in DIR
-EOF
- if test -n "$ac_help"; then
- echo "--enable and --with options recognized:$ac_help"
- fi
- exit 0 ;;
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
-host | --host | --hos | --ho)
- ac_prev=host ;;
+ ac_prev=host_alias ;;
-host=* | --host=* | --hos=* | --ho=*)
- host="$ac_optarg" ;;
+ host_alias=$ac_optarg ;;
-includedir | --includedir | --includedi | --included | --include \
| --includ | --inclu | --incl | --inc)
ac_prev=includedir ;;
-includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
| --includ=* | --inclu=* | --incl=* | --inc=*)
- includedir="$ac_optarg" ;;
+ includedir=$ac_optarg ;;
-infodir | --infodir | --infodi | --infod | --info | --inf)
ac_prev=infodir ;;
-infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
- infodir="$ac_optarg" ;;
+ infodir=$ac_optarg ;;
-libdir | --libdir | --libdi | --libd)
ac_prev=libdir ;;
-libdir=* | --libdir=* | --libdi=* | --libd=*)
- libdir="$ac_optarg" ;;
+ libdir=$ac_optarg ;;
-libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
| --libexe | --libex | --libe)
ac_prev=libexecdir ;;
-libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
| --libexe=* | --libex=* | --libe=*)
- libexecdir="$ac_optarg" ;;
+ libexecdir=$ac_optarg ;;
-localstatedir | --localstatedir | --localstatedi | --localstated \
| --localstate | --localstat | --localsta | --localst \
@@ -232,19 +455,19 @@ EOF
-localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
| --localstate=* | --localstat=* | --localsta=* | --localst=* \
| --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
- localstatedir="$ac_optarg" ;;
+ localstatedir=$ac_optarg ;;
-mandir | --mandir | --mandi | --mand | --man | --ma | --m)
ac_prev=mandir ;;
-mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
- mandir="$ac_optarg" ;;
+ mandir=$ac_optarg ;;
-nfp | --nfp | --nf)
# Obsolete; use --without-fp.
with_fp=no ;;
-no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c)
+ | --no-cr | --no-c | -n)
no_create=yes ;;
-no-recursion | --no-recursion | --no-recursio | --no-recursi \
@@ -258,26 +481,26 @@ EOF
-oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
| --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
| --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
- oldincludedir="$ac_optarg" ;;
+ oldincludedir=$ac_optarg ;;
-prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
ac_prev=prefix ;;
-prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
- prefix="$ac_optarg" ;;
+ prefix=$ac_optarg ;;
-program-prefix | --program-prefix | --program-prefi | --program-pref \
| --program-pre | --program-pr | --program-p)
ac_prev=program_prefix ;;
-program-prefix=* | --program-prefix=* | --program-prefi=* \
| --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
- program_prefix="$ac_optarg" ;;
+ program_prefix=$ac_optarg ;;
-program-suffix | --program-suffix | --program-suffi | --program-suff \
| --program-suf | --program-su | --program-s)
ac_prev=program_suffix ;;
-program-suffix=* | --program-suffix=* | --program-suffi=* \
| --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
- program_suffix="$ac_optarg" ;;
+ program_suffix=$ac_optarg ;;
-program-transform-name | --program-transform-name \
| --program-transform-nam | --program-transform-na \
@@ -294,7 +517,7 @@ EOF
| --program-transfo=* | --program-transf=* \
| --program-trans=* | --program-tran=* \
| --progr-tra=* | --program-tr=* | --program-t=*)
- program_transform_name="$ac_optarg" ;;
+ program_transform_name=$ac_optarg ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil)
@@ -304,7 +527,7 @@ EOF
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
| --sbi=* | --sb=*)
- sbindir="$ac_optarg" ;;
+ sbindir=$ac_optarg ;;
-sharedstatedir | --sharedstatedir | --sharedstatedi \
| --sharedstated | --sharedstate | --sharedstat | --sharedsta \
@@ -315,58 +538,57 @@ EOF
| --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
| --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
| --sha=* | --sh=*)
- sharedstatedir="$ac_optarg" ;;
+ sharedstatedir=$ac_optarg ;;
-site | --site | --sit)
ac_prev=site ;;
-site=* | --site=* | --sit=*)
- site="$ac_optarg" ;;
+ site=$ac_optarg ;;
-srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
ac_prev=srcdir ;;
-srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
- srcdir="$ac_optarg" ;;
+ srcdir=$ac_optarg ;;
-sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
| --syscon | --sysco | --sysc | --sys | --sy)
ac_prev=sysconfdir ;;
-sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
| --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
- sysconfdir="$ac_optarg" ;;
+ sysconfdir=$ac_optarg ;;
-target | --target | --targe | --targ | --tar | --ta | --t)
- ac_prev=target ;;
+ ac_prev=target_alias ;;
-target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
- target="$ac_optarg" ;;
+ target_alias=$ac_optarg ;;
-v | -verbose | --verbose | --verbos | --verbo | --verb)
verbose=yes ;;
- -version | --version | --versio | --versi | --vers)
- echo "configure generated by autoconf version 2.13"
- exit 0 ;;
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
-with-* | --with-*)
- ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
# Reject names that are not valid shell variable names.
- if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
- { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
- fi
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
ac_package=`echo $ac_package| sed 's/-/_/g'`
- case "$ac_option" in
- *=*) ;;
+ case $ac_option in
+ *=*) ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`;;
*) ac_optarg=yes ;;
esac
- eval "with_${ac_package}='$ac_optarg'" ;;
+ eval "with_$ac_package='$ac_optarg'" ;;
-without-* | --without-*)
- ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'`
# Reject names that are not valid shell variable names.
- if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
- { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
- fi
- ac_package=`echo $ac_package| sed 's/-/_/g'`
- eval "with_${ac_package}=no" ;;
+ expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid package name: $ac_package" >&2
+ { (exit 1); exit 1; }; }
+ ac_package=`echo $ac_package | sed 's/-/_/g'`
+ eval "with_$ac_package=no" ;;
--x)
# Obsolete; use --with-x.
@@ -377,99 +599,110 @@ EOF
ac_prev=x_includes ;;
-x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
| --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
- x_includes="$ac_optarg" ;;
+ x_includes=$ac_optarg ;;
-x-libraries | --x-libraries | --x-librarie | --x-librari \
| --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
ac_prev=x_libraries ;;
-x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
| --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
- x_libraries="$ac_optarg" ;;
+ x_libraries=$ac_optarg ;;
- -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ -*) { echo "$as_me: error: unrecognized option: $ac_option
+Try \`$0 --help' for more information." >&2
+ { (exit 1); exit 1; }; }
;;
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null &&
+ { echo "$as_me: error: invalid variable name: $ac_envvar" >&2
+ { (exit 1); exit 1; }; }
+ ac_optarg=`echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"`
+ eval "$ac_envvar='$ac_optarg'"
+ export $ac_envvar ;;
+
*)
- if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
- echo "configure: warning: $ac_option: invalid host type" 1>&2
- fi
- if test "x$nonopt" != xNONE; then
- { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
- fi
- nonopt="$ac_option"
+ # FIXME: should be removed in autoconf 3.0.
+ echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}
;;
esac
done
if test -n "$ac_prev"; then
- { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
-fi
-
-trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
-
-# File descriptor usage:
-# 0 standard input
-# 1 file creation
-# 2 errors and warnings
-# 3 some systems may open it to /dev/tty
-# 4 used on the Kubota Titan
-# 6 checking for... messages and results
-# 5 compiler messages saved in config.log
-if test "$silent" = yes; then
- exec 6>/dev/null
-else
- exec 6>&1
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ { echo "$as_me: error: missing argument to $ac_option" >&2
+ { (exit 1); exit 1; }; }
fi
-exec 5>./config.log
-echo "\
-This file contains any messages produced by compilers while
-running configure, to aid debugging if configure makes a mistake.
-" 1>&5
+# Be sure to have absolute paths.
+for ac_var in exec_prefix prefix
+do
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* | NONE | '' ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
+ esac
+done
-# Strip out --no-create and --no-recursion so they do not pile up.
-# Also quote any args containing shell metacharacters.
-ac_configure_args=
-for ac_arg
+# Be sure to have absolute paths.
+for ac_var in bindir sbindir libexecdir datadir sysconfdir sharedstatedir \
+ localstatedir libdir includedir oldincludedir infodir mandir
do
- case "$ac_arg" in
- -no-create | --no-create | --no-creat | --no-crea | --no-cre \
- | --no-cr | --no-c) ;;
- -no-recursion | --no-recursion | --no-recursio | --no-recursi \
- | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
- *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
- ac_configure_args="$ac_configure_args '$ac_arg'" ;;
- *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ eval ac_val=$`echo $ac_var`
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) ;;
+ *) { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2
+ { (exit 1); exit 1; }; };;
esac
done
-# NLS nuisances.
-# Only set these to C if already set. These must not be set unconditionally
-# because not all systems understand e.g. LANG=C (notably SCO).
-# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
-# Non-C LC_CTYPE values break the ctype check.
-if test "${LANG+set}" = set; then LANG=C; export LANG; fi
-if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
-if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
-if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host.
+ If a cross compiler is detected then cross compile mode will be used." >&2
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
-# confdefs.h avoids OS command line length limits that DEFS can exceed.
-rm -rf conftest* confdefs.h
-# AIX cpp loses on an empty file, so make sure it contains at least a newline.
-echo > confdefs.h
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
-# A filename unique to this package, relative to the directory that
-# configure is in, which we can look for to find out if srcdir is correct.
-ac_unique_file=d_arithmetic.c
# Find the source files, if location was not specified.
if test -z "$srcdir"; then
ac_srcdir_defaulted=yes
# Try the directory containing this script, then its parent.
- ac_prog=$0
- ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
- test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ ac_confdir=`(dirname "$0") 2>/dev/null ||
+$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$0" : 'X\(//\)[^/]' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$0" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
srcdir=$ac_confdir
if test ! -r $srcdir/$ac_unique_file; then
srcdir=..
@@ -479,13 +712,378 @@ else
fi
if test ! -r $srcdir/$ac_unique_file; then
if test "$ac_srcdir_defaulted" = yes; then
- { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2
+ { (exit 1); exit 1; }; }
else
- { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2
+ { (exit 1); exit 1; }; }
fi
fi
-srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'`
+ac_env_build_alias_set=${build_alias+set}
+ac_env_build_alias_value=$build_alias
+ac_cv_env_build_alias_set=${build_alias+set}
+ac_cv_env_build_alias_value=$build_alias
+ac_env_host_alias_set=${host_alias+set}
+ac_env_host_alias_value=$host_alias
+ac_cv_env_host_alias_set=${host_alias+set}
+ac_cv_env_host_alias_value=$host_alias
+ac_env_target_alias_set=${target_alias+set}
+ac_env_target_alias_value=$target_alias
+ac_cv_env_target_alias_set=${target_alias+set}
+ac_cv_env_target_alias_value=$target_alias
+ac_env_CC_set=${CC+set}
+ac_env_CC_value=$CC
+ac_cv_env_CC_set=${CC+set}
+ac_cv_env_CC_value=$CC
+ac_env_CFLAGS_set=${CFLAGS+set}
+ac_env_CFLAGS_value=$CFLAGS
+ac_cv_env_CFLAGS_set=${CFLAGS+set}
+ac_cv_env_CFLAGS_value=$CFLAGS
+ac_env_LDFLAGS_set=${LDFLAGS+set}
+ac_env_LDFLAGS_value=$LDFLAGS
+ac_cv_env_LDFLAGS_set=${LDFLAGS+set}
+ac_cv_env_LDFLAGS_value=$LDFLAGS
+ac_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_env_CPPFLAGS_value=$CPPFLAGS
+ac_cv_env_CPPFLAGS_set=${CPPFLAGS+set}
+ac_cv_env_CPPFLAGS_value=$CPPFLAGS
+ac_env_CPP_set=${CPP+set}
+ac_env_CPP_value=$CPP
+ac_cv_env_CPP_set=${CPP+set}
+ac_cv_env_CPP_value=$CPP
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures this package to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+_ACEOF
+
+ cat <<_ACEOF
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --infodir=DIR info documentation [PREFIX/info]
+ --mandir=DIR man documentation [PREFIX/man]
+_ACEOF
+
+ cat <<\_ACEOF
+
+X features:
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --disable-alsa disable ALSA
+ --enable-jack jack audio server
+ --enable-debug debugging support
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-x use the X Window System
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ CPPFLAGS C/C++ preprocessor flags, e.g. -I<include dir> if you have
+ headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+_ACEOF
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ ac_popdir=`pwd`
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d $ac_dir || continue
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
+
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+ cd $ac_dir
+ # Check for guested configure; otherwise get Cygnus style configure.
+ if test -f $ac_srcdir/configure.gnu; then
+ echo
+ $SHELL $ac_srcdir/configure.gnu --help=recursive
+ elif test -f $ac_srcdir/configure; then
+ echo
+ $SHELL $ac_srcdir/configure --help=recursive
+ elif test -f $ac_srcdir/configure.ac ||
+ test -f $ac_srcdir/configure.in; then
+ echo
+ $ac_configure --help
+ else
+ echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi
+ cd $ac_popdir
+ done
+fi
+
+test -n "$ac_init_help" && exit 0
+if $ac_init_version; then
+ cat <<\_ACEOF
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
+Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit 0
+fi
+exec 5>config.log
+cat >&5 <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by $as_me, which was
+generated by GNU Autoconf 2.53. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+hostinfo = `(hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ echo "PATH: $as_dir"
+done
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell meta-characters.
+ac_configure_args=
+ac_sep=
+for ac_arg
+do
+ case $ac_arg in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n ) continue ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ continue ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args$ac_sep'$ac_arg'"
+ ac_sep=" " ;;
+ esac
+ # Get rid of the leading space.
+done
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Be sure not to use single quotes in there, as some shells,
+# such as our DU 5.0 friend, will then `close' the trap.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+ cat <<\_ASBOX
+## ---------------- ##
+## Cache variables. ##
+## ---------------- ##
+_ASBOX
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+{
+ (set) 2>&1 |
+ case `(ac_space='"'"' '"'"'; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ sed -n \
+ "s/'"'"'/'"'"'\\\\'"'"''"'"'/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='"'"'\\2'"'"'/p"
+ ;;
+ *)
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+}
+ echo
+ if test -s confdefs.h; then
+ cat <<\_ASBOX
+## ----------- ##
+## confdefs.h. ##
+## ----------- ##
+_ASBOX
+ echo
+ sed "/^$/d" confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ echo "$as_me: caught signal $ac_signal"
+ echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core core.* *.core &&
+ rm -rf conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+ ' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo >confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
# Prefer explicitly selected file to automatically selected ones.
if test -z "$CONFIG_SITE"; then
if test "x$prefix" != xNONE; then
@@ -496,39 +1094,99 @@ if test -z "$CONFIG_SITE"; then
fi
for ac_site_file in $CONFIG_SITE; do
if test -r "$ac_site_file"; then
- echo "loading site script $ac_site_file"
+ { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5
+echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
. "$ac_site_file"
fi
done
if test -r "$cache_file"; then
- echo "loading cache $cache_file"
- . $cache_file
+ # Some versions of bash will fail to source /dev/null (special
+ # files actually), so we avoid doing that.
+ if test -f "$cache_file"; then
+ { echo "$as_me:$LINENO: loading cache $cache_file" >&5
+echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . $cache_file;;
+ *) . ./$cache_file;;
+ esac
+ fi
else
- echo "creating cache $cache_file"
- > $cache_file
+ { echo "$as_me:$LINENO: creating cache $cache_file" >&5
+echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in `(set) 2>&1 |
+ sed -n 's/^ac_env_\([a-zA-Z_0-9]*\)_set=.*/\1/p'`; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val="\$ac_cv_env_${ac_var}_value"
+ eval ac_new_val="\$ac_env_${ac_var}_value"
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5
+echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5
+echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { echo "$as_me:$LINENO: former value: $ac_old_val" >&5
+echo "$as_me: former value: $ac_old_val" >&2;}
+ { echo "$as_me:$LINENO: current value: $ac_new_val" >&5
+echo "$as_me: current value: $ac_new_val" >&2;}
+ ac_cache_corrupted=:
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?\"\']*)
+ ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5
+echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5
+echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;}
+ { (exit 1); exit 1; }; }
fi
ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-ac_exeext=
-ac_objext=o
-if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
- # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
- if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
- ac_n= ac_c='
-' ac_t=' '
- else
- ac_n=-n ac_c= ac_t=
- fi
-else
- ac_n= ac_c='\c' ac_t=
-fi
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -549,241 +1207,649 @@ fi
-# Check whether --enable-alsa or --disable-alsa was given.
-if test "${enable_alsa+set}" = set; then
- enableval="$enable_alsa"
- alsa="yes"
-fi
-# Check whether --enable-old-alsa or --disable-old-alsa was given.
-if test "${enable_old_alsa+set}" = set; then
- enableval="$enable_old_alsa"
- alsa="old"
-fi
-# Check whether --enable-rme or --disable-rme was given.
-if test "${enable_rme+set}" = set; then
- enableval="$enable_rme"
- rme="yes"
-fi
+# Check whether --enable-alsa or --disable-alsa was given.
+if test "${enable_alsa+set}" = set; then
+ enableval="$enable_alsa"
+ alsa="no"
+fi;
+# Check whether --enable-jack or --disable-jack was given.
+if test "${enable_jack+set}" = set; then
+ enableval="$enable_jack"
+ jack="yes"
+fi;
# Check whether --enable-debug or --disable-debug was given.
if test "${enable_debug+set}" = set; then
enableval="$enable_debug"
USE_OPT_CFLAGS="NO"
else
USE_OPT_CFLAGS="YES"
+fi;
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-
-# Extract the first word of "gcc", so it can be a program name with args.
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:583: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_CC="gcc"
- break
- fi
- done
- IFS="$ac_save_ifs"
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
fi
fi
-CC="$ac_cv_prog_CC"
+CC=$ac_cv_prog_CC
if test -n "$CC"; then
- echo "$ac_t""$CC" 1>&6
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
+fi
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
- echo "$ac_t""no" 1>&6
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
+ CC=$ac_ct_CC
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:613: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
ac_prog_rejected=no
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
- ac_prog_rejected=yes
- continue
- fi
- ac_cv_prog_CC="cc"
- break
- fi
- done
- IFS="$ac_save_ifs"
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
if test $ac_prog_rejected = yes; then
# We found a bogon in the path, so make sure we never use it.
set dummy $ac_cv_prog_CC
shift
- if test $# -gt 0; then
+ if test $# != 0; then
# We chose a different compiler from the bogus one.
# However, it has the same basename, so the bogon will be chosen
# first if we set CC to just the basename; use the full file name.
shift
- set dummy "$ac_dir/$ac_word" "$@"
+ set dummy "$as_dir/$ac_word" ${1+"$@"}
shift
ac_cv_prog_CC="$@"
fi
fi
fi
fi
-CC="$ac_cv_prog_CC"
+CC=$ac_cv_prog_CC
if test -n "$CC"; then
- echo "$ac_t""$CC" 1>&6
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
else
- echo "$ac_t""no" 1>&6
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
- if test -z "$CC"; then
- case "`uname -s`" in
- *win32* | *WIN32*)
- # Extract the first word of "cl", so it can be a program name with args.
-set dummy cl; ac_word=$2
-echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:664: checking for $ac_word" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
- IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":"
- ac_dummy="$PATH"
- for ac_dir in $ac_dummy; do
- test -z "$ac_dir" && ac_dir=.
- if test -f $ac_dir/$ac_word; then
- ac_cv_prog_CC="cl"
- break
- fi
- done
- IFS="$ac_save_ifs"
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+done
+
fi
fi
-CC="$ac_cv_prog_CC"
+CC=$ac_cv_prog_CC
if test -n "$CC"; then
- echo "$ac_t""$CC" 1>&6
+ echo "$as_me:$LINENO: result: $CC" >&5
+echo "${ECHO_T}$CC" >&6
else
- echo "$ac_t""no" 1>&6
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
- ;;
- esac
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo "$as_me:$LINENO: checking for $ac_word" >&5
+echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6
+if test "${ac_cv_prog_ac_ct_CC+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
fi
- test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+done
+done
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ echo "$as_me:$LINENO: result: $ac_ct_CC" >&5
+echo "${ECHO_T}$ac_ct_CC" >&6
+else
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
fi
-echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
-echo "configure:696: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+ test -n "$ac_ct_CC" && break
+done
+
+ CC=$ac_ct_CC
+fi
+
+fi
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-cat > conftest.$ac_ext << EOF
+test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH" >&5
+echo "$as_me: error: no acceptable C compiler found in \$PATH" >&2;}
+ { (exit 1); exit 1; }; }
-#line 707 "configure"
+# Provide some information about the compiler.
+echo "$as_me:$LINENO:" \
+ "checking for C compiler version" >&5
+ac_compiler=`set X $ac_compile; echo $2`
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5
+ (eval $ac_compiler --version </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v </dev/null >&5\"") >&5
+ (eval $ac_compiler -v </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V </dev/null >&5\"") >&5
+ (eval $ac_compiler -V </dev/null >&5) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-main(){return(0);}
-EOF
-if { (eval echo configure:712: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- ac_cv_prog_cc_works=yes
- # If we can't run a trivial program, we are probably using a cross compiler.
- if (./conftest; exit) 2>/dev/null; then
- ac_cv_prog_cc_cross=no
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.exe"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+echo "$as_me:$LINENO: checking for C compiler default output" >&5
+echo $ECHO_N "checking for C compiler default output... $ECHO_C" >&6
+ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+if { (eval echo "$as_me:$LINENO: \"$ac_link_default\"") >&5
+ (eval $ac_link_default) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # Find the output, starting from the most likely. This scheme is
+# not robust to junk in `.', hence go to wildcards (a.*) only as a last
+# resort.
+
+# Be careful to initialize this variable, since it used to be cached.
+# Otherwise an old cache value of `no' led to `EXEEXT = no' in a Makefile.
+ac_cv_exeext=
+for ac_file in `ls a_out.exe a.exe conftest.exe 2>/dev/null;
+ ls a.out conftest 2>/dev/null;
+ ls a.* conftest.* 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb | *.xSYM ) ;;
+ a.out ) # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ # FIXME: I believe we export ac_cv_exeext for Libtool --akim.
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:$LINENO: error: C compiler cannot create executables" >&5
+echo "$as_me: error: C compiler cannot create executables" >&2;}
+ { (exit 77); exit 77; }; }
+fi
+
+ac_exeext=$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_file" >&5
+echo "${ECHO_T}$ac_file" >&6
+
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether the C compiler works" >&5
+echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6
+# FIXME: These cross compiler hacks should be removed for Autoconf 3.0
+# If not cross compiling, check that we can run a simple program.
+if test "$cross_compiling" != yes; then
+ if { ac_try='./$ac_file'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ cross_compiling=no
else
- ac_cv_prog_cc_cross=yes
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { echo "$as_me:$LINENO: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&5
+echo "$as_me: error: cannot run C compiled programs.
+If you meant to cross compile, use \`--host'." >&2;}
+ { (exit 1); exit 1; }; }
+ fi
fi
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- ac_cv_prog_cc_works=no
fi
-rm -fr conftest*
-ac_ext=c
-# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
-ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
-cross_compiling=$ac_cv_prog_cc_cross
-
-echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
-if test $ac_cv_prog_cc_works = no; then
- { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
-fi
-echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
-echo "configure:738: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
-echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
-cross_compiling=$ac_cv_prog_cc_cross
-
-echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:743: checking whether we are using GNU C" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.c <<EOF
-#ifdef __GNUC__
- yes;
-#endif
-EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:752: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
- ac_cv_prog_gcc=yes
+echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
+
+rm -f a.out a.exe conftest$ac_cv_exeext
+ac_clean_files=$ac_clean_files_save
+# Check the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+echo "$as_me:$LINENO: checking whether we are cross compiling" >&5
+echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6
+echo "$as_me:$LINENO: result: $cross_compiling" >&5
+echo "${ECHO_T}$cross_compiling" >&6
+
+echo "$as_me:$LINENO: checking for suffix of executables" >&5
+echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in `(ls conftest.exe; ls conftest; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.o | *.obj | *.xcoff | *.tds | *.d | *.pdb ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ export ac_cv_exeext
+ break;;
+ * ) break;;
+ esac
+done
else
- ac_cv_prog_gcc=no
-fi
+ { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link" >&5
+echo "$as_me: error: cannot compute suffix of executables: cannot compile and link" >&2;}
+ { (exit 1); exit 1; }; }
fi
-echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+rm -f conftest$ac_cv_exeext
+echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5
+echo "${ECHO_T}$ac_cv_exeext" >&6
-if test $ac_cv_prog_gcc = yes; then
- GCC=yes
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+echo "$as_me:$LINENO: checking for suffix of object files" >&5
+echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6
+if test "${ac_cv_objext+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- GCC=
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; then
+ for ac_file in `(ls conftest.o conftest.obj; ls conftest.*) 2>/dev/null`; do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile" >&5
+echo "$as_me: error: cannot compute suffix of object files: cannot compile" >&2;}
+ { (exit 1); exit 1; }; }
fi
-ac_test_CFLAGS="${CFLAGS+set}"
-ac_save_CFLAGS="$CFLAGS"
-CFLAGS=
-echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:771: checking whether ${CC-cc} accepts -g" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_objext" >&5
+echo "${ECHO_T}$ac_cv_objext" >&6
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5
+echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6
+if test "${ac_cv_c_compiler_gnu+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- echo 'void f(){}' > conftest.c
-if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_compiler_gnu=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_compiler_gnu=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5
+echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6
+GCC=`test $ac_compiler_gnu = yes && echo yes`
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+CFLAGS="-g"
+echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5
+echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_g+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
ac_cv_prog_cc_g=yes
else
- ac_cv_prog_cc_g=no
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_prog_cc_g=no
fi
-rm -f conftest*
-
+rm -f conftest.$ac_objext conftest.$ac_ext
fi
-
-echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_g" >&6
if test "$ac_test_CFLAGS" = set; then
- CFLAGS="$ac_save_CFLAGS"
+ CFLAGS=$ac_save_CFLAGS
elif test $ac_cv_prog_cc_g = yes; then
if test "$GCC" = yes; then
CFLAGS="-g -O2"
@@ -797,6 +1863,128 @@ else
CFLAGS=
fi
fi
+# Some people use a C++ compiler to compile C. Since we use `exit',
+# in C++ we need to declare it. In case someone uses the same compiler
+# for both compiling C and C++ we need to have the C++ compiler decide
+# the declaration of exit, since it's the most demanding environment.
+cat >conftest.$ac_ext <<_ACEOF
+#ifndef __cplusplus
+ choke me
+#endif
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ for ac_declaration in \
+ ''\
+ '#include <stdlib.h>' \
+ 'extern "C" void std::exit (int) throw (); using std::exit;' \
+ 'extern "C" void std::exit (int); using std::exit;' \
+ 'extern "C" void exit (int) throw ();' \
+ 'extern "C" void exit (int);' \
+ 'void exit (int);'
+do
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+$ac_declaration
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ :
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+continue
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_declaration
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+exit (42);
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+done
+rm -f conftest*
+if test -n "$ac_declaration"; then
+ echo '#ifdef __cplusplus' >>confdefs.h
+ echo $ac_declaration >>confdefs.h
+ echo '#endif' >>confdefs.h
+fi
+
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
ac_aux_dir=
for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
@@ -808,14 +1996,20 @@ for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
ac_aux_dir=$ac_dir
ac_install_sh="$ac_aux_dir/install.sh -c"
break
+ elif test -f $ac_dir/shtool; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
fi
done
if test -z "$ac_aux_dir"; then
- { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+ { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&5
+echo "$as_me: error: cannot find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." >&2;}
+ { (exit 1); exit 1; }; }
fi
-ac_config_guess=$ac_aux_dir/config.guess
-ac_config_sub=$ac_aux_dir/config.sub
-ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess"
+ac_config_sub="$SHELL $ac_aux_dir/config.sub"
+ac_configure="$SHELL $ac_aux_dir/configure" # This should be Cygnus configure.
# Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
@@ -824,286 +2018,555 @@ ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
# SunOS /usr/etc/install
# IRIX /sbin/install
# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
# AFS /usr/afsws/bin/install, which mishandles nonexistent args
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
-echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:833: checking for a BSD compatible install" >&5
+echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5
+echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6
if test -z "$INSTALL"; then
-if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS=":"
- for ac_dir in $PATH; do
- # Account for people who put trailing slashes in PATH elements.
- case "$ac_dir/" in
- /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
- *)
- # OSF1 and SCO ODT 3.0 have their own names for install.
- # Don't use installbsd from OSF since it installs stuff as root
- # by default.
- for ac_prog in ginstall scoinst install; do
- if test -f $ac_dir/$ac_prog; then
- if test $ac_prog = install &&
- grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
- # AIX install. It has an incompatible calling convention.
- :
- else
- ac_cv_path_install="$ac_dir/$ac_prog -c"
- break 2
- fi
- fi
+if test "${ac_cv_path_install+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in
+ ./ | .// | /cC/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
done
- ;;
- esac
- done
- IFS="$ac_save_IFS"
+ done
+ ;;
+esac
+done
+
fi
if test "${ac_cv_path_install+set}" = set; then
- INSTALL="$ac_cv_path_install"
+ INSTALL=$ac_cv_path_install
else
# As a last resort, use the slow shell script. We don't cache a
# path for INSTALL within a source directory, because that will
# break other packages using the cache if that directory is
# removed, or if the path is relative.
- INSTALL="$ac_install_sh"
+ INSTALL=$ac_install_sh
fi
fi
-echo "$ac_t""$INSTALL" 1>&6
+echo "$as_me:$LINENO: result: $INSTALL" >&5
+echo "${ECHO_T}$INSTALL" >&6
# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
# It thinks the first close brace ends the variable substitution.
test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
-test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
-echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:886: checking whether ${MAKE-make} sets \${MAKE}" >&5
-set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo $ECHO_N "checking whether ${MAKE-make} sets \${MAKE}... $ECHO_C" >&6
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y,./+-,__p_,'`
+if eval "test \"\${ac_cv_prog_make_${ac_make}_set+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- cat > conftestmake <<\EOF
+ cat >conftest.make <<\_ACEOF
all:
@echo 'ac_maketemp="${MAKE}"'
-EOF
+_ACEOF
# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
-eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+eval `${MAKE-make} -f conftest.make 2>/dev/null | grep temp=`
if test -n "$ac_maketemp"; then
eval ac_cv_prog_make_${ac_make}_set=yes
else
eval ac_cv_prog_make_${ac_make}_set=no
fi
-rm -f conftestmake
+rm -f conftest.make
fi
if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
- echo "$ac_t""yes" 1>&6
+ echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6
SET_MAKE=
else
- echo "$ac_t""no" 1>&6
+ echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6
SET_MAKE="MAKE=${MAKE-make}"
fi
-echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
-echo "configure:913: checking how to run the C preprocessor" >&5
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5
+echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
fi
if test -z "$CPP"; then
-if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- # This must be in double quotes, not single quotes, because CPP may get
- # substituted into the Makefile and "${CC-cc}" will confuse make.
- CPP="${CC-cc} -E"
+ if test "${ac_cv_prog_CPP+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
# On the NeXT, cc -E runs the code through the compiler's parser,
- # not just through cpp.
- cat > conftest.$ac_ext <<EOF
-#line 928 "configure"
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:934: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
:
else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
+ echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
- rm -rf conftest*
- CPP="${CC-cc} -E -traditional-cpp"
- cat > conftest.$ac_ext <<EOF
-#line 945 "configure"
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:951: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- :
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
- rm -rf conftest*
- CPP="${CC-cc} -nologo -E"
- cat > conftest.$ac_ext <<EOF
-#line 962 "configure"
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+echo "$as_me:$LINENO: result: $CPP" >&5
+echo "${ECHO_T}$CPP" >&6
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <assert.h>
-Syntax Error
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:968: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
+ Syntax error
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
:
else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
+ echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
- rm -rf conftest*
- CPP=/lib/cpp
+ # Broken: fails on valid input.
+continue
fi
-rm -f conftest*
-fi
-rm -f conftest*
+rm -f conftest.err conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether non-existent headers
+ # can be detected and how.
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <ac_nonexistent.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
fi
-rm -f conftest*
- ac_cv_prog_CPP="$CPP"
+if test -z "$ac_cpp_err"; then
+ # Broken: success on invalid input.
+continue
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ # Passes both tests.
+ac_preproc_ok=:
+break
fi
- CPP="$ac_cv_prog_CPP"
+rm -f conftest.err conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then
+ :
else
- ac_cv_prog_CPP="$CPP"
+ { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check" >&5
+echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check" >&2;}
+ { (exit 1); exit 1; }; }
fi
-echo "$ac_t""$CPP" 1>&6
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
-echo $ac_n "checking for working const""... $ac_c" 1>&6
-echo "configure:994: checking for working const" >&5
-if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for $CC option to accept ANSI C" >&5
+echo $ECHO_N "checking for $CC option to accept ANSI C... $ECHO_C" >&6
+if test "${ac_cv_prog_cc_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- cat > conftest.$ac_ext <<EOF
-#line 999 "configure"
+ ac_cv_prog_cc_stdc=no
+ac_save_CC=$CC
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-
-int main() {
-
-/* Ultrix mips cc rejects this. */
-typedef int charset[2]; const charset x;
-/* SunOS 4.1.1 cc rejects this. */
-char const *const *ccp;
-char **p;
-/* NEC SVR4.0.2 mips cc rejects this. */
-struct point {int x, y;};
-static struct point const zero = {0,0};
-/* AIX XL C 1.02.0.0 rejects this.
- It does not let you subtract one const X* pointer from another in an arm
- of an if-expression whose if-part is not a constant expression */
-const char *g = "string";
-ccp = &g + (g ? g-g : 0);
-/* HPUX 7.0 cc rejects these. */
-++ccp;
-p = (char**) ccp;
-ccp = (char const *const *) p;
-{ /* SCO 3.2v4 cc rejects this. */
- char *t;
- char const *s = 0 ? (char *) 0 : (char const *) 0;
-
- *t++ = 0;
-}
-{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
- int x[] = {25, 17};
- const int *foo = &x[0];
- ++foo;
-}
-{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
- typedef const int *iptr;
- iptr p = 0;
- ++p;
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
}
-{ /* AIX XL C 1.02.0.0 rejects this saying
- "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
- struct s { int j; const int *ap[3]; };
- struct s *b; b->j = 5;
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
}
-{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
- const int foo = 10;
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
}
+_ACEOF
+# Don't try gcc -ansi; that turns off useful extensions and
+# breaks some systems' header files.
+# AIX -qlanglvl=ansi
+# Ultrix and OSF/1 -std1
+# HP-UX 10.20 and later -Ae
+# HP-UX older versions -Aa -D_HPUX_SOURCE
+# SVR4 -Xc -D__EXTENSIONS__
+for ac_arg in "" -qlanglvl=ansi -std1 -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_prog_cc_stdc=$ac_arg
+break
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+fi
+rm -f conftest.$ac_objext
+done
+rm -f conftest.$ac_ext conftest.$ac_objext
+CC=$ac_save_CC
+
+fi
-; return 0; }
-EOF
-if { (eval echo configure:1048: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
- rm -rf conftest*
+case "x$ac_cv_prog_cc_stdc" in
+ x|xno)
+ echo "$as_me:$LINENO: result: none needed" >&5
+echo "${ECHO_T}none needed" >&6 ;;
+ *)
+ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_stdc" >&5
+echo "${ECHO_T}$ac_cv_prog_cc_stdc" >&6
+ CC="$CC $ac_cv_prog_cc_stdc" ;;
+esac
+
+echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
+echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
+if test "${ac_cv_c_const+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* FIXME: Include the comments suggested by Paul. */
+#ifndef __cplusplus
+ /* Ultrix mips cc rejects this. */
+ typedef int charset[2];
+ const charset x;
+ /* SunOS 4.1.1 cc rejects this. */
+ char const *const *ccp;
+ char **p;
+ /* NEC SVR4.0.2 mips cc rejects this. */
+ struct point {int x, y;};
+ static struct point const zero = {0,0};
+ /* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in
+ an arm of an if-expression whose if-part is not a constant
+ expression */
+ const char *g = "string";
+ ccp = &g + (g ? g-g : 0);
+ /* HPUX 7.0 cc rejects these. */
+ ++ccp;
+ p = (char**) ccp;
+ ccp = (char const *const *) p;
+ { /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+ }
+ { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+ }
+ { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+ }
+ { /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+ }
+ { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+ }
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
ac_cv_c_const=yes
else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- ac_cv_c_const=no
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_c_const=no
fi
-rm -f conftest*
+rm -f conftest.$ac_objext conftest.$ac_ext
fi
-
-echo "$ac_t""$ac_cv_c_const" 1>&6
+echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5
+echo "${ECHO_T}$ac_cv_c_const" >&6
if test $ac_cv_c_const = no; then
- cat >> confdefs.h <<\EOF
-#define const
-EOF
+
+cat >>confdefs.h <<\_ACEOF
+#define const
+_ACEOF
fi
-echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1069: checking for ANSI C header files" >&5
-if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- cat > conftest.$ac_ext <<EOF
-#line 1074 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1082: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
+
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
ac_cv_header_stdc=yes
else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
+ echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
- rm -rf conftest*
ac_cv_header_stdc=no
fi
-rm -f conftest*
+rm -f conftest.err conftest.$ac_ext
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-cat > conftest.$ac_ext <<EOF
-#line 1099 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <string.h>
-EOF
+
+_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "memchr" >/dev/null 2>&1; then
:
else
- rm -rf conftest*
ac_cv_header_stdc=no
fi
rm -f conftest*
@@ -1112,16 +2575,16 @@ fi
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
-cat > conftest.$ac_ext <<EOF
-#line 1117 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <stdlib.h>
-EOF
+
+_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "free" >/dev/null 2>&1; then
:
else
- rm -rf conftest*
ac_cv_header_stdc=no
fi
rm -f conftest*
@@ -1130,186 +2593,351 @@ fi
if test $ac_cv_header_stdc = yes; then
# /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
-if test "$cross_compiling" = yes; then
+ if test "$cross_compiling" = yes; then
:
else
- cat > conftest.$ac_ext <<EOF
-#line 1138 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <ctype.h>
-#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int main () { int i; for (i = 0; i < 256; i++)
-if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
-exit (0); }
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
-EOF
-if { (eval echo configure:1149: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
:
else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -fr conftest*
- ac_cv_header_stdc=no
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+( exit $ac_status )
+ac_cv_header_stdc=no
fi
-rm -fr conftest*
+rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
-
fi
fi
-
-echo "$ac_t""$ac_cv_header_stdc" 1>&6
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
if test $ac_cv_header_stdc = yes; then
- cat >> confdefs.h <<\EOF
+
+cat >>confdefs.h <<\_ACEOF
#define STDC_HEADERS 1
-EOF
+_ACEOF
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+
+
+
+
+
+
+
+
+
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+$ac_includes_default
+
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_Header=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_Header=no"
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
fi
-echo $ac_n "checking for pid_t""... $ac_c" 1>&6
-echo "configure:1173: checking for pid_t" >&5
-if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+done
+
+
+echo "$as_me:$LINENO: checking for pid_t" >&5
+echo $ECHO_N "checking for pid_t... $ECHO_C" >&6
+if test "${ac_cv_type_pid_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- cat > conftest.$ac_ext <<EOF
-#line 1178 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-#include <sys/types.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
+$ac_includes_default
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
#endif
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
- rm -rf conftest*
+int
+main ()
+{
+if ((pid_t *) 0)
+ return 0;
+if (sizeof (pid_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
ac_cv_type_pid_t=yes
else
- rm -rf conftest*
- ac_cv_type_pid_t=no
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_type_pid_t=no
fi
-rm -f conftest*
-
+rm -f conftest.$ac_objext conftest.$ac_ext
fi
-echo "$ac_t""$ac_cv_type_pid_t" 1>&6
-if test $ac_cv_type_pid_t = no; then
- cat >> confdefs.h <<\EOF
+echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5
+echo "${ECHO_T}$ac_cv_type_pid_t" >&6
+if test $ac_cv_type_pid_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
#define pid_t int
-EOF
+_ACEOF
fi
-echo $ac_n "checking for size_t""... $ac_c" 1>&6
-echo "configure:1206: checking for size_t" >&5
-if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for size_t" >&5
+echo $ECHO_N "checking for size_t... $ECHO_C" >&6
+if test "${ac_cv_type_size_t+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- cat > conftest.$ac_ext <<EOF
-#line 1211 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-#include <sys/types.h>
-#if STDC_HEADERS
-#include <stdlib.h>
-#include <stddef.h>
+$ac_includes_default
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
#endif
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
- rm -rf conftest*
+int
+main ()
+{
+if ((size_t *) 0)
+ return 0;
+if (sizeof (size_t))
+ return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
ac_cv_type_size_t=yes
else
- rm -rf conftest*
- ac_cv_type_size_t=no
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_type_size_t=no
fi
-rm -f conftest*
-
+rm -f conftest.$ac_objext conftest.$ac_ext
fi
-echo "$ac_t""$ac_cv_type_size_t" 1>&6
-if test $ac_cv_type_size_t = no; then
- cat >> confdefs.h <<\EOF
+echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5
+echo "${ECHO_T}$ac_cv_type_size_t" >&6
+if test $ac_cv_type_size_t = yes; then
+ :
+else
+
+cat >>confdefs.h <<_ACEOF
#define size_t unsigned
-EOF
+_ACEOF
fi
-echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6
-echo "configure:1239: checking whether time.h and sys/time.h may both be included" >&5
-if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5
+echo $ECHO_N "checking whether time.h and sys/time.h may both be included... $ECHO_C" >&6
+if test "${ac_cv_header_time+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- cat > conftest.$ac_ext <<EOF
-#line 1244 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
-int main() {
-struct tm *tp;
-; return 0; }
-EOF
-if { (eval echo configure:1253: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
- rm -rf conftest*
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
ac_cv_header_time=yes
else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- ac_cv_header_time=no
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_header_time=no
fi
-rm -f conftest*
+rm -f conftest.$ac_objext conftest.$ac_ext
fi
-
-echo "$ac_t""$ac_cv_header_time" 1>&6
+echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5
+echo "${ECHO_T}$ac_cv_header_time" >&6
if test $ac_cv_header_time = yes; then
- cat >> confdefs.h <<\EOF
+
+cat >>confdefs.h <<\_ACEOF
#define TIME_WITH_SYS_TIME 1
-EOF
+_ACEOF
fi
-echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
-echo "configure:1275: checking for ANSI C header files" >&5
-if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for ANSI C header files" >&5
+echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6
+if test "${ac_cv_header_stdc+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- cat > conftest.$ac_ext <<EOF
-#line 1280 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <float.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1288: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
+
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
ac_cv_header_stdc=yes
else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
+ echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
- rm -rf conftest*
ac_cv_header_stdc=no
fi
-rm -f conftest*
+rm -f conftest.err conftest.$ac_ext
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-cat > conftest.$ac_ext <<EOF
-#line 1305 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <string.h>
-EOF
+
+_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "memchr" >/dev/null 2>&1; then
:
else
- rm -rf conftest*
ac_cv_header_stdc=no
fi
rm -f conftest*
@@ -1318,16 +2946,16 @@ fi
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
-cat > conftest.$ac_ext <<EOF
-#line 1323 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <stdlib.h>
-EOF
+
+_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "free" >/dev/null 2>&1; then
:
else
- rm -rf conftest*
ac_cv_header_stdc=no
fi
rm -f conftest*
@@ -1336,144 +2964,245 @@ fi
if test $ac_cv_header_stdc = yes; then
# /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
-if test "$cross_compiling" = yes; then
+ if test "$cross_compiling" = yes; then
:
else
- cat > conftest.$ac_ext <<EOF
-#line 1344 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <ctype.h>
-#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int main () { int i; for (i = 0; i < 256; i++)
-if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
-exit (0); }
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
-EOF
-if { (eval echo configure:1355: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ exit(2);
+ exit (0);
+}
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
:
else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -fr conftest*
- ac_cv_header_stdc=no
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+( exit $ac_status )
+ac_cv_header_stdc=no
fi
-rm -fr conftest*
+rm -f core core.* *.core conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
-
fi
fi
-
-echo "$ac_t""$ac_cv_header_stdc" 1>&6
+echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5
+echo "${ECHO_T}$ac_cv_header_stdc" >&6
if test $ac_cv_header_stdc = yes; then
- cat >> confdefs.h <<\EOF
+
+cat >>confdefs.h <<\_ACEOF
#define STDC_HEADERS 1
-EOF
+_ACEOF
fi
-for ac_hdr in fcntl.h limits.h malloc.h sys/ioctl.h sys/time.h unistd.h bstring.h
+
+
+
+
+
+
+
+for ac_header in fcntl.h limits.h malloc.h sys/ioctl.h sys/time.h unistd.h bstring.h
do
-ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
-echo "configure:1382: checking for $ac_hdr" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1387 "configure"
+as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking $ac_header usability" >&5
+echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-#include <$ac_hdr>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1392: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
+$ac_includes_default
+#include <$ac_header>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking $ac_header presence" >&5
+echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+#include <$ac_header>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
fi
-rm -f conftest*
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_header_preproc=no
fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_hdr 1
-EOF
-
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5
+echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;};;
+esac
+echo "$as_me:$LINENO: checking for $ac_header" >&5
+echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6
+if eval "test \"\${$as_ac_Header+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- echo "$ac_t""no" 1>&6
+ eval "$as_ac_Header=$ac_header_preproc"
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_Header'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_Header'}'`" >&6
+
+fi
+if test `eval echo '${'$as_ac_Header'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
fi
+
done
-if test $ac_cv_prog_gcc = yes; then
- echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6
-echo "configure:1421: checking whether ${CC-cc} needs -traditional" >&5
-if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+if test $ac_cv_c_compiler_gnu = yes; then
+ echo "$as_me:$LINENO: checking whether $CC needs -traditional" >&5
+echo $ECHO_N "checking whether $CC needs -traditional... $ECHO_C" >&6
+if test "${ac_cv_prog_gcc_traditional+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_pattern="Autoconf.*'x'"
- cat > conftest.$ac_ext <<EOF
-#line 1427 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <sgtty.h>
Autoconf TIOCGETP
-EOF
+_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "$ac_pattern" >/dev/null 2>&1; then
- rm -rf conftest*
ac_cv_prog_gcc_traditional=yes
else
- rm -rf conftest*
ac_cv_prog_gcc_traditional=no
fi
rm -f conftest*
if test $ac_cv_prog_gcc_traditional = no; then
- cat > conftest.$ac_ext <<EOF
-#line 1445 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <termio.h>
Autoconf TCGETA
-EOF
+_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
egrep "$ac_pattern" >/dev/null 2>&1; then
- rm -rf conftest*
ac_cv_prog_gcc_traditional=yes
fi
rm -f conftest*
fi
fi
-
-echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6
+echo "$as_me:$LINENO: result: $ac_cv_prog_gcc_traditional" >&5
+echo "${ECHO_T}$ac_cv_prog_gcc_traditional" >&6
if test $ac_cv_prog_gcc_traditional = yes; then
CC="$CC -traditional"
fi
fi
-echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6
-echo "configure:1467: checking return type of signal handlers" >&5
-if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking return type of signal handlers" >&5
+echo $ECHO_N "checking return type of signal handlers... $ECHO_C" >&6
+if test "${ac_cv_type_signal+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- cat > conftest.$ac_ext <<EOF
-#line 1472 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
#include <sys/types.h>
#include <signal.h>
#ifdef signal
-#undef signal
+# undef signal
#endif
#ifdef __cplusplus
extern "C" void (*signal (int, void (*)(int)))(int);
@@ -1481,456 +3210,597 @@ extern "C" void (*signal (int, void (*)(int)))(int);
void (*signal ()) ();
#endif
-int main() {
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
int i;
-; return 0; }
-EOF
-if { (eval echo configure:1489: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
- rm -rf conftest*
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
ac_cv_type_signal=void
else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- ac_cv_type_signal=int
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_type_signal=int
fi
-rm -f conftest*
+rm -f conftest.$ac_objext conftest.$ac_ext
fi
+echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5
+echo "${ECHO_T}$ac_cv_type_signal" >&6
-echo "$ac_t""$ac_cv_type_signal" 1>&6
-cat >> confdefs.h <<EOF
+cat >>confdefs.h <<_ACEOF
#define RETSIGTYPE $ac_cv_type_signal
-EOF
+_ACEOF
-echo $ac_n "checking for vprintf""... $ac_c" 1>&6
-echo "configure:1508: checking for vprintf" >&5
-if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1513 "configure"
+
+for ac_func in vprintf
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char vprintf(); below. */
+ which can conflict with char $ac_func (); below. */
#include <assert.h>
/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char vprintf();
-
-int main() {
-
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
-#if defined (__stub_vprintf) || defined (__stub___vprintf)
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
choke me
#else
-vprintf();
+f = $ac_func;
#endif
-; return 0; }
-EOF
-if { (eval echo configure:1536: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func_vprintf=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func_vprintf=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
-#define HAVE_VPRINTF 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
-fi
-
-if test "$ac_cv_func_vprintf" != yes; then
-echo $ac_n "checking for _doprnt""... $ac_c" 1>&6
-echo "configure:1560: checking for _doprnt" >&5
-if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1565 "configure"
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+echo "$as_me:$LINENO: checking for _doprnt" >&5
+echo $ECHO_N "checking for _doprnt... $ECHO_C" >&6
+if test "${ac_cv_func__doprnt+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char _doprnt(); below. */
+ which can conflict with char _doprnt (); below. */
#include <assert.h>
/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char _doprnt();
-
-int main() {
-
+ builtin and then its argument prototype would still apply. */
+char _doprnt ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined (__stub__doprnt) || defined (__stub____doprnt)
choke me
#else
-_doprnt();
+f = _doprnt;
#endif
-; return 0; }
-EOF
-if { (eval echo configure:1588: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func__doprnt=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func__doprnt=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<\EOF
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func__doprnt=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func__doprnt=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func__doprnt" >&5
+echo "${ECHO_T}$ac_cv_func__doprnt" >&6
+if test $ac_cv_func__doprnt = yes; then
+
+cat >>confdefs.h <<\_ACEOF
#define HAVE_DOPRNT 1
-EOF
+_ACEOF
-else
- echo "$ac_t""no" 1>&6
fi
fi
+done
+
+
+
+
+
for ac_func in gettimeofday select socket strerror
do
-echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1615: checking for $ac_func" >&5
-if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 1620 "configure"
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
+if eval "test \"\${$as_ac_var+set}\" = set"; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char $ac_func(); below. */
+ which can conflict with char $ac_func (); below. */
#include <assert.h>
/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char $ac_func();
-
-int main() {
-
+ builtin and then its argument prototype would still apply. */
+char $ac_func ();
+char (*f) ();
+
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
choke me
#else
-$ac_func();
+f = $ac_func;
#endif
-; return 0; }
-EOF
-if { (eval echo configure:1643: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func_$ac_func=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func_$ac_func=no"
-fi
-rm -f conftest*
-fi
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ eval "$as_ac_var=yes"
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+eval "$as_ac_var=no"
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
+echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
-if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_func 1
-EOF
-
-else
- echo "$ac_t""no" 1>&6
fi
done
-echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
-echo "configure:1670: checking for dlopen in -ldl" >&5
-ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
+echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
+if test "${ac_cv_lib_dl_dlopen+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ldl $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1678 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
+
/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char dlopen();
-
-int main() {
-dlopen()
-; return 0; }
-EOF
-if { (eval echo configure:1689: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
+ builtin and then its argument prototype would still apply. */
+char dlopen ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_dl_dlopen=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_dl_dlopen=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_dl_dlopen" >&5
+echo "${ECHO_T}$ac_cv_lib_dl_dlopen" >&6
+if test $ac_cv_lib_dl_dlopen = yes; then
PDLIB="$PDLIB -ldl"
else
- echo "$ac_t""no" 1>&6
-echo "dynamic link support required" || exit 1
+ echo "dynamic link support required" || exit 1
fi
-echo $ac_n "checking for sin in -lffm""... $ac_c" 1>&6
-echo "configure:1712: checking for sin in -lffm" >&5
-ac_lib_var=`echo ffm'_'sin | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for sin in -lffm" >&5
+echo $ECHO_N "checking for sin in -lffm... $ECHO_C" >&6
+if test "${ac_cv_lib_ffm_sin+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-lffm $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1720 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
+
/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char sin();
-
-int main() {
-sin()
-; return 0; }
-EOF
-if { (eval echo configure:1731: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
+ builtin and then its argument prototype would still apply. */
+char sin ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+sin ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_ffm_sin=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_ffm_sin=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_ffm_sin" >&5
+echo "${ECHO_T}$ac_cv_lib_ffm_sin" >&6
+if test $ac_cv_lib_ffm_sin = yes; then
PDLIB="$PDLIB -lffm"
-else
- echo "$ac_t""no" 1>&6
fi
-echo $ac_n "checking for sin in -lm""... $ac_c" 1>&6
-echo "configure:1753: checking for sin in -lm" >&5
-ac_lib_var=`echo m'_'sin | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for sin in -lm" >&5
+echo $ECHO_N "checking for sin in -lm... $ECHO_C" >&6
+if test "${ac_cv_lib_m_sin+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-lm $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1761 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
+
/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char sin();
-
-int main() {
-sin()
-; return 0; }
-EOF
-if { (eval echo configure:1772: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
+ builtin and then its argument prototype would still apply. */
+char sin ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+sin ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_m_sin=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_m_sin=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_m_sin" >&5
+echo "${ECHO_T}$ac_cv_lib_m_sin" >&6
+if test $ac_cv_lib_m_sin = yes; then
PDLIB="$PDLIB -lm"
else
- echo "$ac_t""no" 1>&6
-echo "math library required" || exit 1
+ echo "math library required" || exit 1
fi
-echo $ac_n "checking for pthread_create in -lpthread""... $ac_c" 1>&6
-echo "configure:1795: checking for pthread_create in -lpthread" >&5
-ac_lib_var=`echo pthread'_'pthread_create | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for pthread_create in -lpthread" >&5
+echo $ECHO_N "checking for pthread_create in -lpthread... $ECHO_C" >&6
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-lpthread $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1803 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
+
/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char pthread_create();
-
-int main() {
-pthread_create()
-; return 0; }
-EOF
-if { (eval echo configure:1814: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
+ builtin and then its argument prototype would still apply. */
+char pthread_create ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+pthread_create ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_pthread_pthread_create=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_pthread_pthread_create" >&5
+echo "${ECHO_T}$ac_cv_lib_pthread_pthread_create" >&6
+if test $ac_cv_lib_pthread_pthread_create = yes; then
PDLIB="$PDLIB -lpthread"
else
- echo "$ac_t""no" 1>&6
-echo "pthreads required" || exit 1
+ echo "pthreads required" || exit 1
fi
-if test "$alsa" = yes; then
- echo $ac_n "checking for snd_pcm_info in -lasound""... $ac_c" 1>&6
-echo "configure:1838: checking for snd_pcm_info in -lasound" >&5
-ac_lib_var=`echo asound'_'snd_pcm_info | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+if test "$alsa" != no; then
+ echo "$as_me:$LINENO: checking for snd_pcm_info in -lasound" >&5
+echo $ECHO_N "checking for snd_pcm_info in -lasound... $ECHO_C" >&6
+if test "${ac_cv_lib_asound_snd_pcm_info+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-lasound $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1846 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
+
/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char snd_pcm_info();
-
-int main() {
-snd_pcm_info()
-; return 0; }
-EOF
-if { (eval echo configure:1857: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
+ builtin and then its argument prototype would still apply. */
+char snd_pcm_info ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+snd_pcm_info ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_asound_snd_pcm_info=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_asound_snd_pcm_info=no
fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- PDLIB="$PDLIB -lasound"
+echo "$as_me:$LINENO: result: $ac_cv_lib_asound_snd_pcm_info" >&5
+echo "${ECHO_T}$ac_cv_lib_asound_snd_pcm_info" >&6
+if test $ac_cv_lib_asound_snd_pcm_info = yes; then
+ PDLIB="$PDLIB -lasound" ; alsa="yes"
else
- echo "$ac_t""no" 1>&6
-alsa=""
+ alsa=""
fi
-elif test "$alsa" = old; then
- echo $ac_n "checking for snd_pcm_info in -lasound""... $ac_c" 1>&6
-echo "configure:1880: checking for snd_pcm_info in -lasound" >&5
-ac_lib_var=`echo asound'_'snd_pcm_info | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- ac_save_LIBS="$LIBS"
-LIBS="-lasound $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 1888 "configure"
-#include "confdefs.h"
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char snd_pcm_info();
-
-int main() {
-snd_pcm_info()
-; return 0; }
-EOF
-if { (eval echo configure:1899: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- PDLIB="$PDLIB -lasound"
-else
- echo "$ac_t""no" 1>&6
-alsa=""
-fi
-
-fi
+echo "$as_me:$LINENO: checking for X" >&5
+echo $ECHO_N "checking for X... $ECHO_C" >&6
-# If we find X, set shell vars x_includes and x_libraries to the
-# paths, otherwise set no_x=yes.
-# Uses ac_ vars as temps to allow command line to override cache and checks.
-# --without-x overrides everything else, but does not touch the cache.
-echo $ac_n "checking for X""... $ac_c" 1>&6
-echo "configure:1927: checking for X" >&5
# Check whether --with-x or --without-x was given.
if test "${with_x+set}" = set; then
withval="$with_x"
- :
-fi
+fi;
# $have_x is `yes', `no', `disabled', or empty when we do not yet know.
if test "x$with_x" = xno; then
# The user explicitly disabled X.
@@ -1940,193 +3810,180 @@ else
# Both variables are already set.
have_x=yes
else
-if eval "test \"`echo '$''{'ac_cv_have_x'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+ if test "${ac_cv_have_x+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
# One or both of the vars are not set, and there is no cached value.
-ac_x_includes=NO ac_x_libraries=NO
-rm -fr conftestdir
-if mkdir conftestdir; then
- cd conftestdir
+ac_x_includes=no ac_x_libraries=no
+rm -fr conftest.dir
+if mkdir conftest.dir; then
+ cd conftest.dir
# Make sure to not put "make" in the Imakefile rules, since we grep it out.
- cat > Imakefile <<'EOF'
+ cat >Imakefile <<'_ACEOF'
acfindx:
@echo 'ac_im_incroot="${INCROOT}"; ac_im_usrlibdir="${USRLIBDIR}"; ac_im_libdir="${LIBDIR}"'
-EOF
+_ACEOF
if (xmkmf) >/dev/null 2>/dev/null && test -f Makefile; then
# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
eval `${MAKE-make} acfindx 2>/dev/null | grep -v make`
# Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR.
for ac_extension in a so sl; do
if test ! -f $ac_im_usrlibdir/libX11.$ac_extension &&
- test -f $ac_im_libdir/libX11.$ac_extension; then
+ test -f $ac_im_libdir/libX11.$ac_extension; then
ac_im_usrlibdir=$ac_im_libdir; break
fi
done
# Screen out bogus values from the imake configuration. They are
# bogus both because they are the default anyway, and because
# using them would break gcc on systems where it needs fixed includes.
- case "$ac_im_incroot" in
+ case $ac_im_incroot in
/usr/include) ;;
- *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes="$ac_im_incroot" ;;
+ *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;;
esac
- case "$ac_im_usrlibdir" in
+ case $ac_im_usrlibdir in
/usr/lib | /lib) ;;
- *) test -d "$ac_im_usrlibdir" && ac_x_libraries="$ac_im_usrlibdir" ;;
+ *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;;
esac
fi
cd ..
- rm -fr conftestdir
+ rm -fr conftest.dir
fi
-if test "$ac_x_includes" = NO; then
- # Guess where to find include files, by looking for this one X11 .h file.
- test -z "$x_direct_test_include" && x_direct_test_include=X11/Intrinsic.h
-
+# Standard set of common directories for X headers.
+# Check X11 before X11Rn because it is often a symlink to the current release.
+ac_x_header_dirs='
+/usr/X11/include
+/usr/X11R6/include
+/usr/X11R5/include
+/usr/X11R4/include
+
+/usr/include/X11
+/usr/include/X11R6
+/usr/include/X11R5
+/usr/include/X11R4
+
+/usr/local/X11/include
+/usr/local/X11R6/include
+/usr/local/X11R5/include
+/usr/local/X11R4/include
+
+/usr/local/include/X11
+/usr/local/include/X11R6
+/usr/local/include/X11R5
+/usr/local/include/X11R4
+
+/usr/X386/include
+/usr/x386/include
+/usr/XFree86/include/X11
+
+/usr/include
+/usr/local/include
+/usr/unsupported/include
+/usr/athena/include
+/usr/local/x11r5/include
+/usr/lpp/Xamples/include
+
+/usr/openwin/include
+/usr/openwin/share/include'
+
+if test "$ac_x_includes" = no; then
+ # Guess where to find include files, by looking for Intrinsic.h.
# First, try using that file with no special directory specified.
-cat > conftest.$ac_ext <<EOF
-#line 1989 "configure"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-#include <$x_direct_test_include>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:1994: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
+#include <X11/Intrinsic.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
# We can compile using X headers with no special include directory.
ac_x_includes=
else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
+ echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
- rm -rf conftest*
- # Look for the header file in a standard set of common directories.
-# Check X11 before X11Rn because it is often a symlink to the current release.
- for ac_dir in \
- /usr/X11/include \
- /usr/X11R6/include \
- /usr/X11R5/include \
- /usr/X11R4/include \
- \
- /usr/include/X11 \
- /usr/include/X11R6 \
- /usr/include/X11R5 \
- /usr/include/X11R4 \
- \
- /usr/local/X11/include \
- /usr/local/X11R6/include \
- /usr/local/X11R5/include \
- /usr/local/X11R4/include \
- \
- /usr/local/include/X11 \
- /usr/local/include/X11R6 \
- /usr/local/include/X11R5 \
- /usr/local/include/X11R4 \
- \
- /usr/X386/include \
- /usr/x386/include \
- /usr/XFree86/include/X11 \
- \
- /usr/include \
- /usr/local/include \
- /usr/unsupported/include \
- /usr/athena/include \
- /usr/local/x11r5/include \
- /usr/lpp/Xamples/include \
- \
- /usr/openwin/include \
- /usr/openwin/share/include \
- ; \
- do
- if test -r "$ac_dir/$x_direct_test_include"; then
- ac_x_includes=$ac_dir
- break
- fi
- done
+ for ac_dir in $ac_x_header_dirs; do
+ if test -r "$ac_dir/X11/Intrinsic.h"; then
+ ac_x_includes=$ac_dir
+ break
+ fi
+done
fi
-rm -f conftest*
-fi # $ac_x_includes = NO
+rm -f conftest.err conftest.$ac_ext
+fi # $ac_x_includes = no
-if test "$ac_x_libraries" = NO; then
+if test "$ac_x_libraries" = no; then
# Check for the libraries.
-
- test -z "$x_direct_test_library" && x_direct_test_library=Xt
- test -z "$x_direct_test_function" && x_direct_test_function=XtMalloc
-
# See if we find them without any special options.
# Don't add to $LIBS permanently.
- ac_save_LIBS="$LIBS"
- LIBS="-l$x_direct_test_library $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2063 "configure"
+ ac_save_LIBS=$LIBS
+ LIBS="-lXt $LIBS"
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-
-int main() {
-${x_direct_test_function}()
-; return 0; }
-EOF
-if { (eval echo configure:2070: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- LIBS="$ac_save_LIBS"
+#include <X11/Intrinsic.h>
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+XtMalloc (0)
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ LIBS=$ac_save_LIBS
# We can link X programs with no special library path.
ac_x_libraries=
else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- LIBS="$ac_save_LIBS"
-# First see if replacing the include by lib works.
-# Check X11 before X11Rn because it is often a symlink to the current release.
-for ac_dir in `echo "$ac_x_includes" | sed s/include/lib/` \
- /usr/X11/lib \
- /usr/X11R6/lib \
- /usr/X11R5/lib \
- /usr/X11R4/lib \
- \
- /usr/lib/X11 \
- /usr/lib/X11R6 \
- /usr/lib/X11R5 \
- /usr/lib/X11R4 \
- \
- /usr/local/X11/lib \
- /usr/local/X11R6/lib \
- /usr/local/X11R5/lib \
- /usr/local/X11R4/lib \
- \
- /usr/local/lib/X11 \
- /usr/local/lib/X11R6 \
- /usr/local/lib/X11R5 \
- /usr/local/lib/X11R4 \
- \
- /usr/X386/lib \
- /usr/x386/lib \
- /usr/XFree86/lib/X11 \
- \
- /usr/lib \
- /usr/local/lib \
- /usr/unsupported/lib \
- /usr/athena/lib \
- /usr/local/x11r5/lib \
- /usr/lpp/Xamples/lib \
- /lib/usr/lib/X11 \
- \
- /usr/openwin/lib \
- /usr/openwin/share/lib \
- ; \
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+LIBS=$ac_save_LIBS
+for ac_dir in `echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g`
do
+ # Don't even attempt the hair of trying to link an X program!
for ac_extension in a so sl; do
- if test -r $ac_dir/lib${x_direct_test_library}.$ac_extension; then
+ if test -r $ac_dir/libXt.$ac_extension; then
ac_x_libraries=$ac_dir
break 2
fi
done
done
fi
-rm -f conftest*
-fi # $ac_x_libraries = NO
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi # $ac_x_libraries = no
-if test "$ac_x_includes" = NO || test "$ac_x_libraries" = NO; then
+if test "$ac_x_includes" = no || test "$ac_x_libraries" = no; then
# Didn't find X anywhere. Cache the known absence of X.
ac_cv_have_x="have_x=no"
else
@@ -2135,12 +3992,14 @@ else
ac_x_includes=$ac_x_includes ac_x_libraries=$ac_x_libraries"
fi
fi
+
fi
eval "$ac_cv_have_x"
fi # $with_x != no
if test "$have_x" != yes; then
- echo "$ac_t""$have_x" 1>&6
+ echo "$as_me:$LINENO: result: $have_x" >&5
+echo "${ECHO_T}$have_x" >&6
no_x=yes
else
# If each of the values was on the command line, it overrides each guess.
@@ -2149,605 +4008,587 @@ else
# Update the cache value to reflect the command line values.
ac_cv_have_x="have_x=yes \
ac_x_includes=$x_includes ac_x_libraries=$x_libraries"
- echo "$ac_t""libraries $x_libraries, headers $x_includes" 1>&6
+ echo "$as_me:$LINENO: result: libraries $x_libraries, headers $x_includes" >&5
+echo "${ECHO_T}libraries $x_libraries, headers $x_includes" >&6
fi
-echo $ac_n "checking for XCreateWindow in -lX11""... $ac_c" 1>&6
-echo "configure:2157: checking for XCreateWindow in -lX11" >&5
-ac_lib_var=`echo X11'_'XCreateWindow | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for XCreateWindow in -lX11" >&5
+echo $ECHO_N "checking for XCreateWindow in -lX11... $ECHO_C" >&6
+if test "${ac_cv_lib_X11_XCreateWindow+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-lX11 -L$x_libraries $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2165 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
+
/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char XCreateWindow();
-
-int main() {
-XCreateWindow()
-; return 0; }
-EOF
-if { (eval echo configure:2176: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
+ builtin and then its argument prototype would still apply. */
+char XCreateWindow ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+XCreateWindow ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_X11_XCreateWindow=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_X11_XCreateWindow=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_X11_XCreateWindow" >&5
+echo "${ECHO_T}$ac_cv_lib_X11_XCreateWindow" >&6
+if test $ac_cv_lib_X11_XCreateWindow = yes; then
LIBS="$LIBS -lX11 -L$x_libraries"
else
- echo "$ac_t""no" 1>&6
-echo "no X11 found" || exit 1
+ echo "no X11 found" || exit 1
fi
-ac_safe=`echo "tcl.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for tcl.h""... $ac_c" 1>&6
-echo "configure:2201: checking for tcl.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2206 "configure"
-#include "confdefs.h"
-#include <tcl.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2211: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
+if test "${ac_cv_header_tcl_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for tcl.h" >&5
+echo $ECHO_N "checking for tcl.h... $ECHO_C" >&6
+if test "${ac_cv_header_tcl_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- :
-else
- echo "$ac_t""no" 1>&6
-ac_safe=`echo "tcl8.1/tcl.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for tcl8.1/tcl.h""... $ac_c" 1>&6
-echo "configure:2232: checking for tcl8.1/tcl.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: result: $ac_cv_header_tcl_h" >&5
+echo "${ECHO_T}$ac_cv_header_tcl_h" >&6
else
- cat > conftest.$ac_ext <<EOF
-#line 2237 "configure"
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking tcl.h usability" >&5
+echo $ECHO_N "checking tcl.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-#include <tcl8.1/tcl.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2242: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.1"
-else
- echo "$ac_t""no" 1>&6
-ac_safe=`echo "tcl8.2/tcl.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for tcl8.2/tcl.h""... $ac_c" 1>&6
-echo "configure:2263: checking for tcl8.2/tcl.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2268 "configure"
-#include "confdefs.h"
-#include <tcl8.2/tcl.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2273: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.2"
-else
- echo "$ac_t""no" 1>&6
-ac_safe=`echo "tcl8.3/tcl.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for tcl8.3/tcl.h""... $ac_c" 1>&6
-echo "configure:2294: checking for tcl8.3/tcl.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2299 "configure"
-#include "confdefs.h"
-#include <tcl8.3/tcl.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2304: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.3"
-else
- echo "$ac_t""no" 1>&6
-ac_safe=`echo "tcl8.4/tcl.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for tcl8.4/tcl.h""... $ac_c" 1>&6
-echo "configure:2325: checking for tcl8.4/tcl.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2330 "configure"
-#include "confdefs.h"
-#include <tcl8.4/tcl.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2335: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.4"
-else
- echo "$ac_t""no" 1>&6
-ac_safe=`echo "tcl8.5/tcl.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for tcl8.5/tcl.h""... $ac_c" 1>&6
-echo "configure:2356: checking for tcl8.5/tcl.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2361 "configure"
+$ac_includes_default
+#include <tcl.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_header_compiler=no
+fi
+rm -f conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking tcl.h presence" >&5
+echo $ECHO_N "checking tcl.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-#include <tcl8.5/tcl.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2366: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.5"
-else
- echo "$ac_t""no" 1>&6
-ac_safe=`echo "tcl8.6/tcl.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for tcl8.6/tcl.h""... $ac_c" 1>&6
-echo "configure:2387: checking for tcl8.6/tcl.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+#include <tcl.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ egrep -v '^ *\+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ else
+ ac_cpp_err=
+ fi
else
- cat > conftest.$ac_ext <<EOF
-#line 2392 "configure"
-#include "confdefs.h"
-#include <tcl8.6/tcl.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2397: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
+ ac_cpp_err=yes
fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.5"
-else
- echo "$ac_t""no" 1>&6
-ac_safe=`echo "tcl8.7/tcl.h" | sed 'y%./+-%__p_%'`
-echo $ac_n "checking for tcl8.7/tcl.h""... $ac_c" 1>&6
-echo "configure:2418: checking for tcl8.7/tcl.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
else
- cat > conftest.$ac_ext <<EOF
-#line 2423 "configure"
-#include "confdefs.h"
-#include <tcl8.7/tcl.h>
-EOF
-ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2428: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
-ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
-if test -z "$ac_err"; then
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=yes"
-else
- echo "$ac_err" >&5
- echo "configure: failed program was:" >&5
+ echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_header_$ac_safe=no"
-fi
-rm -f conftest*
-fi
-if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.5"
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc in
+ yes:no )
+ { echo "$as_me:$LINENO: WARNING: tcl.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: tcl.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: tcl.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: tcl.h: proceeding with the preprocessor's result" >&2;};;
+ no:yes )
+ { echo "$as_me:$LINENO: WARNING: tcl.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: tcl.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: tcl.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: tcl.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: tcl.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: tcl.h: proceeding with the preprocessor's result" >&2;};;
+esac
+echo "$as_me:$LINENO: checking for tcl.h" >&5
+echo $ECHO_N "checking for tcl.h... $ECHO_C" >&6
+if test "${ac_cv_header_tcl_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_tcl_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_tcl_h" >&5
+echo "${ECHO_T}$ac_cv_header_tcl_h" >&6
+
+fi
+if test $ac_cv_header_tcl_h = yes; then
+ :
else
- echo "$ac_t""no" 1>&6
-echo "no tcl/tk header found" || exit 1
-fi
-
-fi
-
-fi
-
+ echo "no tcl/tk header found" || exit 1
fi
-fi
-fi
-fi
-fi
-
-
-echo $ac_n "checking for main in -ltcl8.7""... $ac_c" 1>&6
-echo "configure:2466: checking for main in -ltcl8.7" >&5
-ac_lib_var=`echo tcl8.7'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+echo "$as_me:$LINENO: checking for main in -ltcl8.7" >&5
+echo $ECHO_N "checking for main in -ltcl8.7... $ECHO_C" >&6
+if test "${ac_cv_lib_tcl8_7_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltcl8.7 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2474 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2481: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tcl8.7 | sed -e 's/[^a-zA-Z0-9_]/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tcl8_7_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tcl8_7_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tcl8_7_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tcl8_7_main" >&6
+if test $ac_cv_lib_tcl8_7_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTCL8_7 1
+_ACEOF
LIBS="-ltcl8.7 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltcl8.6""... $ac_c" 1>&6
-echo "configure:2507: checking for main in -ltcl8.6" >&5
-ac_lib_var=`echo tcl8.6'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltcl8.6" >&5
+echo $ECHO_N "checking for main in -ltcl8.6... $ECHO_C" >&6
+if test "${ac_cv_lib_tcl8_6_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltcl8.6 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2515 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2522: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tcl8.6 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tcl8_6_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tcl8_6_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tcl8_6_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tcl8_6_main" >&6
+if test $ac_cv_lib_tcl8_6_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTCL8_6 1
+_ACEOF
LIBS="-ltcl8.6 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltcl8.5""... $ac_c" 1>&6
-echo "configure:2548: checking for main in -ltcl8.5" >&5
-ac_lib_var=`echo tcl8.5'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltcl8.5" >&5
+echo $ECHO_N "checking for main in -ltcl8.5... $ECHO_C" >&6
+if test "${ac_cv_lib_tcl8_5_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltcl8.5 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2556 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2563: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tcl8.5 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tcl8_5_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tcl8_5_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tcl8_5_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tcl8_5_main" >&6
+if test $ac_cv_lib_tcl8_5_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTCL8_5 1
+_ACEOF
LIBS="-ltcl8.5 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltcl8.4""... $ac_c" 1>&6
-echo "configure:2589: checking for main in -ltcl8.4" >&5
-ac_lib_var=`echo tcl8.4'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltcl8.4" >&5
+echo $ECHO_N "checking for main in -ltcl8.4... $ECHO_C" >&6
+if test "${ac_cv_lib_tcl8_4_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltcl8.4 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2597 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2604: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tcl8.4 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tcl8_4_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tcl8_4_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tcl8_4_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tcl8_4_main" >&6
+if test $ac_cv_lib_tcl8_4_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTCL8_4 1
+_ACEOF
LIBS="-ltcl8.4 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltcl8.3""... $ac_c" 1>&6
-echo "configure:2630: checking for main in -ltcl8.3" >&5
-ac_lib_var=`echo tcl8.3'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltcl8.3" >&5
+echo $ECHO_N "checking for main in -ltcl8.3... $ECHO_C" >&6
+if test "${ac_cv_lib_tcl8_3_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltcl8.3 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2638 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2645: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tcl8.3 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tcl8_3_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tcl8_3_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tcl8_3_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tcl8_3_main" >&6
+if test $ac_cv_lib_tcl8_3_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTCL8_3 1
+_ACEOF
LIBS="-ltcl8.3 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltcl8.2""... $ac_c" 1>&6
-echo "configure:2671: checking for main in -ltcl8.2" >&5
-ac_lib_var=`echo tcl8.2'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltcl8.2" >&5
+echo $ECHO_N "checking for main in -ltcl8.2... $ECHO_C" >&6
+if test "${ac_cv_lib_tcl8_2_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltcl8.2 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2679 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2686: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tcl8.2 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tcl8_2_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tcl8_2_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tcl8_2_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tcl8_2_main" >&6
+if test $ac_cv_lib_tcl8_2_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTCL8_2 1
+_ACEOF
LIBS="-ltcl8.2 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltcl8.0""... $ac_c" 1>&6
-echo "configure:2712: checking for main in -ltcl8.0" >&5
-ac_lib_var=`echo tcl8.0'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltcl8.0" >&5
+echo $ECHO_N "checking for main in -ltcl8.0... $ECHO_C" >&6
+if test "${ac_cv_lib_tcl8_0_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltcl8.0 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2720 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2727: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tcl8.0 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tcl8_0_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tcl8_0_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tcl8_0_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tcl8_0_main" >&6
+if test $ac_cv_lib_tcl8_0_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTCL8_0 1
+_ACEOF
LIBS="-ltcl8.0 $LIBS"
-else
- echo "$ac_t""no" 1>&6
fi
fi
@@ -2763,293 +4604,411 @@ fi
fi
-echo $ac_n "checking for main in -ltk8.7""... $ac_c" 1>&6
-echo "configure:2768: checking for main in -ltk8.7" >&5
-ac_lib_var=`echo tk8.7'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltk8.7" >&5
+echo $ECHO_N "checking for main in -ltk8.7... $ECHO_C" >&6
+if test "${ac_cv_lib_tk8_7_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltk8.7 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2776 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2783: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tk8.7 | sed -e 's/[^a-zA-Z0-9_]/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tk8_7_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tk8_7_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tk8_7_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tk8_7_main" >&6
+if test $ac_cv_lib_tk8_7_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTK8_7 1
+_ACEOF
LIBS="-ltk8.7 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltk8.6""... $ac_c" 1>&6
-echo "configure:2809: checking for main in -ltk8.6" >&5
-ac_lib_var=`echo tk8.6'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltk8.6" >&5
+echo $ECHO_N "checking for main in -ltk8.6... $ECHO_C" >&6
+if test "${ac_cv_lib_tk8_6_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltk8.6 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2817 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2824: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tk8.6 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tk8_6_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tk8_6_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tk8_6_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tk8_6_main" >&6
+if test $ac_cv_lib_tk8_6_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTK8_6 1
+_ACEOF
LIBS="-ltk8.6 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltk8.5""... $ac_c" 1>&6
-echo "configure:2850: checking for main in -ltk8.5" >&5
-ac_lib_var=`echo tk8.5'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltk8.5" >&5
+echo $ECHO_N "checking for main in -ltk8.5... $ECHO_C" >&6
+if test "${ac_cv_lib_tk8_5_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltk8.5 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2858 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2865: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tk8.5 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tk8_5_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tk8_5_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tk8_5_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tk8_5_main" >&6
+if test $ac_cv_lib_tk8_5_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTK8_5 1
+_ACEOF
LIBS="-ltk8.5 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltk8.4""... $ac_c" 1>&6
-echo "configure:2891: checking for main in -ltk8.4" >&5
-ac_lib_var=`echo tk8.4'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltk8.4" >&5
+echo $ECHO_N "checking for main in -ltk8.4... $ECHO_C" >&6
+if test "${ac_cv_lib_tk8_4_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltk8.4 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2899 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2906: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tk8.4 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tk8_4_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tk8_4_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tk8_4_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tk8_4_main" >&6
+if test $ac_cv_lib_tk8_4_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTK8_4 1
+_ACEOF
LIBS="-ltk8.4 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltk8.3""... $ac_c" 1>&6
-echo "configure:2932: checking for main in -ltk8.3" >&5
-ac_lib_var=`echo tk8.3'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltk8.3" >&5
+echo $ECHO_N "checking for main in -ltk8.3... $ECHO_C" >&6
+if test "${ac_cv_lib_tk8_3_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltk8.3 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2940 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2947: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tk8.3 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tk8_3_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tk8_3_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tk8_3_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tk8_3_main" >&6
+if test $ac_cv_lib_tk8_3_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTK8_3 1
+_ACEOF
LIBS="-ltk8.3 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltk8.2""... $ac_c" 1>&6
-echo "configure:2973: checking for main in -ltk8.2" >&5
-ac_lib_var=`echo tk8.2'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltk8.2" >&5
+echo $ECHO_N "checking for main in -ltk8.2... $ECHO_C" >&6
+if test "${ac_cv_lib_tk8_2_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltk8.2 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 2981 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:2988: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tk8.2 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tk8_2_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tk8_2_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tk8_2_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tk8_2_main" >&6
+if test $ac_cv_lib_tk8_2_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTK8_2 1
+_ACEOF
LIBS="-ltk8.2 $LIBS"
else
- echo "$ac_t""no" 1>&6
-echo $ac_n "checking for main in -ltk8.0""... $ac_c" 1>&6
-echo "configure:3014: checking for main in -ltk8.0" >&5
-ac_lib_var=`echo tk8.0'_'main | sed 'y%./+-%__p_%'`
-if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
+
+echo "$as_me:$LINENO: checking for main in -ltk8.0" >&5
+echo $ECHO_N "checking for main in -ltk8.0... $ECHO_C" >&6
+if test "${ac_cv_lib_tk8_0_main+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
else
- ac_save_LIBS="$LIBS"
+ ac_check_lib_save_LIBS=$LIBS
LIBS="-ltk8.0 $LIBS"
-cat > conftest.$ac_ext <<EOF
-#line 3022 "configure"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
#include "confdefs.h"
-int main() {
-main()
-; return 0; }
-EOF
-if { (eval echo configure:3029: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_lib_$ac_lib_var=no"
-fi
-rm -f conftest*
-LIBS="$ac_save_LIBS"
-fi
-if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo tk8.0 | sed -e 's/^a-zA-Z0-9_/_/g' \
- -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
- cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+main ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_tk8_0_main=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_tk8_0_main=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_tk8_0_main" >&5
+echo "${ECHO_T}$ac_cv_lib_tk8_0_main" >&6
+if test $ac_cv_lib_tk8_0_main = yes; then
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBTK8_0 1
+_ACEOF
LIBS="-ltk8.0 $LIBS"
-else
- echo "$ac_t""no" 1>&6
fi
fi
@@ -3066,24 +5025,29 @@ fi
-
-if test `uname -s` = FreeBSD;
-then
- LDFLAGS="-Wl,-export-dynamic"
- EXT=pd_freebsd
- MORECFLAGS=-DDL_OPEN
- SYSSRC=s_freebsd.c
- STRIPFLAG=-s
- GUINAME="pd-gui"
- OSNUMBER=0
-fi
-
if test `uname -s` = Linux;
then
LDFLAGS="-Wl,-export-dynamic"
EXT=pd_linux
- MORECFLAGS=-DDL_OPEN
- SYSSRC=s_linux.c
+ MORECFLAGS="-DDL_OPEN -DUSEAPI_PORTAUDIO -DPA_USE_OSS -DPA_LITTLE_ENDIAN \
+ -DUSEAPI_OSS \
+ -I../portaudio/pa_common \
+ -I../portaudio/pablio -I../portaudio/portmidi-macosx -Werror"
+ SYSSRC="s_midi_oss.c s_audio_pa.c s_audio_oss.c \
+ ../portaudio/pa_common/pa_allocation.c \
+ ../portaudio/pa_common/pa_converters.c \
+ ../portaudio/pa_common/pa_cpuload.c \
+ ../portaudio/pa_common/pa_dither.c \
+ ../portaudio/pa_common/pa_front.c \
+ ../portaudio/pa_common/pa_process.c \
+ ../portaudio/pa_common/pa_skeleton.c \
+ ../portaudio/pa_common/pa_stream.c \
+ ../portaudio/pa_common/pa_trace.c \
+ ../portaudio/pablio/pablio_pd.c \
+ ../portaudio/pablio/ringbuffer_pd.c \
+ ../portaudio/pa_unix/pa_unix_hostapis.c \
+ ../portaudio/pa_unix/pa_unix_util.c \
+ ../portaudio/pa_unix_oss/pa_unix_oss.c "
STRIPFLAG=-s
GUINAME="pd-gui"
if test $USE_OPT_CFLAGS == "YES";
@@ -3095,6 +5059,7 @@ then
OSNUMBER=0
fi
+
if test `uname -s` = IRIX64;
then
LDFLAGS="-n32 -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \
@@ -3125,19 +5090,24 @@ then
-framework AudioUnit -framework AudioToolbox \
-framework Carbon -framework CoreMIDI"
EXT=pd_darwin
- MORECFLAGS="-DMACOSX -I/usr/X11R6/include -I../portaudio/pa_common \
- -I../portaudio/pablio -I../portaudio/portmidi-macosx -Wno-error"
- SYSSRC="s_mac.c s_portaudio.c ../portaudio/pa_common/pa_lib.c \
- ../portaudio/pa_common/pa_trace.c \
- ../portaudio/pa_common/pa_convert.c \
- ../portaudio/pablio/pablio_pd.c \
- ../portaudio/pablio/ringbuffer_pd.c \
- ../portaudio/pa_mac_core/pa_mac_core.c \
- ../portaudio/portmidi-macosx/pmdarwin.c \
- ../portaudio/portmidi-macosx/pmmacosx.c \
- ../portaudio/portmidi-macosx/pmutil.c \
- ../portaudio/portmidi-macosx/portmidi.c \
- ../portaudio/portmidi-macosx/ptdarwin.c "
+ MORECFLAGS="-DMACOSX -I/usr/X11R6/include \
+ -I../portaudio_v18/pa_common \
+ -I../portaudio_v18/pablio \
+ -I../portmidi_osx \
+ -Wno-error \
+ -DUSEAPI_PORTAUDIO -DPA_BIG_ENDIAN"
+ SYSSRC="s_midi_pm.c s_audio_pa.c \
+ ../portaudio_v18/pa_common/pa_lib.c \
+ ../portaudio_v18/pa_common/pa_trace.c \
+ ../portaudio_v18/pa_common/pa_convert.c \
+ ../portaudio_v18/pablio/pablio_pd.c \
+ ../portaudio_v18/pablio/ringbuffer_pd.c \
+ ../portaudio_v18/pa_mac_core/pa_mac_core.c \
+ ../portmidi_osx/pmdarwin.c \
+ ../portmidi_osx/pmmacosx.c \
+ ../portmidi_osx/pmutil.c \
+ ../portmidi_osx/portmidi.c \
+ ../portmidi_osx/ptdarwin.c "
STRIPFLAG=""
GUINAME="pdtcl"
GUIFLAGS="-framework Tcl -framework Tk \
@@ -3154,281 +5124,836 @@ then
EXTERNTARGET=pd_darwin
fi
-trap '' 1 2 15
-cat > confcache <<\EOF
+ac_config_files="$ac_config_files makefile"
+cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
# tests run on this system so they can be shared between configure
-# scripts and configure runs. It is not useful on other systems.
-# If it contains results you don't want to keep, you may remove or edit it.
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
#
-# By default, configure uses ./config.cache as the cache file,
-# creating it if it does not exist already. You can give configure
-# the --cache-file=FILE option to use a different cache file; that is
-# what configure does when it calls configure scripts in
-# subdirectories, so they share the cache.
-# Giving --cache-file=/dev/null disables caching, for debugging configure.
-# config.status only pays attention to the cache file if you give it the
-# --recheck option to rerun configure.
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
#
-EOF
+# `ac_cv_env_foo' variables (set or unset) will be overriden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
# The following way of writing the cache mishandles newlines in values,
# but we know of no workaround that is simple, portable, and efficient.
# So, don't put newlines in cache variables' values.
# Ultrix sh set writes to stderr and can't be redirected directly,
# and sets the high bit in the cache file unless we assign to the vars.
-(set) 2>&1 |
- case `(ac_space=' '; set | grep ac_space) 2>&1` in
- *ac_space=\ *)
- # `set' does not quote correctly, so add quotes (double-quote substitution
- # turns \\\\ into \\, and sed turns \\ into \).
- sed -n \
- -e "s/'/'\\\\''/g" \
- -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
- ;;
- *)
- # `set' quotes correctly as required by POSIX, so do not add quotes.
- sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
- ;;
- esac >> confcache
-if cmp -s $cache_file confcache; then
- :
-else
+{
+ (set) 2>&1 |
+ case `(ac_space=' '; set | grep ac_space) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n \
+ "s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1=\\2/p"
+ ;;
+ esac;
+} |
+ sed '
+ t clear
+ : clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ /^ac_cv_env/!s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ : end' >>confcache
+if cmp -s $cache_file confcache; then :; else
if test -w $cache_file; then
- echo "updating cache $cache_file"
- cat confcache > $cache_file
+ test "x$cache_file" != "x/dev/null" && echo "updating cache $cache_file"
+ cat confcache >$cache_file
else
echo "not updating unwritable cache $cache_file"
fi
fi
rm -f confcache
-trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
-
test "x$prefix" = xNONE && prefix=$ac_default_prefix
# Let make expand exec_prefix.
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
-# Any assignment to VPATH causes Sun make to only execute
-# the first set of double-colon rules, so remove it if not needed.
-# If there is a colon in the path, we need to keep it.
+# VPATH may cause trouble with some makes, so we remove $(srcdir),
+# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
if test "x$srcdir" = x.; then
- ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+ ac_vpsub='/^[ ]*VPATH[ ]*=/{
+s/:*\$(srcdir):*/:/;
+s/:*\${srcdir}:*/:/;
+s/:*@srcdir@:*/:/;
+s/^\([^=]*=[ ]*\):*/\1/;
+s/:*$//;
+s/^[^=]*=[ ]*$//;
+}'
fi
-trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
-
# Transform confdefs.h into DEFS.
# Protect against shell expansion while executing Makefile rules.
# Protect against Makefile macro expansion.
-cat > conftest.defs <<\EOF
-s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%-D\1=\2%g
-s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g
-s%\[%\\&%g
-s%\]%\\&%g
-s%\$%$$%g
-EOF
-DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '`
-rm -f conftest.defs
-
-
-# Without the "./", some shells look in PATH for config.status.
-: ${CONFIG_STATUS=./config.status}
+#
+# If the first sed substitution is executed (which looks for macros that
+# take arguments), then we branch to the quote section. Otherwise,
+# look for a macro that doesn't take arguments.
+cat >confdef2opt.sed <<\_ACEOF
+t clear
+: clear
+s,^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\),-D\1=\2,g
+t quote
+s,^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\),-D\1=\2,g
+t quote
+d
+: quote
+s,[ `~#$^&*(){}\\|;'"<>?],\\&,g
+s,\[,\\&,g
+s,\],\\&,g
+s,\$,$$,g
+p
+_ACEOF
+# We use echo to avoid assuming a particular line-breaking character.
+# The extra dot is to prevent the shell from consuming trailing
+# line-breaks from the sub-command output. A line-break within
+# single-quotes doesn't work because, if this script is created in a
+# platform that uses two characters for line-breaks (e.g., DOS), tr
+# would break.
+ac_LF_and_DOT=`echo; echo .`
+DEFS=`sed -n -f confdef2opt.sed confdefs.h | tr "$ac_LF_and_DOT" ' .'`
+rm -f confdef2opt.sed
-echo creating $CONFIG_STATUS
-rm -f $CONFIG_STATUS
-cat > $CONFIG_STATUS <<EOF
-#! /bin/sh
-# Generated automatically by configure.
+
+
+: ${CONFIG_STATUS=./config.status}
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5
+echo "$as_me: creating $CONFIG_STATUS" >&6;}
+cat >$CONFIG_STATUS <<_ACEOF
+#! $SHELL
+# Generated by $as_me.
# Run this file to recreate the current configuration.
-# This directory was configured as follows,
-# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
-#
-# $0 $ac_configure_args
-#
# Compiler output produced by configure, useful for debugging
-# configure, is in ./config.log if it exists.
+# configure, is in config.log if it exists.
-ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
-for ac_option
+debug=false
+SHELL=\${CONFIG_SHELL-$SHELL}
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+## --------------------- ##
+## M4sh Initialization. ##
+## --------------------- ##
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+elif test -n "${BASH_VERSION+set}" && (set -o posix) >/dev/null 2>&1; then
+ set -o posix
+fi
+
+# NLS nuisances.
+# Support unset when possible.
+if (FOO=FOO; unset FOO) >/dev/null 2>&1; then
+ as_unset=unset
+else
+ as_unset=false
+fi
+
+(set +x; test -n "`(LANG=C; export LANG) 2>&1`") &&
+ { $as_unset LANG || test "${LANG+set}" != set; } ||
+ { LANG=C; export LANG; }
+(set +x; test -n "`(LC_ALL=C; export LC_ALL) 2>&1`") &&
+ { $as_unset LC_ALL || test "${LC_ALL+set}" != set; } ||
+ { LC_ALL=C; export LC_ALL; }
+(set +x; test -n "`(LC_TIME=C; export LC_TIME) 2>&1`") &&
+ { $as_unset LC_TIME || test "${LC_TIME+set}" != set; } ||
+ { LC_TIME=C; export LC_TIME; }
+(set +x; test -n "`(LC_CTYPE=C; export LC_CTYPE) 2>&1`") &&
+ { $as_unset LC_CTYPE || test "${LC_CTYPE+set}" != set; } ||
+ { LC_CTYPE=C; export LC_CTYPE; }
+(set +x; test -n "`(LANGUAGE=C; export LANGUAGE) 2>&1`") &&
+ { $as_unset LANGUAGE || test "${LANGUAGE+set}" != set; } ||
+ { LANGUAGE=C; export LANGUAGE; }
+(set +x; test -n "`(LC_COLLATE=C; export LC_COLLATE) 2>&1`") &&
+ { $as_unset LC_COLLATE || test "${LC_COLLATE+set}" != set; } ||
+ { LC_COLLATE=C; export LC_COLLATE; }
+(set +x; test -n "`(LC_NUMERIC=C; export LC_NUMERIC) 2>&1`") &&
+ { $as_unset LC_NUMERIC || test "${LC_NUMERIC+set}" != set; } ||
+ { LC_NUMERIC=C; export LC_NUMERIC; }
+(set +x; test -n "`(LC_MESSAGES=C; export LC_MESSAGES) 2>&1`") &&
+ { $as_unset LC_MESSAGES || test "${LC_MESSAGES+set}" != set; } ||
+ { LC_MESSAGES=C; export LC_MESSAGES; }
+
+
+# Name of the executable.
+as_me=`(basename "$0") 2>/dev/null ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)$' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/; q; }
+ /^X\/\(\/\/\)$/{ s//\1/; q; }
+ /^X\/\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+
+# PATH needs CR, and LINENO needs CR and PATH.
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ echo "#! /bin/sh" >conftest.sh
+ echo "exit 0" >>conftest.sh
+ chmod +x conftest.sh
+ if (PATH=".;."; conftest.sh) >/dev/null 2>&1; then
+ PATH_SEPARATOR=';'
+ else
+ PATH_SEPARATOR=:
+ fi
+ rm -f conftest.sh
+fi
+
+
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" || {
+ # Find who we are. Look in the path if we contain no path at all
+ # relative or not.
+ case $0 in
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
do
- case "\$ac_option" in
- -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
- echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
- exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
- -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
- echo "$CONFIG_STATUS generated by autoconf version 2.13"
- exit 0 ;;
- -help | --help | --hel | --he | --h)
- echo "\$ac_cs_usage"; exit 0 ;;
- *) echo "\$ac_cs_usage"; exit 1 ;;
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+done
+
+ ;;
esac
+ # We did not find ourselves, most probably we were run as `sh COMMAND'
+ # in which case we are not to be found in the path.
+ if test "x$as_myself" = x; then
+ as_myself=$0
+ fi
+ if test ! -f "$as_myself"; then
+ { { echo "$as_me:$LINENO: error: cannot find myself; rerun with an absolute path" >&5
+echo "$as_me: error: cannot find myself; rerun with an absolute path" >&2;}
+ { (exit 1); exit 1; }; }
+ fi
+ case $CONFIG_SHELL in
+ '')
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for as_base in sh bash ksh sh5; do
+ case $as_dir in
+ /*)
+ if ("$as_dir/$as_base" -c '
+ as_lineno_1=$LINENO
+ as_lineno_2=$LINENO
+ as_lineno_3=`(expr $as_lineno_1 + 1) 2>/dev/null`
+ test "x$as_lineno_1" != "x$as_lineno_2" &&
+ test "x$as_lineno_3" = "x$as_lineno_2" ') 2>/dev/null; then
+ CONFIG_SHELL=$as_dir/$as_base
+ export CONFIG_SHELL
+ exec "$CONFIG_SHELL" "$0" ${1+"$@"}
+ fi;;
+ esac
+ done
done
+;;
+ esac
-ac_given_srcdir=$srcdir
-ac_given_INSTALL="$INSTALL"
+ # Create $as_me.lineno as a copy of $as_myself, but with $LINENO
+ # uniformly replaced by the line number. The first 'sed' inserts a
+ # line-number line before each line; the second 'sed' does the real
+ # work. The second script uses 'N' to pair each line-number line
+ # with the numbered line, and appends trailing '-' during
+ # substitution so that $LINENO is not a special case at line end.
+ # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the
+ # second 'sed' script. Blame Lee E. McMahon for sed's syntax. :-)
+ sed '=' <$as_myself |
+ sed '
+ N
+ s,$,-,
+ : loop
+ s,^\(['$as_cr_digits']*\)\(.*\)[$]LINENO\([^'$as_cr_alnum'_]\),\1\2\1\3,
+ t loop
+ s,-$,,
+ s,^['$as_cr_digits']*\n,,
+ ' >$as_me.lineno &&
+ chmod +x $as_me.lineno ||
+ { { echo "$as_me:$LINENO: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&5
+echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2;}
+ { (exit 1); exit 1; }; }
+
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensible to this).
+ . ./$as_me.lineno
+ # Exit status is that of the last command.
+ exit
+}
-trap 'rm -fr `echo "makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
-EOF
-cat >> $CONFIG_STATUS <<EOF
-# Protect against being on the right side of a sed subst in config.status.
-sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
- s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
-$ac_vpsub
-$extrasub
-s%@SHELL@%$SHELL%g
-s%@CFLAGS@%$CFLAGS%g
-s%@CPPFLAGS@%$CPPFLAGS%g
-s%@CXXFLAGS@%$CXXFLAGS%g
-s%@FFLAGS@%$FFLAGS%g
-s%@DEFS@%$DEFS%g
-s%@LDFLAGS@%$LDFLAGS%g
-s%@LIBS@%$LIBS%g
-s%@exec_prefix@%$exec_prefix%g
-s%@prefix@%$prefix%g
-s%@program_transform_name@%$program_transform_name%g
-s%@bindir@%$bindir%g
-s%@sbindir@%$sbindir%g
-s%@libexecdir@%$libexecdir%g
-s%@datadir@%$datadir%g
-s%@sysconfdir@%$sysconfdir%g
-s%@sharedstatedir@%$sharedstatedir%g
-s%@localstatedir@%$localstatedir%g
-s%@libdir@%$libdir%g
-s%@includedir@%$includedir%g
-s%@oldincludedir@%$oldincludedir%g
-s%@infodir@%$infodir%g
-s%@mandir@%$mandir%g
-s%@alsa@%$alsa%g
-s%@rme@%$rme%g
-s%@PDLIB@%$PDLIB%g
-s%@DEFINES@%$DEFINES%g
-s%@MORECFLAGS@%$MORECFLAGS%g
-s%@EXT@%$EXT%g
-s%@OPT_CFLAGS@%$OPT_CFLAGS%g
-s%@USE_OPT_CFLAGS@%$USE_OPT_CFLAGS%g
-s%@SYSSRC@%$SYSSRC%g
-s%@STRIPFLAG@%$STRIPFLAG%g
-s%@GUINAME@%$GUINAME%g
-s%@GUIFLAGS@%$GUIFLAGS%g
-s%@OSNUMBER@%$OSNUMBER%g
-s%@EXTERNTARGET@%$EXTERNTARGET%g
-s%@CC@%$CC%g
-s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
-s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
-s%@INSTALL_DATA@%$INSTALL_DATA%g
-s%@SET_MAKE@%$SET_MAKE%g
-s%@CPP@%$CPP%g
+case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in
+ *c*,-n*) ECHO_N= ECHO_C='
+' ECHO_T=' ' ;;
+ *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;;
+ *) ECHO_N= ECHO_C='\c' ECHO_T= ;;
+esac
-CEOF
-EOF
-
-cat >> $CONFIG_STATUS <<\EOF
-
-# Split the substitutions into bite-sized pieces for seds with
-# small command number limits, like on Digital OSF/1 and HP-UX.
-ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
-ac_file=1 # Number of current file.
-ac_beg=1 # First line for current file.
-ac_end=$ac_max_sed_cmds # Line after last line for current file.
-ac_more_lines=:
-ac_sed_cmds=""
-while $ac_more_lines; do
- if test $ac_beg -gt 1; then
- sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+if expr a : '\(a\)' >/dev/null 2>&1; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+rm -f conf$$ conf$$.exe conf$$.file
+echo >conf$$.file
+if ln -s conf$$.file conf$$ 2>/dev/null; then
+ # We could just check for DJGPP; but this test a) works b) is more generic
+ # and c) will remain valid once DJGPP supports symlinks (DJGPP 2.04).
+ if test -f conf$$.exe; then
+ # Don't use ln at all; we don't have any links
+ as_ln_s='cp -p'
else
- sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ as_ln_s='ln -s'
fi
- if test ! -s conftest.s$ac_file; then
- ac_more_lines=false
- rm -f conftest.s$ac_file
- else
- if test -z "$ac_sed_cmds"; then
- ac_sed_cmds="sed -f conftest.s$ac_file"
- else
- ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
- fi
- ac_file=`expr $ac_file + 1`
- ac_beg=$ac_end
- ac_end=`expr $ac_end + $ac_max_sed_cmds`
- fi
-done
-if test -z "$ac_sed_cmds"; then
- ac_sed_cmds=cat
+elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+else
+ as_ln_s='cp -p'
fi
-EOF
+rm -f conf$$ conf$$.exe conf$$.file
-cat >> $CONFIG_STATUS <<EOF
+as_executable_p="test -f"
-CONFIG_FILES=\${CONFIG_FILES-"makefile"}
-EOF
-cat >> $CONFIG_STATUS <<\EOF
-for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
- # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
- case "$ac_file" in
- *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
- ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
- *) ac_file_in="${ac_file}.in" ;;
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="sed y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="sed y%*+%pp%;s%[^_$as_cr_alnum]%_%g"
+
+
+# IFS
+# We need space, tab and new line, in precisely that order.
+as_nl='
+'
+IFS=" $as_nl"
+
+# CDPATH.
+$as_unset CDPATH || test "${CDPATH+set}" != set || { CDPATH=$PATH_SEPARATOR; export CDPATH; }
+
+exec 6>&1
+
+# Open the log real soon, to keep \$[0] and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling. Logging --version etc. is OK.
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+} >&5
+cat >&5 <<_CSEOF
+
+This file was extended by $as_me, which was
+generated by GNU Autoconf 2.53. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+_CSEOF
+echo "on `(hostname || uname -n) 2>/dev/null | sed 1q`" >&5
+echo >&5
+_ACEOF
+
+# Files that config.status was made for.
+if test -n "$ac_config_files"; then
+ echo "config_files=\"$ac_config_files\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_headers"; then
+ echo "config_headers=\"$ac_config_headers\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_links"; then
+ echo "config_links=\"$ac_config_links\"" >>$CONFIG_STATUS
+fi
+
+if test -n "$ac_config_commands"; then
+ echo "config_commands=\"$ac_config_commands\"" >>$CONFIG_STATUS
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+
+ac_cs_usage="\
+\`$as_me' instantiates files from templates according to the
+current configuration.
+
+Usage: $0 [OPTIONS] [FILE]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+
+Configuration files:
+$config_files
+
+Report bugs to <bug-autoconf@gnu.org>."
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+ac_cs_version="\\
+config.status
+configured by $0, generated by GNU Autoconf 2.53,
+ with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
+
+Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001
+Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+srcdir=$srcdir
+INSTALL="$INSTALL"
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+# If no file are specified by the user, then we need to provide default
+# value. By we need to know if files were specified by the user.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=*)
+ ac_option=`expr "x$1" : 'x\([^=]*\)='`
+ ac_optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
+ shift
+ set dummy "$ac_option" "$ac_optarg" ${1+"$@"}
+ shift
+ ;;
+ -*);;
+ *) # This is not an option, so the user has probably given explicit
+ # arguments.
+ ac_need_defaults=false;;
esac
- # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+ case $1 in
+ # Handling of the options.
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running $SHELL $0 " $ac_configure_args " --no-create --no-recursion"
+ exec $SHELL $0 $ac_configure_args --no-create --no-recursion ;;
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+ --version | --vers* | -V )
+ echo "$ac_cs_version"; exit 0 ;;
+ --he | --h)
+ # Conflict between --help and --header
+ { { echo "$as_me:$LINENO: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: ambiguous option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; };;
+ --help | --hel | -h )
+ echo "$ac_cs_usage"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ shift
+ CONFIG_FILES="$CONFIG_FILES $1"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ shift
+ CONFIG_HEADERS="$CONFIG_HEADERS $1"
+ ac_need_defaults=false;;
+
+ # This is an error.
+ -*) { { echo "$as_me:$LINENO: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&5
+echo "$as_me: error: unrecognized option: $1
+Try \`$0 --help' for more information." >&2;}
+ { (exit 1); exit 1; }; } ;;
- # Remove last slash and all that follows it. Not all systems have dirname.
- ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
- if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
- # The file is in a subdirectory.
- test ! -d "$ac_dir" && mkdir "$ac_dir"
- ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
- # A "../" for each directory in $ac_dir_suffix.
- ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
- else
- ac_dir_suffix= ac_dots=
+ *) ac_config_targets="$ac_config_targets $1" ;;
+
+ esac
+ shift
+done
+
+_ACEOF
+
+
+
+
+
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_config_target in $ac_config_targets
+do
+ case "$ac_config_target" in
+ # Handling of arguments.
+ "makefile" ) CONFIG_FILES="$CONFIG_FILES makefile" ;;
+ *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5
+echo "$as_me: error: invalid argument: $ac_config_target" >&2;}
+ { (exit 1); exit 1; }; };;
+ esac
+done
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+fi
+
+# Create a temporary directory, and hook for its removal unless debugging.
+$debug ||
+{
+ trap 'exit_status=$?; rm -rf $tmp && exit $exit_status' 0
+ trap '{ (exit 1); exit 1; }' 1 2 13 15
+}
+
+# Create a (secure) tmp directory for tmp files.
+: ${TMPDIR=/tmp}
+{
+ tmp=`(umask 077 && mktemp -d -q "$TMPDIR/csXXXXXX") 2>/dev/null` &&
+ test -n "$tmp" && test -d "$tmp"
+} ||
+{
+ tmp=$TMPDIR/cs$$-$RANDOM
+ (umask 077 && mkdir $tmp)
+} ||
+{
+ echo "$me: cannot create a temporary directory in $TMPDIR" >&2
+ { (exit 1); exit 1; }
+}
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<_ACEOF
+
+#
+# CONFIG_FILES section.
+#
+
+# No need to generate the scripts if there are no CONFIG_FILES.
+# This happens for instance when ./config.status config.h
+if test -n "\$CONFIG_FILES"; then
+ # Protect against being on the right side of a sed subst in config.status.
+ sed 's/,@/@@/; s/@,/@@/; s/,;t t\$/@;t t/; /@;t t\$/s/[\\\\&,]/\\\\&/g;
+ s/@@/,@/; s/@@/@,/; s/@;t t\$/,;t t/' >\$tmp/subs.sed <<\\CEOF
+s,@SHELL@,$SHELL,;t t
+s,@PATH_SEPARATOR@,$PATH_SEPARATOR,;t t
+s,@PACKAGE_NAME@,$PACKAGE_NAME,;t t
+s,@PACKAGE_TARNAME@,$PACKAGE_TARNAME,;t t
+s,@PACKAGE_VERSION@,$PACKAGE_VERSION,;t t
+s,@PACKAGE_STRING@,$PACKAGE_STRING,;t t
+s,@PACKAGE_BUGREPORT@,$PACKAGE_BUGREPORT,;t t
+s,@exec_prefix@,$exec_prefix,;t t
+s,@prefix@,$prefix,;t t
+s,@program_transform_name@,$program_transform_name,;t t
+s,@bindir@,$bindir,;t t
+s,@sbindir@,$sbindir,;t t
+s,@libexecdir@,$libexecdir,;t t
+s,@datadir@,$datadir,;t t
+s,@sysconfdir@,$sysconfdir,;t t
+s,@sharedstatedir@,$sharedstatedir,;t t
+s,@localstatedir@,$localstatedir,;t t
+s,@libdir@,$libdir,;t t
+s,@includedir@,$includedir,;t t
+s,@oldincludedir@,$oldincludedir,;t t
+s,@infodir@,$infodir,;t t
+s,@mandir@,$mandir,;t t
+s,@build_alias@,$build_alias,;t t
+s,@host_alias@,$host_alias,;t t
+s,@target_alias@,$target_alias,;t t
+s,@DEFS@,$DEFS,;t t
+s,@ECHO_C@,$ECHO_C,;t t
+s,@ECHO_N@,$ECHO_N,;t t
+s,@ECHO_T@,$ECHO_T,;t t
+s,@LIBS@,$LIBS,;t t
+s,@alsa@,$alsa,;t t
+s,@jack@,$jack,;t t
+s,@PDLIB@,$PDLIB,;t t
+s,@DEFINES@,$DEFINES,;t t
+s,@MORECFLAGS@,$MORECFLAGS,;t t
+s,@EXT@,$EXT,;t t
+s,@OPT_CFLAGS@,$OPT_CFLAGS,;t t
+s,@USE_OPT_CFLAGS@,$USE_OPT_CFLAGS,;t t
+s,@SYSSRC@,$SYSSRC,;t t
+s,@STRIPFLAG@,$STRIPFLAG,;t t
+s,@GUINAME@,$GUINAME,;t t
+s,@GUIFLAGS@,$GUIFLAGS,;t t
+s,@OSNUMBER@,$OSNUMBER,;t t
+s,@EXTERNTARGET@,$EXTERNTARGET,;t t
+s,@CC@,$CC,;t t
+s,@CFLAGS@,$CFLAGS,;t t
+s,@LDFLAGS@,$LDFLAGS,;t t
+s,@CPPFLAGS@,$CPPFLAGS,;t t
+s,@ac_ct_CC@,$ac_ct_CC,;t t
+s,@EXEEXT@,$EXEEXT,;t t
+s,@OBJEXT@,$OBJEXT,;t t
+s,@INSTALL_PROGRAM@,$INSTALL_PROGRAM,;t t
+s,@INSTALL_SCRIPT@,$INSTALL_SCRIPT,;t t
+s,@INSTALL_DATA@,$INSTALL_DATA,;t t
+s,@SET_MAKE@,$SET_MAKE,;t t
+s,@CPP@,$CPP,;t t
+CEOF
+
+_ACEOF
+
+ cat >>$CONFIG_STATUS <<\_ACEOF
+ # Split the substitutions into bite-sized pieces for seds with
+ # small command number limits, like on Digital OSF/1 and HP-UX.
+ ac_max_sed_lines=48
+ ac_sed_frag=1 # Number of current file.
+ ac_beg=1 # First line for current file.
+ ac_end=$ac_max_sed_lines # Line after last line for current file.
+ ac_more_lines=:
+ ac_sed_cmds=
+ while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ else
+ sed "${ac_end}q" $tmp/subs.sed >$tmp/subs.frag
+ fi
+ if test ! -s $tmp/subs.frag; then
+ ac_more_lines=false
+ else
+ # The purpose of the label and of the branching condition is to
+ # speed up the sed processing (if there are no `@' at all, there
+ # is no need to browse any of the substitutions).
+ # These are the two extra sed commands mentioned above.
+ (echo ':t
+ /@[a-zA-Z_][a-zA-Z_0-9]*@/!b' && cat $tmp/subs.frag) >$tmp/subs-$ac_sed_frag.sed
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f $tmp/subs-$ac_sed_frag.sed"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f $tmp/subs-$ac_sed_frag.sed"
+ fi
+ ac_sed_frag=`expr $ac_sed_frag + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_lines`
+ fi
+ done
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
fi
+fi # test -n "$CONFIG_FILES"
- case "$ac_given_srcdir" in
- .) srcdir=.
- if test -z "$ac_dots"; then top_srcdir=.
- else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
- /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
- *) # Relative path.
- srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
- top_srcdir="$ac_dots$ac_given_srcdir" ;;
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+for ac_file in : $CONFIG_FILES; do test "x$ac_file" = x: && continue
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case $ac_file in
+ - | *:- | *:-:* ) # input from stdin
+ cat >$tmp/stdin
+ ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ *:* ) ac_file_in=`echo "$ac_file" | sed 's,[^:]*:,,'`
+ ac_file=`echo "$ac_file" | sed 's,:.*,,'` ;;
+ * ) ac_file_in=$ac_file.in ;;
esac
- case "$ac_given_INSTALL" in
- [/$]*) INSTALL="$ac_given_INSTALL" ;;
- *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ # Compute @srcdir@, @top_srcdir@, and @INSTALL@ for subdirectories.
+ ac_dir=`(dirname "$ac_file") 2>/dev/null ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| \
+ . : '\(.\)' 2>/dev/null ||
+echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/; q; }
+ /^X\(\/\/\)[^/].*/{ s//\1/; q; }
+ /^X\(\/\/\)$/{ s//\1/; q; }
+ /^X\(\/\).*/{ s//\1/; q; }
+ s/.*/./; q'`
+ { case "$ac_dir" in
+ [\\/]* | ?:[\\/]* ) as_incr_dir=;;
+ *) as_incr_dir=.;;
+esac
+as_dummy="$ac_dir"
+for as_mkdir_dir in `IFS='/\\'; set X $as_dummy; shift; echo "$@"`; do
+ case $as_mkdir_dir in
+ # Skip DOS drivespec
+ ?:) as_incr_dir=$as_mkdir_dir ;;
+ *)
+ as_incr_dir=$as_incr_dir/$as_mkdir_dir
+ test -d "$as_incr_dir" ||
+ mkdir "$as_incr_dir" ||
+ { { echo "$as_me:$LINENO: error: cannot create \"$ac_dir\"" >&5
+echo "$as_me: error: cannot create \"$ac_dir\"" >&2;}
+ { (exit 1); exit 1; }; }
+ ;;
esac
+done; }
+
+ ac_builddir=.
+
+if test "$ac_dir" != .; then
+ ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'`
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_top_builddir=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,../,g'`
+else
+ ac_dir_suffix= ac_top_builddir=
+fi
- echo creating "$ac_file"
- rm -f "$ac_file"
- configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
- case "$ac_file" in
- *Makefile*) ac_comsub="1i\\
-# $configure_input" ;;
- *) ac_comsub= ;;
+case $srcdir in
+ .) # No --srcdir option. We are building in place.
+ ac_srcdir=.
+ if test -z "$ac_top_builddir"; then
+ ac_top_srcdir=.
+ else
+ ac_top_srcdir=`echo $ac_top_builddir | sed 's,/$,,'`
+ fi ;;
+ [\\/]* | ?:[\\/]* ) # Absolute path.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir ;;
+ *) # Relative path.
+ ac_srcdir=$ac_top_builddir$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_builddir$srcdir ;;
+esac
+# Don't blindly perform a `cd "$ac_dir"/$ac_foo && pwd` since $ac_foo can be
+# absolute.
+ac_abs_builddir=`cd "$ac_dir" && cd $ac_builddir && pwd`
+ac_abs_top_builddir=`cd "$ac_dir" && cd $ac_top_builddir && pwd`
+ac_abs_srcdir=`cd "$ac_dir" && cd $ac_srcdir && pwd`
+ac_abs_top_srcdir=`cd "$ac_dir" && cd $ac_top_srcdir && pwd`
+
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_builddir$INSTALL ;;
esac
- ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
- sed -e "$ac_comsub
-s%@configure_input@%$configure_input%g
-s%@srcdir@%$srcdir%g
-s%@top_srcdir@%$top_srcdir%g
-s%@INSTALL@%$INSTALL%g
-" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
-fi; done
-rm -f conftest.s*
+ if test x"$ac_file" != x-; then
+ { echo "$as_me:$LINENO: creating $ac_file" >&5
+echo "$as_me: creating $ac_file" >&6;}
+ rm -f "$ac_file"
+ fi
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ if test x"$ac_file" = x-; then
+ configure_input=
+ else
+ configure_input="$ac_file. "
+ fi
+ configure_input=$configure_input"Generated from `echo $ac_file_in |
+ sed 's,.*/,,'` by configure."
+
+ # First look for the input files in the build tree, otherwise in the
+ # src tree.
+ ac_file_inputs=`IFS=:
+ for f in $ac_file_in; do
+ case $f in
+ -) echo $tmp/stdin ;;
+ [\\/$]*)
+ # Absolute (can't be DOS-style, as IFS=:)
+ test -f "$f" || { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ echo $f;;
+ *) # Relative
+ if test -f "$f"; then
+ # Build tree
+ echo $f
+ elif test -f "$srcdir/$f"; then
+ # Source tree
+ echo $srcdir/$f
+ else
+ # /dev/null tree
+ { { echo "$as_me:$LINENO: error: cannot find input file: $f" >&5
+echo "$as_me: error: cannot find input file: $f" >&2;}
+ { (exit 1); exit 1; }; }
+ fi;;
+ esac
+ done` || { (exit 1); exit 1; }
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF
+ sed "$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s,@configure_input@,$configure_input,;t t
+s,@srcdir@,$ac_srcdir,;t t
+s,@abs_srcdir@,$ac_abs_srcdir,;t t
+s,@top_srcdir@,$ac_top_srcdir,;t t
+s,@abs_top_srcdir@,$ac_abs_top_srcdir,;t t
+s,@builddir@,$ac_builddir,;t t
+s,@abs_builddir@,$ac_abs_builddir,;t t
+s,@top_builddir@,$ac_top_builddir,;t t
+s,@abs_top_builddir@,$ac_abs_top_builddir,;t t
+s,@INSTALL@,$ac_INSTALL,;t t
+" $ac_file_inputs | (eval "$ac_sed_cmds") >$tmp/out
+ rm -f $tmp/stdin
+ if test x"$ac_file" != x-; then
+ mv $tmp/out $ac_file
+ else
+ cat $tmp/out
+ rm -f $tmp/out
+ fi
-EOF
-cat >> $CONFIG_STATUS <<EOF
+done
+_ACEOF
-EOF
-cat >> $CONFIG_STATUS <<\EOF
+cat >>$CONFIG_STATUS <<\_ACEOF
-exit 0
-EOF
+{ (exit 0); exit 0; }
+_ACEOF
chmod +x $CONFIG_STATUS
-rm -fr confdefs* $ac_clean_files
-test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+ac_clean_files=$ac_clean_files_save
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || { (exit 1); exit 1; }
+fi
diff --git a/pd/src/configure.in b/pd/src/configure.in
index da70b29e..52d45609 100644
--- a/pd/src/configure.in
+++ b/pd/src/configure.in
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(d_arithmetic.c)
AC_SUBST(alsa)
-AC_SUBST(rme)
+AC_SUBST(jack)
AC_SUBST(PDLIB)
AC_SUBST(DEFINES)
AC_SUBST(MORECFLAGS)
@@ -20,12 +20,10 @@ dnl other defaults
dnl check for features
-AC_ARG_ENABLE(alsa, [ --enable-alsa compile ALSA support],
- alsa="yes")
-AC_ARG_ENABLE(old-alsa,[ --enable-old-alsa ALSA 0.5x support],
- alsa="old")
-AC_ARG_ENABLE(rme, [ --enable-rme compile RME support],
- rme="yes")
+AC_ARG_ENABLE(alsa, [ --disable-alsa disable ALSA],
+ alsa="no")
+AC_ARG_ENABLE(jack, [ --enable-jack jack audio server],
+ jack="yes")
AC_ARG_ENABLE(debug, [ --enable-debug debugging support],
USE_OPT_CFLAGS="NO", USE_OPT_CFLAGS="YES")
@@ -70,10 +68,8 @@ AC_CHECK_LIB(pthread, pthread_create,PDLIB="$PDLIB -lpthread",
echo "pthreads required" || exit 1)
dnl This should be fixed so Pd can use ALSA shared libraries where appropriate.
-if test "$alsa" = yes; then
- AC_CHECK_LIB(asound,snd_pcm_info,PDLIB="$PDLIB -lasound",alsa="")
-elif test "$alsa" = old; then
- AC_CHECK_LIB(asound,snd_pcm_info,PDLIB="$PDLIB -lasound",alsa="")
+if test "$alsa" != no; then
+ AC_CHECK_LIB(asound,snd_pcm_info,PDLIB="$PDLIB -lasound" ; alsa="yes",alsa="")
fi
dnl Find paths to includes and libraries for X11
@@ -84,15 +80,7 @@ AC_CHECK_LIB(X11, XCreateWindow, LIBS="$LIBS -lX11 -L$x_libraries",
dnl look for tcl 8.x... do I really have to go through all this!?
-AC_CHECK_HEADER(tcl.h,,
- AC_CHECK_HEADER(tcl8.1/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.1",
- AC_CHECK_HEADER(tcl8.2/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.2",
- AC_CHECK_HEADER(tcl8.3/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.3",
- AC_CHECK_HEADER(tcl8.4/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.4",
- AC_CHECK_HEADER(tcl8.5/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.5",
- AC_CHECK_HEADER(tcl8.6/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.5",
- AC_CHECK_HEADER(tcl8.7/tcl.h,GUIFLAGS="$GUIFLAGS -I /usr/include/tcl8.5",
- echo "no tcl/tk header found" || exit 1))))))))
+AC_CHECK_HEADER(tcl.h,, echo "no tcl/tk header found" || exit 1)
AC_CHECK_LIB(tcl8.7, main,,
AC_CHECK_LIB(tcl8.6, main,,
@@ -114,24 +102,29 @@ dnl Checking for tk.h or tkstep.h - not used at the moment
dnl AC_CHECK_HEADER(tk.h,DEFINES="$DEFINES -DTKINC=\\\"tk.h\\\"")
dnl AC_CHECK_HEADER(tkstep.h,DEFINES="$DEFINES -DTKINC=\\\"tkstep.h\\\"")
-
-if test `uname -s` = FreeBSD;
-then
- LDFLAGS="-Wl,-export-dynamic"
- EXT=pd_freebsd
- MORECFLAGS=-DDL_OPEN
- SYSSRC=s_freebsd.c
- STRIPFLAG=-s
- GUINAME="pd-gui"
- OSNUMBER=0
-fi
-
if test `uname -s` = Linux;
then
LDFLAGS="-Wl,-export-dynamic"
EXT=pd_linux
- MORECFLAGS=-DDL_OPEN
- SYSSRC=s_linux.c
+ MORECFLAGS="-DDL_OPEN -DUSEAPI_PORTAUDIO -DPA_USE_OSS -DPA_LITTLE_ENDIAN \
+ -DUSEAPI_OSS \
+ -I../portaudio/pa_common \
+ -I../portaudio/pablio -I../portaudio/portmidi-macosx -Werror"
+ SYSSRC="s_midi_oss.c s_audio_pa.c s_audio_oss.c \
+ ../portaudio/pa_common/pa_allocation.c \
+ ../portaudio/pa_common/pa_converters.c \
+ ../portaudio/pa_common/pa_cpuload.c \
+ ../portaudio/pa_common/pa_dither.c \
+ ../portaudio/pa_common/pa_front.c \
+ ../portaudio/pa_common/pa_process.c \
+ ../portaudio/pa_common/pa_skeleton.c \
+ ../portaudio/pa_common/pa_stream.c \
+ ../portaudio/pa_common/pa_trace.c \
+ ../portaudio/pablio/pablio_pd.c \
+ ../portaudio/pablio/ringbuffer_pd.c \
+ ../portaudio/pa_unix/pa_unix_hostapis.c \
+ ../portaudio/pa_unix/pa_unix_util.c \
+ ../portaudio/pa_unix_oss/pa_unix_oss.c "
STRIPFLAG=-s
GUINAME="pd-gui"
if test $USE_OPT_CFLAGS == "YES";
@@ -143,6 +136,8 @@ then
OSNUMBER=0
fi
+dnl **** note -- SGI/IRIX code is broken here!!! ***
+
if test `uname -s` = IRIX64;
then
LDFLAGS="-n32 -DUNIX -DIRIX -DN32 -woff 1080,1064,1185 \
@@ -173,19 +168,24 @@ then
-framework AudioUnit -framework AudioToolbox \
-framework Carbon -framework CoreMIDI"
EXT=pd_darwin
- MORECFLAGS="-DMACOSX -I/usr/X11R6/include -I../portaudio/pa_common \
- -I../portaudio/pablio -I../portaudio/portmidi-macosx -Wno-error"
- SYSSRC="s_mac.c s_portaudio.c ../portaudio/pa_common/pa_lib.c \
- ../portaudio/pa_common/pa_trace.c \
- ../portaudio/pa_common/pa_convert.c \
- ../portaudio/pablio/pablio_pd.c \
- ../portaudio/pablio/ringbuffer_pd.c \
- ../portaudio/pa_mac_core/pa_mac_core.c \
- ../portaudio/portmidi-macosx/pmdarwin.c \
- ../portaudio/portmidi-macosx/pmmacosx.c \
- ../portaudio/portmidi-macosx/pmutil.c \
- ../portaudio/portmidi-macosx/portmidi.c \
- ../portaudio/portmidi-macosx/ptdarwin.c "
+ MORECFLAGS="-DMACOSX -I/usr/X11R6/include \
+ -I../portaudio_v18/pa_common \
+ -I../portaudio_v18/pablio \
+ -I../portmidi_osx \
+ -Wno-error \
+ -DUSEAPI_PORTAUDIO -DPA_BIG_ENDIAN"
+ SYSSRC="s_midi_pm.c s_audio_pa.c \
+ ../portaudio_v18/pa_common/pa_lib.c \
+ ../portaudio_v18/pa_common/pa_trace.c \
+ ../portaudio_v18/pa_common/pa_convert.c \
+ ../portaudio_v18/pablio/pablio_pd.c \
+ ../portaudio_v18/pablio/ringbuffer_pd.c \
+ ../portaudio_v18/pa_mac_core/pa_mac_core.c \
+ ../portmidi_osx/pmdarwin.c \
+ ../portmidi_osx/pmmacosx.c \
+ ../portmidi_osx/pmutil.c \
+ ../portmidi_osx/portmidi.c \
+ ../portmidi_osx/ptdarwin.c "
STRIPFLAG=""
GUINAME="pdtcl"
GUIFLAGS="-framework Tcl -framework Tk \
diff --git a/pd/src/d_array.c b/pd/src/d_array.c
index e870b522..2a78e144 100644
--- a/pd/src/d_array.c
+++ b/pd/src/d_array.c
@@ -6,7 +6,7 @@
/* LATER make tabread4 and tabread~ */
-#include "m_imp.h"
+#include "m_pd.h"
/* ------------------------- tabwrite~ -------------------------- */
@@ -432,8 +432,8 @@ static t_int *tabread4_tilde_perform(t_int *w)
post("fp = %lx, shit = %lx, b = %f", fp, buf->b_shit, b); */
cminusb = c-b;
*out++ = b + frac * (
- cminusb - 0.5f * (frac-1.) * (
- (a - d + 3.0f * cminusb) * frac + (b - a - cminusb)
+ cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
)
);
}
@@ -501,7 +501,7 @@ static void tabread4_tilde_setup(void)
#define LOWOFFSET 1 /* word offset to find LSB */
#define int32 long /* a data type that has 32 bits */
#else
-#ifdef NT
+#ifdef MSW
/* little-endian; most significant byte is at highest address */
#define HIOFFSET 1
#define LOWOFFSET 0
@@ -545,7 +545,7 @@ static void tabread4_tilde_setup(void)
#endif /* MACOSX */
#endif /* __linux__ */
-#endif /* NT */
+#endif /* MSW */
#endif /* SGI */
union tabfudge
@@ -616,8 +616,8 @@ static t_int *tabosc4_tilde_perform(t_int *w)
d = addr[3];
cminusb = c-b;
*out++ = b + frac * (
- cminusb - 0.5f * (frac-1.) * (
- (a - d + 3.0f * cminusb) * frac + (b - a - cminusb)
+ cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
)
);
}
@@ -944,8 +944,8 @@ static void tabread4_float(t_tabread4 *x, t_float f)
d = fp[2];
cminusb = c-b;
outlet_float(x->x_obj.ob_outlet, b + frac * (
- cminusb - 0.5f * (frac-1.) * (
- (a - d + 3.0f * cminusb) * frac + (b - a - cminusb))));
+ cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b))));
}
}
diff --git a/pd/src/d_ctl.c b/pd/src/d_ctl.c
index 461703d2..a2f5cd76 100644
--- a/pd/src/d_ctl.c
+++ b/pd/src/d_ctl.c
@@ -2,15 +2,15 @@
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-/* The sig~ and line~ routines; possibly fancier envelope generators to
- come later.
+/* sig~ and line~ control-to-signal converters;
+ snapshot~ signal-to-control converter.
*/
#include "m_pd.h"
#include "math.h"
/* -------------------------- sig~ ------------------------------ */
-static t_class *sig_class;
+static t_class *sig_tilde_class;
typedef struct _sig
{
@@ -18,16 +18,17 @@ typedef struct _sig
float x_f;
} t_sig;
-static t_int *sig_perform(t_int *w)
+static t_int *sig_tilde_perform(t_int *w)
{
t_float f = *(t_float *)(w[1]);
t_float *out = (t_float *)(w[2]);
int n = (int)(w[3]);
- while (n--) *out++ = f;
+ while (n--)
+ *out++ = f;
return (w+4);
}
-static t_int *sig_perf8(t_int *w)
+static t_int *sig_tilde_perf8(t_int *w)
{
t_float f = *(t_float *)(w[1]);
t_float *out = (t_float *)(w[2]);
@@ -50,39 +51,39 @@ static t_int *sig_perf8(t_int *w)
void dsp_add_scalarcopy(t_sample *in, t_sample *out, int n)
{
if (n&7)
- dsp_add(sig_perform, 3, in, out, n);
+ dsp_add(sig_tilde_perform, 3, in, out, n);
else
- dsp_add(sig_perf8, 3, in, out, n);
+ dsp_add(sig_tilde_perf8, 3, in, out, n);
}
-static void sig_float(t_sig *x, t_float f)
+static void sig_tilde_float(t_sig *x, t_float f)
{
x->x_f = f;
}
-static void sig_dsp(t_sig *x, t_signal **sp)
+static void sig_tilde_dsp(t_sig *x, t_signal **sp)
{
- dsp_add(sig_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
+ dsp_add(sig_tilde_perform, 3, &x->x_f, sp[0]->s_vec, sp[0]->s_n);
}
-static void *sig_new(t_floatarg f)
+static void *sig_tilde_new(t_floatarg f)
{
- t_sig *x = (t_sig *)pd_new(sig_class);
+ t_sig *x = (t_sig *)pd_new(sig_tilde_class);
x->x_f = f;
outlet_new(&x->x_obj, gensym("signal"));
return (x);
}
-static void sig_setup(void)
+static void sig_tilde_setup(void)
{
- sig_class = class_new(gensym("sig~"), (t_newmethod)sig_new, 0,
+ sig_tilde_class = class_new(gensym("sig~"), (t_newmethod)sig_tilde_new, 0,
sizeof(t_sig), 0, A_DEFFLOAT, 0);
- class_addfloat(sig_class, (t_method)sig_float);
- class_addmethod(sig_class, (t_method)sig_dsp, gensym("dsp"), 0);
+ class_addfloat(sig_tilde_class, (t_method)sig_tilde_float);
+ class_addmethod(sig_tilde_class, (t_method)sig_tilde_dsp, gensym("dsp"), 0);
}
/* -------------------------- line~ ------------------------------ */
-static t_class *line_class;
+static t_class *line_tilde_class;
typedef struct _line
{
@@ -92,14 +93,14 @@ typedef struct _line
float x_biginc;
float x_inc;
float x_1overn;
- float x_msectodsptick;
+ float x_dspticktomsec;
float x_inletvalue;
float x_inletwas;
int x_ticksleft;
int x_retarget;
} t_line;
-static t_int *line_perform(t_int *w)
+static t_int *line_tilde_perform(t_int *w)
{
t_line *x = (t_line *)(w[1]);
t_float *out = (t_float *)(w[2]);
@@ -110,7 +111,7 @@ static t_int *line_perform(t_int *w)
x->x_value = f = 0;
if (x->x_retarget)
{
- int nticks = x->x_inletwas * x->x_msectodsptick;
+ int nticks = x->x_inletwas * x->x_dspticktomsec;
if (!nticks) nticks = 1;
x->x_ticksleft = nticks;
x->x_biginc = (x->x_target - x->x_value)/(float)nticks;
@@ -132,7 +133,7 @@ static t_int *line_perform(t_int *w)
return (w+4);
}
-static void line_float(t_line *x, t_float f)
+static void line_tilde_float(t_line *x, t_float f)
{
if (x->x_inletvalue <= 0)
{
@@ -148,22 +149,22 @@ static void line_float(t_line *x, t_float f)
}
}
-static void line_stop(t_line *x)
+static void line_tilde_stop(t_line *x)
{
x->x_target = x->x_value;
x->x_ticksleft = x->x_retarget = 0;
}
-static void line_dsp(t_line *x, t_signal **sp)
+static void line_tilde_dsp(t_line *x, t_signal **sp)
{
- dsp_add(line_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ dsp_add(line_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
x->x_1overn = 1./sp[0]->s_n;
- x->x_msectodsptick = sp[0]->s_sr / (1000 * sp[0]->s_n);
+ x->x_dspticktomsec = sp[0]->s_sr / (1000 * sp[0]->s_n);
}
-static void *line_new(void)
+static void *line_tilde_new(void)
{
- t_line *x = (t_line *)pd_new(line_class);
+ t_line *x = (t_line *)pd_new(line_tilde_class);
outlet_new(&x->x_obj, gensym("signal"));
floatinlet_new(&x->x_obj, &x->x_inletvalue);
x->x_ticksleft = x->x_retarget = 0;
@@ -171,17 +172,200 @@ static void *line_new(void)
return (x);
}
-static void line_setup(void)
+static void line_tilde_setup(void)
{
- line_class = class_new(gensym("line~"), line_new, 0,
+ line_tilde_class = class_new(gensym("line~"), line_tilde_new, 0,
sizeof(t_line), 0, 0);
- class_addfloat(line_class, (t_method)line_float);
- class_addmethod(line_class, (t_method)line_dsp, gensym("dsp"), 0);
- class_addmethod(line_class, (t_method)line_stop, gensym("stop"), 0);
+ class_addfloat(line_tilde_class, (t_method)line_tilde_float);
+ class_addmethod(line_tilde_class, (t_method)line_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(line_tilde_class, (t_method)line_tilde_stop,
+ gensym("stop"), 0);
+}
+
+/* -------------------------- vline~ ------------------------------ */
+static t_class *vline_tilde_class;
+
+typedef struct _vseg
+{
+ double s_targettime;
+ double s_starttime;
+ float s_target;
+ struct _vseg *s_next;
+} t_vseg;
+
+typedef struct _vline
+{
+ t_object x_obj;
+ double x_value;
+ double x_inc;
+ double x_referencetime;
+ double x_samppermsec;
+ double x_msecpersamp;
+ double x_targettime;
+ float x_target;
+ float x_inlet1;
+ float x_inlet2;
+ t_vseg *x_list;
+} t_vline;
+
+static t_int *vline_tilde_perform(t_int *w)
+{
+ t_vline *x = (t_vline *)(w[1]);
+ t_float *out = (t_float *)(w[2]);
+ int n = (int)(w[3]), i;
+ double f = x->x_value;
+ double inc = x->x_inc;
+ double msecpersamp = x->x_msecpersamp;
+ double samppermsec = x->x_samppermsec;
+ double timenow = clock_gettimesince(x->x_referencetime) - n * msecpersamp;
+ t_vseg *s = x->x_list;
+ for (i = 0; i < n; i++)
+ {
+ double timenext = timenow + msecpersamp;
+ checknext:
+ if (s)
+ {
+ /* has starttime elapsed? If so update value and increment */
+ if (s->s_starttime < timenext)
+ {
+ if (x->x_targettime <= timenext)
+ f = x->x_target, inc = 0;
+ /* if zero-length segment bash output value */
+ if (s->s_targettime <= s->s_starttime)
+ {
+ f = s->s_target;
+ inc = 0;
+ }
+ else
+ {
+ double incpermsec = (s->s_target - f)/
+ (s->s_targettime - s->s_starttime);
+ f = f + incpermsec * (timenext - s->s_starttime);
+ inc = incpermsec * msecpersamp;
+ }
+ x->x_inc = inc;
+ x->x_target = s->s_target;
+ x->x_targettime = s->s_targettime;
+ x->x_list = s->s_next;
+ t_freebytes(s, sizeof(*s));
+ s = x->x_list;
+ goto checknext;
+ }
+ }
+ if (x->x_targettime <= timenext)
+ f = x->x_target, inc = 0;
+ *out++ = f;
+ f = f + inc;
+ timenow = timenext;
+ }
+ x->x_value = f;
+ return (w+4);
+}
+
+static void vline_tilde_stop(t_vline *x)
+{
+ t_vseg *s1, *s2;
+ for (s1 = x->x_list; s1; s1 = s2)
+ s2 = s1->s_next, t_freebytes(s1, sizeof(*s1));
+ x->x_list = 0;
+ x->x_inc = 0;
+ x->x_inlet1 = x->x_inlet2 = 0;
+}
+
+static void vline_tilde_float(t_vline *x, t_float f)
+{
+ double timenow = clock_gettimesince(x->x_referencetime);
+ float inlet1 = (x->x_inlet1 < 0 ? 0 : x->x_inlet1);
+ float inlet2 = x->x_inlet2;
+ double starttime = timenow + inlet2;
+ t_vseg *s1, *s2, *deletefrom = 0,
+ *snew = (t_vseg *)t_getbytes(sizeof(*snew));
+ if (PD_BADFLOAT(f))
+ f = 0;
+
+ /* negative delay input means stop and jump immediately to new value */
+ if (inlet2 < 0)
+ {
+ vline_tilde_stop(x);
+ x->x_value = f;
+ return;
+ }
+ /* check if we supplant the first item in the list. We supplant
+ an item by having an earlier starttime, or an equal starttime unless
+ the equal one was instantaneous and the new one isn't (in which case
+ we'll do a jump-and-slide starting at that time.) */
+ if (!x->x_list || x->x_list->s_starttime > starttime ||
+ (x->x_list->s_starttime == starttime &&
+ (x->x_list->s_targettime > x->x_list->s_starttime || inlet1 <= 0)))
+ {
+ deletefrom = x->x_list;
+ x->x_list = snew;
+ }
+ else
+ {
+ for (s1 = x->x_list; s2 = s1->s_next; s1 = s2)
+ {
+ if (s2->s_starttime > starttime ||
+ (s2->s_starttime == starttime &&
+ (s2->s_targettime > s2->s_starttime || inlet1 <= 0)))
+ {
+ deletefrom = s2;
+ s1->s_next = snew;
+ goto didit;
+ }
+ }
+ s1->s_next = snew;
+ deletefrom = 0;
+ didit: ;
+ }
+ while (deletefrom)
+ {
+ s1 = deletefrom->s_next;
+ t_freebytes(deletefrom, sizeof(*deletefrom));
+ deletefrom = s1;
+ }
+ snew->s_next = 0;
+ snew->s_target = f;
+ snew->s_starttime = starttime;
+ snew->s_targettime = starttime + inlet1;
+ x->x_inlet1 = x->x_inlet2 = 0;
+}
+
+static void vline_tilde_dsp(t_vline *x, t_signal **sp)
+{
+ dsp_add(vline_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ x->x_samppermsec = ((double)(sp[0]->s_sr)) / 1000;
+ x->x_msecpersamp = ((double)1000) / sp[0]->s_sr;
+}
+
+static void *vline_tilde_new(void)
+{
+ t_vline *x = (t_vline *)pd_new(vline_tilde_class);
+ outlet_new(&x->x_obj, gensym("signal"));
+ floatinlet_new(&x->x_obj, &x->x_inlet1);
+ floatinlet_new(&x->x_obj, &x->x_inlet2);
+ x->x_inlet1 = x->x_inlet2 = 0;
+ x->x_value = x->x_inc = 0;
+ x->x_referencetime = clock_getlogicaltime();
+ x->x_list = 0;
+ x->x_samppermsec = 0;
+ return (x);
+}
+
+static void vline_tilde_setup(void)
+{
+ vline_tilde_class = class_new(gensym("vline~"), vline_tilde_new,
+ (t_method)vline_tilde_stop, sizeof(t_vline), 0, 0);
+ class_addfloat(vline_tilde_class, (t_method)vline_tilde_float);
+ class_addmethod(vline_tilde_class, (t_method)vline_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(vline_tilde_class, (t_method)vline_tilde_stop,
+ gensym("stop"), 0);
}
/* -------------------------- snapshot~ ------------------------------ */
-static t_class *snapshot_class;
+static t_class *snapshot_tilde_class;
typedef struct _snapshot
{
@@ -190,16 +374,16 @@ typedef struct _snapshot
float x_f;
} t_snapshot;
-static void *snapshot_new(void)
+static void *snapshot_tilde_new(void)
{
- t_snapshot *x = (t_snapshot *)pd_new(snapshot_class);
+ t_snapshot *x = (t_snapshot *)pd_new(snapshot_tilde_class);
x->x_value = 0;
outlet_new(&x->x_obj, &s_float);
x->x_f = 0;
return (x);
}
-static t_int *snapshot_perform(t_int *w)
+static t_int *snapshot_tilde_perform(t_int *w)
{
t_float *in = (t_float *)(w[1]);
t_float *out = (t_float *)(w[2]);
@@ -207,25 +391,120 @@ static t_int *snapshot_perform(t_int *w)
return (w+3);
}
-static void snapshot_dsp(t_snapshot *x, t_signal **sp)
+static void snapshot_tilde_dsp(t_snapshot *x, t_signal **sp)
{
- dsp_add(snapshot_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1), &x->x_value);
+ dsp_add(snapshot_tilde_perform, 2, sp[0]->s_vec + (sp[0]->s_n-1),
+ &x->x_value);
}
-static void snapshot_bang(t_snapshot *x)
+static void snapshot_tilde_bang(t_snapshot *x)
{
outlet_float(x->x_obj.ob_outlet, x->x_value);
}
-static void snapshot_setup(void)
+static void snapshot_tilde_set(t_snapshot *x, t_floatarg f)
{
- snapshot_class = class_new(gensym("snapshot~"), snapshot_new, 0,
+ x->x_value = f;
+}
+
+static void snapshot_tilde_setup(void)
+{
+ snapshot_tilde_class = class_new(gensym("snapshot~"), snapshot_tilde_new, 0,
sizeof(t_snapshot), 0, 0);
- CLASS_MAINSIGNALIN(snapshot_class, t_snapshot, x_f);
- class_addmethod(snapshot_class, (t_method)snapshot_dsp, gensym("dsp"), 0);
- class_addbang(snapshot_class, snapshot_bang);
+ CLASS_MAINSIGNALIN(snapshot_tilde_class, t_snapshot, x_f);
+ class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_dsp,
+ gensym("dsp"), 0);
+ class_addmethod(snapshot_tilde_class, (t_method)snapshot_tilde_set,
+ gensym("set"), A_DEFFLOAT, 0);
+ class_addbang(snapshot_tilde_class, snapshot_tilde_bang);
+}
+
+/* -------------------------- vsnapshot~ ------------------------------ */
+static t_class *vsnapshot_tilde_class;
+
+typedef struct _vsnapshot
+{
+ t_object x_obj;
+ int x_n;
+ int x_gotone;
+ t_sample *x_vec;
+ float x_f;
+ float x_sampspermsec;
+ double x_time;
+} t_vsnapshot;
+
+static void *vsnapshot_tilde_new(void)
+{
+ t_vsnapshot *x = (t_vsnapshot *)pd_new(vsnapshot_tilde_class);
+ outlet_new(&x->x_obj, &s_float);
+ x->x_f = 0;
+ x->x_n = 0;
+ x->x_vec = 0;
+ x->x_gotone = 0;
+ return (x);
}
+static t_int *vsnapshot_tilde_perform(t_int *w)
+{
+ t_float *in = (t_float *)(w[1]);
+ t_vsnapshot *x = (t_vsnapshot *)(w[2]);
+ t_float *out = x->x_vec;
+ int n = x->x_n, i;
+ for (i = 0; i < n; i++)
+ out[i] = in[i];
+ x->x_time = clock_getlogicaltime();
+ x->x_gotone = 1;
+ return (w+3);
+}
+
+static void vsnapshot_tilde_dsp(t_vsnapshot *x, t_signal **sp)
+{
+ int n = sp[0]->s_n;
+ if (n != x->x_n)
+ {
+ if (x->x_vec)
+ t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
+ x->x_vec = (t_sample *)getbytes(n * sizeof(t_sample));
+ x->x_gotone = 0;
+ x->x_n = n;
+ }
+ x->x_sampspermsec = sp[0]->s_sr / 1000;
+ dsp_add(vsnapshot_tilde_perform, 2, sp[0]->s_vec, x);
+}
+
+static void vsnapshot_tilde_bang(t_vsnapshot *x)
+{
+ float val;
+ if (x->x_gotone)
+ {
+ int indx = clock_gettimesince(x->x_time) * x->x_sampspermsec;
+ if (indx < 0)
+ indx = 0;
+ else if (indx >= x->x_n)
+ indx = x->x_n - 1;
+ val = x->x_vec[indx];
+ }
+ else val = 0;
+ outlet_float(x->x_obj.ob_outlet, val);
+}
+
+static void vsnapshot_tilde_ff(t_vsnapshot *x)
+{
+ if (x->x_vec)
+ t_freebytes(x->x_vec, x->x_n * sizeof(t_sample));
+}
+
+static void vsnapshot_tilde_setup(void)
+{
+ vsnapshot_tilde_class = class_new(gensym("vsnapshot~"),
+ vsnapshot_tilde_new, (t_method)vsnapshot_tilde_ff,
+ sizeof(t_vsnapshot), 0, 0);
+ CLASS_MAINSIGNALIN(vsnapshot_tilde_class, t_vsnapshot, x_f);
+ class_addmethod(vsnapshot_tilde_class, (t_method)vsnapshot_tilde_dsp, gensym("dsp"), 0);
+ class_addbang(vsnapshot_tilde_class, vsnapshot_tilde_bang);
+}
+
+
/* ---------------- env~ - simple envelope follower. ----------------- */
#define MAXOVERLAP 10
@@ -246,10 +525,10 @@ typedef struct sigenv
float x_f;
} t_sigenv;
-t_class *sigenv_class;
-static void sigenv_tick(t_sigenv *x);
+t_class *env_tilde_class;
+static void env_tilde_tick(t_sigenv *x);
-static void *sigenv_new(t_floatarg fnpoints, t_floatarg fperiod)
+static void *env_tilde_new(t_floatarg fnpoints, t_floatarg fperiod)
{
int npoints = fnpoints;
int period = fperiod;
@@ -266,7 +545,7 @@ static void *sigenv_new(t_floatarg fnpoints, t_floatarg fperiod)
error("env: couldn't allocate buffer");
return (0);
}
- x = (t_sigenv *)pd_new(sigenv_class);
+ x = (t_sigenv *)pd_new(env_tilde_class);
x->x_buf = buf;
x->x_npoints = npoints;
x->x_phase = 0;
@@ -275,13 +554,13 @@ static void *sigenv_new(t_floatarg fnpoints, t_floatarg fperiod)
for (i = 0; i < npoints; i++)
buf[i] = (1. - cos((2 * 3.14159 * i) / npoints))/npoints;
for (; i < npoints+MAXVSTAKEN; i++) buf[i] = 0;
- x->x_clock = clock_new(x, (t_method)sigenv_tick);
+ x->x_clock = clock_new(x, (t_method)env_tilde_tick);
x->x_outlet = outlet_new(&x->x_obj, gensym("float"));
x->x_f = 0;
return (x);
}
-static t_int *sigenv_perform(t_int *w)
+static t_int *env_tilde_perform(t_int *w)
{
t_sigenv *x = (t_sigenv *)(w[1]);
t_float *in = (t_float *)(w[2]);
@@ -319,33 +598,33 @@ static t_int *sigenv_perform(t_int *w)
return (w+4);
}
-static void sigenv_dsp(t_sigenv *x, t_signal **sp)
+static void env_tilde_dsp(t_sigenv *x, t_signal **sp)
{
if (x->x_period % sp[0]->s_n) x->x_realperiod =
x->x_period + sp[0]->s_n - (x->x_period % sp[0]->s_n);
else x->x_realperiod = x->x_period;
- dsp_add(sigenv_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
- if (sp[0]->s_n > MAXVSTAKEN) bug("sigenv_dsp");
+ dsp_add(env_tilde_perform, 3, x, sp[0]->s_vec, sp[0]->s_n);
+ if (sp[0]->s_n > MAXVSTAKEN) bug("env_tilde_dsp");
}
-static void sigenv_tick(t_sigenv *x) /* callback function for the clock */
+static void env_tilde_tick(t_sigenv *x) /* callback function for the clock */
{
outlet_float(x->x_outlet, powtodb(x->x_result));
}
-static void sigenv_ff(t_sigenv *x) /* cleanup on free */
+static void env_tilde_ff(t_sigenv *x) /* cleanup on free */
{
clock_free(x->x_clock);
freebytes(x->x_buf, (x->x_npoints + MAXVSTAKEN) * sizeof(float));
}
-void sigenv_setup(void )
+void env_tilde_setup(void )
{
- sigenv_class = class_new(gensym("env~"), (t_newmethod)sigenv_new,
- (t_method)sigenv_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
- CLASS_MAINSIGNALIN(sigenv_class, t_sigenv, x_f);
- class_addmethod(sigenv_class, (t_method)sigenv_dsp, gensym("dsp"), 0);
+ env_tilde_class = class_new(gensym("env~"), (t_newmethod)env_tilde_new,
+ (t_method)env_tilde_ff, sizeof(t_sigenv), 0, A_DEFFLOAT, A_DEFFLOAT, 0);
+ CLASS_MAINSIGNALIN(env_tilde_class, t_sigenv, x_f);
+ class_addmethod(env_tilde_class, (t_method)env_tilde_dsp, gensym("dsp"), 0);
}
/* --------------------- threshold~ ----------------------------- */
@@ -487,10 +766,12 @@ static void threshold_tilde_setup( void)
void d_ctl_setup(void)
{
- sig_setup();
- line_setup();
- snapshot_setup();
- sigenv_setup();
+ sig_tilde_setup();
+ line_tilde_setup();
+ vline_tilde_setup();
+ snapshot_tilde_setup();
+ vsnapshot_tilde_setup();
+ env_tilde_setup();
threshold_tilde_setup();
}
diff --git a/pd/src/d_dac.c b/pd/src/d_dac.c
index 620adba5..c090a214 100644
--- a/pd/src/d_dac.c
+++ b/pd/src/d_dac.c
@@ -5,7 +5,8 @@
/* The dac~ and adc~ routines.
*/
-#include "m_imp.h"
+#include "m_pd.h"
+#include "s_stuff.h"
/* ----------------------------- dac~ --------------------------- */
static t_class *dac_class;
@@ -47,11 +48,11 @@ static void dac_dsp(t_dac *x, t_signal **sp)
for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
{
int ch = *ip - 1;
- if ((*sp2)->s_n != DACBLKSIZE)
+ if ((*sp2)->s_n != DEFDACBLKSIZE)
error("dac~: bad vector size");
else if (ch >= 0 && ch < sys_get_outchannels())
- dsp_add(plus_perform, 4, sys_soundout + DACBLKSIZE*ch,
- (*sp2)->s_vec, sys_soundout + DACBLKSIZE*ch, DACBLKSIZE);
+ dsp_add(plus_perform, 4, sys_soundout + DEFDACBLKSIZE*ch,
+ (*sp2)->s_vec, sys_soundout + DEFDACBLKSIZE*ch, DEFDACBLKSIZE);
}
}
@@ -153,12 +154,12 @@ static void adc_dsp(t_adc *x, t_signal **sp)
for (i = x->x_n, ip = x->x_vec, sp2 = sp; i--; ip++, sp2++)
{
int ch = *ip - 1;
- if ((*sp2)->s_n != DACBLKSIZE)
+ if ((*sp2)->s_n != DEFDACBLKSIZE)
error("adc~: bad vector size");
else if (ch >= 0 && ch < sys_get_inchannels())
- dsp_add_copy(sys_soundin + DACBLKSIZE*ch,
- (*sp2)->s_vec, DACBLKSIZE);
- else dsp_add_zero((*sp2)->s_vec, DACBLKSIZE);
+ dsp_add_copy(sys_soundin + DEFDACBLKSIZE*ch,
+ (*sp2)->s_vec, DEFDACBLKSIZE);
+ else dsp_add_zero((*sp2)->s_vec, DEFDACBLKSIZE);
}
}
@@ -170,7 +171,7 @@ static void adc_free(t_adc *x)
static void adc_setup(void)
{
adc_class = class_new(gensym("adc~"), (t_newmethod)adc_new,
- (t_method)adc_free, sizeof(t_adc), 0, A_GIMME, 0);
+ (t_method)adc_free, sizeof(t_adc), CLASS_NOINLET, A_GIMME, 0);
class_addmethod(adc_class, (t_method)adc_dsp, gensym("dsp"), A_CANT, 0);
class_sethelpsymbol(adc_class, gensym("adc~_dac~"));
}
diff --git a/pd/src/d_delay.c b/pd/src/d_delay.c
index edcf1235..1d4defcf 100644
--- a/pd/src/d_delay.c
+++ b/pd/src/d_delay.c
@@ -269,8 +269,8 @@ static t_int *sigvd_perform(t_int *w)
a = bp[0];
cminusb = c-b;
*out++ = b + frac * (
- cminusb - 0.5f * (frac-1.) * (
- (a - d + 3.0f * cminusb) * frac + (b - a - cminusb)
+ cminusb - 0.1666667f * (1.-frac) * (
+ (d - a - 3.0f * cminusb) * frac + (d + 2.0f*a - 3.0f*b)
)
);
}
diff --git a/pd/src/d_fftroutine.c b/pd/src/d_fftroutine.c
index 7f0d2523..1920aca5 100644
--- a/pd/src/d_fftroutine.c
+++ b/pd/src/d_fftroutine.c
@@ -88,7 +88,7 @@
#include <math.h>
#include <stdlib.h>
- /* the following is needed only to declare pd_fft() as exportable in NT */
+ /* the following is needed only to declare pd_fft() as exportable in MSW */
#include "m_pd.h"
/* some basic definitions */
diff --git a/pd/src/d_mayer_fft.c b/pd/src/d_mayer_fft.c
index c221e33e..ea884018 100644
--- a/pd/src/d_mayer_fft.c
+++ b/pd/src/d_mayer_fft.c
@@ -48,7 +48,7 @@
* of work. -msp
*/
-#ifdef NT
+#ifdef MSW
#pragma warning( disable : 4305 ) /* uncast const double to float */
#pragma warning( disable : 4244 ) /* uncast double to float */
#pragma warning( disable : 4101 ) /* unused local variables */
diff --git a/pd/src/d_osc.c b/pd/src/d_osc.c
index 27dceae9..a7990fc6 100644
--- a/pd/src/d_osc.c
+++ b/pd/src/d_osc.c
@@ -18,7 +18,7 @@
#define LOWOFFSET 1 /* word offset to find LSB */
#define int32 long /* a data type that has 32 bits */
#else
-#ifdef NT
+#ifdef MSW
/* little-endian; most significant byte is at highest address */
#define HIOFFSET 1
#define LOWOFFSET 0
@@ -63,7 +63,7 @@
#endif /* MACOSX */
#endif /* __linux__ */
-#endif /* NT */
+#endif /* MSW */
#endif /* SGI */
union tabfudge
diff --git a/pd/src/d_soundfile.c b/pd/src/d_soundfile.c
index 33de90b7..a55e4d27 100644
--- a/pd/src/d_soundfile.c
+++ b/pd/src/d_soundfile.c
@@ -17,7 +17,7 @@ for Windows if someone were willing to find a Pthreads package for it. */
#include <fcntl.h>
#endif
#include <pthread.h>
-#ifdef NT
+#ifdef MSW
#include <io.h>
#endif
#include <stdio.h>
@@ -69,7 +69,7 @@ typedef struct _wave
char w_waveid[4]; /* wave chunk id 'WAVE' */
char w_fmtid[4]; /* format chunk id 'fmt ' */
uint32 w_fmtchunksize; /* format chunk size */
- uint16 w_fmttag; /* format tag, 1 for PCM */
+ uint16 w_fmttag; /* format tag (WAV_INT etc) */
uint16 w_nchannels; /* number of channels */
uint32 w_samplespersec; /* sample rate in hz */
uint32 w_navgbytespersec; /* average bytes per second */
@@ -95,6 +95,9 @@ typedef struct _wavechunk /* ... and the last two items */
uint32 wc_size; /* length of data chunk */
} t_wavechunk;
+#define WAV_INT 1
+#define WAV_FLOAT 3
+
/* the AIFF header. I'm assuming AIFC is compatible but don't really know
that. */
@@ -141,7 +144,7 @@ typedef struct _aiff
#define OBUFSIZE MAXPDSTRING /* assume MAXPDSTRING is bigger than headers */
-#ifdef NT
+#ifdef MSW
#include <fcntl.h>
#define BINCREATE _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY
#else
@@ -541,10 +544,15 @@ static int soundfiler_writeargparse(void *obj, int *p_argc, t_atom **p_argv,
}
else goto usage;
}
- /* only NextStep handles floating point samples */
+ /* don't handle AIFF floating point samples */
if (bytespersamp == 4)
- filetype = FORMAT_NEXT;
-
+ {
+ if (filetype == FORMAT_AIFF)
+ {
+ pd_error(obj, "AIFF floating-point file format unavailable");
+ goto usage;
+ }
+ }
/* for WAVE force little endian; for nextstep use machine native */
if (filetype == FORMAT_WAVE)
{
@@ -647,7 +655,8 @@ static int create_soundfile(t_canvas *canvas, const char *filename,
strncpy(wavehdr->w_waveid, "WAVE", 4);
strncpy(wavehdr->w_fmtid, "fmt ", 4);
wavehdr->w_fmtchunksize = swap4(16, swap);
- wavehdr->w_fmttag = swap2(1, swap);
+ wavehdr->w_fmttag =
+ swap2((bytespersamp == 4 ? WAV_FLOAT : WAV_INT), swap);
wavehdr->w_nchannels = swap2(nchannels, swap);
wavehdr->w_samplespersec = swap4(44100, swap);
wavehdr->w_navgbytespersec = swap4(44100 * nchannels * bytespersamp, swap);
@@ -1191,7 +1200,7 @@ static void soundfiler_setup(void)
/* READSF uses the Posix threads package; for the moment we're Linux
only although this should be portable to the other platforms.
-Each instance of readsf~ owns a "child" thread for doing the UNIX (NT?) file
+Each instance of readsf~ owns a "child" thread for doing the UNIX (MSW?) file
reading. The parent thread signals the child each time:
(1) a file wants opening or closing;
(2) we've eaten another 1/16 of the shared buffer (so that the
@@ -1753,18 +1762,15 @@ static void readsf_free(t_readsf *x)
void *threadrtn;
pthread_mutex_lock(&x->x_mutex);
x->x_requestcode = REQUEST_QUIT;
- post("stopping readsf thread...");
sfread_cond_signal(&x->x_requestcondition);
while (x->x_requestcode != REQUEST_NOTHING)
{
- post("signalling...");
sfread_cond_signal(&x->x_requestcondition);
sfread_cond_wait(&x->x_answercondition, &x->x_mutex);
}
pthread_mutex_unlock(&x->x_mutex);
if (pthread_join(x->x_childthread, &threadrtn))
error("readsf_free: join failed");
- post("... done.");
pthread_cond_destroy(&x->x_requestcondition);
pthread_cond_destroy(&x->x_answercondition);
diff --git a/pd/src/d_ugen.c b/pd/src/d_ugen.c
index 68e931e6..2bc99936 100644
--- a/pd/src/d_ugen.c
+++ b/pd/src/d_ugen.c
@@ -23,14 +23,11 @@
#include "m_pd.h"
+#include "m_imp.h"
#include <stdlib.h>
#include <stdarg.h>
extern t_class *vinlet_class, *voutlet_class, *canvas_class;
-int obj_nsiginlets(t_object *x);
-int obj_siginletindex(t_object *x, int m);
-int obj_nsigoutlets(t_object *x);
-int obj_sigoutletindex(t_object *x, int m);
t_sample *obj_findsignalscalar(t_object *x, int m);
static int ugen_loud;
EXTERN_STRUCT _vinlet;
diff --git a/pd/src/g_all_guis.c b/pd/src/g_all_guis.c
index 2cd4994a..97075684 100644
--- a/pd/src/g_all_guis.c
+++ b/pd/src/g_all_guis.c
@@ -10,13 +10,13 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include "t_tk.h"
#include "g_all_guis.h"
#include <math.h>
-#ifdef NT
+#ifdef MSW
#include <io.h>
#else
#include <unistd.h>
@@ -770,19 +770,11 @@ void iemgui_delete(t_gobj *z, t_glist *glist)
void iemgui_vis(t_gobj *z, t_glist *glist, int vis)
{
t_iemguidummy *x = (t_iemguidummy *)z;
- t_rtext *y;
- if(vis)
- {
- y = rtext_new_without_senditup(glist, (t_text *)z, glist->gl_editor->e_rtext);
+ if (vis)
(*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_NEW);
- }
else
- {
- y = glist_findrtext(glist, (t_text *)z);
(*x->x_gui.x_draw)((void *)z, glist, IEM_GUI_DRAW_MODE_ERASE);
- rtext_free(y);
- }
}
void iemgui_save(t_iemgui *iemgui, t_symbol **srl, int *bflcol)
diff --git a/pd/src/g_all_guis.h b/pd/src/g_all_guis.h
index 5fab095d..77cf710d 100644
--- a/pd/src/g_all_guis.h
+++ b/pd/src/g_all_guis.h
@@ -46,7 +46,7 @@
#define IEM_GUI_MINSIZE 8
#define IEM_GUI_MAXSIZE 1000
#define IEM_SL_DEFAULTSIZE 128
-#define IEM_SL_MINSIZE 20
+#define IEM_SL_MINSIZE 2
#define IEM_FONT_MINSIZE 4
#define IEM_BNG_DEFAULTHOLDFLASHTIME 250
@@ -314,7 +314,6 @@ EXTERN void iemgui_save(t_iemgui *iemgui, t_symbol **srl, int *bflcol);
EXTERN void iemgui_properties(t_iemgui *iemgui, t_symbol **srl);
EXTERN int iemgui_dialog(t_iemgui *iemgui, t_symbol **srl, int argc, t_atom *argv);
-EXTERN t_rtext *rtext_new_without_senditup(t_glist *glist, t_text *who, t_rtext *next);
EXTERN int canvas_getdollarzero(void);
EXTERN void canvas_getargs(int *argcp, t_atom **argvp);
diff --git a/pd/src/g_array.c b/pd/src/g_array.c
index 7a9fb3f7..2c2dfa8b 100644
--- a/pd/src/g_array.c
+++ b/pd/src/g_array.c
@@ -81,11 +81,20 @@ void array_resize(t_array *x, t_template *template, int n)
}
}
+void word_free(t_word *wp, t_template *template);
+
void array_free(t_array *x)
{
+ int i;
+ t_template *scalartemplate = template_findbyname(x->a_templatesym);
/* we don't unset our gpointer here since it was never "set." */
/* gpointer_unset(&x->a_gp); */
gstub_cutoff(x->a_stub);
+ for (i = 0; i < x->a_n; i++)
+ {
+ t_word *wp = (t_word *)(x->a_vec + x->a_elemsize * i);
+ word_free(wp, scalartemplate);
+ }
freebytes(x->a_vec, x->a_elemsize * x->a_n);
freebytes(x, sizeof *x);
}
diff --git a/pd/src/g_bang.c b/pd/src/g_bang.c
index 399f45f4..07553972 100644
--- a/pd/src/g_bang.c
+++ b/pd/src/g_bang.c
@@ -10,13 +10,13 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include "t_tk.h"
#include "g_all_guis.h"
#include <math.h>
-#ifdef NT
+#ifdef MSW
#include <io.h>
#else
#include <unistd.h>
diff --git a/pd/src/g_canvas.c b/pd/src/g_canvas.c
index 1eba8ac5..be771aa0 100644
--- a/pd/src/g_canvas.c
+++ b/pd/src/g_canvas.c
@@ -7,7 +7,6 @@ to be different but are now unified except for some fossilized names.) */
/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
-/* improvement: line-delete-protection, look for "protect" */
/* bug-fix: canvas_menuclose(): by Krzysztof Czaja */
/* bug-fix: table_new(): I reversed the y-bounds */
@@ -21,7 +20,9 @@ to be different but are now unified except for some fossilized names.) */
#include <stdlib.h>
#include <stdio.h>
+#include "m_pd.h"
#include "m_imp.h"
+#include "s_stuff.h"
#include "g_canvas.h"
#include <string.h>
#include "g_all_guis.h"
@@ -104,7 +105,8 @@ void canvas_updatewindowlist( void)
/* find all root canvases */
for (x = canvas_list; x; x = x->gl_next)
glist_doupdatewindowlist(x, sbuf);
- strcat(sbuf, "}\n");
+ /* next line updates the window menu state before -postcommand tries it */
+ strcat(sbuf, "}\npdtk_fixwindowmenu\n");
sys_gui(sbuf);
}
@@ -681,18 +683,31 @@ static void editor_free(t_editor *x, t_glist *y)
void canvas_create_editor(t_glist *x, int createit)
{
t_gobj *y;
+ t_object *ob;
if (createit)
{
if (x->gl_editor)
bug("canvas_create_editor");
- else x->gl_editor = editor_new(x);
+ else
+ {
+ x->gl_editor = editor_new(x);
+ for (y = x->gl_list; y; y = y->g_next)
+ if (ob = pd_checkobject(&y->g_pd))
+ rtext_new(x, ob);
+ }
}
else
{
if (!x->gl_editor)
bug("canvas_create_editor");
- else editor_free(x->gl_editor, x);
- x->gl_editor = 0;
+ else
+ {
+ for (y = x->gl_list; y; y = y->g_next)
+ if (ob = pd_checkobject(&y->g_pd))
+ rtext_free(glist_findrtext(x, ob));
+ editor_free(x->gl_editor, x);
+ x->gl_editor = 0;
+ }
}
for (y = x->gl_list; y; y = y->g_next)
if (pd_class(&y->g_pd) == canvas_class &&
@@ -712,7 +727,7 @@ void canvas_vis(t_canvas *x, t_floatarg f)
/* test if we're already visible and toplevel */
if (glist_isvisible(x) && !x->gl_isgraph)
{ /* just put us in front */
-#ifdef NT
+#ifdef MSW
canvas_vis(x, 0);
canvas_vis(x, 1);
#else
@@ -756,7 +771,7 @@ void canvas_vis(t_canvas *x, t_floatarg f)
sys_vgui("destroy .x%x\n", x);
for (i = 1, x2 = x; x2; x2 = x2->gl_next, i++)
;
- sys_vgui(".mbar.find.menu delete %d\n", i);
+ sys_vgui(".mbar.find delete %d\n", i);
/* if we're a graph on our parent, and if the parent exists
and is visible, show ourselves on parent. */
if (glist_isgraph(x) && x->gl_owner)
@@ -819,7 +834,6 @@ void canvas_free(t_canvas *x)
{
t_gobj *y;
int dspstate = canvas_suspend_dsp();
-
canvas_noundo(x);
if (canvas_editing == x)
canvas_editing = 0;
@@ -1019,7 +1033,7 @@ void canvas_loadbang(t_canvas *x)
you gave it to open it; perhaps there's a 1-pixel border all around it
or something. Anyway, we just add the 2 pixels back here: */
-#ifdef NT
+#ifdef MSW
#define HORIZBORDER 2
#define VERTBORDER 2
#else
@@ -1199,10 +1213,6 @@ void ugen_connect(t_dspcontext *dc, t_object *x1, int outno,
t_object *x2, int inno);
void ugen_done_graph(t_dspcontext *dc);
-int obj_issignaloutlet(t_object *x, int outno);
-int obj_nsiginlets(t_object *x);
-int obj_nsigoutlets(t_object *x);
-
/* schedule one canvas for DSP. This is called below for all "root"
canvases, but is also called from the "dsp" method for sub-
canvases, which are treated almost like any other tilde object. */
@@ -1328,10 +1338,10 @@ static void glist_redrawall(t_glist *gl)
}
/* public interface for above */
-void canvas_redrawallfortemplate(t_canvas *template)
+void canvas_redrawallfortemplate(t_canvas *templatecanvas)
{
t_canvas *x;
- if (!template->gl_imatemplate) return;
+ if (!templatecanvas->gl_imatemplate) return;
/* find all root canvases */
for (x = canvas_list; x; x = x->gl_next)
glist_redrawall(x);
@@ -1373,10 +1383,10 @@ static void glist_zapall(t_glist *gl)
}
/* public interface for above */
-void canvas_zapallfortemplate(t_canvas *template)
+void canvas_zapallfortemplate(t_canvas *templatecanvas)
{
t_canvas *x;
- if (!template->gl_imatemplate) return;
+ if (!templatecanvas->gl_imatemplate) return;
/* find all root canvases */
for (x = canvas_list; x; x = x->gl_next)
glist_zapall(x);
@@ -1511,5 +1521,4 @@ void g_canvas_setup(void)
g_graph_setup();
g_editor_setup();
g_readwrite_setup();
-
}
diff --git a/pd/src/g_canvas.h b/pd/src/g_canvas.h
index e4eecfc0..afaecbf5 100644
--- a/pd/src/g_canvas.h
+++ b/pd/src/g_canvas.h
@@ -33,6 +33,13 @@ glist has its own window, even if miniaturized.
*/
+/* NOTE: this file describes Pd implementation details which may change
+in future releases. The public (stable) API is in m_pd.h. */
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+extern "C" {
+#endif
+
/* --------------------- geometry ---------------------------- */
#define IOWIDTH 7 /* width of an inlet/outlet in pixels */
#define IOMIDDLE ((IOWIDTH-1)/2)
@@ -190,9 +197,11 @@ typedef struct _dataslot
t_symbol *ds_arraytemplate; /* filled in for arrays only */
} t_dataslot;
+
+/* T.Grill - changed t_pd member to t_pdobj to avoid name clashed */
typedef struct _template
{
- t_pd t_pd; /* header */
+ t_pd t_pdobj; /* header */
struct _gtemplate *t_list; /* list of "struct"/gtemplate objects */
t_symbol *t_sym; /* name */
int t_n; /* number of dataslots (fields) */
@@ -280,27 +289,27 @@ doesn't work on array elements... LATER reconsider this */
/* bounding rectangle: */
typedef void (*t_parentgetrectfn)(t_gobj *x, struct _glist *glist,
- t_word *data, t_template *template, float basex, float basey,
+ t_word *data, t_template *tmpl, float basex, float basey,
int *x1, int *y1, int *x2, int *y2);
/* displace it */
typedef void (*t_parentdisplacefn)(t_gobj *x, struct _glist *glist,
- t_word *data, t_template *template, float basex, float basey,
+ t_word *data, t_template *tmpl, float basex, float basey,
int dx, int dy);
/* change color to show selection */
typedef void (*t_parentselectfn)(t_gobj *x, struct _glist *glist,
- t_word *data, t_template *template, float basex, float basey,
+ t_word *data, t_template *tmpl, float basex, float basey,
int state);
/* change appearance to show activation/deactivation: */
typedef void (*t_parentactivatefn)(t_gobj *x, struct _glist *glist,
- t_word *data, t_template *template, float basex, float basey,
+ t_word *data, t_template *tmpl, float basex, float basey,
int state);
/* making visible or invisible */
typedef void (*t_parentvisfn)(t_gobj *x, struct _glist *glist,
- t_word *data, t_template *template, float basex, float basey,
+ t_word *data, t_template *tmpl, float basex, float basey,
int flag);
/* field a mouse click */
typedef int (*t_parentclickfn)(t_gobj *x, struct _glist *glist,
- t_scalar *sc, t_template *template, float basex, float basey,
+ t_scalar *sc, t_template *tmpl, float basex, float basey,
int xpix, int ypix, int shift, int alt, int dbl, int doit);
struct _parentwidgetbehavior
@@ -411,10 +420,11 @@ EXTERN int text_shouldvis(t_text *x, t_glist *glist);
#define RTEXT_DBL 3
#define RTEXT_SHIFT 4
-EXTERN t_rtext *rtext_new(t_glist *glist, t_text *who, t_rtext *next,
- int sendipup);
-EXTERN t_rtext *rtext_remove(t_rtext *first, t_rtext *x);
+EXTERN t_rtext *rtext_new(t_glist *glist, t_text *who);
EXTERN t_rtext *glist_findrtext(t_glist *gl, t_text *who);
+EXTERN void rtext_draw(t_rtext *x);
+EXTERN void rtext_erase(t_rtext *x);
+EXTERN t_rtext *rtext_remove(t_rtext *first, t_rtext *x);
EXTERN int rtext_height(t_rtext *x);
EXTERN void rtext_displace(t_rtext *x, int dx, int dy);
EXTERN void rtext_select(t_rtext *x, int state);
@@ -444,8 +454,8 @@ EXTERN t_inlet *canvas_addinlet(t_canvas *x, t_pd *who, t_symbol *sym);
EXTERN void canvas_rminlet(t_canvas *x, t_inlet *ip);
EXTERN t_outlet *canvas_addoutlet(t_canvas *x, t_pd *who, t_symbol *sym);
EXTERN void canvas_rmoutlet(t_canvas *x, t_outlet *op);
-EXTERN void canvas_redrawallfortemplate(t_canvas *template);
-EXTERN void canvas_zapallfortemplate(t_canvas *template);
+EXTERN void canvas_redrawallfortemplate(t_canvas *tmpl);
+EXTERN void canvas_zapallfortemplate(t_canvas *tmpl);
EXTERN void canvas_setusedastemplate(t_canvas *x);
EXTERN t_canvas *canvas_getcurrent(void);
EXTERN void canvas_setcurrent(t_canvas *x);
@@ -485,6 +495,17 @@ EXTERN void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf,
EXTERN void canvas_noundo(t_canvas *x);
EXTERN int canvas_getindex(t_canvas *x, t_gobj *y);
+/* T.Grill - made public for dynamic object creation */
+/* in g_editor.c */
+EXTERN void canvas_connect(t_canvas *x,
+ t_floatarg fwhoout, t_floatarg foutno,t_floatarg fwhoin, t_floatarg finno);
+EXTERN void canvas_disconnect(t_canvas *x,
+ float index1, float outno, float index2, float inno);
+EXTERN int canvas_isconnected (t_canvas *x,
+ t_text *ob1, int n1, t_text *ob2, int n2);
+EXTERN void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy);
+
+
/* ---- functions on canvasses as objects --------------------- */
EXTERN void canvas_fattenforscalars(t_canvas *x,
@@ -511,10 +532,10 @@ EXTERN int tscalar_click(t_tscalar *x, int xpix, int ypix, int shift,
EXTERN t_template *garray_template(t_garray *x);
/* -------------------- arrays --------------------- */
-EXTERN t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *template,
+EXTERN t_garray *graph_array(t_glist *gl, t_symbol *s, t_symbol *tmpl,
t_floatarg f, t_floatarg saveit);
EXTERN t_array *array_new(t_symbol *templatesym, t_gpointer *parent);
-EXTERN void array_resize(t_array *x, t_template *template, int n);
+EXTERN void array_resize(t_array *x, t_template *tmpl, int n);
EXTERN void array_free(t_array *x);
/* --------------------- gpointers and stubs ---------------- */
@@ -523,8 +544,8 @@ EXTERN void gstub_cutoff(t_gstub *gs);
EXTERN void gpointer_setglist(t_gpointer *gp, t_glist *glist, t_scalar *x);
/* --------------------- scalars ------------------------- */
-EXTERN void word_init(t_word *wp, t_template *template, t_gpointer *gp);
-EXTERN void word_restore(t_word *wp, t_template *template,
+EXTERN void word_init(t_word *wp, t_template *tmpl, t_gpointer *gp);
+EXTERN void word_restore(t_word *wp, t_template *tmpl,
int argc, t_atom *argv);
EXTERN t_scalar *scalar_new(t_glist *owner,
t_symbol *templatesym);
@@ -563,7 +584,7 @@ EXTERN void template_setsymbol(t_template *x, t_symbol *fieldname,
EXTERN t_template *gtemplate_get(t_gtemplate *x);
EXTERN t_template *template_findbyname(t_symbol *s);
-EXTERN t_canvas *template_findcanvas(t_template *template);
+EXTERN t_canvas *template_findcanvas(t_template *tmpl);
EXTERN t_float template_getfloat(t_template *x, t_symbol *fieldname,
t_word *wp, int loud);
@@ -581,3 +602,7 @@ EXTERN void guiconnect_notarget(t_guiconnect *x, double timedelay);
/* ------------- IEMGUI routines used in other g_ files ---------------- */
EXTERN t_symbol *iemgui_raute2dollar(t_symbol *s);
EXTERN t_symbol *iemgui_dollar2raute(t_symbol *s);
+
+#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
+}
+#endif
diff --git a/pd/src/g_editor.c b/pd/src/g_editor.c
index 470030e9..3612d61f 100644
--- a/pd/src/g_editor.c
+++ b/pd/src/g_editor.c
@@ -4,13 +4,18 @@
#include <stdlib.h>
#include <stdio.h>
+#include "m_pd.h"
#include "m_imp.h"
+#include "s_stuff.h"
#include "g_canvas.h"
#include <string.h>
void glist_readfrombinbuf(t_glist *x, t_binbuf *b, char *filename,
int selectem);
+void open_via_helppath(const char *name, const char *dir);
+char *class_gethelpdir(t_class *c);
+
/* ------------------ forward declarations --------------- */
static void canvas_doclear(t_canvas *x);
static void glist_setlastxy(t_glist *gl, int xval, int yval);
@@ -297,10 +302,11 @@ void canvas_setundo(t_canvas *x, t_undofn undofn, void *buf,
canvas_undo_buf = buf;
canvas_undo_whatnext = UNDO_UNDO;
canvas_undo_name = name;
- if (x)
+ if (x && glist_isvisible(x) && glist_istoplevel(x))
/* enable undo in menu */
sys_vgui("pdtk_undomenu .x%x %s no\n", x, name);
- else if (hadone) sys_vgui("pdtk_undomenu .x%x no no\n", x, name);
+ else if (hadone)
+ sys_vgui("pdtk_undomenu nobody no no\n");
}
/* clear undo if it happens to be for the canvas x.
@@ -322,7 +328,8 @@ static void canvas_undo(t_canvas *x)
/* post("undo"); */
(*canvas_undo_fn)(canvas_undo_canvas, canvas_undo_buf, UNDO_UNDO);
/* enable redo in menu */
- sys_vgui("pdtk_undomenu .x%x no %s\n", x, canvas_undo_name);
+ if (glist_isvisible(x) && glist_istoplevel(x))
+ sys_vgui("pdtk_undomenu .x%x no %s\n", x, canvas_undo_name);
canvas_undo_whatnext = UNDO_REDO;
}
}
@@ -338,7 +345,8 @@ static void canvas_redo(t_canvas *x)
/* post("redo"); */
(*canvas_undo_fn)(canvas_undo_canvas, canvas_undo_buf, UNDO_REDO);
/* enable undo in menu */
- sys_vgui("pdtk_undomenu .x%x %s no\n", x, canvas_undo_name);
+ if (glist_isvisible(x) && glist_istoplevel(x))
+ sys_vgui("pdtk_undomenu .x%x %s no\n", x, canvas_undo_name);
canvas_undo_whatnext = UNDO_UNDO;
}
}
@@ -364,11 +372,8 @@ static void *canvas_undo_set_disconnect(t_canvas *x,
return (buf);
}
-static void canvas_connect(t_canvas *x, t_floatarg fwhoout, t_floatarg foutno,
- t_floatarg fwhoin, t_floatarg finno);
-
-static void canvas_disconnect(t_canvas *x,
- int index1, int outno, int index2, int inno)
+void canvas_disconnect(t_canvas *x,
+ float index1, float outno, float index2, float inno)
{
t_linetraverser t;
t_outconnect *oc;
@@ -661,6 +666,55 @@ else if (action == UNDO_FREE)
t_freebytes(buf, sizeof(*buf));
}
+ /* recursively check for abstractions to reload as result of a save.
+ Don't reload the one we just saved ("except") though. */
+ /* LATER try to do the same trick for externs. */
+static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir,
+ t_gobj *except)
+{
+ t_gobj *g;
+ int i, nobj = glist_getindex(gl, 0); /* number of objects */
+ for (g = gl->gl_list, i = 0; g && i < nobj; i++)
+ {
+ if (g != except && pd_class(&g->g_pd) == canvas_class &&
+ canvas_isabstraction((t_canvas *)g) &&
+ ((t_canvas *)g)->gl_name == name &&
+ canvas_getdir((t_canvas *)g) == dir)
+ {
+ /* we're going to remake the object, so "g" will go stale.
+ Get its index here, and afterward restore g. Also, the
+ replacement will be at teh end of the list, so we don't
+ do g = g->g_next in this case. */
+ int j = glist_getindex(gl, g);
+ if (!gl->gl_havewindow)
+ canvas_vis(glist_getcanvas(gl), 1);
+ glist_noselect(gl);
+ glist_select(gl, g);
+ canvas_setundo(gl, canvas_undo_cut,
+ canvas_undo_set_cut(gl, UCUT_CLEAR), "clear");
+ canvas_doclear(gl);
+ canvas_undo(gl);
+ glist_noselect(gl);
+ g = glist_nth(gl, j);
+ }
+ else
+ {
+ if (g != except && pd_class(&g->g_pd) == canvas_class)
+ glist_doreload((t_canvas *)g, name, dir, except);
+ g = g->g_next;
+ }
+ }
+}
+
+ /* call canvas_doreload on everyone */
+void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except)
+{
+ t_canvas *x;
+ /* find all root canvases */
+ for (x = canvas_list; x; x = x->gl_next)
+ glist_doreload(x, name, dir, except);
+}
+
/* ------------------------ event handling ------------------------ */
#define CURSOR_RUNMODE_NOTHING 0
@@ -672,7 +726,7 @@ else if (action == UNDO_FREE)
#define CURSOR_EDITMODE_DISCONNECT 6
static char *cursorlist[] = {
-#ifdef NT
+#ifdef MSW
"right_ptr", /* CURSOR_RUNMODE_NOTHING */
#else
"left_ptr", /* CURSOR_RUNMODE_NOTHING */
@@ -866,13 +920,26 @@ static void canvas_done_popup(t_canvas *x, float which, float xpos, float ypos)
}
else /* help */
{
- char *s = class_gethelpname(pd_class(&y->g_pd));
- strcpy(pathbuf, sys_libdir->s_name);
- strcat(pathbuf, "/doc/5.reference");
- strcpy(namebuf, s);
- if (strcmp(namebuf + strlen(namebuf) - 3, ".pd"))
+ char *dir;
+ if (pd_class(&y->g_pd) == canvas_class &&
+ canvas_isabstraction((t_canvas *)y))
+ {
+ t_object *ob = (t_object *)y;
+ int ac = binbuf_getnatom(ob->te_binbuf);
+ t_atom *av = binbuf_getvec(ob->te_binbuf);
+ if (ac < 1)
+ return;
+ atom_string(av, namebuf, MAXPDSTRING);
+ dir = canvas_getdir((t_canvas *)y)->s_name;
+ }
+ else
+ {
+ strcpy(namebuf, class_gethelpname(pd_class(&y->g_pd)));
+ dir = class_gethelpdir(pd_class(&y->g_pd));
+ }
+ if (strcmp(namebuf + strlen(namebuf) - 3, ".pd"))
strcat(namebuf, ".pd");
- glob_evalfile(0, gensym(namebuf), gensym(pathbuf));
+ open_via_helppath(namebuf, dir);
return;
}
}
@@ -905,15 +972,6 @@ static int canvas_upx, canvas_upy;
#define DCLICKINTERVAL 0.25
#endif
- /* figure out of the outlet is a "signal" outlet. "nout" is the
- index of the outlet, counting from zero. */
-int obj_sigoutletindex(t_object *x, int m);
-static int canvas_issigoutlet(t_object *ob, int nout)
-{
- int ret = obj_sigoutletindex(ob, nout);
- return (obj_sigoutletindex(ob, nout) >= 0);
-}
-
/* mouse click */
void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
int mod, int doit)
@@ -1025,7 +1083,7 @@ void canvas_doclick(t_canvas *x, int xpos, int ypos, int which,
{
if (doit)
{
- int issignal = canvas_issigoutlet(ob, closest);
+ int issignal = obj_issignaloutlet(ob, closest);
x->gl_editor->e_onmotion = MA_CONNECT;
x->gl_editor->e_xwas = xpos;
x->gl_editor->e_ywas = ypos;
@@ -1126,7 +1184,7 @@ void canvas_mousedown(t_canvas *x, t_floatarg xpos, t_floatarg ypos,
canvas_doclick(x, xpos, ypos, which, mod, 1);
}
-static int canvas_isconnected (t_canvas *x, t_text *ob1, int n1,
+int canvas_isconnected (t_canvas *x, t_text *ob1, int n1,
t_text *ob2, int n2)
{
t_linetraverser t;
@@ -1193,6 +1251,14 @@ void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
return;
}
+ if (obj_issignaloutlet(ob1, closest1) &&
+ !obj_issignalinlet(ob2, closest2))
+ {
+ if (doit)
+ error("can't connect signal outlet to control inlet");
+ canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
+ return;
+ }
if (doit)
{
oc = obj_connect(ob1, closest1, ob2, closest2);
@@ -1207,7 +1273,7 @@ void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
glist_getcanvas(x),
lx1, ly1, lx2, ly2,
- (canvas_issigoutlet(ob1, closest1) ? 2 : 1), oc);
+ (obj_issignaloutlet(ob1, closest1) ? 2 : 1), oc);
canvas_setundo(x, canvas_undo_connect,
canvas_undo_set_connect(x,
canvas_getindex(x, &ob1->ob_g), closest1,
@@ -1221,11 +1287,23 @@ void canvas_doconnect(t_canvas *x, int xpos, int ypos, int which, int doit)
canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
}
-void canvas_doregion(t_canvas *x, int xpos, int ypos, int doit)
+void canvas_selectinrect(t_canvas *x, int lox, int loy, int hix, int hiy)
+{
+ t_gobj *y;
+ for (y = x->gl_list; y; y = y->g_next)
+ {
+ int x1, y1, x2, y2;
+ gobj_getrect(y, x, &x1, &y1, &x2, &y2);
+ if (hix >= x1 && lox <= x2 && hiy >= y1 && loy <= y2
+ && !glist_isselected(x, y))
+ glist_select(x, y);
+ }
+}
+
+static void canvas_doregion(t_canvas *x, int xpos, int ypos, int doit)
{
if (doit)
{
- t_gobj *y;
int lox, loy, hix, hiy;
if (x->gl_editor->e_xwas < xpos)
lox = x->gl_editor->e_xwas, hix = xpos;
@@ -1233,14 +1311,7 @@ void canvas_doregion(t_canvas *x, int xpos, int ypos, int doit)
if (x->gl_editor->e_ywas < ypos)
loy = x->gl_editor->e_ywas, hiy = ypos;
else hiy = x->gl_editor->e_ywas, loy = ypos;
- for (y = x->gl_list; y; y = y->g_next)
- {
- int x1, y1, x2, y2;
- gobj_getrect(y, x, &x1, &y1, &x2, &y2);
- if (hix >= x1 && lox <= x2 && hiy >= y1 && loy <= y2
- && !glist_isselected(x, y))
- glist_select(x, y);
- }
+ canvas_selectinrect(x, lox, loy, hix, hiy);
sys_vgui(".x%x.c delete x\n", x);
x->gl_editor->e_onmotion = 0;
}
@@ -1312,7 +1383,7 @@ static void canvas_displaceselection(t_canvas *x, int dx, int dy)
void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
{
static t_symbol *keynumsym, *keyupsym, *keynamesym;
- float keynum, fflag;
+ int keynum, fflag;
t_symbol *gotkeysym;
int down, shift;
@@ -1325,7 +1396,6 @@ void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
return;
}
canvas_undo_already_set_move = 0;
-
down = (atom_getfloat(av) != 0); /* nonzero if it's a key down */
shift = (atom_getfloat(av+2) != 0); /* nonzero if shift-ed */
if (av[1].a_type == A_SYMBOL)
@@ -1345,7 +1415,6 @@ void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
return;
}
if (keynum == '\r') keynum = '\n';
- /* post("key %c", keynum); */
if (av[1].a_type == A_SYMBOL &&
!strcmp(av[1].a_w.w_symbol->s_name, "Return"))
keynum = '\n';
@@ -1355,10 +1424,20 @@ void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
keyupsym = gensym("#keyup");
keynamesym = gensym("#keyname");
}
+#ifdef MACOSX
+ if (keynum == 30)
+ keynum = 0, gotkeysym = gensym("Up");
+ else if (keynum == 31)
+ keynum = 0, gotkeysym = gensym("Down");
+ else if (keynum == 28)
+ keynum = 0, gotkeysym = gensym("Left");
+ else if (keynum == 29)
+ keynum = 0, gotkeysym = gensym("Right");
+#endif
if (keynumsym->s_thing && down)
- pd_float(keynumsym->s_thing, keynum);
+ pd_float(keynumsym->s_thing, (float)keynum);
if (keyupsym->s_thing && !down)
- pd_float(keyupsym->s_thing, keynum);
+ pd_float(keyupsym->s_thing, (float)keynum);
if (keynamesym->s_thing)
{
t_atom at[2];
@@ -1373,7 +1452,7 @@ void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
if (x->gl_editor->e_grab
&& x->gl_editor->e_keyfn && keynum)
(* x->gl_editor->e_keyfn)
- (x->gl_editor->e_grab, keynum);
+ (x->gl_editor->e_grab, (float)keynum);
/* if a text editor is open send it on */
else if (x->gl_editor->e_textedfor)
{
@@ -1383,8 +1462,7 @@ void canvas_key(t_canvas *x, t_symbol *s, int ac, t_atom *av)
canvas_undo_set_cut(x, UCUT_TEXT), "typing");
}
rtext_key(x->gl_editor->e_textedfor,
- (int)keynum,
- (av[1].a_type == A_SYMBOL ? av[1].a_w.w_symbol : &s_));
+ (int)keynum, gotkeysym);
if (x->gl_editor->e_textdirty)
canvas_dirty(x, 1);
}
@@ -1475,50 +1553,6 @@ void canvas_print(t_canvas *x, t_symbol *s)
else sys_vgui(".x%x.c postscript -file x.ps\n", x);
}
-
-#if 0 /* LATER fix this to re-load abstractions when the patch changes.
- The best way to do this is probably to rewrite "stowconnections"
- so that it can operate either on the selection as now or on
- another replacement criterion. Could do the same trick for
- externs if we wish. */
- /* recursively check for abstractions to reload as result of a save. */
-static void glist_doreload(t_glist *gl, t_symbol *name, t_symbol *dir)
-{
- t_gobj *g;
- for (g = gl->gl_list; g; g = g->g_next)
- {
- if (pd_class(&g->g_pd) == canvas_class &&
- canvas_isabstraction(&g->g_pd) &&
- ((t_canvas *)g)->gl_name == name &&
- ((t_canvas *)g)->gl_env->ce_dir == dir)
- {
- .....
- glist_noselect(gl);
- canvas_vis(glist_getcanvas(gl), 1);
- canvas_editmode(glist_getcanvas(gl), 1.);
- glist_select(gl, g);
- return (1);
- }
- else if (pd_class(&g->g_pd) == graph_class)
- glist_doreload((t_glist *)g, name, dir);
- else if (pd_class(&g->g_pd) == canvas_class)
- glist_doreload(&((t_canvas *)g),
- name, dir);
- }
- }
- return (0);
-}
-
-static void canvas_reload(t_symbol *name, t_symbol *dir)
-{
- t_canvas *x;
- /* find all root canvases */
- for (x = canvas_list; x; x = x->gl_next)
- glist_doreload(x, name, dir);
-}
-
-#endif /* 0 -- also uncomment call to canvas_reload below */
-
void canvas_menuclose(t_canvas *x, t_floatarg force)
{
if (x->gl_owner)
@@ -1568,7 +1602,7 @@ static int canvas_dofind(t_canvas *x, int *myindex1p)
glist_noselect(x);
if (glist_isvisible(x))
{
-#ifdef NT
+#ifdef MSW
/* For windows canvas_vis() does something
special so here we explicitly invis
the window and proceed as in the "invis"
@@ -1951,7 +1985,7 @@ static void canvas_selectall(t_canvas *x)
}
}
-static void canvas_connect(t_canvas *x, t_floatarg fwhoout, t_floatarg foutno,
+void canvas_connect(t_canvas *x, t_floatarg fwhoout, t_floatarg foutno,
t_floatarg fwhoin, t_floatarg finno)
{
int whoout = fwhoout, outno = foutno, whoin = fwhoin, inno = finno;
@@ -1972,7 +2006,7 @@ static void canvas_connect(t_canvas *x, t_floatarg fwhoout, t_floatarg foutno,
{
sys_vgui(".x%x.c create line %d %d %d %d -width %d -tags l%x\n",
glist_getcanvas(x), 0, 0, 0, 0,
- (canvas_issigoutlet(objsrc, outno) ? 2 : 1),oc);
+ (obj_issignaloutlet(objsrc, outno) ? 2 : 1),oc);
canvas_fixlinesfor(x, objsrc);
}
return;
@@ -2104,7 +2138,6 @@ static void canvas_texteditor(t_canvas *x)
}
-
void glob_key(void *dummy, t_symbol *s, int ac, t_atom *av)
{
/* canvas_editing can be zero; canvas_key checks for that */
@@ -2116,12 +2149,14 @@ void canvas_editmode(t_canvas *x, t_floatarg fyesplease)
int yesplease = fyesplease;
if (yesplease && x->gl_edit)
return;
- if (x->gl_edit = !x->gl_edit)
+ x->gl_edit = !x->gl_edit;
+ if (x->gl_edit && glist_isvisible(x) && glist_istoplevel(x))
canvas_setcursor(x, CURSOR_EDITMODE_NOTHING);
else
{
glist_noselect(x);
- canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
+ if (glist_isvisible(x) && glist_istoplevel(x))
+ canvas_setcursor(x, CURSOR_RUNMODE_NOTHING);
}
sys_vgui("pdtk_canvas_editval .x%x %d\n",
glist_getcanvas(x), x->gl_edit);
@@ -2250,6 +2285,8 @@ void g_editor_setup(void)
class_addmethod(canvas_class, (t_method)canvas_connect,
gensym("connect"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
+ class_addmethod(canvas_class, (t_method)canvas_disconnect,
+ gensym("disconnect"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
/* -------------- copy buffer ------------------ */
copy_binbuf = binbuf_new();
}
diff --git a/pd/src/g_graph.c b/pd/src/g_graph.c
index b893d42d..9bf998f8 100644
--- a/pd/src/g_graph.c
+++ b/pd/src/g_graph.c
@@ -25,6 +25,7 @@ static void graph_getrect(t_gobj *z, t_glist *glist,
void glist_add(t_glist *x, t_gobj *y)
{
+ t_object *ob;
y->g_next = 0;
if (!x->gl_list) x->gl_list = y;
else
@@ -33,6 +34,8 @@ void glist_add(t_glist *x, t_gobj *y)
for (y2 = x->gl_list; y2->g_next; y2 = y2->g_next);
y2->g_next = y;
}
+ if (x->gl_editor && (ob = pd_checkobject(&y->g_pd)))
+ rtext_new(x, ob);
if (glist_isvisible(x))
gobj_vis(y, x, 1);
if (class_isdrawcommand(y->g_pd))
@@ -53,14 +56,14 @@ int canvas_setdeleting(t_canvas *x, int flag)
void glist_delete(t_glist *x, t_gobj *y)
{
t_gobj *g;
+ t_object *ob;
t_gotfn chkdsp = zgetfn(&y->g_pd, gensym("dsp"));
t_canvas *canvas = glist_getcanvas(x);
int drawcommand = class_isdrawcommand(y->g_pd);
int wasdeleting;
wasdeleting = canvas_setdeleting(canvas, 1);
- /* LATER decide whether all visible glists must have an editor? */
- if (glist_isvisible(canvas) && x->gl_editor)
+ if (x->gl_editor)
{
if (x->gl_editor->e_grab == y) x->gl_editor->e_grab = 0;
if (glist_isselected(x, y)) glist_deselect(x, y);
@@ -88,7 +91,10 @@ void glist_delete(t_glist *x, t_gobj *y)
}
}
gobj_delete(y, x);
- if (glist_isvisible(canvas)) gobj_vis(y, x, 0);
+ if (glist_isvisible(canvas))
+ gobj_vis(y, x, 0);
+ if (x->gl_editor && (ob = pd_checkobject(&y->g_pd)))
+ rtext_new(x, ob);
if (x->gl_list == y) x->gl_list = y->g_next;
else for (g = x->gl_list; g; g = g->g_next)
if (g->g_next == y)
@@ -640,14 +646,12 @@ static void graph_vis(t_gobj *gr, t_glist *parent_glist, int vis)
text_widgetbehavior.w_visfn(gr, parent_glist, vis);
return;
}
-
- if (vis)
- rtext_new(parent_glist, &x->gl_obj,
- parent_glist->gl_editor->e_rtext,
- canvas_showtext(x));
+
+ if (vis && canvas_showtext(x))
+ rtext_draw(glist_findrtext(parent_glist, &x->gl_obj));
graph_getrect(gr, parent_glist, &x1, &y1, &x2, &y2);
if (!vis)
- rtext_free(glist_findrtext(parent_glist, &x->gl_obj));
+ rtext_erase(glist_findrtext(parent_glist, &x->gl_obj));
sprintf(tag, "graph%x", (int)x);
if (vis)
diff --git a/pd/src/g_hdial.c b/pd/src/g_hdial.c
index 9f0db2cc..1d1b4c6d 100644
--- a/pd/src/g_hdial.c
+++ b/pd/src/g_hdial.c
@@ -12,13 +12,13 @@ put out a "float" as in sliders, toggles, etc. */
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include "t_tk.h"
#include "g_all_guis.h"
#include <math.h>
-#ifdef NT
+#ifdef MSW
#include <io.h>
#else
#include <unistd.h>
@@ -357,7 +357,12 @@ static void hradio_bang(t_hradio *x)
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
}
- else outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
+ else
+ {
+ outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, x->x_on);
+ }
}
static void hradio_fout(t_hradio *x, t_floatarg f)
@@ -393,6 +398,8 @@ static void hradio_fout(t_hradio *x, t_floatarg f)
else
{
outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on = i);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, x->x_on);
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
x->x_on_old = x->x_on;
}
diff --git a/pd/src/g_hslider.c b/pd/src/g_hslider.c
index 5b08a9bb..ed805f4b 100644
--- a/pd/src/g_hslider.c
+++ b/pd/src/g_hslider.c
@@ -10,13 +10,13 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include "t_tk.h"
#include "g_all_guis.h"
#include <math.h>
-#ifdef NT
+#ifdef MSW
#include <io.h>
#else
#include <unistd.h>
diff --git a/pd/src/g_mycanvas.c b/pd/src/g_mycanvas.c
index 726b6770..6af4e269 100644
--- a/pd/src/g_mycanvas.c
+++ b/pd/src/g_mycanvas.c
@@ -10,13 +10,13 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include "t_tk.h"
#include "g_all_guis.h"
#include <math.h>
-#ifdef NT
+#ifdef MSW
#include <io.h>
#else
#include <unistd.h>
diff --git a/pd/src/g_numbox.c b/pd/src/g_numbox.c
index b8f962bc..abf19e44 100644
--- a/pd/src/g_numbox.c
+++ b/pd/src/g_numbox.c
@@ -8,13 +8,13 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include "t_tk.h"
#include "g_all_guis.h"
#include <math.h>
-#ifdef NT
+#ifdef MSW
#include <io.h>
#else
#include <unistd.h>
diff --git a/pd/src/g_readwrite.c b/pd/src/g_readwrite.c
index 40755bb0..ddf11670 100644
--- a/pd/src/g_readwrite.c
+++ b/pd/src/g_readwrite.c
@@ -10,7 +10,7 @@ scalars into a file and reload them; also, support is included here for
#include <stdlib.h>
#include <stdio.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include <string.h>
@@ -662,6 +662,8 @@ static void canvas_savetemplatesto(t_canvas *x, t_binbuf *b, int wholething)
}
}
+void canvas_reload(t_symbol *name, t_symbol *dir, t_gobj *except);
+
/* save a "root" canvas to a file; cf. canvas_saveto() which saves the
body (and which is called recursively.) */
static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir)
@@ -677,9 +679,7 @@ static void canvas_savetofile(t_canvas *x, t_symbol *filename, t_symbol *dir)
canvas_rename(x, filename, dir);
post("saved to: %s/%s", dir->s_name, filename->s_name);
canvas_dirty(x, 0);
-#if 0 /* not yet written */
- canvas_reload(filename, dir);
-#endif
+ canvas_reload(filename, dir, &x->gl_gobj);
}
binbuf_free(b);
}
diff --git a/pd/src/g_rtext.c b/pd/src/g_rtext.c
index 4b48dcc0..ee894b7e 100644
--- a/pd/src/g_rtext.c
+++ b/pd/src/g_rtext.c
@@ -10,7 +10,8 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
+#include "s_stuff.h"
#include "g_canvas.h"
#include "t_tk.h"
@@ -23,9 +24,6 @@
#define SEND_UPDATE 2
#define SEND_CHECK 0
-static void rtext_senditup(t_rtext *x, int action, int *widthp, int *heightp,
- int *indexp);
-
struct _rtext
{
char *x_buf;
@@ -43,7 +41,7 @@ struct _rtext
struct _rtext *x_next;
};
-t_rtext *rtext_new(t_glist *glist, t_text *who, t_rtext *next, int senditup)
+t_rtext *rtext_new(t_glist *glist, t_text *who)
{
t_rtext *x = (t_rtext *)getbytes(sizeof *x);
int w = 0, h = 0, indx;
@@ -57,24 +55,13 @@ t_rtext *rtext_new(t_glist *glist, t_text *who, t_rtext *next, int senditup)
glist->gl_editor->e_rtext = x;
sprintf(x->x_tag, ".x%x.t%x", (t_int)glist_getcanvas(x->x_glist),
(t_int)x);
- if (senditup)
- rtext_senditup(x, SEND_FIRST, &w, &h, &indx);
return (x);
}
-/* iemlib version (now incorporated into rtext_new() via the "senditup" arg) */
-
-t_rtext *rtext_new_without_senditup(t_glist *glist, t_text *who, t_rtext *next)
-{
- return (rtext_new(glist, who, next, 0));
-}
-
static t_rtext *rtext_entered;
void rtext_free(t_rtext *x)
{
- sys_vgui(".x%x.c delete %s\n", glist_getcanvas(x->x_glist),
- x->x_tag);
if (x->x_glist->gl_editor->e_textedfor == x)
x->x_glist->gl_editor->e_textedfor = 0;
if (x->x_glist->gl_editor->e_rtext == x)
@@ -339,6 +326,17 @@ int rtext_height(t_rtext *x)
return (h);
}
+void rtext_draw(t_rtext *x)
+{
+ int w = 0, h = 0, indx;
+ rtext_senditup(x, SEND_FIRST, &w, &h, &indx);
+}
+
+void rtext_erase(t_rtext *x)
+{
+ sys_vgui(".x%x.c delete %s\n", glist_getcanvas(x->x_glist), x->x_tag);
+}
+
void rtext_displace(t_rtext *x, int dx, int dy)
{
sys_vgui(".x%x.c move %s %d %d\n", glist_getcanvas(x->x_glist),
diff --git a/pd/src/g_scalar.c b/pd/src/g_scalar.c
index 362fb108..d24564e4 100644
--- a/pd/src/g_scalar.c
+++ b/pd/src/g_scalar.c
@@ -85,6 +85,19 @@ void word_restore(t_word *wp, t_template *template,
post("warning: word_restore: extra arguments");
}
+void word_free(t_word *wp, t_template *template)
+{
+ int i;
+ t_dataslot *dt;
+ for (dt = template->t_vec, i = 0; i < template->t_n; i++, dt++)
+ {
+ if (dt->ds_type == DT_ARRAY)
+ array_free(wp[i].w_array);
+ else if (dt->ds_type == DT_LIST)
+ canvas_free(wp[i].w_list);
+ }
+}
+
/* make a new scalar and add to the glist. We create a "gp" here which
will be used for array items to point back here. This gp doesn't do
reference counting or "validation" updates though; the parent won't go away
@@ -350,13 +363,7 @@ static void scalar_free(t_scalar *x)
error("scalar: couldn't find template %s", templatesym->s_name);
return;
}
- for (dt = template->t_vec, i = 0; i < template->t_n; i++, dt++)
- {
- if (dt->ds_type == DT_ARRAY)
- array_free(x->sc_vec[i].w_array);
- else if (dt->ds_type == DT_LIST)
- canvas_free(x->sc_vec[i].w_list);
- }
+ word_free(x->sc_vec, template);
gfxstub_deleteforkey(x);
/* the "size" field in the class is zero, so Pd doesn't try to free
us automatically (see pd_free()) */
diff --git a/pd/src/g_template.c b/pd/src/g_template.c
index 8dc897a3..67c35413 100644
--- a/pd/src/g_template.c
+++ b/pd/src/g_template.c
@@ -6,7 +6,8 @@
#include <string.h>
#include <stdio.h>
-#include "m_imp.h" /* for sys_hostfontsize */
+#include "m_pd.h"
+#include "s_stuff.h" /* for sys_hostfontsize */
#include "g_canvas.h"
/*
@@ -15,6 +16,9 @@ template. Templates describe objects of type "array" (g_array.c) and
"scalar" (g_scalar.c).
*/
+/* T.Grill - changed the _template.t_pd member to t_pdobj to avoid name clashes
+with the t_pd type */
+
/* the structure of a "struct" object (also the obsolete "gtemplate"
you get when using the name "template" in a box.) */
@@ -122,7 +126,7 @@ t_template *template_new(t_symbol *templatesym, int argc, t_atom *argv)
if (templatesym->s_name)
{
x->t_sym = templatesym;
- pd_bind(&x->t_pd, x->t_sym);
+ pd_bind(&x->t_pdobj, x->t_sym);
}
else x->t_sym = templatesym;
return (x);
@@ -496,11 +500,11 @@ static void *template_usetemplate(void *dummy, t_symbol *s,
{
/* conform everyone to the new template */
template_conform(x, y);
- pd_free(&x->t_pd);
+ pd_free(&x->t_pdobj);
template_new(templatesym, argc, argv);
}
}
- pd_free(&y->t_pd);
+ pd_free(&y->t_pdobj);
}
/* otherwise, just make one. */
else template_new(templatesym, argc, argv);
@@ -511,7 +515,7 @@ static void *template_usetemplate(void *dummy, t_symbol *s,
void template_free(t_template *x)
{
if (*x->t_sym->s_name)
- pd_unbind(&x->t_pd, x->t_sym);
+ pd_unbind(&x->t_pdobj, x->t_sym);
t_freebytes(x->t_vec, x->t_n * sizeof(*x->t_vec));
}
@@ -572,10 +576,10 @@ static void *gtemplate_donew(t_symbol *sym, int argc, t_atom *argv)
{
/* conform everyone to the new template */
template_conform(t, y);
- pd_free(&t->t_pd);
+ pd_free(&t->t_pdobj);
t = template_new(sym, argc, argv);
}
- pd_free(&y->t_pd);
+ pd_free(&y->t_pdobj);
t->t_list = x;
}
}
@@ -630,8 +634,8 @@ static void gtemplate_free(t_gtemplate *x)
first-on-list and replace teh existing template with it. */
t_template *z = template_new(&s_, x->x_argc, x->x_argv);
template_conform(t, z);
- pd_free(&t->t_pd);
- pd_free(&z->t_pd);
+ pd_free(&t->t_pdobj);
+ pd_free(&z->t_pdobj);
z = template_new(x->x_sym, x->x_argc, x->x_argv);
z->t_list = x->x_next;
}
@@ -1668,7 +1672,7 @@ void g_template_setup(void)
{
template_setup();
gtemplate_setup();
- template_float.t_pd = template_class;
+ template_float.t_pdobj = template_class;
curve_setup();
plot_setup();
drawnumber_setup();
diff --git a/pd/src/g_text.c b/pd/src/g_text.c
index b502446b..13619493 100644
--- a/pd/src/g_text.c
+++ b/pd/src/g_text.c
@@ -7,7 +7,9 @@
/* all changes are labeled with iemlib */
#include <stdlib.h>
+#include "m_pd.h"
#include "m_imp.h"
+#include "s_stuff.h"
#include "t_tk.h"
#include "g_canvas.h"
#include <stdio.h>
@@ -921,8 +923,9 @@ static void text_select(t_gobj *z, t_glist *glist, int state)
t_text *x = (t_text *)z;
t_rtext *y = glist_findrtext(glist, x);
rtext_select(y, state);
- sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
- rtext_gettag(y), (state? "blue" : "black"));
+ if (glist_isvisible(glist) && text_shouldvis(x, glist))
+ sys_vgui(".x%x.c itemconfigure %sR -fill %s\n", glist,
+ rtext_gettag(y), (state? "blue" : "black"));
}
static void text_activate(t_gobj *z, t_glist *glist, int state)
@@ -954,20 +957,22 @@ static void text_vis(t_gobj *z, t_glist *glist, int vis)
{
if (text_shouldvis(x, glist))
{
- t_rtext *y = rtext_new(glist, x, glist->gl_editor->e_rtext, 1);
+ t_rtext *y = glist_findrtext(glist, x);
if (x->te_type == T_ATOM)
glist_retext(glist, x);
text_drawborder(x, glist, rtext_gettag(y),
rtext_width(y), rtext_height(y), 1);
+ rtext_draw(y);
}
- else rtext_new(glist, x, glist->gl_editor->e_rtext, 0);
}
else
{
t_rtext *y = glist_findrtext(glist, x);
if (text_shouldvis(x, glist))
+ {
text_eraseborder(x, glist, rtext_gettag(y));
- rtext_free(y);
+ rtext_erase(y);
+ }
}
}
diff --git a/pd/src/g_toggle.c b/pd/src/g_toggle.c
index a119e242..9f5f5c3c 100644
--- a/pd/src/g_toggle.c
+++ b/pd/src/g_toggle.c
@@ -10,13 +10,13 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include "t_tk.h"
#include "g_all_guis.h"
#include <math.h>
-#ifdef NT
+#ifdef MSW
#include <io.h>
#else
#include <unistd.h>
diff --git a/pd/src/g_vdial.c b/pd/src/g_vdial.c
index 4974227a..6424944a 100644
--- a/pd/src/g_vdial.c
+++ b/pd/src/g_vdial.c
@@ -11,7 +11,7 @@ put out a "float" as in sliders, toggles, etc. */
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include "t_tk.h"
#include "g_all_guis.h"
@@ -356,7 +356,12 @@ static void vradio_bang(t_vradio *x)
if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
pd_list(x->x_gui.x_snd->s_thing, &s_list, 2, x->x_at);
}
- else outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
+ else
+ {
+ outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, x->x_on);
+ }
}
static void vradio_fout(t_vradio *x, t_floatarg f)
@@ -393,6 +398,8 @@ static void vradio_fout(t_vradio *x, t_floatarg f)
else
{
outlet_float(x->x_gui.x_obj.ob_outlet, x->x_on = i);
+ if(x->x_gui.x_fsf.x_snd_able && x->x_gui.x_snd->s_thing)
+ pd_float(x->x_gui.x_snd->s_thing, x->x_on);
(*x->x_gui.x_draw)(x, x->x_gui.x_glist, IEM_GUI_DRAW_MODE_UPDATE);
x->x_on_old = x->x_on;
}
diff --git a/pd/src/g_vslider.c b/pd/src/g_vslider.c
index 81960d48..a7780135 100644
--- a/pd/src/g_vslider.c
+++ b/pd/src/g_vslider.c
@@ -10,13 +10,13 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include "t_tk.h"
#include "g_all_guis.h"
#include <math.h>
-#ifdef NT
+#ifdef MSW
#include <io.h>
#else
#include <unistd.h>
diff --git a/pd/src/g_vumeter.c b/pd/src/g_vumeter.c
index 95b976dd..f538eda7 100644
--- a/pd/src/g_vumeter.c
+++ b/pd/src/g_vumeter.c
@@ -10,13 +10,13 @@
#include <string.h>
#include <stdio.h>
#include <ctype.h>
-#include "m_imp.h"
+#include "m_pd.h"
#include "g_canvas.h"
#include "t_tk.h"
#include "g_all_guis.h"
#include <math.h>
-#ifdef NT
+#ifdef MSW
#include <io.h>
#else
#include <unistd.h>
diff --git a/pd/src/m_atom.c b/pd/src/m_atom.c
index c9c4c284..7e30c82f 100644
--- a/pd/src/m_atom.c
+++ b/pd/src/m_atom.c
@@ -2,7 +2,7 @@
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-#include "m_imp.h"
+#include "m_pd.h"
#include <stdio.h>
#include <string.h>
diff --git a/pd/src/m_binbuf.c b/pd/src/m_binbuf.c
index fab30baf..c40e5dff 100644
--- a/pd/src/m_binbuf.c
+++ b/pd/src/m_binbuf.c
@@ -16,7 +16,7 @@
#ifdef UNIX
#include <unistd.h>
#endif
-#ifdef NT
+#ifdef MSW
#include <io.h>
#endif
#include <fcntl.h>
@@ -599,7 +599,7 @@ broken:
static int binbuf_doopen(char *s, int mode)
{
char namebuf[MAXPDSTRING];
-#ifdef NT
+#ifdef MSW
mode |= O_BINARY;
#endif
sys_bashfilename(s, namebuf);
@@ -903,14 +903,13 @@ static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd)
else if (!strcmp(second, "button"))
{
binbuf_addv(newb, "ssffs;",
- gensym("#X"), gensym("msg"),
+ gensym("#X"), gensym("obj"),
atom_getfloatarg(2, natom, nextmess),
atom_getfloatarg(3, natom, nextmess),
- gensym("bang"));
+ gensym("bng"));
nobj++;
}
- else if (!strcmp(second, "slider") || !strcmp(second, "number")
- || !strcmp(second, "flonum") || !strcmp(second, "toggle"))
+ else if (!strcmp(second, "number") || !strcmp(second, "flonum"))
{
binbuf_addv(newb, "ssff;",
gensym("#X"), gensym("floatatom"),
@@ -918,6 +917,33 @@ static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd)
atom_getfloatarg(3, natom, nextmess));
nobj++;
}
+ else if (!strcmp(second, "slider"))
+ {
+ binbuf_addv(newb, "ssffsffffffsssfffffffff;",
+ gensym("#X"), gensym("obj"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ gensym("vsl"),
+ atom_getfloatarg(4, natom, nextmess),
+ atom_getfloatarg(5, natom, nextmess),
+ atom_getfloatarg(7, natom, nextmess),
+ atom_getfloatarg(7, natom, nextmess)
+ + (atom_getfloatarg(5, natom, nextmess) - 1)
+ * atom_getfloatarg(6, natom, nextmess),
+ 0., 0.,
+ gensym("empty"), gensym("empty"), gensym("empty"),
+ 0., -8., 0., 8., -262144., -1., -1., 0., 1.);
+ nobj++;
+ }
+ else if (!strcmp(second, "toggle"))
+ {
+ binbuf_addv(newb, "ssffs;",
+ gensym("#X"), gensym("obj"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ gensym("tgl"));
+ nobj++;
+ }
else if (!strcmp(second, "inlet"))
{
binbuf_addv(newb, "ssffs;",
@@ -1014,6 +1040,30 @@ static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd)
atom_getfloatarg(2, natom, nextmess),
atom_getfloatarg(3, natom, nextmess),
15., 1.);
+ else if (classname == gensym("bng"))
+ binbuf_addv(newb, "ssffff;", gensym("#P"),
+ gensym("button"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ atom_getfloatarg(5, natom, nextmess), 0.);
+ else if (classname == gensym("tgl"))
+ binbuf_addv(newb, "ssffff;", gensym("#P"),
+ gensym("toggle"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ atom_getfloatarg(5, natom, nextmess), 0.);
+ else if (classname == gensym("vsl"))
+ binbuf_addv(newb, "ssffffff;", gensym("#P"),
+ gensym("slider"),
+ atom_getfloatarg(2, natom, nextmess),
+ atom_getfloatarg(3, natom, nextmess),
+ atom_getfloatarg(5, natom, nextmess),
+ atom_getfloatarg(6, natom, nextmess),
+ (atom_getfloatarg(8, natom, nextmess) -
+ atom_getfloatarg(7, natom, nextmess)) /
+ (atom_getfloatarg(6, natom, nextmess) == 1? 1 :
+ atom_getfloatarg(6, natom, nextmess) - 1),
+ atom_getfloatarg(7, natom, nextmess));
else
{
SETSYMBOL(outmess, gensym("#P"));
@@ -1069,7 +1119,7 @@ static t_binbuf *binbuf_convert(t_binbuf *oldb, int maxtopd)
}
if (!maxtopd)
binbuf_addv(newb, "ss;", gensym("#P"), gensym("pop"));
-#if 1
+#if 0
binbuf_write(newb, "import-result.pd", "/tmp", 0);
#endif
return (newb);
diff --git a/pd/src/m_class.c b/pd/src/m_class.c
index 9d6329d6..b13db89d 100644
--- a/pd/src/m_class.c
+++ b/pd/src/m_class.c
@@ -3,12 +3,14 @@
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
#define PD_CLASS_DEF
+#include "m_pd.h"
#include "m_imp.h"
+#include "s_stuff.h"
#include <stdlib.h>
#ifdef UNIX
#include <unistd.h>
#endif
-#ifdef NT
+#ifdef MSW
#include <io.h>
#endif
@@ -21,6 +23,8 @@ static void pd_defaultlist(t_pd *x, t_symbol *s, int argc, t_atom *argv);
t_pd pd_objectmaker; /* factory for creating "object" boxes */
t_pd pd_canvasmaker; /* factory for creating canvases */
+static t_symbol *class_extern_dir = &s_;
+
static void pd_defaultanything(t_pd *x, t_symbol *s, int argc, t_atom *argv)
{
pd_error(x, "%s: no method for '%s'", (*x)->c_name->s_name, s->s_name);
@@ -200,6 +204,7 @@ t_class *class_new(t_symbol *s, t_newmethod newmethod, t_method freemethod,
c->c_gobj = (typeflag >= CLASS_GOBJ);
c->c_drawcommand = 0;
c->c_floatsignalin = 0;
+ c->c_externdir = class_extern_dir;
#if 0
post("class: %s", c->c_name->s_name);
#endif
@@ -402,6 +407,17 @@ void class_domainsignalin(t_class *c, int onset)
c->c_floatsignalin = onset;
}
+void class_set_extern_dir(t_symbol *s)
+{
+ class_extern_dir = s;
+}
+
+char *class_gethelpdir(t_class *c)
+{
+ return (c->c_externdir->s_name);
+}
+
+
/* ---------------- the symbol table ------------------------ */
#define HASHSIZE 1024
@@ -534,6 +550,13 @@ void mess_init(void)
t_pd *newest;
+/* This is externally available, but note that it might later disappear; the
+whole "newest" thing is a hack which needs to be redesigned. */
+t_pd *pd_newest(void)
+{
+ return (newest);
+}
+
/* horribly, we need prototypes for each of the artificial function
calls in typedmess(), to keep the compiler quiet. */
typedef t_pd *(*t_newgimme)(t_symbol *s, int argc, t_atom *argv);
diff --git a/pd/src/m_conf.c b/pd/src/m_conf.c
index e2ba1689..d529ecd6 100644
--- a/pd/src/m_conf.c
+++ b/pd/src/m_conf.c
@@ -5,7 +5,7 @@
/* changes by Thomas Musil IEM KUG Graz Austria 2001 */
/* all changes are labeled with iemlib */
-#include "m_imp.h"
+#include "m_pd.h"
void g_array_setup(void);
void g_canvas_setup(void);
diff --git a/pd/src/m_glob.c b/pd/src/m_glob.c
index 3be209d6..eb240068 100644
--- a/pd/src/m_glob.c
+++ b/pd/src/m_glob.c
@@ -2,6 +2,7 @@
* 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"
#include "m_imp.h"
static t_class *pdclass;
@@ -19,47 +20,17 @@ void glob_audiostatus(void *dummy);
void glob_finderror(t_pd *dummy);
void glob_ping(t_pd *dummy);
-#if 0 /* this doesn't work for OSS or for ALSA... discouraged... */
-
-#ifdef UNIX
-#include <unistd.h>
-#endif
-
-void glob_restart_audio(t_pd *dummy)
-{
- int inchans = sys_get_inchannels();
- int outchans = sys_get_outchannels();
- post("1");
- sys_close_audio();
- post("2");
-#ifdef UNIX
- sleep(2);
-#endif
- post("3");
- sys_open_audio(1, 0, 1, 0, /* IOhannes */
- 1, &inchans, 1, &outchans, sys_dacsr);
- post("4");
-}
-#endif
-
void alsa_resync( void);
-#ifdef ALSA01
-void glob_restart_alsa(t_pd *dummy)
-{
- alsa_resync();
-}
-#endif
-
-#ifdef NT
+#ifdef MSW
void glob_audio(void *dummy, t_floatarg adc, t_floatarg dac);
#endif
/* a method you add for debugging printout */
void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv);
-#if 0
+#if 1
void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
{
*(int *)1 = 3;
@@ -108,14 +79,6 @@ void glob_init(void)
#ifdef UNIX
class_addmethod(pdclass, (t_method)glob_ping, gensym("ping"), 0);
#endif
-#ifdef NT
- class_addmethod(pdclass, (t_method)glob_audio, gensym("audio"),
- A_DEFFLOAT, A_DEFFLOAT, 0);
-#endif
-#ifdef ALSA01
- class_addmethod(pdclass, (t_method)glob_restart_alsa,
- gensym("restart-audio"), 0);
-#endif
class_addanything(pdclass, max_default);
pd_bind(&pdclass, gensym("pd"));
}
diff --git a/pd/src/m_imp.h b/pd/src/m_imp.h
index 7a6bd69e..b95f5d0e 100644
--- a/pd/src/m_imp.h
+++ b/pd/src/m_imp.h
@@ -5,7 +5,8 @@
/* This file contains function prototypes and data types used to implement
Pd, but not shared with Pd objects. */
-#include "m_pd.h"
+/* NOTE: this file describes Pd implementation details which may change
+in future releases. The public (stable) API is in m_pd.h. */
/* LATER consider whether to use 'char' for method arg types to save space */
@@ -30,6 +31,7 @@ struct _class
{
t_symbol *c_name; /* name (mostly for error reporting) */
t_symbol *c_helpname; /* name of help file */
+ t_symbol *c_externdir; /* directory extern was loaded from */
size_t c_size; /* size of an instance */
t_methodentry *c_methods; /* methods other than bang, etc below */
int c_nmethod; /* number of methods */
@@ -49,162 +51,6 @@ struct _class
char c_drawcommand; /* a drawing command for a template */
};
-/* s_file.c */
-typedef struct _namelist
-{
- struct _namelist *nl_next;
- char *nl_string;
-} t_namelist;
-
-t_namelist *namelist_append(t_namelist *listwas, const char *s);
-void namelist_free(t_namelist *listwas);
-
-extern int sys_debuglevel;
-extern int sys_verbose;
-
-#define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */
-#define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */
-
-extern int sys_noloadbang;
-extern int sys_nogui;
-extern char *sys_guicmd;
-
-/* in s_main.c */
-EXTERN int sys_nearestfontsize(int fontsize);
-EXTERN int sys_hostfontsize(int fontsize);
-
-extern int sys_defaultfont;
-extern t_symbol *sys_libdir; /* library directory for auxilliary files */
-/* s_loader.c */
-int sys_load_lib(char *dirname, char *filename);
-
-/* s_unix.c */
-EXTERN void sys_microsleep(int microsec);
-
-/* s_sgi.c, s_nt.c, s_linux.c each implement the same API for audio
-and MIDI I/O as follows: */
-
-#define DACBLKSIZE 64
-
-#define SENDDACS_NO 0 /* return values for sys_send_dacs() */
-#define SENDDACS_YES 1
-#define SENDDACS_SLEPT 2
-
-#define API_OSS 0 /* API choices */
-#define API_ALSA 1
-#define API_RME 2
-#define API_MMIO 3
-#define API_PORTAUDIO 4
-
-
- /* MIDI input and output */
-#define MAXMIDIINDEV 16 /* max. number of input ports */
-#define MAXMIDIOUTDEV 16 /* max. number of output ports */
-extern int sys_nmidiin;
-extern int sys_nmidiout;
-extern int sys_midiindevlist[];
-extern int sys_midioutdevlist[];
-
-EXTERN void sys_putmidimess(int portno, int a, int b, int c);
-EXTERN void sys_putmidibyte(int portno, int a);
-EXTERN void sys_poll_midi(void);
-EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime);
-EXTERN void sys_midibytein(int portno, int byte);
-
-extern int sys_hipriority; /* real-time flag, true if priority boosted */
-extern t_sample *sys_soundout;
-extern t_sample *sys_soundin;
-extern float sys_dacsr;
-extern int sys_schedadvance;
-extern int sys_sleepgrain;
-EXTERN void sys_open_audio(int naudioindev, int *audioindev, int nchindev, int *chindev,
- int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
- int srate); /* IOhannes */
-
-EXTERN void sys_close_audio(void);
-
-EXTERN void sys_open_midi(int nmidiin, int *midiinvec,
- int nmidiout, int *midioutvec);
-EXTERN void sys_close_midi(void);
-
-EXTERN int sys_send_dacs(void);
-EXTERN void sys_reportidle(void);
-EXTERN void sys_set_priority(int higher);
-EXTERN void sys_audiobuf(int nbufs);
-EXTERN void sys_getmeters(float *inmax, float *outmax);
-EXTERN void sys_listdevs(void);
-EXTERN void sys_setblocksize(int n);
-
- /* for NT and Linux, there are additional bits of fluff as follows. */
-#ifdef NT
-EXTERN void nt_soundindev(int which);
-EXTERN void nt_soundoutdev(int which);
-EXTERN void nt_midiindev(int which);
-EXTERN void nt_midioutdev(int which);
-EXTERN void nt_noresync( void);
-EXTERN void nt_set_sound_api(int which);
-#endif
-
-#ifdef __linux__
- /* the following definitions allow you to switch at run time
- between audio APIs in Linux and later in NT. */
-void linux_set_sound_api(int which);
-
-void linux_setfrags(int n);
-void linux_streammode( void);
-void linux_32bit( void);
-void rme_soundindev(int which);
-void rme_soundoutdev(int which);
-void linux_alsa_queue_size(int size);
-#ifdef ALSA99 /* old fashioned ALSA */
-void linux_alsa_devno(int devno);
-#else
-void linux_alsa_devname(char *devname);
-#endif
-#endif /* __linux__ */
-
-/* portaudio, used in Windows and Mac versions... */
-
-int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
- t_sample *soundout, int framesperbuf, int nbuffers,
- int indeviceno, int outdeviceno);
-void pa_close_audio(void);
-int pa_send_dacs(void);
-void pa_reportidle(void);
-void pa_listdevs(void);
-
-/* m_sched.c */
-EXTERN void sys_log_error(int type);
-#define ERR_NOTHING 0
-#define ERR_ADCSLEPT 1
-#define ERR_DACSLEPT 2
-#define ERR_RESYNC 3
-#define ERR_DATALATE 4
-
-/* s_inter.c */
-
-EXTERN void sys_bail(int exitcode);
-EXTERN int sys_pollgui(void);
-
-EXTERN_STRUCT _socketreceiver;
-#define t_socketreceiver struct _socketreceiver
-
-typedef void (*t_socketnotifier)(void *x);
-typedef void (*t_socketreceivefn)(void *x, t_binbuf *b);
-
-EXTERN t_socketreceiver *socketreceiver_new(void *owner,
- t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp);
-EXTERN void socketreceiver_read(t_socketreceiver *x, int fd);
-EXTERN void sys_sockerror(char *s);
-EXTERN void sys_closesocket(int fd);
-
-typedef void (*t_fdpollfn)(void *ptr, int fd);
-EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
-EXTERN void sys_rmpollfn(int fd);
-#ifdef UNIX
-void sys_setalarm(int microsec);
-void sys_setvirtualalarm( void);
-#endif
/* m_obj.c */
EXTERN int obj_noutlets(t_object *x);
@@ -218,6 +64,13 @@ EXTERN t_outconnect *obj_connect(t_object *source, int outno,
EXTERN void obj_disconnect(t_object *source, int outno, t_object *sink,
int inno);
EXTERN void outlet_setstacklim(void);
+EXTERN int obj_issignalinlet(t_object *x, int m);
+EXTERN int obj_issignaloutlet(t_object *x, int m);
+EXTERN int obj_nsiginlets(t_object *x);
+EXTERN int obj_nsigoutlets(t_object *x);
+EXTERN int obj_siginletindex(t_object *x, int m);
+EXTERN int obj_sigoutletindex(t_object *x, int m);
+
/* misc */
EXTERN void glob_evalfile(t_pd *ignore, t_symbol *name, t_symbol *dir);
EXTERN void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv);
diff --git a/pd/src/m_memory.c b/pd/src/m_memory.c
index cb94e4b1..bb5d79c6 100644
--- a/pd/src/m_memory.c
+++ b/pd/src/m_memory.c
@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
+#include "m_pd.h"
#include "m_imp.h"
/* #define LOUD */
diff --git a/pd/src/m_obj.c b/pd/src/m_obj.c
index 6e3e1c19..e1f0f54a 100644
--- a/pd/src/m_obj.c
+++ b/pd/src/m_obj.c
@@ -6,6 +6,7 @@
can interconnect via inlets and outlets; also, the (terse) generic
behavior for "gobjs" appears at the end of this file. */
+#include "m_pd.h"
#include "m_imp.h"
union inletunion
@@ -609,6 +610,20 @@ int obj_siginletindex(t_object *x, int m)
return (-1);
}
+int obj_issignalinlet(t_object *x, int m)
+{
+ t_inlet *i;
+ if (x->ob_pd->c_firstin)
+ {
+ if (!m)
+ return (x->ob_pd->c_firstin && x->ob_pd->c_floatsignalin);
+ else m--;
+ }
+ for (i = x->ob_inlet; i && m; i = i->i_next, m--)
+ ;
+ return (i && (i->i_symfrom == &s_signal));
+}
+
int obj_nsigoutlets(t_object *x)
{
int n;
diff --git a/pd/src/m_pd.c b/pd/src/m_pd.c
index 713d65ad..8192c7e4 100644
--- a/pd/src/m_pd.c
+++ b/pd/src/m_pd.c
@@ -3,6 +3,7 @@
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
#include <stdlib.h>
+#include "m_pd.h"
#include "m_imp.h"
/* FIXME no out-of-memory testing yet! */
diff --git a/pd/src/m_pd.h b/pd/src/m_pd.h
index 5e8b20bb..b5f7f037 100644
--- a/pd/src/m_pd.h
+++ b/pd/src/m_pd.h
@@ -2,21 +2,31 @@
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+#ifndef __m_pd_h_
+
#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
extern "C" {
#endif
-#define PD_VERSION 0.36
+#define PD_VERSION 0.37 /* oops, don't use this... */ */
+#define PD_MAJOR_VERSION 0 /* ... use these two instead. */
+#define PD_MINOR_VERSION 37
+
+/* old name for "MSW" flag -- we have to take it for the sake of many old
+"nmakefiles" for externs, which will define NT and not MSW */
+#if defined(NT) && !defined(MSW)
+#define MSW
+#endif
-#ifdef NT
+#ifdef MSW
// #pragma warning( disable : 4091 )
#pragma warning( disable : 4305 ) /* uncast const double to float */
#pragma warning( disable : 4244 ) /* uncast float/int conversion etc. */
#pragma warning( disable : 4101 ) /* unused automatic variables */
-#endif /* NT */
+#endif /* MSW */
- /* the external storage class is "extern" in UNIX; in NT it's ugly. */
-#ifdef NT
+ /* the external storage class is "extern" in UNIX; in MSW it's ugly. */
+#ifdef MSW
#ifdef PD_INTERNAL
#define EXTERN __declspec(dllexport) extern
#else
@@ -24,7 +34,7 @@ extern "C" {
#endif /* PD_INTERNAL */
#else
#define EXTERN extern
-#endif /* NT */
+#endif /* MSW */
/* and depending on the compiler, hidden data structures are
declared differently: */
@@ -227,7 +237,8 @@ EXTERN void pd_vmess(t_pd *x, t_symbol *s, char *fmt, ...);
#define mess3(x, s, a,b,c) ((*getfn((x), (s)))((x), (a),(b),(c)))
#define mess4(x, s, a,b,c,d) ((*getfn((x), (s)))((x), (a),(b),(c),(d)))
#define mess5(x, s, a,b,c,d,e) ((*getfn((x), (s)))((x), (a),(b),(c),(d),(e)))
-void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN void obj_list(t_object *x, t_symbol *s, int argc, t_atom *argv);
+EXTERN t_pd *pd_newest(void);
/* --------------- memory management -------------------- */
EXTERN void *getbytes(size_t nbytes);
@@ -443,7 +454,7 @@ EXTERN void sys_bashfilename(const char *from, char *to);
EXTERN void sys_unbashfilename(const char *from, char *to);
EXTERN int open_via_path(const char *name, const char *ext, const char *dir,
char *dirresult, char **nameresult, unsigned int size, int bin);
-EXTERN int sys_geteventno(void);
+EXTERN int sched_geteventno(void);
EXTERN double sys_getrealtime(void);
/* --------------- signals ----------------------------------- */
@@ -600,3 +611,6 @@ test this just now. */
#if defined(_LANGUAGE_C_PLUS_PLUS) || defined(__cplusplus)
}
#endif
+
+#define __m_pd_h_
+#endif /* __m_pd_h_ */
diff --git a/pd/src/m_sched.c b/pd/src/m_sched.c
index 514e6f8b..b4a5dc3b 100644
--- a/pd/src/m_sched.c
+++ b/pd/src/m_sched.c
@@ -4,7 +4,9 @@
/* scheduling stuff */
+#include "m_pd.h"
#include "m_imp.h"
+#include "s_stuff.h"
/* LATER consider making this variable. It's now the LCM of all sample
rates we expect to see: 32000, 44100, 48000, 88200, 96000. */
@@ -12,9 +14,10 @@
static int sys_quit;
static double sys_time;
+static double sys_time_per_msec = TIMEUNITPERSEC / 1000.;
static double sys_time_per_dsp_tick;
-static double sys_time_per_msec;
+int sys_schedblocksize = DEFDACBLKSIZE;
int sys_usecsincelastsleep(void);
int sys_sleepgrain;
@@ -192,9 +195,6 @@ static int oss_resyncphase = 0;
static int oss_nresync = 0;
static t_resync oss_resync[NRESYNC];
-#ifdef __linux__
-void linux_audiostatus(void);
-#endif
static char *(oss_errornames[]) = {
"unknown",
@@ -207,9 +207,6 @@ static char *(oss_errornames[]) = {
void glob_audiostatus(void)
{
int dev, nresync, nresyncphase, i;
-#ifdef __linux__
- linux_audiostatus();
-#endif
nresync = (oss_nresync >= NRESYNC ? NRESYNC : oss_nresync);
nresyncphase = oss_resyncphase - 1;
post("audio I/O error history:");
@@ -225,7 +222,7 @@ void glob_audiostatus(void)
post("%9.2f\t%s",
(sched_diddsp - oss_resync[nresyncphase].r_ntick)
- * ((double)DACBLKSIZE) / sys_dacsr,
+ * ((double)sys_schedblocksize) / sys_dacsr,
oss_errornames[errtype]);
nresyncphase--;
}
@@ -247,7 +244,7 @@ void sys_log_error(int type)
sched_diored = 1;
}
sched_dioredtime =
- sched_diddsp + (int)(sys_dacsr /(double)DACBLKSIZE);
+ sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
}
static int sched_lastinclip, sched_lastoutclip,
@@ -268,7 +265,7 @@ static void sched_pollformeters( void)
glob_ping(0);
/* ping every 2 seconds */
sched_nextpingtime = sched_diddsp +
- 2 * (int)(sys_dacsr /(double)DACBLKSIZE);
+ 2 * (int)(sys_dacsr /(double)sys_schedblocksize);
}
#endif
@@ -303,7 +300,7 @@ static void sched_pollformeters( void)
sched_lastoutdb = outdb;
}
sched_nextmeterpolltime =
- sched_diddsp + (int)(sys_dacsr /(double)DACBLKSIZE);
+ sched_diddsp + (int)(sys_dacsr /(double)sys_schedblocksize);
}
void glob_meters(void *dummy, float f)
@@ -315,7 +312,7 @@ void glob_meters(void *dummy, float f)
-1;
}
-#if 1
+#if 0
void glob_foo(void *dummy, t_symbol *s, int argc, t_atom *argv)
{
if (argc) sys_clearhist();
@@ -331,9 +328,7 @@ static int m_nodacs = 0;
void m_schedsetsr( void)
{
sys_time_per_dsp_tick =
- (TIMEUNITPERSEC) * ((double)DACBLKSIZE) / sys_dacsr;
- sys_time_per_msec =
- TIMEUNITPERSEC / 1000.;
+ (TIMEUNITPERSEC) * ((double)sys_schedblocksize) / sys_dacsr;
}
/*
@@ -357,6 +352,8 @@ int m_scheduler(int nodacs)
int lasttimeforward = SENDDACS_YES;
int idlecount = 0;
double lastdactime = 0;
+ sys_time_per_dsp_tick = (TIMEUNITPERSEC) *
+ ((double)sys_schedblocksize) / sys_dacsr;
sys_clearhist();
m_nodacs = nodacs;
if (sys_sleepgrain < 1000)
@@ -376,7 +373,7 @@ int m_scheduler(int nodacs)
if (elapsed > next)
{
timeforward = SENDDACS_YES;
- next += (double)DACBLKSIZE / sys_dacsr;
+ next += (double)sys_schedblocksize / sys_dacsr;
}
else timeforward = SENDDACS_NO;
}
diff --git a/pd/src/makefile.in b/pd/src/makefile.in
index f9204e78..3f5b24d2 100644
--- a/pd/src/makefile.in
+++ b/pd/src/makefile.in
@@ -1,7 +1,3 @@
-#
-#
-#
-
VPATH = ../obj:./
OBJ_DIR = ../obj
BIN_DIR = ../bin
@@ -20,10 +16,6 @@ MANDIR = @mandir@
SOUND_ALSA = @alsa@
-# RME compilation
-
-SOUND_RME = @rme@
-
DEFINES = @DEFINES@
MORECFLAGS = @MORECFLAGS@
@@ -47,22 +39,13 @@ CFLAGS = $(ARCH_CFLAGS) $(WARN_CFLAGS) $(OPT_CFLAGS) $(DEFINES) $(MORECFLAGS)
# ALSA non-shared, move the # sign below.
ifeq (${SOUND_ALSA},yes)
-CFLAGS += -DALSA01
-#LIB += /usr/lib/libasound.a
-#LIB += -lasound
+CFLAGS += -DPA_USE_ALSA -DUSEAPI_ALSA
+SYSSRC += s_audio_alsa.c \
+ ../portaudio/pa_linux_alsa/callback_thread.c \
+ ../portaudio/pa_linux_alsa/pa_linux_alsa.c \
+ ../portaudio/pa_linux_alsa/blocking_calls.c
endif
-ifeq (${SOUND_ALSA},old)
-CFLAGS += -DALSA99
-#LIB += /usr/lib/libasound.a
-#LIB += -lasound
-endif
-
-ifeq (${SOUND_RME},yes)
-CFLAGS += -DRME_HAMMERFALL
-endif
-
-
# Which system
SYSTEM = $(shell uname -m)
@@ -80,7 +63,7 @@ endif
# the sources
-SYSSRC = @SYSSRC@
+SYSSRC += @SYSSRC@
SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \
@@ -88,8 +71,8 @@ SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \
m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \
m_conf.c m_glob.c m_sched.c \
- s_main.c s_inter.c s_unix.c s_file.c s_print.c \
- s_loader.c s_path.c s_entry.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_delay.c d_resample.c \
diff --git a/pd/src/makefile.nt b/pd/src/makefile.nt
index 4a301882..9105d734 100644
--- a/pd/src/makefile.nt
+++ b/pd/src/makefile.nt
@@ -1,4 +1,4 @@
-# Makefile for portaudio ASIO driver version of PD
+# Makefile for PD on MSW
all: pd gui ..\bin\pd.tk ..\bin\pdsend.exe ..\bin\pdreceive.exe
@@ -14,10 +14,11 @@ LIB = /NODEFAULTLIB:libc /NODEFAULTLIB:oldnames /NODEFAULTLIB:kernel \
$(LDIR)\wsock32.lib $(LDIR)\winmm.lib ..\bin\pthreadVC.lib
GLIB = $(LIB) ..\lib\tcl83.lib ..\lib\tk83.lib
-CFLAGS = /nologo /W3 /DNT /DPD /DPD_INTERNAL /DWIN32 /DWINDOWS /Ox
+CFLAGS = /nologo /W3 /DMSW /DNT /DPD /DPD_INTERNAL /DWIN32 /DWINDOWS /Ox \
+ -DPA_LITTLE_ENDIAN -DUSEAPI_MMIO -DUSEAPI_PORTAUDIO
LFLAGS = /nologo
-SYSSRC = s_nt.c s_portaudio.c
+SYSSRC = s_audio_pa.c s_audio_mmio.c s_midi_pm.c
SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
g_scalar.c g_traversal.c g_guiconnect.c g_readwrite.c g_editor.c \
@@ -25,8 +26,8 @@ SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
g_toggle.c g_vdial.c g_vslider.c g_vumeter.c \
m_pd.c m_class.c m_obj.c m_atom.c m_memory.c m_binbuf.c \
m_conf.c m_glob.c m_sched.c \
- s_main.c s_inter.c s_unix.c s_file.c s_print.c \
- s_loader.c s_path.c s_entry.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_delay.c d_resample.c \
@@ -36,24 +37,63 @@ SRC = g_canvas.c g_graph.c g_text.c g_rtext.c g_array.c g_template.c g_io.c \
PADIR = ..\portaudio
INCPA = -I$(PADIR) -I$(PADIR)\pa_common -I$(PADIR)\pablio -I..\lib\asio
-SRCPA = $(PADIR)/pa_common/pa_lib.c $(PADIR)/pa_common/pa_trace.c \
- $(PADIR)/pablio/pablio_pd.c $(PADIR)/pablio/ringbuffer_pd.c
-SRCASIO = $(PADIR)/pa_asio/pa_asio.cpp
+SRCPA = \
+ $(PADIR)/pa_common/pa_allocation.c \
+ $(PADIR)/pa_common/pa_converters.c \
+ $(PADIR)/pa_common/pa_cpuload.c \
+ $(PADIR)/pa_common/pa_dither.c \
+ $(PADIR)/pa_common/pa_front.c \
+ $(PADIR)/pa_common/pa_process.c \
+ $(PADIR)/pa_common/pa_skeleton.c \
+ $(PADIR)/pa_common/pa_stream.c \
+ $(PADIR)/pa_common/pa_trace.c \
+ $(PADIR)/pablio/pablio_pd.c \
+ $(PADIR)/pablio/ringbuffer_pd.c \
+ $(PADIR)/pa_win/pa_win_hostapis.c \
+ $(PADIR)/pa_win/pa_win_util.c \
+ $(PADIR)/pa_win/pa_x86_plain_converters.c \
+ $(PADIR)/pa_win_wmme/pa_win_wmme.c
+
+# $(PADIR)/pa_win_ds/dsound_wrapper.c \
+# $(PADIR)/pa_win_ds/pa_dsound.c \
+# $(PADIR)/pa_win_ds/pa_win_ds.c \
+
+PAOBJ = \
+ pa_allocation.obj pa_converters.obj pa_cpuload.obj pa_dither.obj pa_front.obj \
+ pa_process.obj pa_skeleton.obj pa_stream.obj pa_trace.obj pablio_pd.obj \
+ ringbuffer_pd.obj pa_win_hostapis.obj pa_win_util.obj \
+ pa_x86_plain_converters.obj \
+ pa_win_wmme.obj pa_asio.obj \
+
+# dsound_wrapper.obj pa_dsound.obj pa_win_ds.obj
+
-ASIOLIB = $(LDIR)\user32.lib $(LDIR)\gdi32.lib $(LDIR)\winspool.lib $(LDIR)\comdlg32.lib \
+SRCASIO = $(PADIR)/pa_asio/pa_asio.cpp
+ASIOLIB = $(LDIR)\user32.lib $(LDIR)\gdi32.lib $(LDIR)\winspool.lib \
+ $(LDIR)\comdlg32.lib \
$(LDIR)\advapi32.lib $(LDIR)\shell32.lib $(LDIR)\ole32.lib $(LDIR)\oleaut32.lib $(LDIR)\uuid.lib \
$(LDIR)\odbc32.lib $(LDIR)\odbccp32.lib ..\lib\asio\asiolib.lib
+PMDIR = ..\portmidi
+INCPM = -I$(PMDIR)\pm_common -I$(PMDIR)\pm_win -I$(PMDIR)\porttime
+SRCPM = \
+ $(PMDIR)/pm_common/portmidi.c \
+ $(PMDIR)/pm_common/pmutil.c \
+ $(PMDIR)/pm_win/pmwin.c \
+ $(PMDIR)/pm_win/pmwinmm.c \
+ $(PMDIR)/porttime/porttime.c \
+ $(PMDIR)/porttime/ptwinmm.c \
-PAOBJ = pa_lib.obj pa_trace.obj pablio_pd.obj ringbuffer_pd.obj pa_asio.obj
-OBJC = $(SRC:.c=.obj) $(PAOBJ)
+PMOBJ = portmidi.obj pmutil.obj pmwin.obj pmwinmm.obj porttime.obj ptwinmm.obj
+
+OBJC = $(SRC:.c=.obj) $(PAOBJ) $(PMOBJ)
GSRC = t_main.c t_tkcmd.c
GOBJ = $(GSRC:.c=.obj)
.PHONY: pd gui
-ALLCF = $(CFLAGS) $(INCLUDE) $(INCASIO) $(INCPA) /D_WINDOWS
+ALLCF = $(CFLAGS) $(INCLUDE) $(INCASIO) $(INCPA) $(INCPM) /D_WINDOWS /DPA_NO_DS
.c.obj:
cl /c $(ALLCF) /Tc$*.c
@@ -84,18 +124,60 @@ gui: ..\bin\pdtcl.dll
link $(LFLAGS) /out:..\bin\pdreceive.exe /INCREMENTAL:NO u_pdreceive.obj \
$(LIB)
-# explicit rules to compile portaudio sources:
-pa_lib.obj: $(PADIR)\pa_common\pa_lib.c
- cl /c $(ALLCF) $(PADIR)\pa_common\pa_lib.c
+# explicit rules to compile portaudio and portmidi sources:
+pa_allocation.obj: $(PADIR)\pa_common\pa_allocation.c
+ cl /c $(ALLCF) $(PADIR)\pa_common\pa_allocation.c
+pa_converters.obj: $(PADIR)\pa_common\pa_converters.c
+ cl /c $(ALLCF) $(PADIR)\pa_common\pa_converters.c
+pa_cpuload.obj: $(PADIR)\pa_common\pa_cpuload.c
+ cl /c $(ALLCF) $(PADIR)\pa_common\pa_cpuload.c
+pa_dither.obj: $(PADIR)\pa_common\pa_dither.c
+ cl /c $(ALLCF) $(PADIR)\pa_common\pa_dither.c
+pa_front.obj: $(PADIR)\pa_common\pa_front.c
+ cl /c $(ALLCF) $(PADIR)\pa_common\pa_front.c
+pa_process.obj: $(PADIR)\pa_common\pa_process.c
+ cl /c $(ALLCF) $(PADIR)\pa_common\pa_process.c
+pa_skeleton.obj: $(PADIR)\pa_common\pa_skeleton.c
+ cl /c $(ALLCF) $(PADIR)\pa_common\pa_skeleton.c
+pa_stream.obj: $(PADIR)\pa_common\pa_stream.c
+ cl /c $(ALLCF) $(PADIR)\pa_common\pa_stream.c
pa_trace.obj: $(PADIR)\pa_common\pa_trace.c
cl /c $(ALLCF) $(PADIR)\pa_common\pa_trace.c
pablio_pd.obj: $(PADIR)\pablio\pablio_pd.c
cl /c $(ALLCF) $(PADIR)\pablio\pablio_pd.c
ringbuffer_pd.obj: $(PADIR)\pablio\ringbuffer_pd.c
cl /c $(ALLCF) $(PADIR)\pablio\ringbuffer_pd.c
+pa_win_hostapis.obj: $(PADIR)\pa_win\pa_win_hostapis.c
+ cl /c $(ALLCF) $(PADIR)\pa_win\pa_win_hostapis.c
+pa_win_util.obj: $(PADIR)\pa_win\pa_win_util.c
+ cl /c $(ALLCF) $(PADIR)\pa_win\pa_win_util.c
+pa_x86_plain_converters.obj: $(PADIR)\pa_win\pa_x86_plain_converters.c
+ cl /c $(ALLCF) $(PADIR)\pa_win\pa_x86_plain_converters.c
+dsound_wrapper.obj: $(PADIR)\pa_win_ds\dsound_wrapper.c
+ cl /c $(ALLCF) $(PADIR)\pa_win_ds\dsound_wrapper.c
+pa_dsound.obj: $(PADIR)\pa_win_ds\pa_dsound.c
+ cl /c $(ALLCF) $(PADIR)\pa_win_ds\pa_dsound.c
+pa_win_ds.obj: $(PADIR)\pa_win_ds\pa_win_ds.c
+ cl /c $(ALLCF) $(PADIR)\pa_win_ds\pa_win_ds.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_asio.obj: $(PADIR)\pa_asio\pa_asio.cpp
cl /c $(ALLCF) $(PADIR)\pa_asio\pa_asio.cpp
+portmidi.obj: $(PMDIR)\pm_common\portmidi.c
+ cl /c $(ALLCF) $(PMDIR)\pm_common\portmidi.c
+pmutil.obj: $(PMDIR)\pm_common\pmutil.c
+ cl /c $(ALLCF) $(PMDIR)\pm_common\pmutil.c
+pmwin.obj: $(PMDIR)\pm_win\pmwin.c
+ cl /c $(ALLCF) $(PMDIR)\pm_win\pmwin.c
+pmwinmm.obj: $(PMDIR)\pm_win\pmwinmm.c
+ cl /c $(ALLCF) $(PMDIR)\pm_win\pmwinmm.c
+porttime.obj: $(PMDIR)\porttime\porttime.c
+ cl /c $(ALLCF) $(PMDIR)\porttime\porttime.c
+ptwinmm.obj: $(PMDIR)\porttime\ptwinmm.c
+ cl /c $(ALLCF) $(PMDIR)\porttime\ptwinmm.c
+
# the following should also clean up "bin" but it doesn't because "bin" holds
# precious stuff from elsewhere.
clean:
diff --git a/pd/src/notes.txt b/pd/src/notes.txt
index 1f0937e8..0f95929d 100644
--- a/pd/src/notes.txt
+++ b/pd/src/notes.txt
@@ -1,18 +1,29 @@
-done for 0.36:
+vline object
+arrow keys in text objs for mac
---------------- dolist --------------------
-
-pddp doc
+vline~ help window
+writesf help window, support 32 bit wav files, and fix sample rate writing
+check that latency is actually set (esp. in windows)
+windows escape from control-C
+dialogs for a/d/a, midi, path
+ALSA deglitch back in
+bug: resizing grow-upward patches leaves line traces around
+
+suspend/resume graphics updates
+scheduler to handle callbacks
scheduler to do DSP computations even if no audio
hook to scheduler to let others get called for DSP I/O
figure out how to avoid "dac freeze" if nosound
-
+new: mline~, msnapshot~, abs~
+flags to defeat adding specified classes from libraries
+incorporate pddp doc
try again to fix the font scene
addcomma message to message
pasting should look at current mouse location
+open/save panel to take messages to init directory
problems:
-messages & comments don't come up with text activated?
arrays of non-existent templates crash
don't draw in/outlets on gui objects in graphs
Alsa degradation after several hours running on soundblaster
@@ -20,7 +31,6 @@ font size should depend on subpatch/abstraction
moving a bang toward top of window creates problem
figure out O_NDELAY for linux audio?
missed Thomas's multi-dialog trick???
-fix iemguis not to bash symbol names
check what happens when going back and forth between graph-on-parent
deal with spaces in iemgui labels and send/receive names
get rid of messages causing renaming; try to prevent patches closing themselves.
@@ -47,6 +57,7 @@ scalar hook to catch the mouse
protect against "plots" going away while you drag on them
features:
+command line flag to defeat loading objects
signal inlets with initialized values...
Pd to open html help on windows/mac
flag to hide array names
@@ -56,14 +67,11 @@ if there's just one array, don't do stringent hit check.
netsend separate thread
netreceive (and netsend?) message to set port number
delete-in-rectangle message to Pds
-"regular" numbers/symbols to do send/receive thing ala IEMGUI
make selecting text grab keyboard focus
think about x and y scale preservation when changing between graph and object
show outlines of objects even when graph is "open"
make graph labels persistent and add to dialog
array click protection (Krzysztof's suggestion)
-Pd support for jack audio system: http://home.t-online.de/home/pdq808/jack-patch
-offer audiooutdev 1,3 feature on Windows
Alsa in data late should carefuly reset DAC/ADC fill&empty pointers
increase MIDIQSIZE to at least 1024 in s_unix.c
add nonblock to linux open calls instead of using alarm
diff --git a/pd/src/s_audio.c b/pd/src/s_audio.c
new file mode 100644
index 00000000..ca5e34c6
--- /dev/null
+++ b/pd/src/s_audio.c
@@ -0,0 +1,410 @@
+/* Copyright (c) 2003, 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. */
+
+/* machine-independent (well, mostly!) audio layer. Stores and recalls
+ audio settings from argparse routine and from dialog window.
+*/
+
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define SYS_DEFAULTCH 2
+#define SYS_MAXCH 100
+#define SYS_DEFAULTSRATE 44100
+typedef long t_pa_sample;
+#define SYS_SAMPLEWIDTH sizeof(t_pa_sample)
+#define SYS_BYTESPERCHAN (DEFDACBLKSIZE * SYS_SAMPLEWIDTH)
+#define SYS_XFERSAMPS (SYS_DEFAULTCH*DEFDACBLKSIZE)
+#define SYS_XFERSIZE (SYS_SAMPLEWIDTH * SYS_XFERSAMPS)
+#define MAXAUDIODEV 4
+
+int sys_inchannels;
+int sys_outchannels;
+int sys_advance_samples; /* scheduler advance in samples */
+int sys_blocksize = 256; /* audio I/O block size in sample frames */
+int sys_audioapi = API_DEFAULT;
+
+static int sys_meters; /* true if we're metering */
+static float sys_inmax; /* max input amplitude */
+static float sys_outmax; /* max output amplitude */
+
+ /* exported variables */
+#ifdef MSW
+#define DEFAULTADVANCE 70000
+#else
+#define DEFAULTADVANCE 50000
+#endif
+int sys_schedadvance = DEFAULTADVANCE; /* scheduler advance in microseconds */
+float sys_dacsr;
+int sys_hipriority = 0;
+t_sample *sys_soundout;
+t_sample *sys_soundin;
+
+ /* set channels and sample rate. */
+
+static void sys_setchsr(int chin, int chout, int sr)
+{
+ int nblk;
+ int inbytes = chin * (DEFDACBLKSIZE*sizeof(float));
+ int outbytes = chout * (DEFDACBLKSIZE*sizeof(float));
+
+ sys_inchannels = chin;
+ sys_outchannels = chout;
+ sys_dacsr = sr;
+ sys_advance_samples = (sys_schedadvance * sys_dacsr) / (1000000.);
+ if (sys_advance_samples < 3 * DEFDACBLKSIZE)
+ sys_advance_samples = 3 * DEFDACBLKSIZE;
+
+ if (sys_soundin)
+ free(sys_soundin);
+ sys_soundin = (t_float *)malloc(inbytes);
+ memset(sys_soundin, 0, inbytes);
+
+ if (sys_soundout)
+ free(sys_soundout);
+ sys_soundout = (t_float *)malloc(outbytes);
+ memset(sys_soundout, 0, outbytes);
+
+ if (sys_verbose)
+ post("input channels = %d, output channels = %d",
+ sys_inchannels, sys_outchannels);
+}
+
+/* ----------------------- public routines ----------------------- */
+
+#if 0
+void sys_open_audio(int naudioindev, int *audioindev, int nchindev,
+ int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
+ int *choutdev, int rate) /* IOhannes */
+{
+ int inchans=
+ (nchindev > 0 ? chindev[0] : (nchindev == 0 ? 0 : SYS_DEFAULTCH));
+ int outchans=
+ (nchoutdev > 0 ? choutdev[0] : (nchoutdev == 0 ? 0 : SYS_DEFAULTCH));
+ int soundindev = (naudioindev <= 0 ? -1 : (audioindev[0]-1));
+ int soundoutdev = (naudiooutdev <= 0 ? -1 : (audiooutdev[0]-1));
+ int sounddev = (inchans > 0 ? soundindev : soundoutdev);
+ if (naudioindev > 1 || nchindev > 1 || naudiooutdev > 1 || nchoutdev > 1)
+ post("sorry, only one portaudio device can be open at once.\n");
+ /* post("nindev %d, noutdev %d", naudioindev, naudiooutdev);
+ post("soundindev %d, soundoutdev %d", soundindev, soundoutdev); */
+ if (sys_verbose)
+ post("channels in %d, out %d", inchans, outchans);
+ if (rate < 1)
+ rate = SYS_DEFAULTSRATE;
+ sys_setchsr(inchans, outchans, rate);
+ pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout,
+ sys_blocksize, sys_advance_samples/sys_blocksize,
+ soundindev, soundoutdev);
+}
+#endif
+
+void sys_open_audio(int naudioindev, int *audioindev, int nchindev,
+ int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
+ int *choutdev, int rate) /* IOhannes */
+{
+ int i, *ip;
+ int defaultchannels = SYS_DEFAULTCH;
+ int inchans, outchans;
+ if (rate < 1)
+ rate = SYS_DEFAULTSRATE;
+
+ if (naudioindev == -1)
+ { /* not set */
+ if (nchindev == -1)
+ {
+ nchindev=1;
+ chindev[0] = defaultchannels;
+ naudioindev = 1;
+ audioindev[0] = DEFAULTAUDIODEV;
+ }
+ else
+ {
+ for (i = 0; i < MAXAUDIODEV; i++)
+ audioindev[i] = i+1;
+ naudioindev = nchindev;
+ }
+ }
+ else
+ {
+ if (nchindev == -1)
+ {
+ nchindev = naudioindev;
+ for (i = 0; i < naudioindev; i++)
+ chindev[i] = defaultchannels;
+ }
+ else if (nchindev > naudioindev)
+ {
+ for (i = naudioindev; i < nchindev; i++)
+ {
+ if (i == 0)
+ audioindev[0] = DEFAULTAUDIODEV;
+ else audioindev[i] = audioindev[i-1] + 1;
+ }
+ naudioindev = nchindev;
+ }
+ else if (nchindev < naudioindev)
+ {
+ for (i = nchindev; i < naudioindev; i++)
+ {
+ if (i == 0)
+ chindev[0] = defaultchannels;
+ else chindev[i] = chindev[i-1];
+ }
+ naudioindev = nchindev;
+ }
+ }
+
+ if (naudiooutdev == -1)
+ { /* not set */
+ if (nchoutdev == -1)
+ {
+ nchoutdev=1;
+ choutdev[0]=defaultchannels;
+ naudiooutdev=1;
+ audiooutdev[0] = DEFAULTAUDIODEV;
+ }
+ else
+ {
+ for (i = 0; i < MAXAUDIODEV; i++)
+ audiooutdev[i] = i+1;
+ naudiooutdev = nchoutdev;
+ }
+ }
+ else
+ {
+ if (nchoutdev == -1)
+ {
+ nchoutdev = naudiooutdev;
+ for (i = 0; i < naudiooutdev; i++)
+ choutdev[i] = defaultchannels;
+ }
+ else if (nchoutdev > naudiooutdev)
+ {
+ for (i = naudiooutdev; i < nchoutdev; i++)
+ {
+ if (i == 0)
+ audiooutdev[0] = DEFAULTAUDIODEV;
+ else audiooutdev[i] = audiooutdev[i-1] + 1;
+ }
+ naudiooutdev = nchoutdev;
+ }
+ else if (nchoutdev < naudiooutdev)
+ {
+ for (i = nchoutdev; i < naudiooutdev; i++)
+ {
+ if (i == 0)
+ choutdev[0] = defaultchannels;
+ else choutdev[i] = choutdev[i-1];
+ }
+ naudiooutdev = nchoutdev;
+ }
+ }
+ for (i = inchans = 0; i < naudioindev; i++)
+ inchans += chindev[i];
+ for (i = outchans = 0; i < naudiooutdev; i++)
+ outchans += choutdev[i];
+
+ sys_setchsr(inchans, outchans, rate);
+#ifdef USEAPI_OSS
+ if (sys_audioapi == API_OSS)
+ oss_open_audio(naudioindev, audioindev, nchindev, chindev,
+ naudiooutdev, audiooutdev, nchoutdev, choutdev, rate);
+ else
+#endif
+#ifdef USEAPI_ALSA
+ /* for alsa, the "device numbers" are ignored; they are sent
+ straight to the alsa code via linux_alsa_devname(). Only one
+ device is supported for each of input, output. */
+ if (sys_audioapi == API_ALSA)
+ alsa_open_audio((naudioindev > 0 ? chindev[0] : 0),
+ (naudiooutdev > 0 ? choutdev[0] : 0), rate);
+ else
+#endif
+#ifdef USEAPI_PORTAUDIO
+ if (sys_audioapi == API_PORTAUDIO)
+ pa_open_audio(inchans, outchans, rate, sys_soundin, sys_soundout,
+ sys_blocksize, sys_advance_samples/sys_blocksize,
+ (naudiooutdev > 0 ? audioindev[0] : 0),
+ (naudiooutdev > 0 ? audiooutdev[0] : 0));
+ else
+#endif
+#ifdef USEAPI_MMIO
+ if (sys_audioapi == API_MMIO)
+ mmio_open_audio(naudioindev, audioindev, nchindev, chindev,
+ naudiooutdev, audiooutdev, nchoutdev, choutdev, rate);
+ else
+#endif
+ post("unknown audio API specified");
+}
+
+void sys_close_audio(void)
+{
+
+#ifdef USEAPI_PORTAUDIO
+ if (sys_audioapi == API_PORTAUDIO)
+ pa_close_audio();
+ else
+#endif
+#ifdef USEAPI_OSS
+ if (sys_audioapi == API_OSS)
+ oss_close_audio();
+ else
+#endif
+#ifdef USEAPI_ALSA
+ if (sys_audioapi == API_ALSA)
+ alsa_close_audio();
+ else
+#ifdef USEAPI_MMIO
+ if (sys_audioapi == API_MMIO)
+ mmio_close_audio();
+ else
+#endif
+#endif
+ post("unknown API");
+
+}
+
+int sys_send_dacs(void)
+{
+ if (sys_meters)
+ {
+ int i, n;
+ float maxsamp;
+ for (i = 0, n = sys_inchannels * DEFDACBLKSIZE, maxsamp = sys_inmax;
+ i < n; i++)
+ {
+ float f = sys_soundin[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ sys_inmax = maxsamp;
+ for (i = 0, n = sys_outchannels * DEFDACBLKSIZE, maxsamp = sys_outmax;
+ i < n; i++)
+ {
+ float f = sys_soundout[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ sys_outmax = maxsamp;
+ }
+
+#ifdef USEAPI_PORTAUDIO
+ if (sys_audioapi == API_PORTAUDIO)
+ return (pa_send_dacs());
+ else
+#endif
+#ifdef USEAPI_OSS
+ if (sys_audioapi == API_OSS)
+ return (oss_send_dacs());
+ else
+#endif
+#ifdef USEAPI_ALSA
+ if (sys_audioapi == API_ALSA)
+ return (alsa_send_dacs());
+ else
+#endif
+#ifdef USEAPI_MMIO
+ if (sys_audioapi == API_MMIO)
+ return (mmio_send_dacs());
+ else
+#endif
+ post("unknown API");
+ return (0);
+}
+
+float sys_getsr(void)
+{
+ return (sys_dacsr);
+}
+
+int sys_get_outchannels(void)
+{
+ return (sys_outchannels);
+}
+
+int sys_get_inchannels(void)
+{
+ return (sys_inchannels);
+}
+
+void sys_audiobuf(int n)
+{
+ /* set the size, in milliseconds, of the audio FIFO */
+ if (n < 5) n = 5;
+ else if (n > 5000) n = 5000;
+ sys_schedadvance = n * 1000;
+}
+
+void sys_getmeters(float *inmax, float *outmax)
+{
+ if (inmax)
+ {
+ sys_meters = 1;
+ *inmax = sys_inmax;
+ *outmax = sys_outmax;
+ }
+ else
+ sys_meters = 0;
+ sys_inmax = sys_outmax = 0;
+}
+
+void sys_reportidle(void)
+{
+}
+
+void sys_listdevs(void )
+{
+#ifdef USEAPI_PORTAUDIO
+ if (sys_audioapi == API_PORTAUDIO)
+ pa_listdevs();
+ else
+#endif
+#ifdef USEAPI_OSS
+ if (sys_audioapi == API_OSS)
+ oss_listdevs();
+ else
+#endif
+#ifdef USEAPI_MMIO
+ if (sys_audioapi == API_MMIO)
+ mmio_listdevs();
+ else
+#endif
+#ifdef USEAPI_ALSA
+ if (sys_audioapi == API_ALSA)
+ alsa_listdevs();
+ else
+#endif
+ post("unknown API");
+
+ sys_listmididevs();
+}
+
+void sys_setblocksize(int n)
+{
+ if (n < 1)
+ n = 1;
+ if (n != (1 << ilog2(n)))
+ post("warning: adjusting blocksize to power of 2: %d",
+ (n = (1 << ilog2(n))));
+ sys_blocksize = n;
+}
+
+void sys_set_sound_api(int which)
+{
+ sys_audioapi = which;
+ if (sys_verbose)
+ post("sys_audioapi %d", sys_audioapi);
+}
+
diff --git a/pd/src/s_audio_alsa.c b/pd/src/s_audio_alsa.c
new file mode 100644
index 00000000..0fa3d791
--- /dev/null
+++ b/pd/src/s_audio_alsa.c
@@ -0,0 +1,630 @@
+/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file inputs and outputs audio using the ALSA API available on linux. */
+
+#include <alsa/asoundlib.h>
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/mman.h>
+
+typedef int16_t t_alsa_sample16;
+typedef int32_t t_alsa_sample32;
+#define ALSA_SAMPLEWIDTH_16 sizeof(t_alsa_sample16)
+#define ALSA_SAMPLEWIDTH_32 sizeof(t_alsa_sample32)
+#define ALSA_XFERSIZE16 (signed int)(sizeof(t_alsa_sample16) * DEFDACBLKSIZE)
+#define ALSA_XFERSIZE32 (signed int)(sizeof(t_alsa_sample32) * DEFDACBLKSIZE)
+#define ALSA_MAXDEV 1
+#define ALSA_JITTER 1024
+#define ALSA_EXTRABUFFER 2048
+#define ALSA_DEFFRAGSIZE 64
+#define ALSA_DEFNFRAG 12
+
+#ifndef INT32_MAX
+#define INT32_MAX 0x7fffffff
+#endif
+
+typedef struct _alsa_dev
+{
+ snd_pcm_t *inhandle;
+ snd_pcm_t *outhandle;
+} t_alsa_dev;
+
+t_alsa_dev alsa_device;
+static short *alsa_buf;
+static int alsa_samplewidth;
+static snd_pcm_status_t* in_status;
+static snd_pcm_status_t* out_status;
+
+static int alsa_mode;
+
+/* Defines */
+#define DEBUG(x) x
+#define DEBUG2(x) {x;}
+
+static char alsa_devname[512] = "hw:0,0";
+static int alsa_use_plugin = 0;
+
+ /* don't assume we can turn all 31 bits when doing float-to-fix;
+ otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
+#define FMAX 0x7ffff000
+#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
+
+ /* ugly Alsa-specific flags */
+void linux_alsa_devname(char *devname)
+{
+ strncpy(alsa_devname, devname, 511);
+}
+
+void linux_alsa_use_plugin(int t)
+{
+ if (t == 1)
+ alsa_use_plugin = 1;
+ else
+ alsa_use_plugin = 0;
+}
+
+/* support for ALSA pcmv2 api by Karl MacMillan<karlmac@peabody.jhu.edu> */
+
+static void check_error(int err, const char *why)
+{
+ if (err < 0)
+ fprintf(stderr, "%s: %s\n", why, snd_strerror(err));
+}
+
+int alsa_open_audio(int wantinchans, int wantoutchans, int srate)
+{
+ int err, inchans = 0, outchans = 0, subunitdir;
+ char devname[512];
+ snd_pcm_hw_params_t* hw_params;
+ snd_pcm_sw_params_t* sw_params;
+ snd_output_t* out;
+ int frag_size = (sys_blocksize ? sys_blocksize : ALSA_DEFFRAGSIZE);
+ int nfrags, i;
+ short* tmp_buf;
+ unsigned int tmp_uint;
+
+ nfrags = sys_schedadvance * (float)srate / (1e6 * frag_size);
+
+ if (sys_verbose)
+ post("audio buffer set to %d", (int)(0.001 * sys_schedadvance));
+ if (wantinchans)
+ {
+ err = snd_pcm_open(&alsa_device.inhandle, alsa_devname,
+ SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK);
+
+ check_error(err, "snd_pcm_open (input)");
+ if (err < 0)
+ inchans = 0;
+ else
+ {
+ inchans = wantinchans;
+ snd_pcm_nonblock(alsa_device.inhandle, 1);
+ }
+ }
+ if (wantoutchans)
+ {
+ err = snd_pcm_open(&alsa_device.outhandle, alsa_devname,
+ SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+
+ check_error(err, "snd_pcm_open (output)");
+ if (err < 0)
+ outchans = 0;
+ else
+ {
+ outchans = wantoutchans;
+ snd_pcm_nonblock(alsa_device.outhandle, 1);
+ }
+ }
+ if (inchans)
+ {
+ if (sys_verbose)
+ post("opening sound input...");
+ err = snd_pcm_hw_params_malloc(&hw_params);
+ check_error(err, "snd_pcm_hw_params_malloc (input)");
+
+ // get the default params
+ err = snd_pcm_hw_params_any(alsa_device.inhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params_any (input)");
+ // set interleaved access - FIXME deal with other access types
+ err = snd_pcm_hw_params_set_access(alsa_device.inhandle, hw_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ check_error(err, "snd_pcm_hw_params_set_access (input)");
+ // Try to set 32 bit format first
+ err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
+ SND_PCM_FORMAT_S32);
+ if (err < 0)
+ {
+ /* fprintf(stderr,
+ "PD-ALSA: 32 bit format not available - using 16\n"); */
+ err = snd_pcm_hw_params_set_format(alsa_device.inhandle, hw_params,
+ SND_PCM_FORMAT_S16);
+ check_error(err, "snd_pcm_hw_params_set_format (input)");
+ alsa_samplewidth = 2;
+ }
+ else
+ {
+ alsa_samplewidth = 4;
+ }
+ post("Sample width set to %d bytes", alsa_samplewidth);
+ // set the subformat
+ err = snd_pcm_hw_params_set_subformat(alsa_device.inhandle, hw_params,
+ SND_PCM_SUBFORMAT_STD);
+ check_error(err, "snd_pcm_hw_params_set_subformat (input)");
+ // set the number of channels
+ tmp_uint = inchans;
+ err = snd_pcm_hw_params_set_channels_min(alsa_device.inhandle,
+ hw_params, &tmp_uint);
+ check_error(err, "snd_pcm_hw_params_set_channels (input)");
+ if (tmp_uint != (unsigned)inchans)
+ post("ALSA: set input channels to %d", tmp_uint);
+ inchans = tmp_uint;
+ // set the sampling rate
+ err = snd_pcm_hw_params_set_rate_min(alsa_device.inhandle, hw_params,
+ &srate, 0);
+ check_error(err, "snd_pcm_hw_params_set_rate_min (input)");
+#if 0
+ err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
+ post("input sample rate %d", err);
+#endif
+ // set the period - ie frag size
+ // post("fragsize a %d", frag_size);
+
+ /* LATER try this to get a recommended period size...
+ right now, it trips an assertion failure in ALSA lib */
+#if 0
+ post("input period was %d, min %d, max %d\n",
+ snd_pcm_hw_params_get_period_size(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_min(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_max(hw_params, 0));
+#endif
+ err = snd_pcm_hw_params_set_period_size_near(alsa_device.inhandle,
+ hw_params,
+ (snd_pcm_uframes_t)
+ frag_size, 0);
+ check_error(err, "snd_pcm_hw_params_set_period_size_near (input)");
+ // post("fragsize b %d", frag_size);
+ // set the number of periods - ie numfrags
+ // post("nfrags a %d", nfrags);
+ err = snd_pcm_hw_params_set_periods_near(alsa_device.inhandle,
+ hw_params, nfrags, 0);
+ check_error(err, "snd_pcm_hw_params_set_periods_near (input)");
+ // set the buffer size
+ err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.inhandle,
+ hw_params, nfrags * frag_size);
+ check_error(err, "snd_pcm_hw_params_set_buffer_size_near (input)");
+
+ err = snd_pcm_hw_params(alsa_device.inhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params (input)");
+
+ snd_pcm_hw_params_free(hw_params);
+
+ err = snd_pcm_sw_params_malloc(&sw_params);
+ check_error(err, "snd_pcm_sw_params_malloc (input)");
+ err = snd_pcm_sw_params_current(alsa_device.inhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params_current (input)");
+#if 1
+ err = snd_pcm_sw_params_set_start_mode(alsa_device.inhandle, sw_params,
+ SND_PCM_START_EXPLICIT);
+ check_error(err, "snd_pcm_sw_params_set_start_mode (input)");
+ err = snd_pcm_sw_params_set_xrun_mode(alsa_device.inhandle, sw_params,
+ SND_PCM_XRUN_NONE);
+ check_error(err, "snd_pcm_sw_params_set_xrun_mode (input)");
+#else
+ err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle,
+ sw_params, nfrags * frag_size);
+ check_error(err, "snd_pcm_sw_params_set_start_threshold (input)");
+ err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle,
+ sw_params, 1);
+ check_error(err, "snd_pcm_sw_params_set_stop_threshold (input)");
+#endif
+
+ err = snd_pcm_sw_params_set_avail_min(alsa_device.inhandle, sw_params,
+ frag_size);
+ check_error(err, "snd_pcm_sw_params_set_avail_min (input)");
+ err = snd_pcm_sw_params(alsa_device.inhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params (input)");
+
+ snd_pcm_sw_params_free(sw_params);
+
+ snd_output_stdio_attach(&out, stderr, 0);
+#if 0
+ if (sys_verbose)
+ {
+ snd_pcm_dump_hw_setup(alsa_device.inhandle, out);
+ snd_pcm_dump_sw_setup(alsa_device.inhandle, out);
+ }
+#endif
+ }
+
+ if (outchans)
+ {
+ int foo;
+ if (sys_verbose)
+ post("opening sound output...");
+ err = snd_pcm_hw_params_malloc(&hw_params);
+ check_error(err, "snd_pcm_sw_params (output)");
+
+ // get the default params
+ err = snd_pcm_hw_params_any(alsa_device.outhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params_any (output)");
+ // set interleaved access - FIXME deal with other access types
+ err = snd_pcm_hw_params_set_access(alsa_device.outhandle, hw_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ check_error(err, "snd_pcm_hw_params_set_access (output)");
+ // Try to set 32 bit format first
+ err = snd_pcm_hw_params_set_format(alsa_device.outhandle, hw_params,
+ SND_PCM_FORMAT_S32);
+ if (err < 0)
+ {
+ err = snd_pcm_hw_params_set_format(alsa_device.outhandle,
+ hw_params,SND_PCM_FORMAT_S16);
+ check_error(err, "snd_pcm_hw_params_set_format (output)");
+ /* fprintf(stderr,
+ "PD-ALSA: 32 bit format not available - using 16\n"); */
+ alsa_samplewidth = 2;
+ }
+ else
+ {
+ alsa_samplewidth = 4;
+ }
+ // set the subformat
+ err = snd_pcm_hw_params_set_subformat(alsa_device.outhandle, hw_params,
+ SND_PCM_SUBFORMAT_STD);
+ check_error(err, "snd_pcm_hw_params_set_subformat (output)");
+ // set the number of channels
+ tmp_uint = outchans;
+ err = snd_pcm_hw_params_set_channels_min(alsa_device.outhandle,
+ hw_params, &tmp_uint);
+ check_error(err, "snd_pcm_hw_params_set_channels (output)");
+ if (tmp_uint != (unsigned)outchans)
+ post("alsa: set output channels to %d", tmp_uint);
+ outchans = tmp_uint;
+ // set the sampling rate
+ err = snd_pcm_hw_params_set_rate_min(alsa_device.outhandle, hw_params,
+ &srate, 0);
+ check_error(err, "snd_pcm_hw_params_set_rate_min (output)");
+#if 0
+ err = snd_pcm_hw_params_get_rate(hw_params, &subunitdir);
+ post("output sample rate %d", err);
+#endif
+ // set the period - ie frag size
+#if 0
+ post("output period was %d, min %d, max %d\n",
+ snd_pcm_hw_params_get_period_size(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_min(hw_params, 0),
+ snd_pcm_hw_params_get_period_size_max(hw_params, 0));
+#endif
+ // post("fragsize c %d", frag_size);
+ err = snd_pcm_hw_params_set_period_size_near(alsa_device.outhandle,
+ hw_params,
+ (snd_pcm_uframes_t)
+ frag_size, 0);
+ // post("fragsize d %d", frag_size);
+ check_error(err, "snd_pcm_hw_params_set_period_size_near (output)");
+ // set the number of periods - ie numfrags
+ err = snd_pcm_hw_params_set_periods_near(alsa_device.outhandle,
+ hw_params, nfrags, 0);
+ check_error(err, "snd_pcm_hw_params_set_periods_near (output)");
+ // set the buffer size
+ err = snd_pcm_hw_params_set_buffer_size_near(alsa_device.outhandle,
+ hw_params, nfrags * frag_size);
+
+ check_error(err, "snd_pcm_hw_params_set_buffer_size_near (output)");
+
+ err = snd_pcm_hw_params(alsa_device.outhandle, hw_params);
+ check_error(err, "snd_pcm_hw_params (output)");
+
+ snd_pcm_hw_params_free(hw_params);
+
+ err = snd_pcm_sw_params_malloc(&sw_params);
+ check_error(err, "snd_pcm_sw_params_malloc (output)");
+ err = snd_pcm_sw_params_current(alsa_device.outhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params_current (output)");
+#if 1
+ err = snd_pcm_sw_params_set_start_mode(alsa_device.outhandle,
+ sw_params,
+ SND_PCM_START_EXPLICIT);
+ check_error(err, "snd_pcm_sw_params_set_start_mode (output)");
+ err = snd_pcm_sw_params_set_xrun_mode(alsa_device.outhandle, sw_params,
+ SND_PCM_XRUN_NONE);
+ check_error(err, "snd_pcm_sw_params_set_xrun_mode (output)");
+#else
+ err = snd_pcm_sw_params_set_start_threshold(alsa_device.inhandle,
+ sw_params, nfrags * frag_size);
+ check_error(err, "snd_pcm_sw_params_set_start_threshold (output)");
+ err = snd_pcm_sw_params_set_stop_threshold(alsa_device.inhandle,
+ sw_params, 1);
+ check_error(err, "snd_pcm_sw_params_set_stop_threshold (output)");
+#endif
+
+ err = snd_pcm_sw_params_set_avail_min(alsa_device.outhandle, sw_params,
+ frag_size);
+ check_error(err, "snd_pcm_sw_params_set_avail_min (output)");
+ err = snd_pcm_sw_params(alsa_device.outhandle, sw_params);
+ check_error(err, "snd_pcm_sw_params (output)");
+
+ snd_pcm_sw_params_free(sw_params);
+
+ snd_output_stdio_attach(&out, stderr, 0);
+#if 0
+ if (sys_verbose)
+ {
+ snd_pcm_dump_hw_setup(alsa_device.outhandle, out);
+ snd_pcm_dump_sw_setup(alsa_device.outhandle, out);
+ }
+#endif
+ }
+
+ if (inchans)
+ snd_pcm_prepare(alsa_device.inhandle);
+ if (outchans)
+ snd_pcm_prepare(alsa_device.outhandle);
+
+ // if duplex we can link the channels so they start together
+ if (inchans && outchans)
+ snd_pcm_link(alsa_device.inhandle, alsa_device.outhandle);
+
+ // set up the buffer
+ if (outchans > inchans)
+ alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth,
+ DEFDACBLKSIZE * outchans);
+ else
+ alsa_buf = (short *)calloc(sizeof(char) * alsa_samplewidth,
+ DEFDACBLKSIZE * inchans);
+ // fill the buffer with silence
+ if (outchans)
+ {
+ i = nfrags + 1;
+ while (i--)
+ snd_pcm_writei(alsa_device.outhandle, alsa_buf, frag_size);
+ }
+
+ // set up the status variables
+ err = snd_pcm_status_malloc(&in_status);
+ check_error(err, "snd_pcm_status_malloc");
+ err = snd_pcm_status_malloc(&out_status);
+ check_error(err, "snd_pcm_status_malloc");
+
+ // start the device
+#if 1
+ if (outchans)
+ {
+ err = snd_pcm_start(alsa_device.outhandle);
+ check_error(err, "snd_pcm_start");
+ }
+ else if (inchans)
+ {
+ err = snd_pcm_start(alsa_device.inhandle);
+ check_error(err, "snd_pcm_start");
+ }
+#endif
+
+ return 0;
+}
+
+void alsa_close_audio(void)
+{
+ int err;
+ if (sys_inchannels)
+ {
+ err = snd_pcm_close(alsa_device.inhandle);
+ check_error(err, "snd_pcm_close (input)");
+ }
+ if (sys_outchannels)
+ {
+ err = snd_pcm_close(alsa_device.outhandle);
+ check_error(err, "snd_pcm_close (output)");
+ }
+}
+
+// #define DEBUG_ALSA_XFER
+
+int alsa_send_dacs(void)
+{
+ static int16_t *sp;
+ static int xferno = 0;
+ static int callno = 0;
+ static double timenow;
+ double timelast;
+ t_sample *fp, *fp1, *fp2;
+ int i, j, k, err, devno = 0;
+ int inputcount = 0, outputcount = 0, inputlate = 0, outputlate = 0;
+ int result;
+ int inchannels = sys_inchannels;
+ int outchannels = sys_outchannels;
+ unsigned int intransfersize = DEFDACBLKSIZE;
+ unsigned int outtransfersize = DEFDACBLKSIZE;
+
+ // get the status
+ if (!inchannels && !outchannels)
+ {
+ return SENDDACS_NO;
+ }
+
+ timelast = timenow;
+ timenow = sys_getrealtime();
+
+#ifdef DEBUG_ALSA_XFER
+ if (timenow - timelast > 0.050)
+ fprintf(stderr, "(%d)",
+ (int)(1000 * (timenow - timelast))), fflush(stderr);
+#endif
+
+ callno++;
+
+ if (inchannels)
+ {
+ snd_pcm_status(alsa_device.inhandle, in_status);
+ if (snd_pcm_status_get_avail(in_status) < intransfersize)
+ return SENDDACS_NO;
+ }
+ if (outchannels)
+ {
+ snd_pcm_status(alsa_device.outhandle, out_status);
+ if (snd_pcm_status_get_avail(out_status) < outtransfersize)
+ return SENDDACS_NO;
+ }
+
+ /* do output */
+ if (outchannels)
+ {
+ fp = sys_soundout;
+ if (alsa_samplewidth == 4)
+ {
+ for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DEFDACBLKSIZE)
+ {
+ for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
+ j += outchannels, fp2++)
+ {
+ float s1 = *fp2 * INT32_MAX;
+ ((t_alsa_sample32 *)alsa_buf)[j] = CLIP32(s1);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0, fp1 = fp; i < outchannels; i++, fp1 += DEFDACBLKSIZE)
+ {
+ for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
+ j += outchannels, fp2++)
+ {
+ int s = *fp2 * 32767.;
+ if (s > 32767)
+ s = 32767;
+ else if (s < -32767)
+ s = -32767;
+ ((t_alsa_sample16 *)alsa_buf)[j] = s;
+ }
+ }
+ }
+
+ result = snd_pcm_writei(alsa_device.outhandle, alsa_buf,
+ outtransfersize);
+ if (result != (int)outtransfersize)
+ {
+ #ifdef DEBUG_ALSA_XFER
+ if (result >= 0 || errno == EAGAIN)
+ fprintf(stderr, "ALSA: write returned %d of %d\n",
+ result, outtransfersize);
+ else fprintf(stderr, "ALSA: write: %s\n",
+ snd_strerror(errno));
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, outbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + sys_advance_samples)
+ * alsa_samplewidth * outchannels);
+ #endif
+ sys_log_error(ERR_DACSLEPT);
+ return (SENDDACS_NO);
+ }
+
+ /* zero out the output buffer */
+ memset(sys_soundout, 0, DEFDACBLKSIZE * sizeof(*sys_soundout) *
+ sys_outchannels);
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+ #ifdef DEBUG_ALSA_XFER
+ fprintf(stderr, "output %d took %d msec\n",
+ callno, (int)(1000 * (timenow - timelast))), fflush(stderr);
+ #endif
+ timenow = sys_getrealtime();
+ sys_log_error(ERR_DACSLEPT);
+ }
+ }
+ /* do input */
+ if (sys_inchannels)
+ {
+ result = snd_pcm_readi(alsa_device.inhandle, alsa_buf, intransfersize);
+ if (result < (int)intransfersize)
+ {
+#ifdef DEBUG_ALSA_XFER
+ if (result < 0)
+ fprintf(stderr,
+ "snd_pcm_read %d %d: %s\n",
+ callno, xferno, snd_strerror(errno));
+ else fprintf(stderr,
+ "snd_pcm_read %d %d returned only %d\n",
+ callno, xferno, result);
+ fprintf(stderr,
+ "inputcount %d, outputcount %d, inbufsize %d\n",
+ inputcount, outputcount,
+ (ALSA_EXTRABUFFER + sys_advance_samples)
+ * alsa_samplewidth * inchannels);
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ return (SENDDACS_NO);
+ }
+ fp = sys_soundin;
+ if (alsa_samplewidth == 4)
+ {
+ for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DEFDACBLKSIZE)
+ {
+ for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--;
+ j += inchannels, fp2++)
+ *fp2 = (float) ((t_alsa_sample32 *)alsa_buf)[j]
+ * (1./ INT32_MAX);
+ }
+ }
+ else
+ {
+ for (i = 0, fp1 = fp; i < inchannels; i++, fp1 += DEFDACBLKSIZE)
+ {
+ for (j = i, k = DEFDACBLKSIZE, fp2 = fp1; k--; j += inchannels,
+ fp2++)
+ *fp2 = (float) ((t_alsa_sample16 *)alsa_buf)[j]
+ * 3.051850e-05;
+ }
+ }
+ }
+ xferno++;
+ if (sys_getrealtime() - timenow > 0.002)
+ {
+#ifdef DEBUG_ALSA_XFER
+ fprintf(stderr, "routine took %d msec\n",
+ (int)(1000 * (sys_getrealtime() - timenow)));
+#endif
+ sys_log_error(ERR_ADCSLEPT);
+ }
+ return SENDDACS_YES;
+}
+
+void alsa_resync( void)
+{
+ int i, result;
+ if (sys_audioapi != API_ALSA)
+ {
+ error("restart-audio: implemented for ALSA only.");
+ return;
+ }
+ memset(alsa_buf, 0,
+ sizeof(char) * alsa_samplewidth * DEFDACBLKSIZE * sys_outchannels);
+ for (i = 0; i < 1000000; i++)
+ {
+ result = snd_pcm_writei(alsa_device.outhandle, alsa_buf,
+ DEFDACBLKSIZE);
+ if (result != (int)DEFDACBLKSIZE)
+ break;
+ }
+ post("%d written", i);
+}
+
+void alsa_listdevs( void)
+{
+ post("device listing not implemented in ALSA yet\n");
+}
+
diff --git a/pd/src/s_audio_mmio.c b/pd/src/s_audio_mmio.c
new file mode 100644
index 00000000..d0657be4
--- /dev/null
+++ b/pd/src/s_audio_mmio.c
@@ -0,0 +1,758 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* modified 2/98 by Winfried Ritsch to deal with up to 4 synchronized
+"wave" devices, which is how ADAT boards appear to the WAVE API. */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+
+#include <windows.h>
+
+#include <MMSYSTEM.H>
+
+/* ------------------------- audio -------------------------- */
+
+static void nt_close_midiin(void);
+static void nt_noresync( void);
+
+static void postflags(void);
+
+#define NAPORTS 16 /* wini hack for multiple ADDA devices */
+#define CHANNELS_PER_DEVICE 2
+#define DEFAULTCHANS 2
+#define DEFAULTSRATE 44100
+#define SAMPSIZE 2
+
+#define REALDACBLKSIZE (4 * DEFDACBLKSIZE) /* larger underlying bufsize */
+
+#define MAXBUFFER 100 /* number of buffers in use at maximum advance */
+#define DEFBUFFER 30 /* default is about 30x6 = 180 msec! */
+static int nt_naudiobuffer = DEFBUFFER;
+
+float sys_dacsr = DEFAULTSRATE;
+
+static int nt_whichapi = API_MMIO;
+static int nt_meters; /* true if we're metering */
+static float nt_inmax; /* max input amplitude */
+static float nt_outmax; /* max output amplitude */
+static int nt_nwavein, nt_nwaveout; /* number of WAVE devices in and out */
+
+typedef struct _sbuf
+{
+ HANDLE hData;
+ HPSTR lpData; // pointer to waveform data memory
+ HANDLE hWaveHdr;
+ WAVEHDR *lpWaveHdr; // pointer to header structure
+} t_sbuf;
+
+t_sbuf ntsnd_outvec[NAPORTS][MAXBUFFER]; /* circular buffer array */
+HWAVEOUT ntsnd_outdev[NAPORTS]; /* output device */
+static int ntsnd_outphase[NAPORTS]; /* index of next buffer to send */
+
+t_sbuf ntsnd_invec[NAPORTS][MAXBUFFER]; /* circular buffer array */
+HWAVEIN ntsnd_indev[NAPORTS]; /* input device */
+static int ntsnd_inphase[NAPORTS]; /* index of next buffer to read */
+
+static void nt_waveinerror(char *s, int err)
+{
+ char t[256];
+ waveInGetErrorText(err, t, 256);
+ fprintf(stderr, s, t);
+}
+
+static void nt_waveouterror(char *s, int err)
+{
+ char t[256];
+ waveOutGetErrorText(err, t, 256);
+ fprintf(stderr, s, t);
+}
+
+static void wave_prep(t_sbuf *bp)
+{
+ WAVEHDR *wh;
+ short *sp;
+ int i;
+ /*
+ * Allocate and lock memory for the waveform data. The memory
+ * for waveform data must be globally allocated with
+ * GMEM_MOVEABLE and GMEM_SHARE flags.
+ */
+
+ if (!(bp->hData =
+ GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
+ (DWORD) (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE))))
+ printf("alloc 1 failed\n");
+
+ if (!(bp->lpData =
+ (HPSTR) GlobalLock(bp->hData)))
+ printf("lock 1 failed\n");
+
+ /* Allocate and lock memory for the header. */
+
+ if (!(bp->hWaveHdr =
+ GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) sizeof(WAVEHDR))))
+ printf("alloc 2 failed\n");
+
+ if (!(wh = bp->lpWaveHdr =
+ (WAVEHDR *) GlobalLock(bp->hWaveHdr)))
+ printf("lock 2 failed\n");
+
+ for (i = CHANNELS_PER_DEVICE * REALDACBLKSIZE,
+ sp = (short *)bp->lpData; i--; )
+ *sp++ = 0;
+
+ wh->lpData = bp->lpData;
+ wh->dwBufferLength = (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE);
+ wh->dwFlags = 0;
+ wh->dwLoops = 0L;
+ wh->lpNext = 0;
+ wh->reserved = 0;
+}
+
+static int nt_inalloc[NAPORTS], nt_outalloc[NAPORTS];
+static UINT nt_whichdac = WAVE_MAPPER, nt_whichadc = WAVE_MAPPER;
+
+int mmio_do_open_audio(void)
+{
+ PCMWAVEFORMAT form;
+ int i;
+ UINT mmresult;
+ int nad, nda;
+
+ if (sys_verbose)
+ post("%d devices in, %d devices out",
+ nt_nwavein, nt_nwaveout);
+
+ form.wf.wFormatTag = WAVE_FORMAT_PCM;
+ form.wf.nChannels = CHANNELS_PER_DEVICE;
+ form.wf.nSamplesPerSec = sys_dacsr;
+ form.wf.nAvgBytesPerSec = sys_dacsr * (CHANNELS_PER_DEVICE * SAMPSIZE);
+ form.wf.nBlockAlign = CHANNELS_PER_DEVICE * SAMPSIZE;
+ form.wBitsPerSample = 8 * SAMPSIZE;
+
+ if (nt_nwavein <= 1 && nt_nwaveout <= 1)
+ nt_noresync();
+ for (nad=0; nad < nt_nwavein; nad++)
+ {
+ /* Open waveform device(s), sucessively numbered, for input */
+
+ mmresult = waveInOpen(&ntsnd_indev[nad], nt_whichadc+nad,
+ (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
+
+ if (sys_verbose)
+ printf("opened adc device %d with return %d\n",
+ nt_whichadc+nad,mmresult);
+
+ if (mmresult != MMSYSERR_NOERROR)
+ {
+ nt_waveinerror("waveInOpen: %s\n", mmresult);
+ nt_nwavein = nad; /* nt_nwavein = 0 wini */
+ }
+ else
+ {
+ if (!nt_inalloc[nad])
+ {
+ for (i = 0; i < nt_naudiobuffer; i++)
+ wave_prep(&ntsnd_invec[nad][i]);
+ nt_inalloc[nad] = 1;
+ }
+ for (i = 0; i < nt_naudiobuffer; i++)
+ {
+ mmresult = waveInPrepareHeader(ntsnd_indev[nad],
+ ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveinerror("waveinprepareheader: %s\n", mmresult);
+ mmresult = waveInAddBuffer(ntsnd_indev[nad],
+ ntsnd_invec[nad][i].lpWaveHdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
+ }
+ }
+ }
+ /* quickly start them all together */
+ for(nad=0; nad < nt_nwavein; nad++)
+ waveInStart(ntsnd_indev[nad]);
+
+ for(nda=0; nda < nt_nwaveout; nda++)
+ {
+
+ /* Open a waveform device for output in sucessiv device numbering*/
+ mmresult = waveOutOpen(&ntsnd_outdev[nda], nt_whichdac + nda,
+ (WAVEFORMATEX *)(&form), 0L, 0L, CALLBACK_NULL);
+
+ if (sys_verbose)
+ fprintf(stderr,"opened dac device %d, with return %d\n",
+ nt_whichdac +nda, mmresult);
+
+ if (mmresult != MMSYSERR_NOERROR)
+ {
+ fprintf(stderr,"Wave out open device %d + %d\n",nt_whichdac,nda);
+ nt_waveouterror("waveOutOpen device: %s\n", mmresult);
+ nt_nwaveout = nda;
+ }
+ else
+ {
+ if (!(nt_outalloc[nda]))
+ {
+ for (i = 0; i < nt_naudiobuffer; i++)
+ {
+ wave_prep(&ntsnd_outvec[nda][i]);
+ /* set DONE flag as if we had queued them */
+ ntsnd_outvec[nda][i].lpWaveHdr->dwFlags = WHDR_DONE;
+ }
+ nt_outalloc[nda] = 1;
+ }
+ }
+ }
+
+ return (0);
+}
+
+void mmio_close_audio( void)
+{
+ int errcode;
+ int nda, nad;
+ if (sys_verbose)
+ post("closing audio...");
+
+ for (nda=0; nda < nt_nwaveout; nda++) /*if (nt_nwaveout) wini */
+ {
+ errcode = waveOutReset(ntsnd_outdev[nda]);
+ if (errcode != MMSYSERR_NOERROR)
+ printf("error resetting output %d: %d\n", nda, errcode);
+ errcode = waveOutClose(ntsnd_outdev[nda]);
+ if (errcode != MMSYSERR_NOERROR)
+ printf("error closing output %d: %d\n",nda , errcode);
+ }
+ nt_nwaveout = 0;
+
+ for(nad=0; nad < nt_nwavein;nad++) /* if (nt_nwavein) wini */
+ {
+ errcode = waveInReset(ntsnd_indev[nad]);
+ if (errcode != MMSYSERR_NOERROR)
+ printf("error resetting input: %d\n", errcode);
+ errcode = waveInClose(ntsnd_indev[nad]);
+ if (errcode != MMSYSERR_NOERROR)
+ printf("error closing input: %d\n", errcode);
+ }
+ nt_nwavein = 0;
+}
+
+
+#define ADCJITTER 10 /* We tolerate X buffers of jitter by default */
+#define DACJITTER 10
+
+static int nt_adcjitterbufsallowed = ADCJITTER;
+static int nt_dacjitterbufsallowed = DACJITTER;
+
+ /* ------------- MIDI time stamping from audio clock ------------ */
+
+#ifdef MIDI_TIMESTAMP
+
+static double nt_hibuftime;
+static double initsystime = -1;
+
+ /* call this whenever we reset audio */
+static void nt_resetmidisync(void)
+{
+ initsystime = clock_getsystime();
+ nt_hibuftime = sys_getrealtime();
+}
+
+ /* call this whenever we're idled waiting for audio to be ready.
+ The routine maintains a high and low water point for the difference
+ between real and DAC time. */
+
+static void nt_midisync(void)
+{
+ double jittersec, diff;
+
+ if (initsystime == -1) nt_resetmidisync();
+ jittersec = (nt_dacjitterbufsallowed > nt_adcjitterbufsallowed ?
+ nt_dacjitterbufsallowed : nt_adcjitterbufsallowed)
+ * REALDACBLKSIZE / sys_getsr();
+ diff = sys_getrealtime() - 0.001 * clock_gettimesince(initsystime);
+ if (diff > nt_hibuftime) nt_hibuftime = diff;
+ if (diff < nt_hibuftime - jittersec)
+ {
+ post("jitter excess %d %f", dac, diff);
+ nt_resetmidisync();
+ }
+}
+
+static double nt_midigettimefor(LARGE_INTEGER timestamp)
+{
+ /* this is broken now... used to work when "timestamp" was derived from
+ QueryPerformanceCounter() instead of the gates approved
+ timeGetSystemTime() call in the MIDI callback routine below. */
+ return (nt_tixtotime(timestamp) - nt_hibuftime);
+}
+#endif /* MIDI_TIMESTAMP */
+
+
+static int nt_fill = 0;
+#define WRAPFWD(x) ((x) >= nt_naudiobuffer ? (x) - nt_naudiobuffer: (x))
+#define WRAPBACK(x) ((x) < 0 ? (x) + nt_naudiobuffer: (x))
+#define MAXRESYNC 500
+
+#if 0 /* this is used for debugging */
+static void nt_printaudiostatus(void)
+{
+ int nad, nda;
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
+ int firstphasedone = -1, firstphasebusy = -1;
+ for (count = 0; count < nt_naudiobuffer; count++)
+ {
+ int donethis =
+ (ntsnd_invec[nad][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
+ int donenext =
+ (ntsnd_invec[nad][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
+ if (donethis && !donenext)
+ {
+ if (firstphasebusy >= 0) goto multipleadc;
+ firstphasebusy = count;
+ }
+ if (!donethis && donenext)
+ {
+ if (firstphasedone >= 0) goto multipleadc;
+ firstphasedone = count;
+ }
+ phase2 = phase3;
+ phase3 = WRAPFWD(phase2 + 1);
+ }
+ post("nad %d phase %d busy %d done %d", nad, phase, firstphasebusy,
+ firstphasedone);
+ continue;
+ multipleadc:
+ startpost("nad %d phase %d: oops:", nad, phase);
+ for (count = 0; count < nt_naudiobuffer; count++)
+ {
+ char buf[80];
+ sprintf(buf, " %d",
+ (ntsnd_invec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
+ poststring(buf);
+ }
+ endpost();
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nad];
+ int phase2 = phase, phase3 = WRAPFWD(phase2), count, ntrans = 0;
+ int firstphasedone = -1, firstphasebusy = -1;
+ for (count = 0; count < nt_naudiobuffer; count++)
+ {
+ int donethis =
+ (ntsnd_outvec[nda][phase2].lpWaveHdr->dwFlags & WHDR_DONE);
+ int donenext =
+ (ntsnd_outvec[nda][phase3].lpWaveHdr->dwFlags & WHDR_DONE);
+ if (donethis && !donenext)
+ {
+ if (firstphasebusy >= 0) goto multipledac;
+ firstphasebusy = count;
+ }
+ if (!donethis && donenext)
+ {
+ if (firstphasedone >= 0) goto multipledac;
+ firstphasedone = count;
+ }
+ phase2 = phase3;
+ phase3 = WRAPFWD(phase2 + 1);
+ }
+ if (firstphasebusy < 0) post("nda %d phase %d all %d",
+ nda, phase, (ntsnd_outvec[nad][0].lpWaveHdr->dwFlags & WHDR_DONE));
+ else post("nda %d phase %d busy %d done %d", nda, phase, firstphasebusy,
+ firstphasedone);
+ continue;
+ multipledac:
+ startpost("nda %d phase %d: oops:", nda, phase);
+ for (count = 0; count < nt_naudiobuffer; count++)
+ {
+ char buf[80];
+ sprintf(buf, " %d",
+ (ntsnd_outvec[nad][count].lpWaveHdr->dwFlags & WHDR_DONE));
+ poststring(buf);
+ }
+ endpost();
+ }
+}
+#endif /* 0 */
+
+/* this is a hack to avoid ever resyncing audio pointers in case for whatever
+reason the sync testing below gives false positives. */
+
+static int nt_resync_cancelled;
+
+static void nt_noresync( void)
+{
+ nt_resync_cancelled = 1;
+}
+
+static void nt_resyncaudio(void)
+{
+ UINT mmresult;
+ int nad, nda, count;
+ if (nt_resync_cancelled)
+ return;
+ /* for each open input device, eat all buffers which are marked
+ ready. The next one will thus be "busy". */
+ post("resyncing audio");
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ for (count = 0; count < MAXRESYNC; count++)
+ {
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ if (!(inwavehdr->dwFlags & WHDR_DONE)) break;
+ if (inwavehdr->dwFlags & WHDR_PREPARED)
+ waveInUnprepareHeader(ntsnd_indev[nad],
+ inwavehdr, sizeof(WAVEHDR));
+ inwavehdr->dwFlags = 0L;
+ waveInPrepareHeader(ntsnd_indev[nad], inwavehdr, sizeof(WAVEHDR));
+ mmresult = waveInAddBuffer(ntsnd_indev[nad], inwavehdr,
+ sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
+ ntsnd_inphase[nad] = phase = WRAPFWD(phase + 1);
+ }
+ if (count == MAXRESYNC) post("resync error 1");
+ }
+ /* Each output buffer which is "ready" is filled with zeros and
+ queued. */
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+ for (count = 0; count < MAXRESYNC; count++)
+ {
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (!(outwavehdr->dwFlags & WHDR_DONE)) break;
+ if (outwavehdr->dwFlags & WHDR_PREPARED)
+ waveOutUnprepareHeader(ntsnd_outdev[nda],
+ outwavehdr, sizeof(WAVEHDR));
+ outwavehdr->dwFlags = 0L;
+ memset((char *)(ntsnd_outvec[nda][phase].lpData),
+ 0, (CHANNELS_PER_DEVICE * REALDACBLKSIZE * SAMPSIZE));
+ waveOutPrepareHeader(ntsnd_outdev[nda], outwavehdr,
+ sizeof(WAVEHDR));
+ mmresult = waveOutWrite(ntsnd_outdev[nda], outwavehdr,
+ sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveouterror("waveOutAddBuffer: %s\n", mmresult);
+ ntsnd_outphase[nda] = phase = WRAPFWD(phase + 1);
+ }
+ if (count == MAXRESYNC) post("resync error 2");
+ }
+
+#ifdef MIDI_TIMESTAMP
+ nt_resetmidisync();
+#endif
+
+}
+
+#define LATE 0
+#define RESYNC 1
+#define NOTHING 2
+static int nt_errorcount;
+static int nt_resynccount;
+static double nt_nextreporttime = -1;
+
+void nt_logerror(int which)
+{
+#if 0
+ post("error %d %d", count, which);
+ if (which < NOTHING) nt_errorcount++;
+ if (which == RESYNC) nt_resynccount++;
+ if (sys_getrealtime() > nt_nextreporttime)
+ {
+ post("%d audio I/O error%s", nt_errorcount,
+ (nt_errorcount > 1 ? "s" : ""));
+ if (nt_resynccount) post("DAC/ADC sync error");
+ nt_errorcount = nt_resynccount = 0;
+ nt_nextreporttime = sys_getrealtime() - 5;
+ }
+#endif
+}
+
+/* system buffer with t_sample types for one tick */
+t_sample *sys_soundout;
+t_sample *sys_soundin;
+float sys_dacsr;
+
+int mmio_send_dacs(void)
+{
+ HMMIO hmmio;
+ UINT mmresult;
+ HANDLE hFormat;
+ int i, j;
+ short *sp1, *sp2;
+ float *fp1, *fp2;
+ int nextfill, doxfer = 0;
+ int nda, nad;
+ if (!nt_nwavein && !nt_nwaveout) return (0);
+
+
+ if (nt_meters)
+ {
+ int i, n;
+ float maxsamp;
+ for (i = 0, n = 2 * nt_nwavein * DEFDACBLKSIZE, maxsamp = nt_inmax;
+ i < n; i++)
+ {
+ float f = sys_soundin[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ nt_inmax = maxsamp;
+ for (i = 0, n = 2 * nt_nwaveout * DEFDACBLKSIZE, maxsamp = nt_outmax;
+ i < n; i++)
+ {
+ float f = sys_soundout[i];
+ if (f > maxsamp) maxsamp = f;
+ else if (-f > maxsamp) maxsamp = -f;
+ }
+ nt_outmax = maxsamp;
+ }
+
+ /* the "fill pointer" nt_fill controls where in the next
+ I/O buffers we will write and/or read. If it's zero, we
+ first check whether the buffers are marked "done". */
+
+ if (!nt_fill)
+ {
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ if (!(inwavehdr->dwFlags & WHDR_DONE)) goto idle;
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+ WAVEHDR *outwavehdr =
+ ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (!(outwavehdr->dwFlags & WHDR_DONE)) goto idle;
+ }
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ WAVEHDR *inwavehdr =
+ ntsnd_invec[nad][phase].lpWaveHdr;
+ if (inwavehdr->dwFlags & WHDR_PREPARED)
+ waveInUnprepareHeader(ntsnd_indev[nad],
+ inwavehdr, sizeof(WAVEHDR));
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (outwavehdr->dwFlags & WHDR_PREPARED)
+ waveOutUnprepareHeader(ntsnd_outdev[nda],
+ outwavehdr, sizeof(WAVEHDR));
+ }
+ }
+
+ /* Convert audio output to fixed-point and put it in the output
+ buffer. */
+ for (nda = 0, fp1 = sys_soundout; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+
+ for (i = 0, sp1 = (short *)(ntsnd_outvec[nda][phase].lpData) +
+ CHANNELS_PER_DEVICE * nt_fill;
+ i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
+ {
+ for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
+ j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
+ {
+ int x1 = 32767.f * *fp2;
+ if (x1 > 32767) x1 = 32767;
+ else if (x1 < -32767) x1 = -32767;
+ *sp2 = x1;
+ }
+ }
+ }
+ memset(sys_soundout, 0,
+ (DEFDACBLKSIZE *sizeof(t_sample)*CHANNELS_PER_DEVICE)*nt_nwaveout);
+
+ /* vice versa for the input buffer */
+
+ for (nad = 0, fp1 = sys_soundin; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+
+ for (i = 0, sp1 = (short *)(ntsnd_invec[nad][phase].lpData) +
+ CHANNELS_PER_DEVICE * nt_fill;
+ i < 2; i++, fp1 += DEFDACBLKSIZE, sp1++)
+ {
+ for (j = 0, fp2 = fp1, sp2 = sp1; j < DEFDACBLKSIZE;
+ j++, fp2++, sp2 += CHANNELS_PER_DEVICE)
+ {
+ *fp2 = ((float)(1./32767.)) * (float)(*sp2);
+ }
+ }
+ }
+
+ nt_fill = nt_fill + DEFDACBLKSIZE;
+ if (nt_fill == REALDACBLKSIZE)
+ {
+ nt_fill = 0;
+
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ HWAVEIN device = ntsnd_indev[nad];
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ waveInPrepareHeader(device, inwavehdr, sizeof(WAVEHDR));
+ mmresult = waveInAddBuffer(device, inwavehdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveinerror("waveInAddBuffer: %s\n", mmresult);
+ ntsnd_inphase[nad] = WRAPFWD(phase + 1);
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+ HWAVEOUT device = ntsnd_outdev[nda];
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ waveOutPrepareHeader(device, outwavehdr, sizeof(WAVEHDR));
+ mmresult = waveOutWrite(device, outwavehdr, sizeof(WAVEHDR));
+ if (mmresult != MMSYSERR_NOERROR)
+ nt_waveouterror("waveOutWrite: %s\n", mmresult);
+ ntsnd_outphase[nda] = WRAPFWD(phase + 1);
+ }
+
+ /* check for DAC underflow or ADC overflow. */
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = WRAPBACK(ntsnd_inphase[nad] - 2);
+ WAVEHDR *inwavehdr = ntsnd_invec[nad][phase].lpWaveHdr;
+ if (inwavehdr->dwFlags & WHDR_DONE) goto late;
+ }
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = WRAPBACK(ntsnd_outphase[nda] - 2);
+ WAVEHDR *outwavehdr = ntsnd_outvec[nda][phase].lpWaveHdr;
+ if (outwavehdr->dwFlags & WHDR_DONE) goto late;
+ }
+ }
+ return (1);
+
+late:
+
+ nt_logerror(LATE);
+ nt_resyncaudio();
+ return (1);
+
+idle:
+
+ /* If more than nt_adcjitterbufsallowed ADC buffers are ready
+ on any input device, resynchronize */
+
+ for (nad = 0; nad < nt_nwavein; nad++)
+ {
+ int phase = ntsnd_inphase[nad];
+ WAVEHDR *inwavehdr =
+ ntsnd_invec[nad]
+ [WRAPFWD(phase + nt_adcjitterbufsallowed)].lpWaveHdr;
+ if (inwavehdr->dwFlags & WHDR_DONE)
+ {
+ nt_resyncaudio();
+ return (0);
+ }
+ }
+
+ /* test dac sync the same way */
+ for (nda = 0; nda < nt_nwaveout; nda++)
+ {
+ int phase = ntsnd_outphase[nda];
+ WAVEHDR *outwavehdr =
+ ntsnd_outvec[nda]
+ [WRAPFWD(phase + nt_dacjitterbufsallowed)].lpWaveHdr;
+ if (outwavehdr->dwFlags & WHDR_DONE)
+ {
+ nt_resyncaudio();
+ return (0);
+ }
+ }
+#ifdef MIDI_TIMESTAMP
+ nt_midisync();
+#endif
+ return (0);
+}
+
+/* ------------------- public routines -------------------------- */
+
+void mmio_open_audio(int naudioindev, int *audioindev,
+ int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
+ int nchoutdev, int *choutdev, int rate) /* IOhannes */
+{
+ int nbuf;
+
+ nbuf = sys_advance_samples/REALDACBLKSIZE;
+ if (nbuf >= MAXBUFFER)
+ {
+ fprintf(stderr, "pd: audio buffering maxed out to %d\n",
+ (int)(MAXBUFFER * ((REALDACBLKSIZE * 1000.)/44100.)));
+ nbuf = MAXBUFFER;
+ }
+ else if (nbuf < 4) nbuf = 4;
+ fprintf(stderr, "%d audio buffers\n", nbuf);
+ nt_naudiobuffer = nbuf;
+ if (nt_adcjitterbufsallowed > nbuf - 2)
+ nt_adcjitterbufsallowed = nbuf - 2;
+ if (nt_dacjitterbufsallowed > nbuf - 2)
+ nt_dacjitterbufsallowed = nbuf - 2;
+
+ nt_nwavein = sys_inchannels / 2;
+ nt_nwaveout = sys_outchannels / 2;
+ nt_whichadc = (naudioindev < 1 ?
+ (nt_nwavein > 1 ? WAVE_MAPPER : -1) :
+ (audioindev[0] == DEFAULTAUDIODEV ? WAVE_MAPPER :
+ audioindev[0] - 1));
+ nt_whichdac = (naudiooutdev < 1 ?
+ (nt_nwaveout > 1 ? WAVE_MAPPER : -1) :
+ (audiooutdev[0] == DEFAULTAUDIODEV ? WAVE_MAPPER :
+ audiooutdev[0] - 1));
+ if (naudiooutdev > 1 || naudioindev > 1)
+ post("separate audio device choice not supported; using sequential devices.");
+ mmio_do_open_audio();
+}
+
+
+void mmio_reportidle(void)
+{
+}
+
+
+/* list the audio and MIDI device names */
+void mmio_listdevs(void)
+{
+ UINT wRtn, ndevices;
+ unsigned int i;
+
+ ndevices = waveInGetNumDevs();
+ for (i = 0; i < ndevices; i++)
+ {
+ WAVEINCAPS wicap;
+ wRtn = waveInGetDevCaps(i, (LPWAVEINCAPS) &wicap,
+ sizeof(wicap));
+ if (wRtn) nt_waveinerror("waveInGetDevCaps: %s\n", wRtn);
+ else fprintf(stderr,
+ "audio input device #%d: %s\n", i+1, wicap.szPname);
+ }
+
+ ndevices = waveOutGetNumDevs();
+ for (i = 0; i < ndevices; i++)
+ {
+ WAVEOUTCAPS wocap;
+ wRtn = waveOutGetDevCaps(i, (LPWAVEOUTCAPS) &wocap,
+ sizeof(wocap));
+ if (wRtn) nt_waveouterror("waveOutGetDevCaps: %s\n", wRtn);
+ else fprintf(stderr,
+ "audio output device #%d: %s\n", i+1, wocap.szPname);
+ }
+}
diff --git a/pd/src/s_audio_oss.c b/pd/src/s_audio_oss.c
new file mode 100644
index 00000000..382e6a75
--- /dev/null
+++ b/pd/src/s_audio_oss.c
@@ -0,0 +1,772 @@
+/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* this file inputs and outputs audio using the OSS API available on linux. */
+
+#include <linux/soundcard.h>
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <sys/mman.h>
+
+
+/* Defines */
+#define DEBUG(x) x
+#define DEBUG2(x) {x;}
+
+#define OSS_MAXCHPERDEV 32 /* max channels per OSS device */
+#define OSS_MAXDEV 4 /* maximum number of input or output devices */
+#define OSS_DEFFRAGSIZE 256 /* default log fragment size (frames) */
+#define OSS_DEFAUDIOBUF 40000 /* default audiobuffer, microseconds */
+#define OSS_DEFAULTCH 2
+#define RME_DEFAULTCH 8 /* need this even if RME undefined */
+typedef int16_t t_oss_int16;
+typedef int32_t t_oss_int32;
+#define OSS_MAXSAMPLEWIDTH sizeof(t_oss_int32)
+#define OSS_BYTESPERCHAN(width) (DEFDACBLKSIZE * (width))
+#define OSS_XFERSAMPS(chans) (DEFDACBLKSIZE* (chans))
+#define OSS_XFERSIZE(chans, width) (DEFDACBLKSIZE * (chans) * (width))
+
+/* GLOBALS */
+static int linux_meters; /* true if we're metering */
+static float linux_inmax; /* max input amplitude */
+static float linux_outmax; /* max output amplitude */
+static int linux_fragsize = 0; /* for block mode; block size (sample frames) */
+
+/* our device handles */
+
+typedef struct _oss_dev
+{
+ int d_fd;
+ unsigned int d_space; /* bytes available for writing/reading */
+ int d_bufsize; /* total buffer size in blocks for this device */
+ int d_dropcount; /* # of buffers to drop for resync (output only) */
+ unsigned int d_nchannels; /* number of channels for this device */
+ unsigned int d_bytespersamp; /* bytes per sample (2 for 16 bit, 4 for 32) */
+} t_oss_dev;
+
+static t_oss_dev linux_dacs[OSS_MAXDEV];
+static t_oss_dev linux_adcs[OSS_MAXDEV];
+static int linux_noutdevs = 0;
+static int linux_nindevs = 0;
+
+ /* exported variables */
+float sys_dacsr;
+t_sample *sys_soundout;
+t_sample *sys_soundin;
+
+ /* OSS-specific private variables */
+static int oss_blockmode = 1; /* flag to use "blockmode" */
+static int oss_32bit = 0; /* allow 23 bit transfers in OSS */
+static char ossdsp[] = "/dev/dsp%d";
+
+ /* don't assume we can turn all 31 bits when doing float-to-fix;
+ otherwise some audio drivers (e.g. Midiman/ALSA) wrap around. */
+#define FMAX 0x7ffff000
+#define CLIP32(x) (((x)>FMAX)?FMAX:((x) < -FMAX)?-FMAX:(x))
+
+
+/* ------------- private routines for all APIS ------------------- */
+
+static void linux_flush_all_underflows_to_zero(void)
+{
+/*
+ TODO: Implement similar thing for linux (GGeiger)
+
+ One day we will figure this out, I hope, because it
+ costs CPU time dearly on Intel - LT
+ */
+ /* union fpc_csr f;
+ f.fc_word = get_fpc_csr();
+ f.fc_struct.flush = 1;
+ set_fpc_csr(f.fc_word);
+ */
+}
+
+
+void oss_set32bit( void)
+{
+ oss_32bit = 1;
+}
+
+
+typedef struct _multidev {
+ int fd;
+ int channels;
+ int format;
+} t_multidev;
+
+int oss_reset(int fd) {
+ int err;
+ if ((err = ioctl(fd,SNDCTL_DSP_RESET)) < 0)
+ error("OSS: Could not reset");
+ return err;
+}
+
+ /* The AFMT_S32_BLOCKED format is not defined in standard linux kernels
+ but is proposed by Guenter Geiger to support extending OSS to handle
+ 32 bit sample. This is user in Geiger's OSS driver for RME Hammerfall.
+ I'm not clear why this isn't called AFMT_S32_[SLN]E... */
+
+#ifndef AFMT_S32_BLOCKED
+#define AFMT_S32_BLOCKED 0x0000400
+#endif
+
+void oss_configure(t_oss_dev *dev, int srate, int dac, int skipblocksize)
+{ /* IOhannes */
+ int orig, param, nblk, fd = dev->d_fd, wantformat;
+ int nchannels = dev->d_nchannels;
+ int advwas = sys_schedadvance;
+
+ audio_buf_info ainfo;
+
+ /* IOhannes :
+ * pd is very likely to crash if different formats are used on
+ multiple soundcards
+ */
+
+ /* set resolution - first try 4 byte samples */
+ if (oss_32bit && (ioctl(fd,SNDCTL_DSP_GETFMTS,&param) >= 0) &&
+ (param & AFMT_S32_BLOCKED))
+ {
+ wantformat = AFMT_S32_BLOCKED;
+ dev->d_bytespersamp = 4;
+ }
+ else
+ {
+ wantformat = AFMT_S16_NE;
+ dev->d_bytespersamp = 2;
+ }
+ param = wantformat;
+
+ if (sys_verbose)
+ post("bytes per sample = %d", dev->d_bytespersamp);
+ if (ioctl(fd, SNDCTL_DSP_SETFMT, &param) == -1)
+ fprintf(stderr,"OSS: Could not set DSP format\n");
+ else if (wantformat != param)
+ fprintf(stderr,"OSS: DSP format: wanted %d, got %d\n",
+ wantformat, param);
+
+ /* sample rate */
+ orig = param = srate;
+ if (ioctl(fd, SNDCTL_DSP_SPEED, &param) == -1)
+ fprintf(stderr,"OSS: Could not set sampling rate for device\n");
+ else if( orig != param )
+ fprintf(stderr,"OSS: sampling rate: wanted %d, got %d\n",
+ orig, param );
+
+ if (oss_blockmode && !skipblocksize)
+ {
+ int fragbytes, logfragsize, nfragment;
+ /* setting fragment count and size. */
+ if (!linux_fragsize)
+ {
+ linux_fragsize = OSS_DEFFRAGSIZE;
+ while (linux_fragsize > DEFDACBLKSIZE
+ && linux_fragsize * 4 > sys_advance_samples)
+ linux_fragsize = linux_fragsize/2;
+ }
+ /* post("adv_samples %d", sys_advance_samples); */
+ nfragment = (sys_schedadvance * (44100. * 1.e-6)) / linux_fragsize;
+
+ fragbytes = linux_fragsize * (dev->d_bytespersamp * nchannels);
+ logfragsize = ilog2(fragbytes);
+
+ if (fragbytes != (1 << logfragsize))
+ post("warning: OSS takes only power of 2 blocksize; using %d",
+ (1 << logfragsize)/(dev->d_bytespersamp * nchannels));
+ if (sys_verbose)
+ post("setting nfrags = %d, fragsize %d\n", nfragment, fragbytes);
+
+ param = orig = (nfragment<<16) + logfragsize;
+ if (ioctl(fd,SNDCTL_DSP_SETFRAGMENT, &param) == -1)
+ error("OSS: Could not set or read fragment size\n");
+ if (param != orig)
+ {
+ nfragment = ((param >> 16) & 0xffff);
+ logfragsize = (param & 0xffff);
+ post("warning: actual fragments %d, blocksize %d",
+ nfragment, (1 << logfragsize));
+ }
+ if (sys_verbose)
+ post("audiobuffer set to %d msec", (int)(0.001 * sys_schedadvance));
+ }
+
+ if (dac)
+ {
+ /* use "free space" to learn the buffer size. Normally you
+ should set this to your own desired value; but this seems not
+ to be implemented uniformly across different sound cards. LATER
+ we should figure out what to do if the requested scheduler advance
+ is greater than this buffer size; for now, we just print something
+ out. */
+
+ int defect;
+ if (ioctl(fd, SOUND_PCM_GETOSPACE,&ainfo) < 0)
+ fprintf(stderr,"OSS: ioctl on output device failed");
+ dev->d_bufsize = ainfo.bytes;
+
+ defect = sys_advance_samples * (dev->d_bytespersamp * nchannels)
+ - dev->d_bufsize - OSS_XFERSIZE(nchannels, dev->d_bytespersamp);
+ if (defect > 0)
+ {
+ if (sys_verbose || defect > (dev->d_bufsize >> 2))
+ fprintf(stderr,
+ "OSS: requested audio buffer size %d limited to %d\n",
+ sys_advance_samples * (dev->d_bytespersamp * nchannels),
+ dev->d_bufsize);
+ sys_advance_samples =
+ (dev->d_bufsize - OSS_XFERSAMPS(nchannels)) /
+ (dev->d_bytespersamp *nchannels);
+ }
+ }
+}
+
+static int oss_setchannels(int fd, int wantchannels, char *devname)
+{ /* IOhannes */
+ int param = wantchannels;
+
+ while (param>1) {
+ int save = param;
+ if (ioctl(fd, SNDCTL_DSP_CHANNELS, &param) == -1) {
+ error("OSS: SNDCTL_DSP_CHANNELS failed %s",devname);
+ } else {
+ if (param == save) return (param);
+ }
+ param=save-1;
+ }
+
+ return (0);
+}
+
+#define O_AUDIOFLAG 0 /* O_NDELAY */
+
+int oss_open_audio(int nindev, int *indev, int nchin, int *chin,
+ int noutdev, int *outdev, int nchout, int *chout, int rate)
+{ /* IOhannes */
+ int capabilities = 0;
+ int inchannels = 0, outchannels = 0;
+ char devname[20];
+ int n, i, fd;
+ char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
+ int num_devs = 0;
+ int wantmore=0;
+ int spread = 0;
+ audio_buf_info ainfo;
+
+ linux_nindevs = linux_noutdevs = 0;
+
+
+ /* mark input devices unopened */
+ for (i = 0; i < OSS_MAXDEV; i++)
+ linux_adcs[i].d_fd = -1;
+
+ /* open output devices */
+ wantmore=0;
+ if (noutdev < 0 || nindev < 0)
+ bug("linux_open_audio");
+
+ for (n = 0; n < noutdev; n++)
+ {
+ int gotchans, j, inindex = -1;
+ int thisdevice = (outdev[n] >= 0 ? outdev[n] : n-1);
+ int wantchannels = (nchout>n) ? chout[n] : wantmore;
+ fd = -1;
+ if (!wantchannels)
+ goto end_out_loop;
+
+ if (thisdevice > 1)
+ sprintf(devname, "/dev/dsp%d", thisdevice-1);
+ else sprintf(devname, "/dev/dsp");
+
+ /* search for input request for same device. Succeed only
+ if the number of channels matches. */
+ for (j = 0; j < nindev; j++)
+ if (indev[j] == thisdevice && chin[j] == wantchannels)
+ inindex = j;
+
+ /* if the same device is requested for input and output,
+ try to open it read/write */
+ if (inindex >= 0)
+ {
+ sys_setalarm(1000000);
+ if ((fd = open(devname, O_RDWR | O_AUDIOFLAG)) == -1)
+ {
+ post("%s (read/write): %s", devname, strerror(errno));
+ post("(now will try write-only...)");
+ }
+ else
+ {
+ if (sys_verbose)
+ post("opened %s for reading and writing\n", devname);
+ linux_adcs[inindex].d_fd = fd;
+ }
+ }
+ /* if that didn't happen or if it failed, try write-only */
+ if (fd == -1)
+ {
+ sys_setalarm(1000000);
+ if ((fd = open(devname, O_WRONLY | O_AUDIOFLAG)) == -1)
+ {
+ post("%s (writeonly): %s",
+ devname, strerror(errno));
+ break;
+ }
+ if (sys_verbose)
+ post("opened %s for writing only\n", devname);
+ }
+ if (ioctl(fd, SNDCTL_DSP_GETCAPS, &capabilities) == -1)
+ error("OSS: SNDCTL_DSP_GETCAPS failed %s", devname);
+
+ gotchans = oss_setchannels(fd,
+ (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
+ devname);
+
+ if (sys_verbose)
+ post("opened audio output on %s; got %d channels",
+ devname, gotchans);
+
+ if (gotchans < 2)
+ {
+ /* can't even do stereo? just give up. */
+ close(fd);
+ }
+ else
+ {
+ linux_dacs[linux_noutdevs].d_nchannels = gotchans;
+ linux_dacs[linux_noutdevs].d_fd = fd;
+ oss_configure(linux_dacs+linux_noutdevs, rate, 1, 0);
+
+ linux_noutdevs++;
+ outchannels += gotchans;
+ if (inindex >= 0)
+ {
+ linux_adcs[inindex].d_nchannels = gotchans;
+ chin[inindex] = gotchans;
+ }
+ }
+ /* LATER think about spreading large numbers of channels over
+ various dsp's and vice-versa */
+ wantmore = wantchannels - gotchans;
+ end_out_loop: ;
+ }
+
+ /* open input devices */
+ wantmore = 0;
+ for (n = 0; n < nindev; n++)
+ {
+ int gotchans=0;
+ int thisdevice = (indev[n] >= 0 ? indev[n] : n-1);
+ int wantchannels = (nchin>n)?chin[n]:wantmore;
+ int alreadyopened = 0;
+ if (!wantchannels)
+ goto end_in_loop;
+
+ if (thisdevice > 1)
+ sprintf(devname, "/dev/dsp%d", thisdevice - 1);
+ else sprintf(devname, "/dev/dsp");
+
+ sys_setalarm(1000000);
+
+ /* perhaps it's already open from the above? */
+ if (linux_dacs[n].d_fd >= 0)
+ {
+ fd = linux_dacs[n].d_fd;
+ alreadyopened = 1;
+ }
+ else
+ {
+ /* otherwise try to open it here. */
+ if ((fd = open(devname, O_RDONLY | O_AUDIOFLAG)) == -1)
+ {
+ post("%s (readonly): %s", devname, strerror(errno));
+ goto end_in_loop;
+ }
+ if (sys_verbose)
+ post("opened %s for reading only\n", devname);
+ }
+ linux_adcs[linux_nindevs].d_fd = fd;
+ gotchans = oss_setchannels(fd,
+ (wantchannels>OSS_MAXCHPERDEV)?OSS_MAXCHPERDEV:wantchannels,
+ devname);
+ if (sys_verbose)
+ post("opened audio input device %s; got %d channels",
+ devname, gotchans);
+
+ if (gotchans < 1)
+ {
+ close(fd);
+ goto end_in_loop;
+ }
+
+ linux_adcs[linux_nindevs].d_nchannels = gotchans;
+
+ oss_configure(linux_adcs+linux_nindevs, rate, 0, alreadyopened);
+
+ inchannels += gotchans;
+ linux_nindevs++;
+
+ wantmore = wantchannels-gotchans;
+ /* LATER think about spreading large numbers of channels over
+ various dsp's and vice-versa */
+ end_in_loop: ;
+ }
+
+ /* We have to do a read to start the engine. This is
+ necessary because sys_send_dacs waits until the input
+ buffer is filled and only reads on a filled buffer.
+ This is good, because it's a way to make sure that we
+ will not block. But I wonder why we only have to read
+ from one of the devices and not all of them??? */
+
+ if (linux_nindevs)
+ {
+ if (sys_verbose)
+ fprintf(stderr,("OSS: issuing first ADC 'read' ... "));
+ read(linux_adcs[0].d_fd, buf,
+ linux_adcs[0].d_bytespersamp *
+ linux_adcs[0].d_nchannels * DEFDACBLKSIZE);
+ if (sys_verbose)
+ fprintf(stderr, "...done.\n");
+ }
+ sys_setalarm(0);
+ return (0);
+}
+
+void oss_close_audio( void)
+{
+ int i;
+ for (i=0;i<linux_nindevs;i++)
+ close(linux_adcs[i].d_fd);
+
+ for (i=0;i<linux_noutdevs;i++)
+ close(linux_dacs[i].d_fd);
+
+ linux_nindevs = linux_noutdevs = 0;
+}
+
+static int linux_dacs_write(int fd,void* buf,long bytes)
+{
+ return write(fd, buf, bytes);
+}
+
+static int linux_adcs_read(int fd,void* buf,long bytes)
+{
+ return read(fd, buf, bytes);
+}
+
+ /* query audio devices for "available" data size. */
+static void oss_calcspace(void)
+{
+ int dev;
+ audio_buf_info ainfo;
+ for (dev=0; dev < linux_noutdevs; dev++)
+ {
+ if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
+ fprintf(stderr,"OSS: ioctl on output device %d failed",dev);
+ linux_dacs[dev].d_space = ainfo.bytes;
+ }
+
+ for (dev = 0; dev < linux_nindevs; dev++)
+ {
+ if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE,&ainfo) < 0)
+ fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
+ dev, linux_adcs[dev].d_fd);
+ linux_adcs[dev].d_space = ainfo.bytes;
+ }
+}
+
+void linux_audiostatus(void)
+{
+ int dev;
+ if (!oss_blockmode)
+ {
+ oss_calcspace();
+ for (dev=0; dev < linux_noutdevs; dev++)
+ fprintf(stderr, "dac %d space %d\n", dev, linux_dacs[dev].d_space);
+
+ for (dev = 0; dev < linux_nindevs; dev++)
+ fprintf(stderr, "adc %d space %d\n", dev, linux_adcs[dev].d_space);
+
+ }
+}
+
+/* this call resyncs audio output and input which will cause discontinuities
+in audio output and/or input. */
+
+static void oss_doresync( void)
+{
+ int dev, zeroed = 0, wantsize;
+ char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
+ audio_buf_info ainfo;
+
+ /* 1. if any input devices are ahead (have more than 1 buffer stored),
+ drop one or more buffers worth */
+ for (dev = 0; dev < linux_nindevs; dev++)
+ {
+ if (linux_adcs[dev].d_space == 0)
+ {
+ linux_adcs_read(linux_adcs[dev].d_fd, buf,
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp));
+ }
+ else while (linux_adcs[dev].d_space >
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp))
+ {
+ linux_adcs_read(linux_adcs[dev].d_fd, buf,
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp));
+ if (ioctl(linux_adcs[dev].d_fd, SOUND_PCM_GETISPACE, &ainfo) < 0)
+ {
+ fprintf(stderr, "OSS: ioctl on input device %d, fd %d failed",
+ dev, linux_adcs[dev].d_fd);
+ break;
+ }
+ linux_adcs[dev].d_space = ainfo.bytes;
+ }
+ }
+
+ /* 2. if any output devices are behind, feed them zeros to catch them
+ up */
+ for (dev = 0; dev < linux_noutdevs; dev++)
+ {
+ while (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
+ sys_advance_samples * (linux_dacs[dev].d_nchannels *
+ linux_dacs[dev].d_bytespersamp))
+ {
+ if (!zeroed)
+ {
+ unsigned int i;
+ for (i = 0; i < OSS_XFERSAMPS(linux_dacs[dev].d_nchannels);
+ i++)
+ buf[i] = 0;
+ zeroed = 1;
+ }
+ linux_dacs_write(linux_dacs[dev].d_fd, buf,
+ OSS_XFERSIZE(linux_dacs[dev].d_nchannels,
+ linux_dacs[dev].d_bytespersamp));
+ if (ioctl(linux_dacs[dev].d_fd, SOUND_PCM_GETOSPACE, &ainfo) < 0)
+ {
+ fprintf(stderr, "OSS: ioctl on output device %d, fd %d failed",
+ dev, linux_dacs[dev].d_fd);
+ break;
+ }
+ linux_dacs[dev].d_space = ainfo.bytes;
+ }
+ }
+ /* 3. if any DAC devices are too far ahead, plan to drop the
+ number of frames which will let the others catch up. */
+ for (dev = 0; dev < linux_noutdevs; dev++)
+ {
+ if (linux_dacs[dev].d_space > linux_dacs[dev].d_bufsize -
+ (sys_advance_samples - 1) * linux_dacs[dev].d_nchannels *
+ linux_dacs[dev].d_bytespersamp)
+ {
+ linux_dacs[dev].d_dropcount = sys_advance_samples - 1 -
+ (linux_dacs[dev].d_space - linux_dacs[dev].d_bufsize) /
+ (linux_dacs[dev].d_nchannels *
+ linux_dacs[dev].d_bytespersamp) ;
+ }
+ else linux_dacs[dev].d_dropcount = 0;
+ }
+}
+
+int oss_send_dacs(void)
+{
+ float *fp1, *fp2;
+ long fill;
+ int i, j, dev, rtnval = SENDDACS_YES;
+ char buf[OSS_MAXSAMPLEWIDTH * DEFDACBLKSIZE * OSS_MAXCHPERDEV];
+ t_oss_int16 *sp;
+ t_oss_int32 *lp;
+ /* the maximum number of samples we should have in the ADC buffer */
+ int idle = 0;
+ int thischan;
+ double timeref, timenow;
+
+ if (!linux_nindevs && !linux_noutdevs)
+ return (SENDDACS_NO);
+
+ if (!oss_blockmode)
+ {
+ /* determine whether we're idle. This is true if either (1)
+ some input device has less than one buffer to read or (2) some
+ output device has fewer than (sys_advance_samples) blocks buffered
+ already. */
+ oss_calcspace();
+
+ for (dev=0; dev < linux_noutdevs; dev++)
+ if (linux_dacs[dev].d_dropcount ||
+ (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space >
+ sys_advance_samples * linux_dacs[dev].d_bytespersamp *
+ linux_dacs[dev].d_nchannels))
+ idle = 1;
+ for (dev=0; dev < linux_nindevs; dev++)
+ if (linux_adcs[dev].d_space <
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp))
+ idle = 1;
+ }
+
+ if (idle && !oss_blockmode)
+ {
+ /* sometimes---rarely---when the ADC available-byte-count is
+ zero, it's genuine, but usually it's because we're so
+ late that the ADC has overrun its entire kernel buffer. We
+ distinguish between the two by waiting 2 msec and asking again.
+ There should be an error flag we could check instead; look for this
+ someday... */
+ for (dev = 0;dev < linux_nindevs; dev++)
+ if (linux_adcs[dev].d_space == 0)
+ {
+ audio_buf_info ainfo;
+ sys_microsleep(2000);
+ oss_calcspace();
+ if (linux_adcs[dev].d_space != 0) continue;
+
+ /* here's the bad case. Give up and resync. */
+ sys_log_error(ERR_DATALATE);
+ oss_doresync();
+ return (SENDDACS_NO);
+ }
+ /* check for slippage between devices, either because
+ data got lost in the driver from a previous late condition, or
+ because the devices aren't synced. When we're idle, no
+ input device should have more than one buffer readable and
+ no output device should have less than sys_advance_samples-1
+ */
+
+ for (dev=0; dev < linux_noutdevs; dev++)
+ if (!linux_dacs[dev].d_dropcount &&
+ (linux_dacs[dev].d_bufsize - linux_dacs[dev].d_space <
+ (sys_advance_samples - 2) *
+ (linux_dacs[dev].d_bytespersamp *
+ linux_dacs[dev].d_nchannels)))
+ goto badsync;
+ for (dev=0; dev < linux_nindevs; dev++)
+ if (linux_adcs[dev].d_space > 3 *
+ OSS_XFERSIZE(linux_adcs[dev].d_nchannels,
+ linux_adcs[dev].d_bytespersamp))
+ goto badsync;
+
+ /* return zero to tell the scheduler we're idle. */
+ return (SENDDACS_NO);
+ badsync:
+ sys_log_error(ERR_RESYNC);
+ oss_doresync();
+ return (SENDDACS_NO);
+
+ }
+
+ /* do output */
+
+ timeref = sys_getrealtime();
+ for (dev=0, thischan = 0; dev < linux_noutdevs; dev++)
+ {
+ int nchannels = linux_dacs[dev].d_nchannels;
+ if (linux_dacs[dev].d_dropcount)
+ linux_dacs[dev].d_dropcount--;
+ else
+ {
+ if (linux_dacs[dev].d_bytespersamp == 4)
+ {
+ for (i = DEFDACBLKSIZE * nchannels, fp1 = sys_soundout +
+ DEFDACBLKSIZE*thischan,
+ lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
+ {
+ float f = *fp1 * 2147483648.;
+ *lp = (f >= 2147483647. ? 2147483647. :
+ (f < -2147483648. ? -2147483648. : f));
+ }
+ }
+ else
+ {
+ for (i = DEFDACBLKSIZE, fp1 = sys_soundout +
+ DEFDACBLKSIZE*thischan,
+ sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
+ {
+ for (j=0, fp2 = fp1; j<nchannels; j++, fp2 += DEFDACBLKSIZE)
+ {
+ int s = *fp2 * 32767.;
+ if (s > 32767) s = 32767;
+ else if (s < -32767) s = -32767;
+ sp[j] = s;
+ }
+ }
+ }
+ linux_dacs_write(linux_dacs[dev].d_fd, buf,
+ OSS_XFERSIZE(nchannels, linux_dacs[dev].d_bytespersamp));
+ if ((timenow = sys_getrealtime()) - timeref > 0.002)
+ {
+ if (!oss_blockmode)
+ sys_log_error(ERR_DACSLEPT);
+ else rtnval = SENDDACS_SLEPT;
+ }
+ timeref = timenow;
+ }
+ thischan += nchannels;
+ }
+ memset(sys_soundout, 0,
+ sys_outchannels * (sizeof(float) * DEFDACBLKSIZE));
+
+ /* do input */
+
+ for (dev = 0, thischan = 0; dev < linux_nindevs; dev++)
+ {
+ int nchannels = linux_adcs[dev].d_nchannels;
+ linux_adcs_read(linux_adcs[dev].d_fd, buf,
+ OSS_XFERSIZE(nchannels, linux_adcs[dev].d_bytespersamp));
+
+ if ((timenow = sys_getrealtime()) - timeref > 0.002)
+ {
+ if (!oss_blockmode)
+ sys_log_error(ERR_ADCSLEPT);
+ else
+ rtnval = SENDDACS_SLEPT;
+ }
+ timeref = timenow;
+
+ if (linux_adcs[dev].d_bytespersamp == 4)
+ {
+ for (i = DEFDACBLKSIZE*nchannels,
+ fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
+ lp = (t_oss_int32 *)buf; i--; fp1++, lp++)
+ {
+ *fp1 = ((float)(*lp))*(float)(1./2147483648.);
+ }
+ }
+ else
+ {
+ for (i = DEFDACBLKSIZE,fp1 = sys_soundin + thischan*DEFDACBLKSIZE,
+ sp = (t_oss_int16 *)buf; i--; fp1++, sp += nchannels)
+ {
+ for (j=0;j<sys_inchannels;j++)
+ fp1[j*DEFDACBLKSIZE] = (float)sp[j]*(float)3.051850e-05;
+ }
+ }
+ thischan += nchannels;
+ }
+ if (thischan != sys_inchannels)
+ bug("inchannels");
+ return (rtnval);
+}
+
+void oss_listdevs( void)
+{
+ post("device listing not implemented in OSS yet\n");
+}
+
diff --git a/pd/src/s_audio_pa.c b/pd/src/s_audio_pa.c
new file mode 100644
index 00000000..253b33cd
--- /dev/null
+++ b/pd/src/s_audio_pa.c
@@ -0,0 +1,186 @@
+/* Copyright (c) 2001 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. */
+
+/* this file calls Ross Bencina's and Phil Burk's Portaudio package. It's
+ the main way in for Mac OS and, with Michael Casey's help, also into
+ ASIO in Windows. */
+
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "portaudio.h"
+#include "pablio_pd.h"
+
+#ifdef MACOSX
+#define Pa_GetDefaultInputDevice Pa_GetDefaultInputDeviceID
+#define Pa_GetDefaultOutputDevice Pa_GetDefaultOutputDeviceID
+#endif
+
+ /* public interface declared in m_imp.h */
+
+ /* implementation */
+static PABLIO_Stream *pa_stream;
+static int pa_inchans, pa_outchans;
+static float *pa_soundin, *pa_soundout;
+
+#define MAX_PA_CHANS 32
+#define MAX_SAMPLES_PER_FRAME MAX_PA_CHANS * DEFDACBLKSIZE
+
+int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
+ t_sample *soundout, int framesperbuf, int nbuffers,
+ int indeviceno, int outdeviceno)
+{
+ PaError err;
+ static int initialized;
+
+ if (!initialized)
+ {
+ /* Initialize PortAudio */
+ int err = Pa_Initialize();
+ if ( err != paNoError )
+ {
+ fprintf( stderr,
+ "Error number %d occured initializing portaudio\n",
+ err);
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return (1);
+ }
+ initialized = 1;
+ }
+ /* post("in %d out %d rate %d device %d", inchans, outchans, rate, deviceno); */
+ if (inchans != 0 && outchans != 0 && inchans != outchans)
+ error("portaudio: number of input and output channels must match");
+ if (sys_verbose)
+ post("portaudio: opening for %d channels in, %d out",
+ inchans, outchans);
+ if (inchans > MAX_PA_CHANS)
+ {
+ post("input channels reduced to maximum %d", MAX_PA_CHANS);
+ inchans = MAX_PA_CHANS;
+ }
+ if (outchans > MAX_PA_CHANS)
+ {
+ post("output channels reduced to maximum %d", MAX_PA_CHANS);
+ outchans = MAX_PA_CHANS;
+ }
+ if (indeviceno < 0)
+ indeviceno = Pa_GetDefaultInputDevice();
+ if (outdeviceno < 0)
+ outdeviceno = Pa_GetDefaultOutputDevice();
+
+ fprintf(stderr, "input device %d, output device %d\n",
+ indeviceno, outdeviceno);
+ if (inchans && outchans)
+ err = OpenAudioStream( &pa_stream, rate, paFloat32,
+ PABLIO_READ_WRITE, inchans, framesperbuf, nbuffers,
+ indeviceno, outdeviceno);
+ else if (inchans)
+ err = OpenAudioStream( &pa_stream, rate, paFloat32,
+ PABLIO_READ, inchans, framesperbuf, nbuffers,
+ indeviceno, outdeviceno);
+ else if (outchans)
+ err = OpenAudioStream( &pa_stream, rate, paFloat32,
+ PABLIO_WRITE, outchans, framesperbuf, nbuffers,
+ indeviceno, outdeviceno);
+ else err = 0;
+ if ( err != paNoError )
+ {
+ fprintf( stderr, "Error number %d occured opening portaudio stream\n",
+ err);
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+ Pa_Terminate();
+ return (1);
+ }
+ else if (sys_verbose)
+ post("... opened OK.");
+ pa_inchans = inchans;
+ pa_outchans = outchans;
+ pa_soundin = soundin;
+ pa_soundout = soundout;
+ return (0);
+}
+
+void pa_close_audio( void)
+{
+ if (pa_inchans || pa_outchans)
+ CloseAudioStream( pa_stream );
+ pa_inchans = pa_outchans = 0;
+}
+
+int pa_send_dacs(void)
+{
+ float samples[MAX_SAMPLES_PER_FRAME], *fp1, *fp2;
+ int i, j;
+ double timebefore;
+
+ timebefore = sys_getrealtime();
+ if (pa_inchans)
+ {
+ ReadAudioStream(pa_stream, samples, DEFDACBLKSIZE);
+ for (j = 0, fp1 = pa_soundin; j < pa_inchans; j++, fp1 += DEFDACBLKSIZE)
+ for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
+ fp2 += pa_inchans)
+ {
+ fp1[i] = *fp2;
+ }
+ }
+ if (pa_outchans)
+ {
+ for (j = 0, fp1 = pa_soundout; j < pa_outchans; j++,
+ fp1 += DEFDACBLKSIZE)
+ for (i = 0, fp2 = samples + j; i < DEFDACBLKSIZE; i++,
+ fp2 += pa_outchans)
+ {
+ *fp2 = fp1[i];
+ fp1[i] = 0;
+ }
+ WriteAudioStream(pa_stream, samples, DEFDACBLKSIZE);
+ }
+
+ if (sys_getrealtime() > timebefore + 0.002)
+ return (SENDDACS_SLEPT);
+ else return (SENDDACS_YES);
+}
+
+
+void pa_listdevs(void) /* lifted from pa_devs.c in portaudio */
+{
+ int i,j;
+ int numDevices;
+ const PaDeviceInfo *pdi;
+ PaError err;
+ Pa_Initialize();
+ numDevices = Pa_CountDevices();
+ if( numDevices < 0 )
+ {
+ fprintf(stderr, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
+ err = numDevices;
+ goto error;
+ }
+ fprintf(stderr, "Audio Devices:\n");
+ for( i=0; i<numDevices; i++ )
+ {
+ pdi = Pa_GetDeviceInfo( i );
+ fprintf(stderr, "device %d:", i+1 );
+ fprintf(stderr, " %s;", pdi->name );
+ fprintf(stderr, "%d inputs, ", pdi->maxInputChannels );
+ fprintf(stderr, "%d outputs", pdi->maxOutputChannels );
+ if ( i == Pa_GetDefaultInputDevice() )
+ fprintf(stderr, " (Default Input)");
+ if ( i == Pa_GetDefaultOutputDevice() )
+ fprintf(stderr, " (Default Output)");
+ fprintf(stderr, "\n");
+ }
+
+ fprintf(stderr, "\n");
+ return;
+
+error:
+ fprintf( stderr, "An error occured while using the portaudio stream\n" );
+ fprintf( stderr, "Error number: %d\n", err );
+ fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
+
+}
diff --git a/pd/src/s_entry.c b/pd/src/s_entry.c
index 354512e5..ad1e28fa 100644
--- a/pd/src/s_entry.c
+++ b/pd/src/s_entry.c
@@ -1,10 +1,51 @@
-/* In NT, this is all there is to pd; the rest sits in a "pdlib" dll so
+/* In MSW, this is all there is to pd; the rest sits in a "pdlib" dll so
that externs can link back to functions defined in pd. */
+#include <stdio.h>
int sys_main(int argc, char **argv);
+ /* WINBASEAPI PVOID WINAPI AddVectoredExceptionHandler(
+ ULONG FirstHandler,
+ PVECTORED_EXCEPTION_HANDLER VectoredHandler ); */
+
+#ifdef MSW
+#if 0
+#incldue "winbase.h"
+
+LONG NTAPI VectoredExceptionHandler(void *PEXCEPTION_POINTERS)
+{
+ fprintf(stderr, "caught exception\n");
+ return(EXCEPTION_CONTINUE_SEARCH);
+}
+
+
+int main(int argc, char **argv)
+{
+ printf("Pd entry point\n");
+ AddVectoredExceptionHandler(
+ ULONG FirstHandler,
+ PVECTORED_EXCEPTION_HANDLER VectoredHandler );
+
+
+#endif
+
+#if 1
+int main(int argc, char **argv)
+{
+ __try
+ {
+ sys_main(argc, argv);
+ }
+ __finally
+ {
+ printf("caught an exception; stopping\n");
+ }
+}
+#endif
+#else /* not MSW */
int main(int argc, char **argv)
{
return (sys_main(argc, argv));
}
+#endif
diff --git a/pd/src/s_file.c b/pd/src/s_file.c
index 32d2fcaa..27825d59 100644
--- a/pd/src/s_file.c
+++ b/pd/src/s_file.c
@@ -6,7 +6,8 @@
* this file contains file-handling routines.
*/
-#include "m_imp.h"
+#include "m_pd.h"
+#include "s_stuff.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -29,7 +30,7 @@ void sys_bashfilename(const char *from, char *to)
char c;
while (c = *from++)
{
-#ifdef NT
+#ifdef MSW
if (c == '/') c = '\\';
#endif
*to++ = c;
@@ -44,7 +45,7 @@ void sys_unbashfilename(const char *from, char *to)
char c;
while (c = *from++)
{
-#ifdef NT
+#ifdef MSW
if (c == '\\') c = '/';
#endif
*to++ = c;
diff --git a/pd/src/s_inter.c b/pd/src/s_inter.c
index eed90b38..004820f6 100644
--- a/pd/src/s_inter.c
+++ b/pd/src/s_inter.c
@@ -2,8 +2,11 @@
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
-/* Pd side of the Pd/Pd-gui interface. */
+/* Pd side of the Pd/Pd-gui interface. Also, some system interface routines
+that didn't really belong anywhere. */
+#include "m_pd.h"
+#include "s_stuff.h"
#include "m_imp.h"
#ifdef UNIX
#include <unistd.h>
@@ -13,11 +16,12 @@
#include <netdb.h>
#include <stdlib.h>
#include <sys/time.h>
+#include <sys/mman.h>
#endif
#ifdef HAVE_BSTRING_H
#include <bstring.h>
#endif
-#ifdef NT
+#ifdef MSW
#include <io.h>
#include <fcntl.h>
#include <process.h>
@@ -35,10 +39,14 @@ typedef int pid_t;
#ifdef MACOSX
#include <sys/types.h>
#include <sys/stat.h>
+#include <pthread.h>
#else
#include <stdlib.h>
#endif
+#define DEBUG_MESSUP 1 /* messages up from pd to pd-gui */
+#define DEBUG_MESSDOWN 2 /* messages down from pd-gui to pd */
+
extern char pd_version[];
typedef struct _fdpoll
@@ -70,9 +78,58 @@ static t_binbuf *inbinbuf;
static t_socketreceiver *sys_socketreceiver;
extern int sys_addhist(int phase);
+#ifdef MSW
+static LARGE_INTEGER nt_inittime;
+static double nt_freq = 0;
+
+static void sys_initntclock(void)
+{
+ LARGE_INTEGER f1;
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ if (!QueryPerformanceFrequency(&f1))
+ {
+ fprintf(stderr, "pd: QueryPerformanceFrequency failed\n");
+ f1.QuadPart = 1;
+ }
+ nt_freq = f1.QuadPart;
+ nt_inittime = now;
+}
+
+#if 0
+ /* this is a version you can call if you did the QueryPerformanceCounter
+ call yourself. Necessary for time tagging incoming MIDI at interrupt
+ level, for instance; but we're not doing that just now. */
+
+double nt_tixtotime(LARGE_INTEGER *dumbass)
+{
+ if (nt_freq == 0) sys_initntclock();
+ return (((double)(dumbass->QuadPart - nt_inittime.QuadPart)) / nt_freq);
+}
+#endif
+#endif /* MSW */
+
+double sys_getrealtime(void) /* get "real time" in seconds */
+{
+#ifdef UNIX
+ static struct timeval then;
+ struct timeval now;
+ gettimeofday(&now, 0);
+ if (then.tv_sec == 0 && then.tv_usec == 0) then = now;
+ return ((now.tv_sec - then.tv_sec) +
+ (1./1000000.) * (now.tv_usec - then.tv_usec));
+#endif
+#ifdef MSW
+ LARGE_INTEGER now;
+ QueryPerformanceCounter(&now);
+ if (nt_freq == 0) sys_initntclock();
+ return (((double)(now.QuadPart - nt_inittime.QuadPart)) / nt_freq);
+#endif
+}
+
void sys_sockerror(char *s)
{
-#ifdef NT
+#ifdef MSW
int err = WSAGetLastError();
if (err == 10054) return;
else if (err == 10044)
@@ -320,7 +377,7 @@ void sys_closesocket(int fd)
#ifdef UNIX
close(fd);
#endif
-#ifdef NT
+#ifdef MSW
closesocket(fd);
#endif
}
@@ -431,6 +488,34 @@ void sys_setalarm(int microsec)
#endif
+#ifdef __linux
+
+#if defined(_POSIX_PRIORITY_SCHEDULING) || defined(_POSIX_MEMLOCK)
+#include <sched.h>
+#endif
+
+void sys_set_priority(int higher)
+{
+#ifdef _POSIX_PRIORITY_SCHEDULING
+ struct sched_param par;
+ int p1 ,p2, p3;
+ p1 = sched_get_priority_min(SCHED_FIFO);
+ p2 = sched_get_priority_max(SCHED_FIFO);
+ p3 = (higher ? p2 - 1 : p2 - 3);
+ par.sched_priority = p3;
+ if (sched_setscheduler(0,SCHED_FIFO,&par) != -1)
+ fprintf(stderr, "priority %d scheduling enabled.\n", p3);
+#endif
+
+#ifdef _POSIX_MEMLOCK
+ if (mlockall(MCL_FUTURE) != -1)
+ fprintf(stderr, "memory locking enabled.\n");
+#endif
+
+}
+
+#endif /* __linux */
+
static int sys_watchfd;
void glob_ping(t_pd *dummy)
@@ -456,7 +541,7 @@ int sys_startgui(const char *guidir)
int len = sizeof(server);
int ntry = 0, portno = FIRSTPORTNUM;
int xsock = -1;
-#ifdef NT
+#ifdef MSW
short version = MAKEWORD(2, 0);
WSADATA nobby;
#endif
@@ -485,7 +570,7 @@ int sys_startgui(const char *guidir)
signal(SIGSTKFLT, sys_exithandler);
#endif
#endif
-#ifdef NT
+#ifdef MSW
if (WSAStartup(version, &nobby)) sys_sockerror("WSAstartup");
#endif
@@ -495,7 +580,7 @@ int sys_startgui(const char *guidir)
skip starting the GUI up. */
t_atom zz[19];
int i;
-#ifdef NT
+#ifdef MSW
if (GetCurrentDirectory(MAXPDSTRING, cmdbuf) == 0)
strcpy(cmdbuf, ".");
#endif
@@ -511,12 +596,16 @@ int sys_startgui(const char *guidir)
}
else
{
-#ifdef NT
+#ifdef MSW
char scriptbuf[MAXPDSTRING+30], wishbuf[MAXPDSTRING+30], portbuf[80];
int spawnret;
#endif
+#ifdef MSW
+ char intarg;
+#else
int intarg;
+#endif
/* create a socket */
xsock = socket(AF_INET, SOCK_STREAM, 0);
@@ -546,7 +635,7 @@ int sys_startgui(const char *guidir)
/* name the socket */
while (bind(xsock, (struct sockaddr *)&server, sizeof(server)) < 0)
{
-#ifdef NT
+#ifdef MSW
int err = WSAGetLastError();
#endif
#ifdef UNIX
@@ -638,8 +727,8 @@ int sys_startgui(const char *guidir)
}
#endif /* UNIX */
-#ifdef NT
- /* in NT land "guipath" is unused; we just do everything from
+#ifdef MSW
+ /* in MSW land "guipath" is unused; we just do everything from
the libdir. */
fprintf(stderr, "%s\n", sys_libdir->s_name);
@@ -662,10 +751,10 @@ int sys_startgui(const char *guidir)
exit(1);
}
-#endif /* NT */
+#endif /* MSW */
}
-#ifdef UNIX
+#ifdef __linux__
/* now that we've spun off the child process we can promote
our process's priority, if we happen to be root. */
if (sys_hipriority)
@@ -733,12 +822,24 @@ int sys_startgui(const char *guidir)
}
seteuid(getuid()); /* lose setuid priveliges */
-#endif /* UNIX */
+#endif /* __linux__ */
-#ifdef NT
+#ifdef MSW
if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
fprintf(stderr, "pd: couldn't set high priority class\n");
#endif
+#ifdef MACOSX
+ {
+ struct sched_param param;
+ int policy = SCHED_RR;
+ int err;
+ param.sched_priority = 80; // adjust 0 : 100
+
+ err = pthread_setschedparam(pthread_self(), policy, &param);
+ if (err)
+ post("warning: high priority scheduling failed\n");
+ }
+#endif /* MACOSX */
if (!sys_nogui)
{
@@ -786,8 +887,13 @@ void sys_bail(int n)
if (!reentered)
{
reentered = 1;
+#ifndef __linux /* sys_close_audio() hangs if you're in a signal? */
+ fprintf(stderr, "closing audio...\n");
sys_close_audio();
+ fprintf(stderr, "closing MIDI...\n");
sys_close_midi();
+ fprintf(stderr, "... done.\n");
+#endif
}
_exit(n);
}
diff --git a/pd/src/s_loader.c b/pd/src/s_loader.c
index 4c0ef972..c210206c 100644
--- a/pd/src/s_loader.c
+++ b/pd/src/s_loader.c
@@ -9,7 +9,7 @@
#include <stdlib.h>
#include <unistd.h>
#endif
-#ifdef NT
+#ifdef MSW
#include <io.h>
#include <windows.h>
#endif
@@ -17,7 +17,8 @@
#include <mach-o/dyld.h>
#endif
#include <string.h>
-#include "m_imp.h"
+#include "m_pd.h"
+#include "s_stuff.h"
#include <stdio.h>
typedef void (*t_xxx)(void);
@@ -39,96 +40,118 @@ static char sys_dllextent[] =
#ifdef MACOSX
".pd_darwin";
#endif
-#ifdef NT
+#ifdef MSW
".dll";
#endif
+void class_set_extern_dir(t_symbol *s);
int sys_load_lib(char *dirname, char *classname)
{
char symname[MAXPDSTRING], filename[MAXPDSTRING], dirbuf[MAXPDSTRING],
- *nameptr, *lastdot;
+ classname2[MAXPDSTRING], *nameptr, *lastdot;
void *dlobj;
- t_xxx makeout;
+ t_xxx makeout = NULL;
int fd;
-#ifdef NT
+#ifdef MSW
HINSTANCE ntdll;
#endif
#if 0
fprintf(stderr, "lib %s %s\n", dirname, classname);
#endif
+ /* try looking in the path for (classname).(sys_dllextent) ... */
if ((fd = open_via_path(dirname, classname, sys_dllextent,
dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
{
- return (0);
+ /* next try (classname)/(classname).(sys_dllextent) ... */
+ strncpy(classname2, classname, MAXPDSTRING);
+ filename[MAXPDSTRING-2] = 0;
+ strcat(classname2, "/");
+ strncat(classname2, classname, MAXPDSTRING-strlen(classname2));
+ filename[MAXPDSTRING-1] = 0;
+ if ((fd = open_via_path(dirname, classname2, sys_dllextent,
+ dirbuf, &nameptr, MAXPDSTRING, 1)) < 0)
+ {
+ return (0);
+ }
}
- else
- {
- close(fd);
- /* refabricate the pathname */
- strcpy(filename, dirbuf);
- strcat(filename, "/");
- strcat(filename, nameptr);
- /* extract the setup function name */
- if (lastdot = strrchr(nameptr, '.'))
- *lastdot = 0;
+
+
+ close(fd);
+ class_set_extern_dir(gensym(dirbuf));
+
+ /* refabricate the pathname */
+ strncpy(filename, dirbuf, MAXPDSTRING);
+ filename[MAXPDSTRING-2] = 0;
+ strcat(filename, "/");
+ strncat(filename, nameptr, MAXPDSTRING-strlen(filename));
+ filename[MAXPDSTRING-1] = 0;
+ /* extract the setup function name */
+ if (lastdot = strrchr(nameptr, '.'))
+ *lastdot = 0;
#ifdef MACOSX
- strcpy(symname, "_");
- strcat(symname, nameptr);
+ strcpy(symname, "_");
+ strcat(symname, nameptr);
#else
- strcpy(symname, nameptr);
+ strcpy(symname, nameptr);
#endif
- /* if the last character is a tilde, replace with "_tilde" */
- if (symname[strlen(symname) - 1] == '~')
- strcpy(symname + (strlen(symname) - 1), "_tilde");
- /* and append _setup to form the C setup function name */
- strcat(symname, "_setup");
+ /* if the last character is a tilde, replace with "_tilde" */
+ if (symname[strlen(symname) - 1] == '~')
+ strcpy(symname + (strlen(symname) - 1), "_tilde");
+ /* and append _setup to form the C setup function name */
+ strcat(symname, "_setup");
#ifdef DL_OPEN
- dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
- if (!dlobj)
- {
- post("%s: %s", filename, dlerror());
- return (0);
- }
- makeout = (t_xxx)dlsym(dlobj, symname);
-#endif
-#ifdef NT
- sys_bashfilename(filename, filename);
- ntdll = LoadLibrary(filename);
- if (!ntdll)
- {
- post("%s: couldn't load", filename);
- return (0);
- }
- makeout = (t_xxx)GetProcAddress(ntdll, symname);
+ dlobj = dlopen(filename, RTLD_NOW | RTLD_GLOBAL);
+ if (!dlobj)
+ {
+ post("%s: %s", filename, dlerror());
+ class_set_extern_dir(&s_);
+ return (0);
+ }
+ makeout = (t_xxx)dlsym(dlobj, symname);
+#endif
+#ifdef MSW
+ sys_bashfilename(filename, filename);
+ ntdll = LoadLibrary(filename);
+ if (!ntdll)
+ {
+ post("%s: couldn't load", filename);
+ class_set_extern_dir(&s_);
+ return (0);
+ }
+ makeout = (t_xxx)GetProcAddress(ntdll, symname);
#endif
#ifdef MACOSX
+ {
+ NSObjectFileImage image;
+ void *ret;
+ NSSymbol s;
+ if ( NSCreateObjectFileImageFromFile( filename, &image) != NSObjectFileImageSuccess )
{
- NSObjectFileImage image;
- void *ret;
- NSSymbol s;
- if ( NSCreateObjectFileImageFromFile( filename, &image) != NSObjectFileImageSuccess )
- {
- post("%s: couldn't load", filename);
- return 0;
- }
- ret = NSLinkModule( image, filename, NSLINKMODULE_OPTION_BINDNOW);
-
- s = NSLookupSymbolInModule(ret, symname);
-
- if (s)
- makeout = (t_xxx)NSAddressOfSymbol( s);
- else makeout = 0;
+ post("%s: couldn't load", filename);
+ class_set_extern_dir(&s_);
+ return 0;
}
-#endif
+ ret = NSLinkModule( image, filename,
+ NSLINKMODULE_OPTION_BINDNOW + NSLINKMODULE_OPTION_PRIVATE);
+
+ s = NSLookupSymbolInModule(ret, symname);
+
+ if (s)
+ makeout = (t_xxx)NSAddressOfSymbol( s);
+ else makeout = 0;
}
+#endif
+
if (!makeout)
{
post("load_object: Symbol \"%s\" not found", symname);
+ class_set_extern_dir(&s_);
return 0;
}
(*makeout)();
+ class_set_extern_dir(&s_);
return (1);
}
diff --git a/pd/src/s_main.c b/pd/src/s_main.c
index fdf36772..f969f27e 100644
--- a/pd/src/s_main.c
+++ b/pd/src/s_main.c
@@ -7,11 +7,13 @@
* 1311:forum::für::umläute:2001
*/
-char pd_version[] = "Pd version 0.36-0\n";
+char pd_version[] = "Pd version 0.37 TEST 4\n";
char pd_compiletime[] = __TIME__;
char pd_compiledate[] = __DATE__;
+#include "m_pd.h"
#include "m_imp.h"
+#include "s_stuff.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
@@ -23,7 +25,7 @@ char pd_compiledate[] = __DATE__;
#ifdef UNIX
#include <unistd.h>
#endif
-#ifdef NT
+#ifdef MSW
#include <io.h>
#include <windows.h>
#include <winbase.h>
@@ -36,6 +38,7 @@ int sys_startgui(const char *guipath);
int sys_rcfile(void);
int m_scheduler(int nodacs);
void m_schedsetsr( void);
+void sys_addhelppath(char *p);
int sys_debuglevel;
int sys_verbose;
@@ -50,16 +53,13 @@ static t_namelist *sys_messagelist;
static int sys_version;
int sys_nmidiout = 1;
-#ifdef NT
+#ifdef MSW
int sys_nmidiin = 0;
-#define DEFMIDIOUTDEV 0 /* For output, in NT, default to "midi_mapper" */
#else
int sys_nmidiin = 1;
-#define DEFMIDIOUTDEV 1 /* in other OSes, default to first MIDI device */
#endif
-#define DEFMIDIINDEV 1 /* for NT this isn't used since sys_nmidiin is 0. */
-int sys_midiindevlist[MAXMIDIINDEV] = {DEFMIDIINDEV};
-int sys_midioutdevlist[MAXMIDIOUTDEV] = {DEFMIDIOUTDEV};
+int sys_midiindevlist[MAXMIDIINDEV] = {DEFMIDIDEV};
+int sys_midioutdevlist[MAXMIDIOUTDEV] = {DEFMIDIDEV};
typedef struct _fontinfo
{
@@ -80,7 +80,7 @@ static t_fontinfo sys_fontlist[] = {
#define NFONT (sizeof(sys_fontlist)/sizeof(*sys_fontlist))
/* here are the actual font size structs on msp's systems:
-NT:
+MSW:
font 8 5 9 8 5 11
font 10 7 13 10 6 13
font 12 9 16 14 8 16
@@ -127,7 +127,7 @@ int sys_fontheight(int fontsize)
}
int sys_defaultfont;
-#ifdef NT
+#ifdef MSW
#define DEFAULTFONT 12
#else
#define DEFAULTFONT 10
@@ -228,6 +228,7 @@ void glob_initfromgui(void *dummy, t_symbol *s, int argc, t_atom *argv)
}
static void sys_addextrapath(void);
+static void sys_addreferencepath(void);
/* this is called from main() in s_entry.c */
int sys_main(int argc, char **argv)
@@ -237,11 +238,12 @@ int sys_main(int argc, char **argv)
#endif
pd_init(); /* start the message system */
sys_findprogdir(argv[0]); /* set sys_progname, guipath */
-#ifdef __linux__
+#ifdef UNIX
sys_rcfile(); /* parse the startup file */
#endif
if (sys_argparse(argc, argv)) return (1); /* parse cmd line */
sys_addextrapath();
+ sys_addreferencepath();
if (sys_verbose || sys_version) fprintf(stderr, "%scompiled %s %s\n",
pd_version, pd_compiletime, pd_compiledate);
if (sys_version) /* if we were just asked our version, exit here. */
@@ -265,13 +267,11 @@ static char *(usagemessage[]) = {
"usage: pd [-flags] [file]...\n",
"\naudio configuration flags:\n",
"-r <n> -- specify sample rate\n",
-#if defined(__linux__) || defined(NT)
-"-inchannels ... -- number of audio in channels (by device, like \"2\" or \"16,8\")\n",
-"-outchannels ... -- number of audio out channels (by device)\n",
-#else
-"-inchannels <n> -- number of audio input channels\n",
-"-outchannels <n> -- number of audio output channels\n",
-#endif
+"-audioindev ... -- audio in devices; e.g., \"1,3\" for first and third\n",
+"-audiooutdev ... -- audio out devices (same)\n",
+"-audiodev ... -- specify input and output together\n",
+"-inchannels ... -- audio input channels (by device, like \"2\" or \"16,8\")\n",
+"-outchannels ... -- number of audio out channels (same)\n",
"-channels ... -- specify both input and output channels\n",
"-audiobuf <n> -- specify size of audio buffer in msec\n",
"-blocksize <n> -- specify audio I/O block size in sample frames\n",
@@ -279,37 +279,30 @@ static char *(usagemessage[]) = {
"-nodac -- suppress audio output\n",
"-noadc -- suppress audio input\n",
"-noaudio -- suppress audio input and output (-nosound is synonym) \n",
-"-listdev -- list audio and MIDI devices\n",
+"-listdev -- list audio and MIDI devices\n",
-#ifdef __linux__
-"-frags <n> -- specify number of audio fragments (defeats audiobuf)\n",
-"-fragsize <n> -- specify log of fragment size ('blocksize' is better...)\n",
-"-stream -- use stream mode audio (e.g., for es1370 audio cards)\n",
-"-32bit -- allow 32 bit OSS audio transfers (for RME Hammerfall)\n",
+#ifdef USEAPI_OSS
+"-oss -- use OSS audio API\n",
+"-32bit ----- allow 32 bit OSS audio (for RME Hammerfall)\n",
#endif
-#ifdef ALSA99
-"-alsa -- use ALSA audio drivers\n",
-"-alsadev <n> -- specify ALSA I/O device number (counting from 1)\n",
+#ifdef USEAPI_ALSA
+"-alsa -- use ALSA audio API\n",
+"-alsadev <n> ----- ALSA device # (count from 1) or name: default hw:0,0\n",
#endif
-#ifdef ALSA01
-"-alsa -- use ALSA audio drivers\n",
-"-alsadev <n> -- ALSA device # (counting from 1) or name: default hw:0,0\n",
+#ifdef USEAPI_PORTAUDIO
+#ifdef MSW
+"-pa -- use Portaudio API (for ASIO)\n",
+#else
+"-pa -- use Portaudio API\n",
#endif
-
-#ifdef RME_HAMMERFALL
-"-rme -- use Ritsch's RME 9652 audio driver\n",
#endif
-"-audioindev ... -- sound in device list; e.g., \"2,1\" for second and first\n",
-"-audiooutdev ... -- sound out device list, same as above \n",
-"-audiodev ... -- specify both -audioindev and -audiooutdev together\n",
-
-#ifdef NT
-"-resync -- resynchronize audio (default if more than 2 channels)\n",
-"-noresync -- never resynchronize audio I/O (default for stereo)\n",
-"-asio -- use ASIO audio driver (and not the 'MMIO' default)\n",
+
+#ifdef USEAPI_MMIO
+"-mmio -- use MMIO audio API\n",
#endif
+" (default audio API for this platform: ", API_DEFSTRING, ")\n\n",
"\nMIDI configuration flags:\n",
"-midiindev ... -- midi in device list; e.g., \"1,3\" for first and third\n",
@@ -319,8 +312,9 @@ static char *(usagemessage[]) = {
"-nomidiout -- suppress MIDI output\n",
"-nomidi -- suppress MIDI input and output\n",
-"\ngeneral flags:\n",
+"\nother flags:\n",
"-path <path> -- add to file search path\n",
+"-helppath <path> -- add to help file search path\n",
"-open <file> -- open file(s) on startup\n",
"-lib <file> -- load object library(s)\n",
"-font <n> -- specify default font size in points\n",
@@ -331,7 +325,7 @@ static char *(usagemessage[]) = {
"-nogui -- suppress starting the GUI\n",
"-guicmd \"cmd...\" -- substitute another GUI program (e.g., rsh)\n",
"-send \"msg...\" -- send a message at startup (after patches are loaded)\n",
-#ifdef UNIX
+#ifdef __linux__
"-rt or -realtime -- use real-time priority (needs root privilege)\n",
#endif
};
@@ -359,18 +353,18 @@ static void sys_parsedevlist(int *np, int *vecp, int max, char *str)
static int sys_getmultidevchannels(int n, int *devlist)
{
- int sum = 0;
- if (n<0)return(-1);
- if (n==0)return 0;
- while(n--)sum+=*devlist++;
- return sum;
+ int sum = 0;
+ if (n<0)return(-1);
+ if (n==0)return 0;
+ while(n--)sum+=*devlist++;
+ return sum;
}
/* this routine tries to figure out where to find the auxilliary files
Pd will need to run. This is either done by looking at the command line
invokation for Pd, or if htat fails, by consulting the variable
- INSTALL_PREFIX. In NT, we don't try to use INSTALL_PREFIX. */
+ INSTALL_PREFIX. In MSW, we don't try to use INSTALL_PREFIX. */
void sys_findprogdir(char *progname)
{
char sbuf[MAXPDSTRING], sbuf2[MAXPDSTRING], *sp;
@@ -380,11 +374,11 @@ void sys_findprogdir(char *progname)
#endif
/* find out by what string Pd was invoked; put answer in "sbuf". */
-#ifdef NT
+#ifdef MSW
GetModuleFileName(NULL, sbuf2, sizeof(sbuf2));
sbuf2[MAXPDSTRING-1] = 0;
sys_unbashfilename(sbuf2, sbuf);
-#endif /* NT */
+#endif /* MSW */
#ifdef UNIX
strncpy(sbuf, progname, MAXPDSTRING);
sbuf[MAXPDSTRING-1] = 0;
@@ -424,7 +418,7 @@ void sys_findprogdir(char *progname)
.../lib/pd/bin/pd-gui
.../lib/pd/doc
To decide which, we stat .../lib/pd; if that exists, we assume it's
- the complicated layout. In NT, it's the "simple" layout, but
+ the complicated layout. In MSW, it's the "simple" layout, but
the gui program is straight wish80:
.../bin/pd
.../bin/wish80.exe
@@ -455,18 +449,15 @@ void sys_findprogdir(char *progname)
sys_guidir = gensym(sbuf);
}
#endif
-#ifdef NT
+#ifdef MSW
sys_libdir = gensym(sbuf2);
- sys_guidir = &s_; /* in NT the guipath just depends on the libdir */
+ sys_guidir = &s_; /* in MSW the guipath just depends on the libdir */
#endif
}
int sys_argparse(int argc, char **argv)
{
char sbuf[MAXPDSTRING];
-#ifdef NT
- int resync = -1;
-#endif
argc--; argv++;
while ((argc > 0) && **argv == '-')
{
@@ -526,26 +517,72 @@ int sys_argparse(int argc, char **argv)
argc -= 2; argv += 2;
}
else if (!strcmp(*argv, "-nodac"))
- { /* IOhannes */
- sys_nsoundout=0;
- sys_nchout = 0;
- outchannels =0;
- argc--; argv++;
+ { /* IOhannes */
+ sys_nsoundout=0;
+ sys_nchout = 0;
+ outchannels =0;
+ argc--; argv++;
}
else if (!strcmp(*argv, "-noadc"))
- { /* IOhannes */
- sys_nsoundin=0;
- sys_nchin = 0;
- inchannels =0;
- argc--; argv++;
+ { /* IOhannes */
+ sys_nsoundin=0;
+ sys_nchin = 0;
+ inchannels =0;
+ argc--; argv++;
}
else if (!strcmp(*argv, "-nosound") || !strcmp(*argv, "-noaudio"))
- { /* IOhannes */
- sys_nsoundin=sys_nsoundout = 0;
- sys_nchin = sys_nchout = 0;
- inchannels =outchannels =0;
- argc--; argv++;
+ { /* IOhannes */
+ sys_nsoundin=sys_nsoundout = 0;
+ sys_nchin = sys_nchout = 0;
+ inchannels =outchannels =0;
+ argc--; argv++;
}
+#ifdef USEAPI_OSS
+ else if (!strcmp(*argv, "-oss"))
+ {
+ sys_set_sound_api(API_OSS);
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-32bit"))
+ {
+ sys_set_sound_api(API_OSS);
+ oss_set32bit();
+ argc--; argv++;
+ }
+#endif
+#ifdef USEAPI_ALSA
+ else if (!strcmp(*argv, "-alsa"))
+ {
+ sys_set_sound_api(API_ALSA);
+ argc--; argv++;
+ }
+ else if (!strcmp(*argv, "-alsadev"))
+ {
+ if (argv[1][0] >= '1' && argv[1][0] <= '9')
+ {
+ char buf[80];
+ sprintf(buf, "hw:%d,0", atoi(argv[1]) - 1);
+ linux_alsa_devname(buf);
+ }
+ else linux_alsa_devname(argv[1]);
+ sys_set_sound_api(API_ALSA);
+ argc -= 2; argv +=2;
+ }
+#endif
+#ifdef USEAPI_PORTAUDIO
+ else if (!strcmp(*argv, "-pa") || !strcmp(*argv, "-portaudio"))
+ {
+ sys_set_sound_api(API_PORTAUDIO);
+ argc--; argv++;
+ }
+#endif
+#ifdef USEAPI_MMIO
+ else if (!strcmp(*argv, "-mmio"))
+ {
+ sys_set_sound_api(API_MMIO);
+ argc--; argv++;
+ }
+#endif
else if (!strcmp(*argv, "-nomidiin"))
{
sys_nmidiin = 0;
@@ -592,6 +629,11 @@ int sys_argparse(int argc, char **argv)
sys_addpath(argv[1]);
argc -= 2; argv += 2;
}
+ else if (!strcmp(*argv, "-helppath"))
+ {
+ sys_addhelppath(argv[1]);
+ argc -= 2; argv += 2;
+ }
else if (!strcmp(*argv, "-open") && argc > 1)
{
sys_openlist = namelist_append(sys_openlist, argv[1]);
@@ -650,80 +692,12 @@ int sys_argparse(int argc, char **argv)
argc--; argv++;
}
#ifdef UNIX
- else if (!strcmp(*argv, "-rt"))
- {
- sys_hipriority = 1;
- argc--; argv++;
- }
- else if (!strcmp(*argv, "-realtime"))
+ else if (!strcmp(*argv, "-rt") || !strcmp(*argv, "-realtime"))
{
sys_hipriority = 1;
argc--; argv++;
}
#endif
-#ifdef __linux__
- else if (!strcmp(*argv, "-frags"))
- {
- linux_setfrags(atoi(argv[1]));
- argc -= 2; argv += 2;
- }
- else if (!strcmp(*argv, "-fragsize"))
- {
- post("pd: -fragsize argument is obsolete; use '-blocksize %d'\n",
- (1 << atoi(argv[1])));
- sys_setblocksize(1 << atoi(argv[1]));
- argc -= 2; argv += 2;
- }
- else if (!strcmp(*argv, "-stream"))
- {
- linux_streammode();
- argc--; argv++;
- }
- else if (!strcmp(*argv, "-32bit"))
- {
- linux_32bit();
- argc--; argv++;
- }
-#ifdef ALSA01
- else if (!strcmp(*argv, "-alsa"))
- {
- linux_set_sound_api(API_ALSA);
- argc--; argv++;
- }
- else if (!strcmp(*argv, "-alsadev"))
- {
- if (argv[1][0] >= '1' && argv[1][0] <= '9')
- {
- char buf[80];
- sprintf(buf, "hw:%d,0", atoi(argv[1]) - 1);
- linux_alsa_devname(buf);
- }
- else linux_alsa_devname(argv[1]);
- linux_set_sound_api(API_ALSA);
- argc -= 2; argv +=2;
- }
-#endif
-#ifdef ALSA99
- else if (!strcmp(*argv, "-alsa"))
- {
- linux_set_sound_api(API_ALSA);
- argc--; argv++;
- }
- else if (!strcmp(*argv, "-alsadev"))
- {
- linux_alsa_devno(atoi(argv[1]));
- linux_set_sound_api(API_ALSA);
- argc -= 2; argv +=2;
- }
-#endif
-#ifdef RME_HAMMERFALL
- else if (!strcmp(*argv, "-rme"))
- {
- linux_set_sound_api(API_RME);
- argc--; argv++;
- }
-#endif
-#endif
else if (!strcmp(*argv, "-soundindev") ||
!strcmp(*argv, "-audioindev"))
{ /* IOhannes */
@@ -752,24 +726,6 @@ int sys_argparse(int argc, char **argv)
goto usage;
argc -= 2; argv += 2;
}
-#ifdef NT
- else if (!strcmp(*argv, "-asio"))
- {
- nt_set_sound_api(API_PORTAUDIO);
- argc--; argv++;
- }
- else if (!strcmp(*argv, "-noresync"))
- {
- resync = 0;
- argc--; argv++;
- }
- else if (!strcmp(*argv, "-resync"))
- {
- resync = 1;
- argc--; argv++;
- }
-
-#endif /* NT */
else
{
unsigned int i;
@@ -779,25 +735,17 @@ int sys_argparse(int argc, char **argv)
return (1);
}
}
-#ifdef NT
- /* resynchronization is on by default for mulltichannel, otherwise
- off. */
- if (resync == -1)
- resync = (inchannels > 2 || outchannels > 2);
- if (!resync)
- nt_noresync();
-#endif
- if (!sys_defaultfont) sys_defaultfont = DEFAULTFONT;
+ if (!sys_defaultfont)
+ sys_defaultfont = DEFAULTFONT;
for (; argc > 0; argc--, argv++)
sys_openlist = namelist_append(sys_openlist, *argv);
-
return (0);
}
int sys_getblksize(void)
{
- return (DACBLKSIZE);
+ return (DEFDACBLKSIZE);
}
static void sys_addextrapath(void)
@@ -810,3 +758,12 @@ static void sys_addextrapath(void)
sys_addpath(sbuf);
}
+static void sys_addreferencepath(void)
+{
+ char sbuf[MAXPDSTRING];
+ /* add "doc/5.reference" library to helppath */
+ strncpy(sbuf, sys_libdir->s_name, MAXPDSTRING-30);
+ sbuf[MAXPDSTRING-30] = 0;
+ strcat(sbuf, "/doc/5.reference");
+ sys_addhelppath(sbuf);
+}
diff --git a/pd/src/s_midi.c b/pd/src/s_midi.c
new file mode 100644
index 00000000..2bba9a45
--- /dev/null
+++ b/pd/src/s_midi.c
@@ -0,0 +1,405 @@
+/* Copyright (c) 1997-1999 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. */
+
+/* Clock functions (which should move, but where?) and MIDI queueing */
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include "m_imp.h"
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/time.h>
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#endif
+#ifdef MSW
+#include <winsock.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <wtypes.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+
+typedef struct _midiqelem
+{
+ double q_time;
+ int q_portno;
+ unsigned char q_onebyte;
+ unsigned char q_byte1;
+ unsigned char q_byte2;
+ unsigned char q_byte3;
+} t_midiqelem;
+
+#define MIDIQSIZE 1024
+
+t_midiqelem midi_outqueue[MIDIQSIZE];
+int midi_outhead, midi_outtail;
+t_midiqelem midi_inqueue[MIDIQSIZE];
+int midi_inhead, midi_intail;
+static double sys_midiinittime;
+
+ /* this is our current estimate for at what "system" real time the
+ current logical time's output should occur. */
+static double sys_dactimeminusrealtime;
+ /* same for input, should be schduler advance earlier. */
+static double sys_adctimeminusrealtime;
+
+static double sys_newdactimeminusrealtime = -1e20;
+static double sys_newadctimeminusrealtime = -1e20;
+static double sys_whenupdate;
+
+void sys_initmidiqueue( void)
+{
+ sys_midiinittime = clock_getlogicaltime();
+ sys_dactimeminusrealtime = sys_adctimeminusrealtime = 0;
+}
+
+ /* this is called from the OS dependent code from time to time when we
+ think we know the delay (outbuftime) in seconds, at which the last-output
+ audio sample will go out the door. */
+void sys_setmiditimediff(double inbuftime, double outbuftime)
+{
+ double dactimeminusrealtime =
+ .001 * clock_gettimesince(sys_midiinittime)
+ - outbuftime - sys_getrealtime();
+ double adctimeminusrealtime =
+ .001 * clock_gettimesince(sys_midiinittime)
+ + inbuftime - sys_getrealtime();
+ if (dactimeminusrealtime > sys_newdactimeminusrealtime)
+ sys_newdactimeminusrealtime = dactimeminusrealtime;
+ if (adctimeminusrealtime > sys_newadctimeminusrealtime)
+ sys_newadctimeminusrealtime = adctimeminusrealtime;
+ if (sys_getrealtime() > sys_whenupdate)
+ {
+ sys_dactimeminusrealtime = sys_newdactimeminusrealtime;
+ sys_adctimeminusrealtime = sys_newadctimeminusrealtime;
+ sys_newdactimeminusrealtime = -1e20;
+ sys_newadctimeminusrealtime = -1e20;
+ sys_whenupdate = sys_getrealtime() + 1;
+ }
+}
+
+ /* return the logical time of the DAC sample we believe is currently
+ going out, based on how much "system time" has elapsed since the
+ last time sys_setmiditimediff got called. */
+static double sys_getmidioutrealtime( void)
+{
+ return (sys_getrealtime() + sys_dactimeminusrealtime);
+}
+
+static double sys_getmidiinrealtime( void)
+{
+ return (sys_getrealtime() + sys_adctimeminusrealtime);
+}
+
+static void sys_putnext( void)
+{
+ int portno = midi_outqueue[midi_outtail].q_portno;
+ if (midi_outqueue[midi_outtail].q_onebyte)
+ sys_putmidibyte(portno, midi_outqueue[midi_outtail].q_byte1);
+ else sys_putmidimess(portno, midi_outqueue[midi_outtail].q_byte1,
+ midi_outqueue[midi_outtail].q_byte2,
+ midi_outqueue[midi_outtail].q_byte3);
+ midi_outtail = (midi_outtail + 1 == MIDIQSIZE ? 0 : midi_outtail + 1);
+}
+
+/* #define TEST_DEJITTER */
+
+void sys_pollmidioutqueue( void)
+{
+#ifdef TEST_DEJITTER
+ static int db = 0;
+#endif
+ double midirealtime = sys_getmidioutrealtime();
+#ifdef TEST_DEJITTER
+ if (midi_outhead == midi_outtail)
+ db = 0;
+#endif
+ while (midi_outhead != midi_outtail)
+ {
+#ifdef TEST_DEJITTER
+ if (!db)
+ {
+ post("out: del %f, midiRT %f logicaltime %f, RT %f dacminusRT %f",
+ (midi_outqueue[midi_outtail].q_time - midirealtime),
+ midirealtime, .001 * clock_gettimesince(sys_midiinittime),
+ sys_getrealtime(), sys_dactimeminusrealtime);
+ db = 1;
+ }
+#endif
+ if (midi_outqueue[midi_outtail].q_time <= midirealtime)
+ sys_putnext();
+ else break;
+ }
+}
+
+static void sys_queuemidimess(int portno, int onebyte, int a, int b, int c)
+{
+ t_midiqelem *midiqelem;
+ int newhead = midi_outhead +1;
+ if (newhead == MIDIQSIZE)
+ newhead = 0;
+ /* if FIFO is full flush an element to make room */
+ if (newhead == midi_outtail)
+ sys_putnext();
+ midi_outqueue[midi_outhead].q_portno = portno;
+ midi_outqueue[midi_outhead].q_onebyte = onebyte;
+ midi_outqueue[midi_outhead].q_byte1 = a;
+ midi_outqueue[midi_outhead].q_byte2 = b;
+ midi_outqueue[midi_outhead].q_byte3 = c;
+ midi_outqueue[midi_outhead].q_time =
+ .001 * clock_gettimesince(sys_midiinittime);
+ midi_outhead = newhead;
+ sys_pollmidioutqueue();
+}
+
+#define MIDI_NOTEON 144
+#define MIDI_POLYAFTERTOUCH 160
+#define MIDI_CONTROLCHANGE 176
+#define MIDI_PROGRAMCHANGE 192
+#define MIDI_AFTERTOUCH 208
+#define MIDI_PITCHBEND 224
+
+void outmidi_noteon(int portno, int channel, int pitch, int velo)
+{
+ if (pitch < 0) pitch = 0;
+ else if (pitch > 127) pitch = 127;
+ if (velo < 0) velo = 0;
+ else if (velo > 127) velo = 127;
+ sys_queuemidimess(portno, 0, MIDI_NOTEON + (channel & 0xf), pitch, velo);
+}
+
+void outmidi_controlchange(int portno, int channel, int ctl, int value)
+{
+ if (ctl < 0) ctl = 0;
+ else if (ctl > 127) ctl = 127;
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_CONTROLCHANGE + (channel & 0xf),
+ ctl, value);
+}
+
+void outmidi_programchange(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0,
+ MIDI_PROGRAMCHANGE + (channel & 0xf), value, 0);
+}
+
+void outmidi_pitchbend(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 16383) value = 16383;
+ sys_queuemidimess(portno, 0, MIDI_PITCHBEND + (channel & 0xf),
+ (value & 127), ((value>>7) & 127));
+}
+
+void outmidi_aftertouch(int portno, int channel, int value)
+{
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_AFTERTOUCH + (channel & 0xf), value, 0);
+}
+
+void outmidi_polyaftertouch(int portno, int channel, int pitch, int value)
+{
+ if (pitch < 0) pitch = 0;
+ else if (pitch > 127) pitch = 127;
+ if (value < 0) value = 0;
+ else if (value > 127) value = 127;
+ sys_queuemidimess(portno, 0, MIDI_POLYAFTERTOUCH + (channel & 0xf),
+ pitch, value);
+}
+
+void outmidi_mclk(int portno)
+{
+ sys_queuemidimess(portno, 1, 0xf8, 0,0);
+}
+
+/* ------------------------- MIDI input queue handling ------------------ */
+typedef struct midiparser
+{
+ int mp_status;
+ int mp_sysex;
+ int mp_gotbyte1;
+ int mp_byte1;
+} t_midiparser;
+
+#define MIDINOTEOFF 0x80
+#define MIDINOTEON 0x90
+#define MIDIPOLYTOUCH 0xa0
+#define MIDICONTROLCHANGE 0xb0
+#define MIDIPROGRAMCHANGE 0xc0
+#define MIDICHANNELTOUCH 0xd0
+#define MIDIPITCHBEND 0xe0
+ /* functions in x_midi.c */
+void inmidi_realtimein(int portno, int cmd);
+void inmidi_byte(int portno, int byte);
+void inmidi_sysex(int portno, int byte);
+void inmidi_noteon(int portno, int channel, int pitch, int velo);
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+void inmidi_programchange(int portno, int channel, int value);
+void inmidi_pitchbend(int portno, int channel, int value);
+void inmidi_aftertouch(int portno, int channel, int value);
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+
+static void sys_dispatchnextmidiin( void)
+{
+ static t_midiparser parser[MAXMIDIINDEV], *parserp;
+ int portno = midi_inqueue[midi_intail].q_portno,
+ byte = midi_inqueue[midi_intail].q_byte1;
+ if (!midi_inqueue[midi_intail].q_onebyte)
+ bug("sys_dispatchnextmidiin");
+ if (portno < 0 || portno >= MAXMIDIINDEV)
+ bug("sys_dispatchnextmidiin 2");
+ parserp = parser + portno;
+ outlet_setstacklim();
+
+ if (byte >= 0xf8)
+ inmidi_realtimein(portno, byte);
+ else
+ {
+ inmidi_byte(portno, byte);
+ if (byte < 0xf0)
+ {
+ if (byte & 0x80)
+ {
+ parserp->mp_status = byte;
+ parserp->mp_gotbyte1 = 0;
+ }
+ else
+ {
+ int cmd = (parserp->mp_status & 0xf0);
+ int chan = (parserp->mp_status & 0xf);
+ int byte1 = parserp->mp_byte1, gotbyte1 = parserp->mp_gotbyte1;
+ switch (cmd)
+ {
+ case MIDINOTEOFF:
+ if (gotbyte1)
+ inmidi_noteon(portno, chan, byte1, 0),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDINOTEON:
+ if (gotbyte1)
+ inmidi_noteon(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDIPOLYTOUCH:
+ if (gotbyte1)
+ inmidi_polyaftertouch(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDICONTROLCHANGE:
+ if (gotbyte1)
+ inmidi_controlchange(portno, chan, byte1, byte),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ case MIDIPROGRAMCHANGE:
+ inmidi_programchange(portno, chan, byte);
+ break;
+ case MIDICHANNELTOUCH:
+ inmidi_aftertouch(portno, chan, byte);
+ break;
+ case MIDIPITCHBEND:
+ if (gotbyte1)
+ inmidi_pitchbend(portno, chan, ((byte << 7) + byte1)),
+ parserp->mp_gotbyte1 = 0;
+ else parserp->mp_byte1 = byte, parserp->mp_gotbyte1 = 1;
+ break;
+ }
+ }
+ }
+ }
+ midi_intail = (midi_intail + 1 == MIDIQSIZE ? 0 : midi_intail + 1);
+}
+
+void sys_pollmidiinqueue( void)
+{
+#ifdef TEST_DEJITTER
+ static int db = 0;
+#endif
+ double logicaltime = .001 * clock_gettimesince(sys_midiinittime);
+#ifdef TEST_DEJITTER
+ if (midi_inhead == midi_intail)
+ db = 0;
+#endif
+ while (midi_inhead != midi_intail)
+ {
+#ifdef TEST_DEJITTER
+ if (!db)
+ {
+ post("in del %f, logicaltime %f, RT %f adcminusRT %f",
+ (midi_inqueue[midi_intail].q_time - logicaltime),
+ logicaltime, sys_getrealtime(), sys_adctimeminusrealtime);
+ db = 1;
+ }
+#endif
+#if 0
+ if (midi_inqueue[midi_intail].q_time <= logicaltime - 0.007)
+ post("late %f",
+ 1000 * (logicaltime - midi_inqueue[midi_intail].q_time));
+#endif
+ if (midi_inqueue[midi_intail].q_time <= logicaltime)
+ {
+#if 0
+ post("diff %f",
+ 1000* (logicaltime - midi_inqueue[midi_intail].q_time));
+#endif
+ sys_dispatchnextmidiin();
+ }
+ else break;
+ }
+}
+
+ /* this should be called from the system dependent MIDI code when a byte
+ comes in, as a result of our calling sys_poll_midi. We stick it on a
+ timetag queue and dispatch it at the appropriate logical time. */
+
+
+void sys_midibytein(int portno, int byte)
+{
+ static int warned = 0;
+ t_midiqelem *midiqelem;
+ int newhead = midi_inhead +1;
+ if (newhead == MIDIQSIZE)
+ newhead = 0;
+ /* if FIFO is full flush an element to make room */
+ if (newhead == midi_intail)
+ {
+ if (!warned)
+ {
+ post("warning: MIDI timing FIFO overflowed");
+ warned = 1;
+ }
+ sys_dispatchnextmidiin();
+ }
+ midi_inqueue[midi_inhead].q_portno = portno;
+ midi_inqueue[midi_inhead].q_onebyte = 1;
+ midi_inqueue[midi_inhead].q_byte1 = byte;
+ midi_inqueue[midi_inhead].q_time = sys_getmidiinrealtime();
+ midi_inhead = newhead;
+ sys_pollmidiinqueue();
+}
+
+void sys_pollmidiqueue( void)
+{
+#if 0
+ static double lasttime;
+ double newtime = sys_getrealtime();
+ if (newtime - lasttime > 0.007)
+ post("delay %d", (int)(1000 * (newtime - lasttime)));
+ lasttime = newtime;
+#endif
+ sys_poll_midi(); /* OS dependent poll for MIDI input */
+ sys_pollmidioutqueue();
+ sys_pollmidiinqueue();
+}
diff --git a/pd/src/s_midi_oss.c b/pd/src/s_midi_oss.c
new file mode 100644
index 00000000..9233f09a
--- /dev/null
+++ b/pd/src/s_midi_oss.c
@@ -0,0 +1,269 @@
+/* Copyright (c) 1997-1999 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* MIDI I/O for Linux using OSS */
+
+#include <stdio.h>
+#ifdef UNIX
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "m_pd.h"
+#include "s_stuff.h"
+
+static int oss_nmidiin;
+static int oss_midiinfd[MAXMIDIINDEV];
+static int oss_nmidiout;
+static int oss_midioutfd[MAXMIDIOUTDEV];
+
+static void oss_midiout(int fd, int n)
+{
+ char b = n;
+ if ((write(fd, (char *) &b, 1)) != 1)
+ perror("midi write");
+}
+
+#define O_MIDIFLAG O_NDELAY
+
+void sys_open_midi(int nmidiin, int *midiinvec, int nmidiout, int *midioutvec)
+{
+ int i;
+ for (i = 0; i < nmidiout; i++)
+ oss_midioutfd[i] = -1;
+ for (i = 0, oss_nmidiin = 0; i < nmidiin; i++)
+ {
+ int fd = -1, j, outdevindex = -1;
+ char namebuf[80];
+ int devno = midiinvec[i];
+
+ for (j = 0; j < nmidiout; j++)
+ if (midioutvec[j] == midiinvec[i])
+ outdevindex = j;
+
+ /* try to open the device for read/write. */
+ if (devno == 1 && fd < 0 && outdevindex >= 0)
+ {
+ sys_setalarm(1000000);
+ fd = open("/dev/midi", O_RDWR | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device 1: tried /dev/midi READ/WRITE; returned %d\n", fd);
+ if (outdevindex >= 0 && fd >= 0)
+ oss_midioutfd[outdevindex] = fd;
+ }
+ if (fd < 0 && outdevindex >= 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%2.2d", devno-1);
+ fd = open(namebuf, O_RDWR | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device %d: tried %s READ/WRITE; returned %d\n",
+ devno, namebuf, fd);
+ if (outdevindex >= 0 && fd >= 0)
+ oss_midioutfd[outdevindex] = fd;
+ }
+ if (fd < 0 && outdevindex >= 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%d", devno-1);
+ fd = open(namebuf, O_RDWR | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s READ/WRITE; returned %d\n",
+ devno, namebuf, fd);
+ if (outdevindex >= 0 && fd >= 0)
+ oss_midioutfd[outdevindex] = fd;
+ }
+ if (devno == 1 && fd < 0)
+ {
+ sys_setalarm(1000000);
+ fd = open("/dev/midi", O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device 1: tried /dev/midi READONLY; returned %d\n", fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%2.2d", devno-1);
+ fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%d", devno-1);
+ fd = open(namebuf, O_RDONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s READONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd >= 0)
+ oss_midiinfd[oss_nmidiin++] = fd;
+ else post("couldn't open MIDI input device %d", devno);
+ }
+ for (i = 0, oss_nmidiout = 0; i < nmidiout; i++)
+ {
+ int fd = oss_midioutfd[i];
+ char namebuf[80];
+ int devno = midioutvec[i];
+ if (devno == 1 && fd < 0)
+ {
+ sys_setalarm(1000000);
+ fd = open("/dev/midi", O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr,
+ "device 1: tried /dev/midi WRITEONLY; returned %d\n", fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%2.2d", devno-1);
+ fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd < 0)
+ {
+ sys_setalarm(1000000);
+ sprintf(namebuf, "/dev/midi%d", devno-1);
+ fd = open(namebuf, O_WRONLY | O_MIDIFLAG);
+ if (sys_verbose)
+ fprintf(stderr, "device %d: tried %s WRITEONLY; returned %d\n",
+ devno, namebuf, fd);
+ }
+ if (fd >= 0)
+ oss_midioutfd[oss_nmidiout++] = fd;
+ else post("couldn't open MIDI output device %d", devno);
+ }
+
+ if (oss_nmidiin < nmidiin || oss_nmidiout < nmidiout || sys_verbose)
+ post("opened %d MIDI input device(s) and %d MIDI output device(s).",
+ oss_nmidiin, oss_nmidiout);
+}
+
+#define md_msglen(x) (((x)<0xC0)?2:((x)<0xE0)?1:((x)<0xF0)?2:\
+ ((x)==0xF2)?2:((x)<0xF4)?1:0)
+
+void sys_putmidimess(int portno, int a, int b, int c)
+{
+ if (portno >= 0 && portno < oss_nmidiout)
+ {
+ switch (md_msglen(a))
+ {
+ case 2:
+ oss_midiout(oss_midioutfd[portno],a);
+ oss_midiout(oss_midioutfd[portno],b);
+ oss_midiout(oss_midioutfd[portno],c);
+ return;
+ case 1:
+ oss_midiout(oss_midioutfd[portno],a);
+ oss_midiout(oss_midioutfd[portno],b);
+ return;
+ case 0:
+ oss_midiout(oss_midioutfd[portno],a);
+ return;
+ };
+ }
+}
+
+void sys_putmidibyte(int portno, int byte)
+{
+ if (portno >= 0 && portno < oss_nmidiout)
+ oss_midiout(oss_midioutfd[portno], byte);
+}
+
+#if 0 /* this is the "select" version which doesn't work with OSS
+ driver for emu10k1 (it doesn't implement select.) */
+void sys_poll_midi(void)
+{
+ int i, throttle = 100;
+ struct timeval timout;
+ int did = 1, maxfd = 0;
+ while (did)
+ {
+ fd_set readset, writeset, exceptset;
+ did = 0;
+ if (throttle-- < 0)
+ break;
+ timout.tv_sec = 0;
+ timout.tv_usec = 0;
+
+ FD_ZERO(&writeset);
+ FD_ZERO(&readset);
+ FD_ZERO(&exceptset);
+ for (i = 0; i < oss_nmidiin; i++)
+ {
+ if (oss_midiinfd[i] > maxfd)
+ maxfd = oss_midiinfd[i];
+ FD_SET(oss_midiinfd[i], &readset);
+ }
+ select(maxfd+1, &readset, &writeset, &exceptset, &timout);
+ for (i = 0; i < oss_nmidiin; i++)
+ if (FD_ISSET(oss_midiinfd[i], &readset))
+ {
+ char c;
+ int ret = read(oss_midiinfd[i], &c, 1);
+ if (ret <= 0)
+ fprintf(stderr, "Midi read error\n");
+ else sys_midibytein(i, (c & 0xff));
+ did = 1;
+ }
+ }
+}
+#else
+
+ /* this version uses the asynchronous "read()" ... */
+void sys_poll_midi(void)
+{
+ int i, throttle = 100;
+ struct timeval timout;
+ int did = 1, maxfd = 0;
+ while (did)
+ {
+ fd_set readset, writeset, exceptset;
+ did = 0;
+ if (throttle-- < 0)
+ break;
+ for (i = 0; i < oss_nmidiin; i++)
+ {
+ char c;
+ int ret = read(oss_midiinfd[i], &c, 1);
+ if (ret < 0)
+ {
+ if (errno != EAGAIN)
+ perror("MIDI");
+ }
+ else if (ret != 0)
+ {
+ sys_midibytein(i, (c & 0xff));
+ did = 1;
+ }
+ }
+ }
+}
+#endif
+
+void sys_close_midi()
+{
+ int i;
+ for (i = 0; i < oss_nmidiin; i++)
+ close(oss_midiinfd[i]);
+ for (i = 0; i < oss_nmidiout; i++)
+ close(oss_midioutfd[i]);
+ oss_nmidiin = oss_nmidiout = 0;
+}
+
+void sys_listmididevs(void)
+{
+ /* LATER figure out how to detect MIDI devs */
+}
diff --git a/pd/src/s_midi_pm.c b/pd/src/s_midi_pm.c
new file mode 100644
index 00000000..afd8ad1a
--- /dev/null
+++ b/pd/src/s_midi_pm.c
@@ -0,0 +1,166 @@
+/* Copyright (c) 1997-2003 Guenter Geiger, Miller Puckette, Larry Troxler,
+* Winfried Ritsch, Karl MacMillan, and others.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
+
+ this file calls portmidi to do MIDI I/O for MSW and Mac OSX.
+
+*/
+
+#include "m_pd.h"
+#include "s_stuff.h"
+#include <stdio.h>
+#ifdef UNIX
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "portaudio.h"
+#include "portmidi.h"
+#include "porttime.h"
+#include "pminternal.h"
+
+static PmStream *mac_midiindevlist[MAXMIDIINDEV];
+static PmStream *mac_midioutdevlist[MAXMIDIOUTDEV];
+static int mac_nmidiindev;
+static int mac_nmidioutdev;
+
+void sys_open_midi(int nmidiin, int *midiinvec,
+ int nmidiout, int *midioutvec)
+{
+ int i = 0;
+ int n = 0;
+ PmError err;
+
+ Pt_Start(1, 0, 0); /* start a timer with millisecond accuracy */
+ mac_nmidiindev = 0;
+
+ /* protect the unwary from having MIDI inputs open; they're
+ bad news if you close Pd's terminal window. see sys_nmidiin
+ in s_main.c too. */
+#ifdef MSW
+ if (nmidiin)
+ {
+ post(
+ "midi input enabled; warning, don't close the DOS window directly!");
+ }
+ else post("not using MIDI input (use 'pd -midiindev 1' to override)");
+#endif
+
+ for (i = 0; i < nmidiin; i++)
+ {
+ if (midiinvec[i] == DEFMIDIDEV)
+ midiinvec[i] = Pm_GetDefaultInputDeviceID();
+ err = Pm_OpenInput(&mac_midiindevlist[mac_nmidiindev], midiinvec[i],
+ NULL, 100, NULL, NULL, NULL);
+ if (err)
+ post("could not open midi input device number %d: %s",
+ midiinvec[i], Pm_GetErrorText(err));
+ else
+ {
+ if (sys_verbose)
+ post("Midi Input opened.\n");
+ mac_nmidiindev++;
+ }
+ }
+
+ mac_nmidioutdev = 0;
+ for (i = 0; i < nmidiout; i++)
+ {
+ if (midioutvec[i] == DEFMIDIDEV)
+ midioutvec[i] = Pm_GetDefaultOutputDeviceID();
+ err = Pm_OpenOutput(&mac_midioutdevlist[mac_nmidioutdev], midioutvec[i],
+ NULL, 0, NULL, NULL, 0);
+ if (err)
+ post("could not open midi output device number %d: %s",
+ midioutvec[i], Pm_GetErrorText(err));
+ else
+ {
+ if (sys_verbose)
+ post("Midi Output opened.\n");
+ mac_nmidioutdev++;
+ }
+ }
+}
+
+void sys_close_midi( void)
+{
+ int i;
+ for (i = 0; i < mac_nmidiindev; i++)
+ Pm_Close(mac_midiindevlist[mac_nmidiindev]);
+ mac_nmidiindev = 0;
+ for (i = 0; i < mac_nmidioutdev; i++)
+ Pm_Close(mac_midioutdevlist[mac_nmidioutdev]);
+ mac_nmidioutdev = 0;
+}
+
+void sys_putmidimess(int portno, int a, int b, int c)
+{
+ PmEvent buffer;
+ fprintf(stderr, "put 1 msg %d %d\n", portno, mac_nmidioutdev);
+ if (portno >= 0 && portno < mac_nmidioutdev)
+ {
+ buffer.message = Pm_Message(a, b, c);
+ buffer.timestamp = 0;
+ fprintf(stderr, "put msg\n");
+ Pm_Write(mac_midioutdevlist[portno], &buffer, 1);
+ }
+}
+
+void sys_putmidibyte(int portno, int byte)
+{
+ post("sorry, no byte-by-byte MIDI output implemented in MAC OSX");
+}
+
+void sys_poll_midi(void)
+{
+ int i, nmess;
+ PmEvent buffer;
+ for (i = 0; i < mac_nmidiindev; i++)
+ {
+ int nmess = Pm_Read(mac_midiindevlist[i], &buffer, 1);
+ if (nmess > 0)
+ {
+ int status = Pm_MessageStatus(buffer.message);
+ int data1 = Pm_MessageData1(buffer.message);
+ int data2 = Pm_MessageData2(buffer.message);
+ int msgtype = (status >> 4) - 8;
+ switch (msgtype)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 6:
+ sys_midibytein(i, status);
+ sys_midibytein(i, data1);
+ sys_midibytein(i, data2);
+ break;
+ case 4:
+ case 5:
+ sys_midibytein(i, status);
+ sys_midibytein(i, data1);
+ break;
+ case 7:
+ sys_midibytein(i, status);
+ break;
+ }
+ }
+ }
+}
+
+void sys_listmididevs(void) /* lifted from pa_devs.c in portaudio */
+{
+ int i,j;
+ for (i = 0; i < Pm_CountDevices(); i++)
+ {
+ const PmDeviceInfo *info = Pm_GetDeviceInfo(i);
+ printf("%d: %s, %s", i, info->interf, info->name);
+ if (info->input) printf(" (input)");
+ if (info->output) printf(" (output)");
+ printf("\n");
+ }
+}
diff --git a/pd/src/s_midi_sgi.c b/pd/src/s_midi_sgi.c
new file mode 100644
index 00000000..7e58dbe3
--- /dev/null
+++ b/pd/src/s_midi_sgi.c
@@ -0,0 +1,188 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+#include "s_stuff.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef HAVE_BSTRING_H
+#include <bstring.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <dmedia/audio.h>
+#include <sys/fpu.h>
+#include <dmedia/midi.h>
+int mdInit(void); /* prototype was messed up in midi.h */
+/* #include "sys/select.h" */
+
+
+ /*
+ set the special "flush zero" but (FS, bit 24) in the
+ Control Status Register of the FPU of R4k and beyond
+ so that the result of any underflowing operation will
+ be clamped to zero, and no exception of any kind will
+ be generated on the CPU.
+
+ thanks to cpirazzi@cp.esd.sgi.com (Chris Pirazzi).
+ */
+
+static void sgi_flush_all_underflows_to_zero(void)
+{
+ union fpc_csr f;
+ f.fc_word = get_fpc_csr();
+ f.fc_struct.flush = 1;
+ set_fpc_csr(f.fc_word);
+}
+
+#define NPORT 2
+
+static MDport sgi_inport[NPORT];
+static MDport sgi_outport[NPORT];
+
+void sgi_open_midi(int midiin, int midiout)
+{
+ int i;
+ int sgi_nports = mdInit();
+ if (sgi_nports < 0) sgi_nports = 0;
+ else if (sgi_nports > NPORT) sgi_nports = NPORT;
+ if (sys_verbose)
+ {
+ if (!sgi_nports)
+ {
+ post("no serial ports are configured for MIDI;");
+ post("if you want to use MIDI, try exiting Pd, typing");
+ post("'startmidi -d /dev/ttyd2' to a shell, and restarting Pd.");
+ }
+ else if (sgi_nports == 1)
+ post("Found one MIDI port on %s", mdGetName(0));
+ else if (sgi_nports == 2)
+ post("Found MIDI ports on %s and %s",
+ mdGetName(0), mdGetName(1));
+ }
+ if (midiin)
+ {
+ for (i = 0; i < sgi_nports; i++)
+ {
+ if (!(sgi_inport[i] = mdOpenInPort(mdGetName(i))))
+ error("MIDI input port %d: open failed", i+1);;
+ }
+ }
+ if (midiout)
+ {
+ for (i = 0; i < sgi_nports; i++)
+ {
+ if (!(sgi_outport[i] = mdOpenOutPort(mdGetName(i))))
+ error("MIDI output port %d: open failed", i+1);;
+ }
+ }
+ return;
+}
+
+void sys_putmidimess(int portno, int a, int b, int c)
+{
+ MDevent mdv;
+ if (portno >= NPORT || portno < 0 || !sgi_outport[portno]) return;
+ mdv.msg[0] = a;
+ mdv.msg[1] = b;
+ mdv.msg[2] = c;
+ mdv.msg[3] = 0;
+ mdv.sysexmsg = 0;
+ mdv.stamp = 0;
+ mdv.msglen = 0;
+ if (mdSend(sgi_outport[portno], &mdv, 1) < 0)
+ error("MIDI output error\n");
+ post("msg out %d %d %d", a, b, c);
+}
+
+void sys_putmidibyte(int portno, int foo)
+{
+ error("MIDI raw byte output not available on SGI");
+}
+
+void inmidi_noteon(int portno, int channel, int pitch, int velo);
+void inmidi_controlchange(int portno, int channel, int ctlnumber, int value);
+void inmidi_programchange(int portno, int channel, int value);
+void inmidi_pitchbend(int portno, int channel, int value);
+void inmidi_aftertouch(int portno, int channel, int value);
+void inmidi_polyaftertouch(int portno, int channel, int pitch, int value);
+
+void sys_poll_midi(void)
+{
+ int i;
+ MDport *mp;
+ for (i = 0, mp = sgi_inport; i < NPORT; i++, mp++)
+ {
+ int ret, status, b1, b2, nfds;
+ MDevent mdv;
+ fd_set inports;
+ struct timeval timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ if (!*mp) continue;
+ FD_ZERO(&inports);
+ FD_SET(mdGetFd(*mp), &inports);
+
+ if (select(mdGetFd(*mp)+1 , &inports, 0, 0, &timeout) < 0)
+ perror("midi select");
+ if (FD_ISSET(mdGetFd(*mp),&inports))
+ {
+ if (mdReceive(*mp, &mdv, 1) < 0)
+ error("failure receiving message\n");
+ else if (mdv.msg[0] == MD_SYSEX) mdFree(mdv.sysexmsg);
+
+ else
+ {
+ int status = mdv.msg[0];
+ int channel = (status & 0xf) + 1;
+ int b1 = mdv.msg[1];
+ int b2 = mdv.msg[2];
+ switch(status & 0xf0)
+ {
+ case MD_NOTEOFF:
+ inmidi_noteon(i, channel, b1, 0);
+ break;
+ case MD_NOTEON:
+ inmidi_noteon(i, channel, b1, b2);
+ break;
+ case MD_POLYKEYPRESSURE:
+ inmidi_polyaftertouch(i, channel, b1, b2);
+ break;
+ case MD_CONTROLCHANGE:
+ inmidi_controlchange(i, channel, b1, b2);
+ break;
+ case MD_PITCHBENDCHANGE:
+ inmidi_pitchbend(i, channel, ((b2 << 7) + b1));
+ break;
+ case MD_PROGRAMCHANGE:
+ inmidi_programchange(i, channel, b1);
+ break;
+ case MD_CHANNELPRESSURE:
+ inmidi_aftertouch(i, channel, b1);
+ break;
+ }
+ }
+ }
+ }
+}
+
+void sys_open_midi(int nmidiin, int *midiinvec,
+ int nmidiout, int *midioutvec)
+{
+ sgi_open_midi(nmidiin!=0, nmidiout!=0);
+}
+
+
+void sys_close_midi( void)
+{
+ /* ??? */
+}
+
+void sys_set_priority(int foo)
+{
+ fprintf(stderr,
+ "warning: priority boosting in IRIX not implemented yet\n");
+}
diff --git a/pd/src/s_path.c b/pd/src/s_path.c
index a61956f1..58d33db7 100644
--- a/pd/src/s_path.c
+++ b/pd/src/s_path.c
@@ -19,16 +19,18 @@ void readsf_banana( void); /* debugging */
#include <unistd.h>
#include <sys/stat.h>
#endif
-#ifdef NT
+#ifdef MSW
#include <io.h>
#endif
#include <string.h>
+#include "m_pd.h"
#include "m_imp.h"
+#include "s_stuff.h"
#include <stdio.h>
#include <fcntl.h>
-static t_namelist *pd_path;
+static t_namelist *pd_path, *pd_helppath;
/* Utility functions */
@@ -51,7 +53,7 @@ static const char* strtokcpy(char *to, const char *from, int delim)
/* add a colon-separated list of names to a namelist */
-#ifdef NT
+#ifdef MSW
#define SEPARATOR ';'
#else
#define SEPARATOR ':'
@@ -110,15 +112,20 @@ void sys_addpath(const char *p)
pd_path = namelist_append(pd_path, p);
}
-#ifdef NT
-#define NTOPENFLAG (bin ? _O_BINARY : _O_TEXT)
+void sys_addhelppath(const char *p)
+{
+ pd_helppath = namelist_append(pd_helppath, p);
+}
+
+#ifdef MSW
+#define MSWOPENFLAG(bin) (bin ? _O_BINARY : _O_TEXT)
#else
-#define NTOPENFLAG 0
+#define MSWOPENFLAG(bin) 0
#endif
/* search for a file in a specified directory, then along the globally
defined search path, using ext as filename extension. Exception:
-if the 'name' starts with a slash or a letter, colon, and slash in NT,
+if the 'name' starts with a slash or a letter, colon, and slash in MSW,
there is no search and instead we just try to open the file literally. The
fd is returned, the directory ends up in the "dirresult" which must be at
least "size" bytes. "nameresult" is set to point to the filename, which
@@ -132,7 +139,7 @@ int open_via_path(const char *dir, const char *name, const char* ext,
char listbuf[MAXPDSTRING];
if (name[0] == '/'
-#ifdef NT
+#ifdef MSW
|| (name[1] == ':' && name[2] == '/')
#endif
)
@@ -149,6 +156,7 @@ int open_via_path(const char *dir, const char *name, const char* ext,
listbuf[MAXPDSTRING-1] = 0;
sys_unbashfilename(listbuf, listbuf);
}
+
for (nl = &thislist; nl; nl = nl->nl_next)
{
if (strlen(nl->nl_string) + strlen(name) + strlen(ext) + 4 >
@@ -163,7 +171,7 @@ int open_via_path(const char *dir, const char *name, const char* ext,
DEBUG(post("looking for %s",dirresult));
/* see if we can open the file for reading */
- if ((fd=open(dirresult,O_RDONLY | NTOPENFLAG)) >= 0)
+ if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(bin))) >= 0)
{
/* in UNIX, further check that it's not a directory */
#ifdef UNIX
@@ -204,9 +212,77 @@ int open_via_path(const char *dir, const char *name, const char* ext,
return (-1);
}
-/* Startup file reading for linux */
+ /* LATER make this use open_via_path above. */
+void open_via_helppath(const char *name, const char *dir)
+{
+ t_namelist *nl, thislist, *listp;
+ int fd = -1;
+ char dirresult[MAXPDSTRING], realdir[MAXPDSTRING], dirbuf2[MAXPDSTRING],
+ realname[MAXPDSTRING];
+
+ /* if directory is supplied, put it at head of search list. */
+ if (*dir)
+ {
+ thislist.nl_string = dirbuf2;
+ thislist.nl_next = pd_helppath;
+ strncpy(dirbuf2, dir, MAXPDSTRING);
+ dirbuf2[MAXPDSTRING-1] = 0;
+ sys_unbashfilename(dirbuf2, dirbuf2);
+ listp = &thislist;
+ }
+ else listp = pd_helppath;
+ strcpy(realname, "help-");
+ strncat(realname, name, MAXPDSTRING-5);
+ realname[MAXPDSTRING-1] = 0;
+ for (nl = listp; nl; nl = nl->nl_next)
+ {
+ strcpy(dirresult, nl->nl_string);
+ strcpy(realdir,dirresult);
+ if (*dirresult && dirresult[strlen(dirresult)-1] != '/')
+ strcat(dirresult, "/");
+ strcat(dirresult, realname);
+ sys_bashfilename(dirresult, dirresult);
-#ifdef __linux__
+ DEBUG(post("looking for %s",dirresult));
+ /* see if we can open the file for reading */
+ if ((fd=open(dirresult,O_RDONLY | MSWOPENFLAG(0))) >= 0)
+ {
+ /* in UNIX, further check that it's not a directory */
+#ifdef UNIX
+ struct stat statbuf;
+ int ok = ((fstat(fd, &statbuf) >= 0) &&
+ !S_ISDIR(statbuf.st_mode));
+ if (!ok)
+ {
+ if (sys_verbose) post("tried %s; stat failed or directory",
+ dirresult);
+ close (fd);
+ fd = -1;
+ }
+ else
+#endif
+ {
+ char *slash;
+ if (sys_verbose) post("tried %s and succeeded", dirresult);
+ sys_unbashfilename(dirresult, dirresult);
+ close (fd);
+ glob_evalfile(0, gensym((char*)realname), gensym(realdir));
+ return;
+ }
+ }
+ else
+ {
+ if (sys_verbose) post("tried %s and failed", dirresult);
+ }
+ }
+ post("sorry, couldn't find help for \"%s\"", name);
+ return;
+}
+
+
+/* Startup file reading for linux and MACOSX */
+
+#ifdef UNIX
#define STARTUPNAME ".pdrc"
#define NUMARGS 1000
@@ -274,6 +350,6 @@ int sys_rcfile(void)
}
return (0);
}
-#endif /* __linux__ */
+#endif /* UNIX */
diff --git a/pd/src/s_stuff.h b/pd/src/s_stuff.h
new file mode 100644
index 00000000..c8ac47f8
--- /dev/null
+++ b/pd/src/s_stuff.h
@@ -0,0 +1,179 @@
+/* Copyright (c) 1997-1999 Miller Puckette.
+* For information on usage and redistribution, and for a DISCLAIMER OF ALL
+* WARRANTIES, see the file, "LICENSE.txt," in this distribution. */
+
+/* Audio and MIDI I/O, and other scheduling and system stuff. */
+
+/* NOTE: this file describes Pd implementation details which may change
+in future releases. The public (stable) API is in m_pd.h. */
+
+/* in s_file.c */
+typedef struct _namelist
+{
+ struct _namelist *nl_next;
+ char *nl_string;
+} t_namelist;
+
+t_namelist *namelist_append(t_namelist *listwas, const char *s);
+void namelist_free(t_namelist *listwas);
+
+/* s_main.c */
+extern int sys_debuglevel;
+extern int sys_verbose;
+extern int sys_noloadbang;
+extern int sys_nogui;
+extern char *sys_guicmd;
+
+EXTERN int sys_nearestfontsize(int fontsize);
+EXTERN int sys_hostfontsize(int fontsize);
+
+extern int sys_defaultfont;
+extern t_symbol *sys_libdir; /* library directory for auxilliary files */
+
+/* s_loader.c */
+int sys_load_lib(char *dirname, char *filename);
+
+/* s_audio.c */
+
+#define SENDDACS_NO 0 /* return values for sys_send_dacs() */
+#define SENDDACS_YES 1
+#define SENDDACS_SLEPT 2
+
+#define DEFDACBLKSIZE 64
+extern int sys_schedblocksize; /* audio block size for scheduler */
+extern int sys_hipriority; /* real-time flag, true if priority boosted */
+extern t_sample *sys_soundout;
+extern t_sample *sys_soundin;
+extern int sys_inchannels;
+extern int sys_outchannels;
+extern int sys_advance_samples; /* scheduler advance in samples */
+extern int sys_blocksize; /* audio I/O block size in sample frames */
+extern float sys_dacsr;
+extern int sys_schedadvance;
+extern int sys_sleepgrain;
+void sys_open_audio(int naudioindev, int *audioindev,
+ int nchindev, int *chindev,
+ int naudiooutdev, int *audiooutdev, int nchoutdev, int *choutdev,
+ int srate); /* IOhannes */
+void sys_close_audio(void);
+
+void sys_open_midi(int nmidiin, int *midiinvec,
+ int nmidiout, int *midioutvec);
+void sys_close_midi(void);
+
+int sys_send_dacs(void);
+void sys_reportidle(void);
+void sys_set_priority(int higher);
+void sys_audiobuf(int nbufs);
+void sys_getmeters(float *inmax, float *outmax);
+void sys_listdevs(void);
+void sys_setblocksize(int n);
+
+/* s_midi.c */
+#define MAXMIDIINDEV 16 /* max. number of input ports */
+#define MAXMIDIOUTDEV 16 /* max. number of output ports */
+extern int sys_nmidiin;
+extern int sys_nmidiout;
+extern int sys_midiindevlist[];
+extern int sys_midioutdevlist[];
+
+EXTERN void sys_putmidimess(int portno, int a, int b, int c);
+EXTERN void sys_putmidibyte(int portno, int a);
+EXTERN void sys_poll_midi(void);
+EXTERN void sys_setmiditimediff(double inbuftime, double outbuftime);
+EXTERN void sys_midibytein(int portno, int byte);
+
+/* m_sched.c */
+EXTERN void sys_log_error(int type);
+#define ERR_NOTHING 0
+#define ERR_ADCSLEPT 1
+#define ERR_DACSLEPT 2
+#define ERR_RESYNC 3
+#define ERR_DATALATE 4
+
+/* s_inter.c */
+
+EXTERN void sys_microsleep(int microsec);
+
+EXTERN void sys_bail(int exitcode);
+EXTERN int sys_pollgui(void);
+
+EXTERN_STRUCT _socketreceiver;
+#define t_socketreceiver struct _socketreceiver
+
+typedef void (*t_socketnotifier)(void *x);
+typedef void (*t_socketreceivefn)(void *x, t_binbuf *b);
+
+EXTERN t_socketreceiver *socketreceiver_new(void *owner,
+ t_socketnotifier notifier, t_socketreceivefn socketreceivefn, int udp);
+EXTERN void socketreceiver_read(t_socketreceiver *x, int fd);
+EXTERN void sys_sockerror(char *s);
+EXTERN void sys_closesocket(int fd);
+
+typedef void (*t_fdpollfn)(void *ptr, int fd);
+EXTERN void sys_addpollfn(int fd, t_fdpollfn fn, void *ptr);
+EXTERN void sys_rmpollfn(int fd);
+#ifdef UNIX
+void sys_setalarm(int microsec);
+void sys_setvirtualalarm( void);
+#endif
+
+#define API_ALSA 1
+#define API_OSS 2
+#define API_MMIO 3
+#define API_PORTAUDIO 4
+
+#ifdef __linux__
+#define API_DEFAULT API_OSS
+#define API_DEFSTRING "OSS"
+#endif
+#ifdef MSW
+#define API_DEFAULT API_MMIO
+#define API_DEFSTRING "MMIO"
+#endif
+#ifdef MACOSX
+#define API_DEFAULT API_PORTAUDIO
+#define API_DEFSTRING "portaudio"
+#endif
+#define DEFAULTAUDIODEV -1
+
+#define DEFMIDIDEV -1
+
+int pa_open_audio(int inchans, int outchans, int rate, t_sample *soundin,
+ t_sample *soundout, int framesperbuf, int nbuffers,
+ int indeviceno, int outdeviceno);
+void pa_close_audio(void);
+int pa_send_dacs(void);
+void sys_reportidle(void);
+void pa_listdevs(void);
+
+int oss_open_audio(int naudioindev, int *audioindev, int nchindev,
+ int *chindev, int naudiooutdev, int *audiooutdev, int nchoutdev,
+ int *choutdev, int rate); /* IOhannes */
+void oss_close_audio(void);
+int oss_send_dacs(void);
+void oss_reportidle(void);
+void oss_listdevs(void);
+
+int alsa_open_audio(int wantinchans, int wantoutchans, int srate);
+void alsa_close_audio(void);
+int alsa_send_dacs(void);
+void alsa_reportidle(void);
+void alsa_listdevs(void);
+
+void mmio_open_audio(int naudioindev, int *audioindev,
+ int nchindev, int *chindev, int naudiooutdev, int *audiooutdev,
+ int nchoutdev, int *choutdev, int rate);
+void mmio_close_audio( void);
+void mmio_reportidle(void);
+int mmio_send_dacs(void);
+void mmio_listdevs(void);
+
+void sys_listmididevs(void);
+void sys_set_sound_api(int whichapi);
+extern int sys_audioapi;
+
+/* API dependent audio flags and settings */
+void oss_set32bit( void);
+void linux_alsa_devname(char *devname);
+
diff --git a/pd/src/t_tkcmd.c b/pd/src/t_tkcmd.c
index a862beda..ff12a284 100644
--- a/pd/src/t_tkcmd.c
+++ b/pd/src/t_tkcmd.c
@@ -23,17 +23,17 @@
#include <sys/time.h>
#include <errno.h>
#endif
-#ifdef NT
+#ifdef MSW
#include <winsock.h>
#include <io.h>
#endif
-#ifdef NT
+#ifdef MSW
#pragma warning( disable : 4305 ) /* uncast const double to float */
#pragma warning( disable : 4244 ) /* uncast double to float */
#pragma warning( disable : 4101 ) /* unused local variables */
#endif
-#ifdef NT
+#ifdef MSW
#include "tk.h"
#endif
@@ -66,7 +66,7 @@ void pdgui_sethost(char *name)
static void pdgui_sockerror(char *s)
{
-#ifdef NT
+#ifdef MSW
int err = WSAGetLastError();
#endif
#ifdef UNIX
@@ -173,7 +173,7 @@ void pdgui_setupsocket(void)
#else
int retry = 1;
#endif
-#ifdef NT
+#ifdef MSW
short version = MAKEWORD(2, 0);
WSADATA nobby;
@@ -345,16 +345,16 @@ void pdgui_startup(Tcl_Interp *interp)
/* add our own TK commands */
- Tcl_CreateCommand(interp, "pd", pdCmd, (ClientData)NULL,
+ Tcl_CreateCommand(interp, "pd", (Tcl_CmdProc*)pdCmd, (ClientData)NULL,
(Tcl_CmdDeleteProc *)NULL);
#ifndef UNIX
- Tcl_CreateCommand(interp, "pd_pollsocket", pd_pollsocketCmd,
+ Tcl_CreateCommand(interp, "pd_pollsocket",(Tcl_CmdProc*) pd_pollsocketCmd,
(ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
#endif
pdgui_setupsocket();
/* read in the startup file */
-#if !defined(NT) && !defined(MACOSX)
+#if !defined(MSW) && !defined(MACOSX)
pdgui_evalfile("pd.tk");
#endif
}
diff --git a/pd/src/u_main.tk b/pd/src/u_main.tk
index 9af14282..b879843a 100644
--- a/pd/src/u_main.tk
+++ b/pd/src/u_main.tk
@@ -14,19 +14,26 @@ set pd_nt 0
#
# all this changes are labeled with #######iemlib##########
+# Tearoff is set to true by default:
+set pd_tearoff 1
+
if {$pd_nt == 1} {
global pd_guidir
+ global pd_tearoff
set pd_gui2 [string range $argv0 0 [expr [string last \\ $argv0 ] - 1]]
regsub -all \\\\ $pd_gui2 / pd_gui3
set pd_guidir $pd_gui3/..
load $pd_guidir/bin/pdtcl
+ set pd_tearoff 1
}
if {$pd_nt == 2} {
global pd_guidir
+ global pd_tearoff
set pd_gui2 [string range $argv0 0 [expr [string last / $argv0 ] - 1]]
set pd_guidir $pd_gui2/..
load $pd_guidir/bin/pdtcl
+ set pd_tearoff 0
}
# it's unfortunate but we seem to have to turn off global bindings
@@ -40,22 +47,27 @@ bind Text <Control-s> {}
# puts stderr [bind all]
################## set up main window #########################
-frame .mbar -relief raised -bd 2
-canvas .dummy -height 1c -width 1c
+menu .mbar
+canvas .dummy -height 2p -width 9c
+
frame .controls
-pack .mbar .controls .dummy -side top -fill x
-menubutton .mbar.file -text File -menu .mbar.file.menu
-menubutton .mbar.find -text Find -menu .mbar.find.menu
-menubutton .mbar.windows -text Windows -menu .mbar.windows.menu
-menubutton .mbar.audio -text Audio -menu .mbar.audio.menu
-menubutton .mbar.help -text Help -menu .mbar.help.menu
-pack .mbar.file .mbar.find .mbar.windows .mbar.audio -side left
-pack .mbar.help -side right
-menu .mbar.file.menu
-menu .mbar.find.menu
-menu .mbar.windows.menu -postcommand [concat pdtk_fixwindowmenu]
-menu .mbar.audio.menu
-menu .mbar.help.menu
+pack .controls .dummy -side top -fill x
+menu .mbar.file -tearoff $pd_tearoff
+.mbar add cascade -label "File" -menu .mbar.file
+menu .mbar.find -tearoff $pd_tearoff
+.mbar add cascade -label "Find" -menu .mbar.find
+menu .mbar.windows -postcommand [concat pdtk_fixwindowmenu] -tearoff $pd_tearoff
+menu .mbar.audio -tearoff $pd_tearoff
+if {$pd_nt != 2} {
+ .mbar add cascade -label "Windows" -menu .mbar.windows
+ .mbar add cascade -label "Audio" -menu .mbar.audio
+} else {
+# Perhaps this is silly, but Mac HIG want "Window Help" as the last menus
+ .mbar add cascade -label "Audio" -menu .mbar.audio
+ .mbar add cascade -label "Window" -menu .mbar.windows
+}
+menu .mbar.help -tearoff $pd_tearoff
+.mbar add cascade -label "Help" -menu .mbar.help
set ctrls_audio_on 0
set ctrls_meter_on 0
@@ -75,28 +87,34 @@ checkbutton .controls.switches.meterbutton -text {peak meters} \
pack .controls.switches.meterbutton .controls.switches.audiobutton -side left
-frame .controls.in
-label .controls.in.label -text IN
-entry .controls.in.level -textvariable ctrls_inlevel -width 3
-button .controls.in.clip -text {CLIP} -state disabled
-pack .controls.in.label .controls.in.level .controls.in.clip -side top
-
-frame .controls.out
-label .controls.out.label -text OUT
-entry .controls.out.level -textvariable ctrls_outlevel -width 3
-button .controls.out.clip -text {CLIP} -state disabled
-pack .controls.out.label .controls.out.level .controls.out.clip -side top
+frame .controls.inout
+frame .controls.inout.in
+label .controls.inout.in.label -text IN
+entry .controls.inout.in.level -textvariable ctrls_inlevel -width 3
+button .controls.inout.in.clip -text {CLIP} -state disabled
+pack .controls.inout.in.label .controls.inout.in.level \
+ .controls.inout.in.clip -side top -pady 2
+
+frame .controls.inout.out
+label .controls.inout.out.label -text OUT
+entry .controls.inout.out.level -textvariable ctrls_outlevel -width 3
+button .controls.inout.out.clip -text {CLIP} -state disabled
+pack .controls.inout.out.label .controls.inout.out.level \
+ .controls.inout.out.clip -side top -pady 2
button .controls.dio -text "DIO\nerrors" \
-command {pd [concat pd audiostatus \;]}
-pack .controls.switches -side bottom
-pack .controls.in .controls.out -side left
-pack .controls.dio -side right
+pack .controls.switches -side bottom -pady 12
+pack .controls.inout.in .controls.inout.out -side left -padx 6
+pack .controls.inout -side left -padx 14
+pack .controls.dio -side right -padx 20
bind . <Control-Key> {pdtk_pd_ctrlkey %W %K 0}
bind . <Control-Shift-Key> {pdtk_pd_ctrlkey %W %K 1}
+wm title . "Pd"
+. configure -menu .mbar -width 200 -height 150
############### set up global variables ################################
@@ -136,13 +154,33 @@ set menu_windowlist {}
proc pdtk_fixwindowmenu {} {
global menu_windowlist
- .mbar.windows.menu delete 0 end
+ .mbar.windows delete 0 end
foreach i $menu_windowlist {
- .mbar.windows.menu add command -label [lindex $i 0] \
+ .mbar.windows add command -label [lindex $i 0] \
-command [concat menu_domenuwindow [lindex $i 1]]
+ menu_fixwindowmenu [lindex $i 1]
+ }
+}
+
+####### Odd little function to make better Mac accelerators #####
+
+proc accel_munge {acc} {
+ global pd_nt
+
+ if {$pd_nt == 2} {
+ if [string is upper [string index $acc end]] {
+ return [format "%s%s" "Shift+" \
+ [string toupper [string map {Ctrl Meta} $acc] end]]
+ } else {
+ return [string toupper [string map {Ctrl Meta} $acc] end]
+ }
+ } else {
+ return $acc
}
}
+
+
############### the "New" menu command ########################
proc menu_new {} {
global untitled_number
@@ -248,6 +286,10 @@ proc menu_documentation {} {
exec sh -c \
[format "mozilla file:%s || netscape file:%s &\n" \
$filename $filename]
+ } elseif {$pd_nt == 2} {
+ puts stderr [format "open %s" $filename]
+ exec sh -c \
+ [format "open %s" $filename]
} else {
tk_messageBox -message \
{sorry -- can't open htm files yet; open this manually} \
@@ -278,33 +320,35 @@ proc menu_doc_open {subdir basename} {
}
#################### the "File" menu for the Pd window ##############
-.mbar.file.menu add command -label New -command {menu_new} \
- -accelerator "Ctrl+n"
-.mbar.file.menu add command -label Open -command {menu_open} \
- -accelerator "Ctrl+o"
-.mbar.file.menu add command -label Message -command {menu_send} \
- -accelerator "Ctrl+m"
-.mbar.file.menu add separator
-.mbar.file.menu add command -label Quit -command {menu_quit} \
- -accelerator "Ctrl+q"
+
+.mbar.file add command -label New -command {menu_new} \
+ -accelerator [accel_munge "Ctrl+n"]
+.mbar.file add command -label Open -command {menu_open} \
+ -accelerator [accel_munge "Ctrl+o"]
+.mbar.file add separator
+.mbar.file add command -label Message -command {menu_send} \
+ -accelerator [accel_munge "Ctrl+m"]
+.mbar.file add separator
+.mbar.file add command -label Quit -command {menu_quit} \
+ -accelerator [accel_munge "Ctrl+q"]
#################### the "Find" menu for the Pd window ##############
-.mbar.find.menu add command -label {last error?} -command {menu_finderror}
+.mbar.find add command -label {last error?} -command {menu_finderror}
#################### the "Audio" menu for the Pd window ##############
-.mbar.audio.menu add command -label On -accelerator "Ctrl+/" \
+.mbar.audio add command -label On -accelerator [accel_munge "Ctrl+/"] \
-command {menu_audio 1}
-.mbar.audio.menu add command -label Off -accelerator "Ctrl+." \
+.mbar.audio add command -label Off -accelerator [accel_munge "Ctrl+."] \
-command {menu_audio 0}
#################### the "Help" menu for the Pd window ##############
-.mbar.help.menu add command -label {About Pd} \
+.mbar.help add command -label {About Pd} \
-command {menu_doc_open doc/1.manual 1.introduction.txt}
-.mbar.help.menu add command -label {Test Audio and MIDI} \
+.mbar.help add command -label {Test Audio and MIDI} \
-command {menu_doc_open doc/7.stuff/tools testtone.pd}
-.mbar.help.menu add command -label {Load Meter} \
+.mbar.help add command -label {Load Meter} \
-command {menu_doc_open doc/7.stuff/tools load-meter.pd}
-.mbar.help.menu add command -label {Pure Documentation...} \
+.mbar.help add command -label {Pure Documentation...} \
-command {menu_documentation}
########### functions for menu functions on document windows ########
@@ -320,7 +364,13 @@ proc menu_saveas {name} {
}
proc menu_print {name} {
- $name.c postscript -file x.ps
+ set filename [tk_getSaveFile -initialfile pd.ps \
+ -defaultextension .ps \
+ -filetypes { {{postscript} {.ps}} }]
+
+ if {$filename != ""} {
+ $name.c postscript -file $filename
+ }
}
proc menu_close {name} {
@@ -456,15 +506,16 @@ proc menu_fixeditmenu {name} {
global pd_undocanvas
# puts stderr [concat menu_fixeditmenu $name $pd_undocanvas $pd_undoaction]
if {$name == $pd_undocanvas && $pd_undoaction != "no"} {
- $name.m.edit.m entryconfigure "Undo*" -state normal \
+ $name.m.edit entryconfigure "Undo*" -state normal \
-label [concat "Undo " $pd_undoaction]
} else {
- $name.m.edit.m entryconfigure "Undo*" -state disabled -label "Undo"
+ $name.m.edit entryconfigure "Undo*" -state disabled -label "Undo"
}
if {$name == $pd_undocanvas && $pd_redoaction != "no"} {
- $name.m.edit.m entryconfigure "Redo" -state normal
+ $name.m.edit entryconfigure "Redo*" -state normal\
+ -label [concat "Redo " $pd_redoaction]
} else {
- $name.m.edit.m entryconfigure "Redo" -state disabled
+ $name.m.edit entryconfigure "Redo*" -state disabled
}
}
@@ -477,6 +528,10 @@ proc pdtk_undomenu {name undoaction redoaction} {
set pd_undocanvas $name
set pd_undoaction $undoaction
set pd_redoaction $redoaction
+ if {$name != "nobody"} {
+# unpleasant way of avoiding a more unpleasant bug situation --atl 2002.11.25
+ menu_fixeditmenu $name
+ }
}
proc menu_windowparent {name} {
@@ -497,10 +552,15 @@ proc menu_domenuwindow {i} {
proc menu_fixwindowmenu {name} {
global menu_windowlist
- $name.m.windows.m add command
- $name.m.windows.m delete 4 end
+ global pd_tearoff
+ $name.m.windows add command
+ if $pd_tearoff {
+ $name.m.windows delete 4 end
+ } else {
+ $name.m.windows delete 3 end
+ }
foreach i $menu_windowlist {
- $name.m.windows.m add command -label [lindex $i 0] \
+ $name.m.windows add command -label [lindex $i 0] \
-command [concat menu_domenuwindow [lindex $i 1]]
}
}
@@ -564,9 +624,10 @@ proc menu_findobject {canvas} {
############# pdtk_canvas_new -- create a new canvas ###############
proc pdtk_canvas_new {name width height geometry editable} {
global pd_opendir
-
- toplevel $name
- frame $name.m -relief raised -bd 2
+ global pd_tearoff
+ global pd_nt
+
+ toplevel $name -menu $name.m
# puts stderr [concat geometry: $geometry]
wm geometry $name $geometry
canvas $name.c -width $width -height $height -background white \
@@ -578,7 +639,6 @@ proc pdtk_canvas_new {name width height geometry editable} {
scrollbar $name.scrollhort -command "$name.c xview" \
-orient horizontal
- pack $name.m -side top -fill x
pack $name.scrollhort -side bottom -fill x
pack $name.scrollvert -side right -fill y
pack $name.c -side left -expand 1 -fill both
@@ -586,209 +646,222 @@ proc pdtk_canvas_new {name width height geometry editable} {
wm geometry $name $geometry
# the file menu
- menubutton $name.m.file -text File -menu $name.m.file.m
- pack $name.m.file -side left
- menu $name.m.file.m
-
- $name.m.file.m add command -label New -command {menu_new} \
- -accelerator "Ctrl+n"
+ menu $name.m
+ menu $name.m.file -tearoff $pd_tearoff
+ $name.m add cascade -label File -menu $name.m.file
- $name.m.file.m add command -label Open -command {menu_open} \
- -accelerator "Ctrl+o"
+ $name.m.file add command -label New -command {menu_new} \
+ -accelerator [accel_munge "Ctrl+n"]
- $name.m.file.m add command -label Message -command {menu_send} \
- -accelerator "Ctrl+m"
+ $name.m.file add command -label Open -command {menu_open} \
+ -accelerator [accel_munge "Ctrl+o"]
- $name.m.file.m add separator
- $name.m.file.m add command -label Save -command [concat menu_save $name] \
- -accelerator "Ctrl+s"
+ $name.m.file add separator
+ $name.m.file add command -label Message -command {menu_send} \
+ -accelerator [accel_munge "Ctrl+m"]
- $name.m.file.m add command -label Close \
+ $name.m.file add separator
+ $name.m.file add command -label Close \
-command [concat menu_close $name] \
- -accelerator "Ctrl+w"
+ -accelerator [accel_munge "Ctrl+w"]
+
+ $name.m.file add command -label Save -command [concat menu_save $name] \
+ -accelerator [accel_munge "Ctrl+s"]
- $name.m.file.m add command -label "Save as..." \
+ $name.m.file add command -label "Save as..." \
-command [concat menu_saveas $name] \
- -accelerator "Ctrl+S"
+ -accelerator [accel_munge "Ctrl+S"]
- $name.m.file.m add command -label Print -command [concat menu_print $name] \
- -accelerator "Ctrl+p"
+ $name.m.file add command -label Print -command [concat menu_print $name] \
+ -accelerator [accel_munge "Ctrl+p"]
- $name.m.file.m add separator
+ $name.m.file add separator
- $name.m.file.m add command -label Quit -command {menu_quit} \
- -accelerator "Ctrl+q"
+ $name.m.file add command -label Quit -command {menu_quit} \
+ -accelerator [accel_munge "Ctrl+q"]
# the edit menu
- menubutton $name.m.edit -text Edit -menu $name.m.edit.m
- pack $name.m.edit -side left
- menu $name.m.edit.m -postcommand [concat menu_fixeditmenu $name]
+ menu $name.m.edit -postcommand [concat menu_fixeditmenu $name] -tearoff $pd_tearoff
+ $name.m add cascade -label Edit -menu $name.m.edit
- $name.m.edit.m add command -label Undo -command [concat menu_undo $name] \
- -accelerator "Ctrl+z"
+ $name.m.edit add command -label Undo -command [concat menu_undo $name] \
+ -accelerator [accel_munge "Ctrl+z"]
- $name.m.edit.m add command -label Redo -command [concat menu_redo $name] \
- -accelerator "Ctrl+Z"
+ $name.m.edit add command -label Redo -command [concat menu_redo $name] \
+ -accelerator [accel_munge "Ctrl+Z"]
- $name.m.edit.m add separator
+ $name.m.edit add separator
- $name.m.edit.m add command -label Cut -command [concat menu_cut $name] \
- -accelerator "Ctrl+x"
+ $name.m.edit add command -label Cut -command [concat menu_cut $name] \
+ -accelerator [accel_munge "Ctrl+x"]
- $name.m.edit.m add command -label Copy -command [concat menu_copy $name] \
- -accelerator "Ctrl+c"
+ $name.m.edit add command -label Copy -command [concat menu_copy $name] \
+ -accelerator [accel_munge "Ctrl+c"]
- $name.m.edit.m add command -label Paste \
+ $name.m.edit add command -label Paste \
-command [concat menu_paste $name] \
- -accelerator "Ctrl+v"
+ -accelerator [accel_munge "Ctrl+v"]
- $name.m.edit.m add command -label Duplicate \
+ $name.m.edit add command -label Duplicate \
-command [concat menu_duplicate $name] \
- -accelerator "Ctrl+d"
+ -accelerator [accel_munge "Ctrl+d"]
- $name.m.edit.m add command -label {Select all} \
+ $name.m.edit add command -label {Select all} \
-command [concat menu_selectall $name] \
- -accelerator "Ctrl+a"
+ -accelerator [accel_munge "Ctrl+a"]
- $name.m.edit.m add command -label {Text Editor} \
+ $name.m.edit add separator
+
+ $name.m.edit add command -label {Text Editor} \
-command [concat menu_texteditor $name] \
- -accelerator "Ctrl+t"
+ -accelerator [accel_munge "Ctrl+t"]
- $name.m.edit.m add command -label Font \
+ $name.m.edit add command -label Font \
-command [concat menu_font $name]
- $name.m.edit.m add command -label {Tidy Up} \
+ $name.m.edit add command -label {Tidy Up} \
-command [concat menu_tidyup $name]
- $name.m.edit.m add separator
+ $name.m.edit add separator
############iemlib##################
# instead of "red = #BC3C60" we take "grey85", so there is no difference,
# if widget is selected or not.
- $name.m.edit.m add checkbutton -label "Edit mode" \
+ $name.m.edit add checkbutton -label "Edit mode" \
-indicatoron true -selectcolor grey85 \
-command [concat menu_editmode $name] \
- -accelerator "Ctrl+e"
+ -accelerator [accel_munge "Ctrl+e"]
if { $editable == 0 } {
- $name.m.edit.m entryconfigure "Edit mode" -indicatoron false }
+ $name.m.edit entryconfigure "Edit mode" -indicatoron false }
############iemlib##################
# the put menu
- menubutton $name.m.put -text Put -menu $name.m.put.m
- pack $name.m.put -side left
- menu $name.m.put.m
+ menu $name.m.put -tearoff $pd_tearoff
+ $name.m add cascade -label Put -menu $name.m.put
- $name.m.put.m add command -label Object \
+ $name.m.put add command -label Object \
-command [concat menu_object $name 0] \
- -accelerator "Ctrl+1"
+ -accelerator [accel_munge "Ctrl+1"]
- $name.m.put.m add command -label Message \
+ $name.m.put add command -label Message \
-command [concat menu_message $name 0] \
- -accelerator "Ctrl+2"
+ -accelerator [accel_munge "Ctrl+2"]
- $name.m.put.m add command -label Number \
+ $name.m.put add command -label Number \
-command [concat menu_floatatom $name 0] \
- -accelerator "Ctrl+3"
+ -accelerator [accel_munge "Ctrl+3"]
- $name.m.put.m add command -label Symbol \
+ $name.m.put add command -label Symbol \
-command [concat menu_symbolatom $name 0] \
- -accelerator "Ctrl+4"
+ -accelerator [accel_munge "Ctrl+4"]
- $name.m.put.m add command -label Comment \
+ $name.m.put add command -label Comment \
-command [concat menu_comment $name 0] \
- -accelerator "Ctrl+5"
+ -accelerator [accel_munge "Ctrl+5"]
+
+ $name.m.put add separator
############iemlib##################
- $name.m.put.m add command -label Bang \
+ $name.m.put add command -label Bang \
-command [concat menu_bng $name 0] \
- -accelerator "Alt+b"
+ -accelerator [accel_munge "Alt+b"]
- $name.m.put.m add command -label Toggle \
+ $name.m.put add command -label Toggle \
-command [concat menu_toggle $name 0] \
- -accelerator "Alt+t"
+ -accelerator [accel_munge "Alt+t"]
- $name.m.put.m add command -label Number2 \
+ $name.m.put add command -label Number2 \
-command [concat menu_numbox $name 0] \
- -accelerator "Alt+n"
+ -accelerator [accel_munge "Alt+n"]
- $name.m.put.m add command -label Vslider \
+ $name.m.put add command -label Vslider \
-command [concat menu_vslider $name 0] \
- -accelerator "Alt+v"
+ -accelerator [accel_munge "Alt+v"]
- $name.m.put.m add command -label Hslider \
+ $name.m.put add command -label Hslider \
-command [concat menu_hslider $name 0] \
- -accelerator "Alt+h"
+ -accelerator [accel_munge "Alt+h"]
- $name.m.put.m add command -label Vradio \
+ $name.m.put add command -label Vradio \
-command [concat menu_vradio $name 0] \
- -accelerator "Alt+d"
+ -accelerator [accel_munge "Alt+d"]
- $name.m.put.m add command -label Hradio \
+ $name.m.put add command -label Hradio \
-command [concat menu_hradio $name 0] \
- -accelerator "Alt+i"
+ -accelerator [accel_munge "Alt+i"]
- $name.m.put.m add command -label VU \
+ $name.m.put add command -label VU \
-command [concat menu_vumeter $name 0] \
- -accelerator "Alt+u"
+ -accelerator [accel_munge "Alt+u"]
- $name.m.put.m add command -label Canvas \
+ $name.m.put add command -label Canvas \
-command [concat menu_mycnv $name 0] \
- -accelerator "Alt+c"
+ -accelerator [accel_munge "Alt+c"]
############iemlib##################
- $name.m.put.m add command -label Graph \
+ $name.m.put add separator
+
+ $name.m.put add command -label Graph \
-command [concat menu_graph $name]
- $name.m.put.m add command -label Array \
+ $name.m.put add command -label Array \
-command [concat menu_array $name]
# the find menu
- menubutton $name.m.find -text Find -menu $name.m.find.m
- pack $name.m.find -side left
- menu $name.m.find.m
- $name.m.find.m add command -label {Find...} -accelerator "Ctrl+f" \
+ menu $name.m.find -tearoff $pd_tearoff
+ $name.m add cascade -label Find -menu $name.m.find
+
+ $name.m.find add command -label {Find...} \
+ -accelerator [accel_munge "Ctrl+f"] \
-command [concat menu_findobject $name]
- $name.m.find.m add command -label {Find Again} -accelerator "Ctrl+g" \
+ $name.m.find add command -label {Find Again} \
+ -accelerator [accel_munge "Ctrl+g"] \
-command [concat menu_findagain $name]
- $name.m.find.m add command -label {Find last error} \
+ $name.m.find add command -label {Find last error} \
-command [concat menu_finderror]
# the window menu
- menubutton $name.m.windows -text Windows -menu $name.m.windows.m
- pack $name.m.windows -side left
- menu $name.m.windows.m -postcommand [concat menu_fixwindowmenu $name]
- $name.m.windows.m add command -label {parent window}\
+ menu $name.m.windows -postcommand [concat menu_fixwindowmenu $name] \
+ -tearoff $pd_tearoff
+
+ $name.m.windows add command -label {parent window}\
-command [concat menu_windowparent $name]
- $name.m.windows.m add command -label {Pd window} -command menu_pop_pd
- $name.m.windows.m add separator
+ $name.m.windows add command -label {Pd window} -command menu_pop_pd
+ $name.m.windows add separator
# the audio menu
- menubutton $name.m.audio -text Audio -menu $name.m.audio.m
- pack $name.m.audio -side left
- menu $name.m.audio.m
- $name.m.audio.m add command -label On -accelerator "Ctrl+/" \
+ menu $name.m.audio -tearoff $pd_tearoff
+
+ $name.m.audio add command -label On -accelerator [accel_munge "Ctrl+/"] \
-command {menu_audio 1}
- $name.m.audio.m add command -label Off -accelerator "Ctrl+." \
+ $name.m.audio add command -label Off -accelerator [accel_munge "Ctrl+."] \
-command {menu_audio 0}
+ if {$pd_nt != 2} {
+ $name.m add cascade -label Windows -menu $name.m.windows
+ $name.m add cascade -label Audio -menu $name.m.audio
+ } else {
+ $name.m add cascade -label Audio -menu $name.m.audio
+ $name.m add cascade -label Window -menu $name.m.windows
+ }
+
# the help menu
- menubutton $name.m.help -text Help -menu $name.m.help.m
- pack $name.m.help -side right
- menu $name.m.help.m
- $name.m.help.m add command -label {Getting Started} \
+ menu $name.m.help -tearoff $pd_tearoff
+ $name.m add cascade -label Help -menu $name.m.help
+ $name.m.help add command -label {Getting Started} \
-command {menu_doc_open doc/1.manual 1.introduction.txt}
- $name.m.help.m add command -label {Test Audio and MIDI} \
+ $name.m.help add command -label {Test Audio and MIDI} \
-command {menu_doc_open doc/7.stuff/tools testtone.pd}
- $name.m.help.m add command -label {Load Meter} \
+ $name.m.help add command -label {Load Meter} \
-command {menu_doc_open doc/7.stuff/tools load-meter.pd}
- $name.m.help.m add command -label {Pure Documentation} \
+ $name.m.help add command -label {Pure Documentation} \
-command {menu_documentation}
# the popup menu
@@ -813,13 +886,20 @@ proc pdtk_canvas_new {name width height geometry editable} {
bind $name.c <Button> {pdtk_canvas_click %W %x %y %b 0}
bind $name.c <Shift-Button> {pdtk_canvas_click %W %x %y %b 1}
- bind $name.c <Control-Button> {pdtk_canvas_click %W %x %y %b 2}
bind $name.c <Control-Shift-Button> {pdtk_canvas_click %W %x %y %b 3}
bind $name.c <Alt-Button> {pdtk_canvas_click %W %x %y %b 4}
bind $name.c <Alt-Shift-Button> {pdtk_canvas_click %W %x %y %b 5}
bind $name.c <Alt-Control-Button> {pdtk_canvas_click %W %x %y %b 6}
bind $name.c <Alt-Control-Shift-Button> {pdtk_canvas_click %W %x %y %b 7}
- bind $name.c <Button-3> {pdtk_canvas_click %W %x %y %b 8}
+ global pd_nt
+ if {$pd_nt == 2} {
+ bind $name.c <Button-2> {pdtk_canvas_click %W %x %y %b 8}
+ bind $name.c <Control-Button> {pdtk_canvas_click %W %x %y %b 8}
+ } else {
+ bind $name.c <Button-3> {pdtk_canvas_click %W %x %y %b 8}
+ bind $name.c <Control-Button> {pdtk_canvas_click %W %x %y %b 2}
+ }
+# change mac to right-click, not middle click -atl 2002.09.02
bind $name.c <ButtonRelease> {pdtk_canvas_mouseup %W %x %y %b}
bind $name.c <Control-Key> {pdtk_canvas_ctrlkey %W %K 0}
@@ -2460,9 +2540,9 @@ proc pdtk_data_dialog {name stuff} {
#####################iemlib#######################
proc pdtk_canvas_editval {name value} {
if { $value } {
- $name.m.edit.m entryconfigure "Edit mode" -indicatoron true
+ $name.m.edit entryconfigure "Edit mode" -indicatoron true
} else {
- $name.m.edit.m entryconfigure "Edit mode" -indicatoron false
+ $name.m.edit entryconfigure "Edit mode" -indicatoron false
}
}
#####################iemlib#######################
@@ -2551,15 +2631,15 @@ proc pdtk_pd_meters {indb outdb inclip outclip} {
global ctrls_inlevel ctrls_outlevel
set ctrls_inlevel $indb
if {$inclip == 1} {
- .controls.in.clip configure -background red
+ .controls.inout.in.clip configure -background red
} else {
- .controls.in.clip configure -background grey
+ .controls.inout.in.clip configure -background grey
}
set ctrls_outlevel $outdb
if {$outclip == 1} {
- .controls.out.clip configure -background red
+ .controls.inout.out.clip configure -background red
} else {
- .controls.out.clip configure -background grey
+ .controls.inout.out.clip configure -background grey
}
}
diff --git a/pd/src/u_pdreceive.c b/pd/src/u_pdreceive.c
index c01be01c..ad71f506 100644
--- a/pd/src/u_pdreceive.c
+++ b/pd/src/u_pdreceive.c
@@ -47,7 +47,7 @@ int main(int argc, char **argv)
int portno;
struct sockaddr_in server;
int nretry = 10;
-#ifdef NT
+#ifdef MSW
short version = MAKEWORD(2, 0);
WSADATA nobby;
#endif
@@ -62,7 +62,7 @@ int main(int argc, char **argv)
else goto usage;
}
else protocol = SOCK_STREAM;
-#ifdef NT
+#ifdef MSW
if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
#endif
sockfd = socket(AF_INET, protocol, 0);
@@ -77,7 +77,7 @@ int main(int argc, char **argv)
#ifdef IRIX
/* this seems to work only in IRIX but is unnecessary in
- Linux. Not sure what NT needs in place of this. */
+ Linux. Not sure what MSW needs in place of this. */
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, 0, 0) < 0)
post("setsockopt failed\n");
#endif
@@ -299,7 +299,7 @@ static void dopoll(void)
static void sockerror(char *s)
{
-#ifdef NT
+#ifdef MSW
int err = WSAGetLastError();
if (err == 10054) return;
else if (err == 10044)
@@ -319,7 +319,7 @@ static void x_closesocket(int fd)
#ifdef UNIX
close(fd);
#endif
-#ifdef NT
+#ifdef MSW
closesocket(fd);
#endif
}
diff --git a/pd/src/u_pdsend.c b/pd/src/u_pdsend.c
index 896c5646..de9488b0 100644
--- a/pd/src/u_pdsend.c
+++ b/pd/src/u_pdsend.c
@@ -31,7 +31,7 @@ int main(int argc, char **argv)
struct hostent *hp;
char *hostname;
int nretry = 10;
-#ifdef NT
+#ifdef MSW
short version = MAKEWORD(2, 0);
WSADATA nobby;
#endif
@@ -49,7 +49,7 @@ int main(int argc, char **argv)
else goto usage;
}
else protocol = SOCK_STREAM;
-#ifdef NT
+#ifdef MSW
if (WSAStartup(version, &nobby)) sockerror("WSAstartup");
#endif
@@ -131,7 +131,7 @@ usage:
void sockerror(char *s)
{
-#ifdef NT
+#ifdef MSW
int err = WSAGetLastError();
if (err == 10054) return;
else if (err == 10044)
@@ -151,7 +151,7 @@ void x_closesocket(int fd)
#ifdef UNIX
close(fd);
#endif
-#ifdef NT
+#ifdef MSW
closesocket(fd);
#endif
}
diff --git a/pd/src/x_arithmetic.c b/pd/src/x_arithmetic.c
index f975f542..b7a94a2d 100644
--- a/pd/src/x_arithmetic.c
+++ b/pd/src/x_arithmetic.c
@@ -10,8 +10,8 @@ inputs to int and their outputs back to float. */
#include <math.h>
-/* NT and OSX don't appear to have single-precision ANSI math */
-#if defined(NT) || defined(MACOSX)
+/* MSW and OSX don't appear to have single-precision ANSI math */
+#if defined(MSW) || defined(MACOSX)
#define sinf sin
#define cosf cos
#define atanf atan
@@ -636,7 +636,7 @@ static void *exp_new(void)
static void exp_float(t_object *x, t_float f)
{
float g;
-#ifdef NT
+#ifdef MSW
char buf[10];
#endif
if (f > MAXLOG) f = MAXLOG;
@@ -665,7 +665,6 @@ static t_class *clip_class;
typedef struct _clip
{
t_object x_ob;
- t_outlet *x_out2;
float x_f1;
float x_f2;
} t_clip;
@@ -676,7 +675,6 @@ static void *clip_new(t_floatarg f1, t_floatarg f2)
floatinlet_new(&x->x_ob, &x->x_f1);
floatinlet_new(&x->x_ob, &x->x_f2);
outlet_new(&x->x_ob, &s_float);
- x->x_out2 = outlet_new(&x->x_ob, &s_float);
x->x_f1 = f1;
x->x_f2 = f2;
return (x);
diff --git a/pd/src/x_midi.c b/pd/src/x_midi.c
index f7d6529f..7eac1108 100644
--- a/pd/src/x_midi.c
+++ b/pd/src/x_midi.c
@@ -611,8 +611,8 @@ static void *midirealtimein_new( void)
x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
pd_bind(&x->x_obj.ob_pd, midirealtimein_sym);
-#ifndef NT
- pd_error(x, "midirealtimein: works under NT only");
+#ifndef MSW
+ pd_error(x, "midirealtimein: works under MSW only");
#endif
return (x);
}
diff --git a/pd/src/x_misc.c b/pd/src/x_misc.c
index 8ba5191f..cd9771b0 100644
--- a/pd/src/x_misc.c
+++ b/pd/src/x_misc.c
@@ -4,7 +4,8 @@
/* misc. */
-#include "m_imp.h"
+#include "m_pd.h"
+#include "s_stuff.h"
#include <math.h>
#include <stdio.h>
#include <string.h>
@@ -14,7 +15,7 @@
#include <sys/times.h>
#include <sys/param.h>
#endif
-#ifdef NT
+#ifdef MSW
#include <wtypes.h>
#include <time.h>
#endif
@@ -140,7 +141,7 @@ static void namecanvas_setup(void)
sizeof(t_namecanvas), CLASS_NOINLET, A_DEFSYM, 0);
}
-/* ---------------serial ports (NT only -- hack) ------------------------- */
+/* ---------------serial ports (MSW only -- hack) ------------------------- */
#define MAXSERIAL 100
static t_class *serial_class;
@@ -192,7 +193,7 @@ typedef struct _cputime
#ifdef UNIX
struct tms x_setcputime;
#endif
-#ifdef NT
+#ifdef MSW
LARGE_INTEGER x_kerneltime;
LARGE_INTEGER x_usertime;
int x_warned;
@@ -204,7 +205,7 @@ static void cputime_bang(t_cputime *x)
#ifdef UNIX
times(&x->x_setcputime);
#endif
-#ifdef NT
+#ifdef MSW
FILETIME ignorethis, ignorethat;
BOOL retval;
retval = GetProcessTimes(GetCurrentProcess(), &ignorethis, &ignorethat,
@@ -231,7 +232,7 @@ static void cputime_bang2(t_cputime *x)
x->x_setcputime.tms_utime - x->x_setcputime.tms_stime) / HZ;
outlet_float(x->x_obj.ob_outlet, elapsedcpu);
#endif
-#ifdef NT
+#ifdef MSW
float elapsedcpu;
FILETIME ignorethis, ignorethat;
LARGE_INTEGER usertime, kerneltime;
@@ -254,7 +255,7 @@ static void *cputime_new(void)
outlet_new(&x->x_obj, gensym("float"));
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("bang"), gensym("bang2"));
-#ifdef NT
+#ifdef MSW
x->x_warned = 0;
#endif
cputime_bang(x);
diff --git a/pd/src/x_net.c b/pd/src/x_net.c
index d14538e7..416b5bc6 100644
--- a/pd/src/x_net.c
+++ b/pd/src/x_net.c
@@ -4,7 +4,8 @@
/* network */
-#include "m_imp.h"
+#include "m_pd.h"
+#include "s_stuff.h"
#include <sys/types.h>
#include <string.h>
diff --git a/pd/src/x_qlist.c b/pd/src/x_qlist.c
index 922cfe12..7dbec5e7 100644
--- a/pd/src/x_qlist.c
+++ b/pd/src/x_qlist.c
@@ -7,7 +7,7 @@
#ifdef UNIX
#include <unistd.h>
#endif
-#ifdef NT
+#ifdef MSW
#include <io.h>
#endif